Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug?]: pnpEnableEsmLoader prevents most file extensions from loading as CJS #3782

Closed
1 task done
kherock opened this issue Nov 22, 2021 · 0 comments · Fixed by #3832
Closed
1 task done

[Bug?]: pnpEnableEsmLoader prevents most file extensions from loading as CJS #3782

kherock opened this issue Nov 22, 2021 · 0 comments · Fixed by #3832
Labels
bug Something isn't working esm

Comments

@kherock
Copy link
Contributor

kherock commented Nov 22, 2021

Self-service

  • I'd be willing to implement a fix

Describe the bug

#3667 fixes import() from CJS contexts by unconditionally initializing the PnP ESM loader. Because --experimental-loader is always passed, it encounters the issue nodejs/node#33226 where Node's default loader method (defaultGetFormat/defaultLoad) only allows .js, .cjs, and .mjs extensions. This ultimately prevents developers from writing entrypoints written in TypeScript or any other language that uses an extension outside of Yarn's whitelist

To reproduce

yarn init -2
yarn set version canary
yarn config set pnpEnableEsmLoader true
yarn install
echo 'console.log(require.resolve)' > entrypoint.ts

Normally, Node can load the file just fine (even with the .ts extension!)

$ node entrypoint.ts
[Function: resolve] { paths: [Function: paths] }

However, passing yarn's PnP ESM loader produces

$ yarn node entrypoint.ts
(node:78007) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/herockk/Workspaces/yarn-esm-loader-entrypoint/entrypoint.ts
    at new NodeError (node:internal/errors:371:5)
    at Object.file: (node:internal/modules/esm/get_format:72:15)
    at defaultGetFormat (node:internal/modules/esm/get_format:85:38)
    at defaultLoad (node:internal/modules/esm/load:13:42)
    at load$1 (file:///Users/herockk/Workspaces/yarn-esm-loader-entrypoint/.pnp.loader.mjs:166:12)
    at ESMLoader.load (node:internal/modules/esm/loader:303:26)
    at ESMLoader.moduleProvider (node:internal/modules/esm/loader:230:58)
    at new ModuleJob (node:internal/modules/esm/module_job:63:26)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:244:11)
    at async Promise.all (index 0) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}

Environment

System:
    OS: macOS 11.5.2
    CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
  Binaries:
    Node: 16.13.0 - /private/var/folders/9f/kl_c86q5651fqmhmzf63jb0x5t_d9j/T/xfs-ccad591b/node
    Yarn: 3.2.0-rc.5 - /private/var/folders/9f/kl_c86q5651fqmhmzf63jb0x5t_d9j/T/xfs-ccad591b/yarn
    npm: 8.1.0 - ~/.volta/tools/image/node/16.13.0/bin/npm

Additional context

Note that the ESM loader error above is identical to the one you get when specifying "type": "module" for the workspace.

I propose that the switch state be modified with the following:

    case `.js`: {
      const pkg = readPackageScope(filepath);
      if (!pkg)
        return `commonjs`;
      return pkg.data.type ?? `commonjs`;
    }
    // Matching files beyond `.js` deviates from Node's default --experimental-loader
    // behavior but is required to work around https://github.com/nodejs/node/issues/33226
    default: {
      const pkg = readPackageScope(filepath);
      // assume CJS for files outside of a package boundary
      if (!pkg)
        return `commonjs`;
      // prevent extensions beyond .mjs or .js from loading as ESM
      if (pkg.data.type === `module`)
        return null;
      return pkg.data.type ?? `commonjs`;
    }

As far as I can tell, this exactly matches Node's behavior when no --experimental-loader is passed. I was surprised to learn that Node normally doesn't allow extensionless files to load as ESM under any circumstance.

@kherock kherock added the bug Something isn't working label Nov 22, 2021
@merceyz merceyz added the esm label Nov 22, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working esm
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants