Skip to content

fix: skip the generated package.json when the root type matches - #957

Open
mrousavy wants to merge 1 commit into
callstack:mainfrom
mrousavy:fix/skip-matching-package-type
Open

mrousavy wants to merge 1 commit into
callstack:mainfrom
mrousavy:fix/skip-matching-package-type

Conversation

@mrousavy

Copy link
Copy Markdown
Contributor

Summary

With esm: true, Bob writes {"type": "module"} to lib/module/package.json and lib/typescript/package.json, and {"type": "commonjs"} for CommonJS output. Node.js, TypeScript and Metro read the imports field from the closest package.json, so a library that uses subpath imports breaks after it's built:

  • Node.js: ERR_PACKAGE_IMPORT_NOT_DEFINED: Package import specifier "#internal/helper" is not defined in package .../lib/module/package.json
  • TypeScript: TS2307: Cannot find module '#internal/helper' or its corresponding type declarations.
  • Metro: The path for #internal/helper could not be resolved.

Setting "type": "module" in the root package.json doesn't help today because Bob writes the file anyway. With this change, Bob skips it when the root type has the same value and the output folder is inside the project, since the built files already get that module type from the root. If Bob still has to write the file and the root package.json has a non-empty imports field, it prints a warning.

Copying imports into the generated file isn't a general fix: targets outside the output folder would need ../, which Node.js, TypeScript and Metro all reject.

Libraries without a root type (the create-react-native-library default) get the same output as before. For libraries that set it, other root fields such as sideEffects now apply to the built files too, as they already do with esm: false. In a dual package setup the CommonJS build still gets its package.json, so subpath imports only work in the ESM build. The ESM docs have a new section about this.

Test plan

  • yarn lint, yarn typecheck and yarn test pass. There are new tests for the helper (including an empty imports field and an output folder outside the project), plus 2 tests in typescript.test.ts that fail without this change.
  • I built 13 fixture libraries with Bob from main and from this branch: ESM-only, dual, CommonJS-only, esm: false and legacy targets, with the root type unset, module or commonjs, with and without imports. The only output difference is the missing package.json where the root type matches.
  • I packed each fixture, installed it in a consumer project and checked it with Node.js 24 (import and require), TypeScript 6.0.3 and 7.0.2 (bundler and node16), Metro 0.87.1 (iOS and Android), esbuild 0.28.2 and webpack 5.111.1. Fixtures without imports behave the same as on main. With "type": "module" and imports, every check passes, including a .cjs target outside lib.

Bob writes a package.json with a `type` field to output folders such as
lib/module and lib/typescript. That file starts a new package scope.
Node.js, TypeScript and Metro resolve the `imports` field from the
closest package.json, so subpath imports used in the source fail to
resolve in the built files.

When the root package.json already has the same `type`, the generated
file isn't needed, so skip it. Also warn when the file is generated and
the root package.json has an `imports` field.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant