diff --git a/package.json b/package.json index 25e6478..47d020f 100644 --- a/package.json +++ b/package.json @@ -56,8 +56,7 @@ }, "dependencies": { "@jitl/quickjs-singlefile-mjs-release-sync": "^0.32.0", - "quickjs-emscripten-core": "^0.32.0", - "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz" + "quickjs-emscripten-core": "^0.32.0" }, "devDependencies": { "@eslint/js": "^10.0.1", @@ -79,7 +78,8 @@ "vitest": "^5.0.5", "vue": "^3.5.44", "vue-eslint-parser": "^10.4.1", - "vue-tsc": "^3.3.13" + "vue-tsc": "^3.3.13", + "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz" }, "keywords": [ "guichat", diff --git a/plans/fix-193-xlsx-dev-dependency.md b/plans/fix-193-xlsx-dev-dependency.md new file mode 100644 index 0000000..6ed5e92 --- /dev/null +++ b/plans/fix-193-xlsx-dev-dependency.md @@ -0,0 +1,18 @@ +# xlsx を devDependencies に移す(#193) + +## 問題 +- `xlsx` を `dependencies` に SheetJS の配布サイトの URL で書いていた。npm 12 は初期設定(`allow-remote=none`)で URL からの取得を拒むため、このパッケージに依存するものはすべてインストールに失敗する(`mulmoclaude@2.8.0` で確認) + +## 方針 +- `vite.config.ts` の `external` に `xlsx` は入っていないので、SheetJS はビルド時に `dist/vue.js` / `dist/vue.cjs` に取り込まれている。使う側に `xlsx` は要らない +- `xlsx` を `devDependencies` に移す(ビルドには要る)。URL の指定はそのまま +- `tests/core/test_packageManifest.ts`:`dependencies` / `peerDependencies` / `optionalDependencies` に、URL・git・`file:`・`owner/repo` 形式の指定があれば落ちる + +## 公開 +- 5.0.1 を `main` から出す +- `mulmoclaude@2.8.0` は `^4.3.0` で指定しているので、4.3.0 のタグから 4.x の枝を切って同じ変更で 4.3.1 を出す(`latest` を動かさないよう `--tag` 付きで公開) + +## 確かめたこと +- 変更前後の `package.json` でビルドした `dist/` が完全に一致する +- `npm pack` した物を npm 12.0.2・空の設定でインストールでき、`xlsx` は入らず、`.`・`./vue`・`./core` が読み込める(`./vue` は `require` でも) +- テストは変更前の `package.json` で落ちる diff --git a/tests/core/test_packageManifest.ts b/tests/core/test_packageManifest.ts new file mode 100644 index 0000000..ae886a5 --- /dev/null +++ b/tests/core/test_packageManifest.ts @@ -0,0 +1,31 @@ +import { describe, it } from "node:test"; +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; + +const manifest: unknown = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8")); + +const isRecord = (value: unknown): value is Record => typeof value === "object" && value !== null && !Array.isArray(value); + +const runtimeRanges = (field: string): [string, unknown][] => { + const ranges = isRecord(manifest) ? manifest[field] : undefined; + return isRecord(ranges) ? Object.entries(ranges) : []; +}; + +// npm 12 refuses URL, git and file specs by default, so one in a published runtime field fails every consumer's install. +const NON_REGISTRY_SPEC = /^(?!npm:)(?:[a-z][a-z0-9+.-]*:|[^@\s/]+\/\S+$)/i; + +describe("package.json", () => { + ["dependencies", "peerDependencies", "optionalDependencies"].forEach((field) => { + it(`${field} resolve from the registry`, () => { + const offRegistry = runtimeRanges(field).filter(([, spec]) => typeof spec !== "string" || NON_REGISTRY_SPEC.test(spec)); + assert.deepEqual(offRegistry, []); + }); + }); + + it("recognises the specs npm 12 refuses", () => { + ["https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", "git+https://github.com/a/b.git", "github:a/b", "file:../x", "a/b"].forEach((spec) => + assert.ok(NON_REGISTRY_SPEC.test(spec), spec), + ); + ["^0.32.0", "~6.0.3", ">=1 <2", "1.2.3", "*", "latest", "npm:@scope/pkg@^1"].forEach((spec) => assert.ok(!NON_REGISTRY_SPEC.test(spec), spec)); + }); +});