Secretlint v7.0.0をリリースしました。Pure ESMへの書き直し
機密情報をLintできるSecretlintのv7.0.0をリリースしました!
このバージョンでは、SecretlintをESMモジュールとして書き直しました。
どのように移行したかは別の記事で紹介しているので、移行方法について記事を参照してください
Secretlint v7.0.0の変更点
ルールと本体のコードを含めて、全部のパッケージをESMに書き直しました。 その中で、いろいろ整理したりもしたので、変更点はいろいろあります。
ただし、secretlint
コマンドや@secretlint/quick-start
、Docker Imageとして使う場合は、そこまで目にみえる変化は少ないと思います。
詳細はリリースノートも参照してください。
Breaking Changes
- Node.js 18+を必要とするようになりました
- これはパッケージのコードをES2022形式で出力するようにしたためです。
- Node.js 14は2023年4月でEOL、Node.js 16は2023年9月でEOLなので、Node.js 18を使うことをおすすめします
- nodejs/Release: Node.js Release Working Group
- Docker ImageのBase ImageをNode.js 18に更新しました
- Exit Statusがあまり明確になっていなかったのを整理しました。
- 基本的には次のようなExit Statusを返すようになりました
0
: Lintに成功し、問題なし1
: Lintに失敗し、問題がある2
: クラッシュするなどのプログラム的な問題がある
- “json” formatterがtextlintの流用だったのを、secretlintように変更しました
- jsonの形式が変わっています
- パッケージをCommonJSからPure ESM packageへ変更しました
- PRs:
- コアとルールをそれぞれ分けて移行しました。
- どうやって過程を段階的に移行したかについてはCommonJSからES Modulesへの移行する方法。トップダウンかボトムアップかで紹介します
@secretlint/types
をDual Packageにしました@secretlint/types
はルールを書くのに必要な型情報をまとめたパッケージです- Dual CommonJS/ES module packagesはCJSとESMどちらからもimportできるパッケージです
- そのため
@secretlint/types
だけは CJS and ESM どちらからでも利用できます。
@secretlint/tester
をESMに書き直して、node:test
ベースにしました- 今まではMochaをベースにしていましたが、Node.js Test runnerを使うことで、Mochaに依存しないようにしました
node:test
はMochaと違ってAsync Describeのようなこともできるため、テストフレームワークを作るテストフレームワークとして便利です。
@secretlint/types
と @secretlint/tester
の変更はちょっとわかりにくいですが、
簡単に言えば、SecretlintのルールをCJSとESMどちらでも書けるようにするための工夫です。
CJSからESMのパッケージを読み込むには、読み込むパッケージがDual Packageになっている必要があります。 一つだけ例外があり、Dynamic Importを使うとCJSからESMのパッケージを読み込むことができます。
ルールを書く際に、types
とtester
は基本的に必要になります。(それ以外は依存しなくても大丈夫です)
@secretlint/types
はDual Packageなので、CJSからESMのパッケージを読み込むことができます@secretlint/tester
はPure ESM Packageなので、Dynamic Importを使うとCJSからも利用できます。
つまり、次のように書けば、ルール自体はCJSのままでも@secretlint/tester
でテストが実行できます。
CommonJS Edition:
- const { snapshot } = require()"@secretlint/tester");
const path = require("path");
const { creator: rule } = require("../src/index");
+ const test = require("node:test");
- describe("@secretlint/secretlint-rule-example", () => {
+ test("@secretlint/secretlint-rule-example", async (t) => {
+ const snapshot = (await import("@secretlint/tester")).snapshot;
- snapshot({
+ await snapshot({
defaultConfig: {
rules: [
{
id: "@secretlint/secretlint-rule-preset-canary",
rule,
rules: [],
options: {},
},
],
},
updateSnapshot: !!process.env.UPDATE_SNAPSHOT,
snapshotDirectory: path.join(__dirname, "snapshots"),
}).forEach((name, test) => {
- it(name, async function () {
+ return it(name, async (context) => {
const status = await test();
if (status === "skip") {
- this.skip();
+ context.skip();
}
});
});
});
もちろん、ルールはESMでも書けるので、次のようにESMでテストを書くこともできます。 (基本はESMが推奨です)
import test from "node:test";
import { snapshot } "@secretlint/teter";
import { creator as rule } from "../src/index.js";
test("@secretlint/secretlint-rule-example", async (t) => {
return snapshot({
defaultConfig: {
rules: [
{
id: "@secretlint/secretlint-rule-example",
rule,
options: {},
},
],
},
updateSnapshot: !!process.env.UPDATE_SNAPSHOT,
snapshotDirectory: new URL("snapshots", import.meta.url),
}).forEach((name, test) => {
return t.test(name, async (context) => {
const status = await test();
if (status === "skip") {
context.skip();
}
});
});
});
Node.js Test runnerの場合は、node --test
を使ってテストを実行できます。
--loader ts-node/esm
を使うことで、TypeScriptで書いたESMのテストを実行できます。
$ node --test test/index.test.js
# or
$ node --loader ts-node/esm --test test/index.test.ts
詳しくは https://github.com/secretlint/secretlint/blob/master/docs/secretlint-rule.md を参照してください。
なんでこんなわざわざ面倒なことしてるかというと、ルールを書くのはユーザーなので、最小限の変更で移行できるようにするためです。 SecretlintのルールはCJSとESMどちらで書いたものでも動作するので、実際に移行が必要なのはテストのエントリーポイントぐらいです。
Secretlintのリポジトリはmonorepoになっていて、Secretlint自体とルールが両方含まれています。 ESMへの移行を段階的にやる方法を模索するときに、まずは本体を移行して、ルールはそのまま(CJS)で後から移行するという方法を試してみました。 その結果生まれたのが、今回の変更です。
この辺の過程については、次の記事にまとめています。
ESMに移行した理由
特にないです。長期的には移行しないといけないので移行しました。
Secretlintは、ライブラリではなくツールなので、あまり深く考えずにESMへ移行しました。
Secretllintは元からブラウザで動いていたので、ESMにしたことでの短期的なメリットはあまりないと思います。 (Top-Level awaitで利用できるとかちょっとしたメリットはあります)
ただ、sindresorhusパッケージなどPure ESMなライブラリは、ESMに移行しないと使いにくいという問題があるので、それが解決できたのは良かったです。
また、移行する過程でnode:test
やutil.parseArgs
などのNode.jsの新しい機能を使いました。
これらを使うことで外部依存が減らせたのは結構良かったです。
実際の移行作業はスクリプトやeslint-cjs-to-esmを使って9割ぐらいは自動化できました。
Secretlintのリポジトリのmonorepoは30-40ぐらいのパッケージがあるので、とにかく数の問題でした。 この数をどうやって切り分けるかについては、次の記事にまとめています。
Secretlint v7でCJSからESMへと移行しましたが、ベンチマーク的にはほとんど変わらなかったです。
お知らせ欄
JavaScript Primerの書籍版がAmazonで購入できます。
JavaScriptに関する最新情報は週一でJSer.infoを更新しています。
GitHub Sponsorsでの支援を募集しています。