chore: update package.json scripts and add pack-smoke script - #319
Draft
shinagawa-web wants to merge 5 commits into
Draft
shinagawa-web wants to merge 5 commits into
shinagawa-web wants to merge 5 commits into
Conversation
shinagawa-web
marked this pull request as draft
September 3, 2026 08:58
…ints
src/index.ts unconditionally re-exported ./msw, and src/express/index.ts
imported shared types via the root barrel ("../index") instead of "../core".
Because tsup bundles re-exports per entrypoint, this meant both the root
package and @notainc/typed-api-spec/express required msw at runtime even
for consumers who never touch mocking, crashing with "Cannot find module
'msw'" when it wasn't installed. Root no longer re-exports msw helpers
(use @notainc/typed-api-spec/msw directly), and express now imports its
shared types straight from core.
package.json exports declared a single "types" key shared by both the require and import conditions, so ESM consumers under moduleResolution node16/nodenext always resolved to the CJS-flavored .d.ts. tsup already emits a matching .d.mts per entrypoint, but nothing referenced it. Nest "types" under "require"/"import" so each module system gets its own declaration file, fixing attw's "Masquerading as CJS" finding for every subpath under node16 (from ESM).
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概要
配布物(npm publish後に実際にユーザーが受け取るファイル)がCIで検証されていなかったため、
exportsの設定ミスや、一部エントリポイントが特定の依存を無条件に必要としてしまう不具合が、これまで誰にも気づかれずに存在していました。今回、実際にtarballをpack→隔離環境にinstallしてrequire/import両方を検証する
test:pack-smokeと、exportsのtypes解決の正しさを静的に検証するtest:attw(@arethetypeswrong/cli)の2つのチェックをCIに追加し、それによって検出された問題を修正します。見つかった問題と対応
1.
.(root)と/expressが、msw未インストール環境で実際にクラッシュする現象:
mswを一切使わないユーザーが@notainc/typed-api-specや@notainc/typed-api-spec/expressをimport/requireしただけで、Cannot find module 'msw'で例外が発生する。原因:
src/index.tsが./mswの関数(newMswHttp等)を無条件に re-export していました。mswはテスト用のモックライブラリで、本来は使う人だけが@notainc/typed-api-spec/mswを明示的にimportすべきものです。加えてsrc/express/index.tsが共有の型を"../index"(root barrel)経由でimportしていたため、tsupがバンドルする際に express のエントリポイントにも root 全体(=msw依存込み)が引き込まれていました。結果として、msw を使う予定がまったくない利用者でも、root か express のどちらかを触った瞬間にmswパッケージのインストールを強制される状態になっていました。対応:
src/index.tsから./mswの re-export を削除(@notainc/typed-api-spec/mswから直接importする形に一本化)。src/express/index.tsは共有型の参照元を"../index"から"../core"に変更し、root全体を引き込まないようにしました。影響(破壊的変更):
import { newMswHttp } from "@notainc/typed-api-spec"としていた利用者はimport { newMswHttp } from "@notainc/typed-api-spec/msw"への変更が必要です。中身は同一なのでimport元を変えるだけで済みます。2. 全サブパスで、ESM向けの型定義(
.d.mts)がexportsから参照されておらず、node16 (from ESM)解決で型が壊れている現象:
moduleResolution: "node16"/"nodenext"の設定で、かつESM側(import)からこのパッケージを使うTypeScriptプロジェクトでは、本来ESM向けに生成されているはずの型定義ファイルではなく、CJS向けの型定義ファイルが解決されてしまう(attwの分類では🎭 Masquerading as CJS)。すぐに型エラーになるとは限りませんが、CJSとESMで型の解釈が食い違う場合に実行時と型情報がズレる潜在的なリスクがあります。原因:
package.jsonのexportsフィールドで、各サブパスのtypesがrequire/importの中に入れ子になっておらず、1つの共通キーとして書かれていました。この書き方だと、TypeScriptはCJSとESMのどちらから解決する場合でも同じ
types(CJS向けの.d.ts)を使ってしまいます。tsupは元々ESM向けの.d.mtsも生成していたのですが、exportsがそれを一度も参照していなかったため、生成されているのに使われない状態でした。対応:
typesをrequire/importそれぞれの内側に移動し、ESM側は対応する.d.mtsを参照するように修正しました。影響: 利用者側の対応は不要です(型解決が正しくなる方向の修正のみ)。
3.
/fetchと/jsonで、CJS側のdefault exportの型と実体が食い違っている現象:
node16 (from CJS)解決で❗️ Incorrect default exportが検出される。原因:
FetchT(/fetch)とJSONT(/json)はどちらもTypeScriptの型エイリアスであり、ランタイム上の値を持ちません。にもかかわらずソースではexport default FetchT;という値エクスポートの構文で書かれています。TypeScriptはこれをコンパイルできてしまい、.d.tsにはtype FetchT as defaultという記述が生成されますが、ビルド後の実際のJSファイルには(値が存在しないため)defaultというキー自体が一切出力されません。型定義は「defaultエクスポートがある」と主張しているのに、実体には存在しない、という食い違いです。対応:
FetchT・JSONTをexport defaultではなく named type export(export type { FetchT }等)に変更します。影響(破壊的変更):
import JSONT from "@notainc/typed-api-spec/json"としていた利用者(examples/miscに実例あり)はimport type { JSONT } from "@notainc/typed-api-spec/json"への変更が必要です(JSONTはランタイム値を持たない型なので、import { JSONT }ではなくimport typeを使うのが正しい書き方です)。実行時の挙動は変わらず、コンパイル時のimport構文の修正のみで済みます。