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

Imports from @react-email/components break with import-in-the-middle #62

Closed
dawnmist opened this issue Jan 26, 2024 · 1 comment · Fixed by #85 or #78
Closed

Imports from @react-email/components break with import-in-the-middle #62

dawnmist opened this issue Jan 26, 2024 · 1 comment · Fixed by #85 or #78

Comments

@dawnmist
Copy link

@react-email/components is a metapackage that re-exports the individual component libraries from @react-email such as @react-email/body, @react-email/html, @react-email/tailwind, etc.

It does this using export * from <package> in its index.mjs file, and the following (compiled) code for index.js:

module.exports = __toCommonJS(src_exports);
__reExport(src_exports, require("@react-email/body"), module.exports);
__reExport(src_exports, require("@react-email/button"), module.exports);
__reExport(src_exports, require("@react-email/column"), module.exports);
// etc for the rest of the component libraries

// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  ...require("@react-email/body"),
  ...require("@react-email/button"),
  ...require("@react-email/column"),
  // etc for the rest of the component libraries
});

I have created an example minimal reproduction at: https://github.com/dawnmist/import-in-the-middle-react-email-issue

Expected Behavior

The application should be able to import any of the individual components directly from the @react-email/components library.

Actual Behavior

When import-in-the-middle is used as an --experimental-loader, the import paths for the @react-email components get incorrectly mapped as subdirectories/siblings of the index.js/index.mjs files of the @react-email/components library, resulting in file not found import errors:

Yarn 4 (nodeLinker=pnpm):

node:internal/process/esm_loader:40
      internalBinding('errors').triggerUncaughtException(
                                ^
[Error: ENOENT: no such file or directory, open '/home/username/project/node_modules/.store/@react-email-components-virtual-daf4c187d9/package/dist/@react-email/body'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: '/home/username/project/node_modules/.store/@react-email-components-virtual-daf4c187d9/package/dist/@react-email/body'
}

Yarn 3 (nodeLinker=pnpm):

(node:1753054) ExperimentalWarning: `--experimental-loader` may be removed in the future; instead use `register()`:
--import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("import-in-the-middle/hook.mjs", pathToFileURL("./"));'
(Use `node --trace-warnings ...` to show where the warning was created)

node:internal/process/esm_loader:34
      internalBinding('errors').triggerUncaughtException(
                                ^
[Error: ENOENT: no such file or directory, open '/home/username/project/node_modules/.store/@react-email-components-virtual-8a501030e1/package/dist/@react-email/body'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: '/home/username/project/node_modules/.store/@react-email-components-virtual-8a501030e1/package/dist/@react-email/body'
}

Steps to Reproduce the Problem

I have created an example reproduction at: https://github.com/dawnmist/import-in-the-middle-react-email-issue

  1. Clone the git repo: https://github.com/dawnmist/import-in-the-middle-react-email-issue
  2. yarn install
  3. yarn build
  4. yarn start - server will run without using import-in-the-middle
  5. Go to http://localhost:3000 and you should see the output "Hello world!"
  6. Stop the server
  7. yarn start:import - the same server will fail to run at all when using import-in-the-middle as an experimental-loader, throwing the error above where the @react-email/body library is instead attempted to be loaded as a subdirectory of the @react-email/components library instead of being treated as a separate npm library.

Specifications

  • Version: import-in-the-middle version 1.7.3
  • Platform: Debian 12 linux, x86_64
  • NodeJS: 18.19.0 & 20.11.0
  • Yarn: 3.7.0 + 4.0.2
@dawnmist dawnmist changed the title Import of @react-email/components breaks with import-in-the-middle Imports from @react-email/components break with import-in-the-middle Jan 26, 2024
@dawnmist
Copy link
Author

dawnmist commented Feb 7, 2024

I've made some attempt to debug what is going on, though it's only been partially successful.

Replacing line: https://github.com/DataDog/import-in-the-middle/blob/c3c2c52c1915b47994af59d507c59029c1f1fae9/hook.js#L157

With:

      const isNodeModule = !(modFile.startsWith('.') || modFile.startsWith('/') || modFile.startsWith('file:'))
      const modUrl = isNodeModule
        ? new URL(require.resolve(modFile, {
          paths: [new URL(srcUrl).pathname]
        }), srcUrl).toString() 
        : new URL(modFile, srcUrl).toString()

This allows import-in-the-middle to get the correct url for submodule/child node_module library imports, however there is still an issue in that when it is processing those submodules import-in-the-middle fails to retrieve the submodule's exports. This results in the parent module being unable to re-export the submodule's exports as it does not know about the items being exported (the setters map for the submodule is returned as empty). The submodule then gets processed a second time after the parent has completed all its processing, this time properly picking up its own exports but it's too late at that point for the parent module to be informed of the child's exports. This then means that node throws errors that the parent "does not provide an export named 'XXX'" when it was one of the exports that the parent module was re-exporting from the submodule.

In terms of the isNodeModule test, I'm not sure if there are any other modFile exports likely to be seen, e.g. http: or deno:. If there are others that need to be treated like file/relative/absolute urls instead of using node resolution, that parameter should be updated to look for those too.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
1 participant