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

Unexpected behavior of the external option #2542

Closed
KingSora opened this issue Sep 12, 2022 · 4 comments
Closed

Unexpected behavior of the external option #2542

KingSora opened this issue Sep 12, 2022 · 4 comments

Comments

@KingSora
Copy link

KingSora commented Sep 12, 2022

I have encountered two unexpected behaviors of the external option.
esbuild config for both cases:

import esbuild from 'esbuild';

esbuild.build({
  entryPoints: ['index.ts'],
  outdir: 'out',
  bundle: true,
  format: 'esm',
  platform: 'node',
  external: [
    './node_modules/*',
    '../node_modules/*',
    '../../node_modules/*',
    '../../../node_modules/*',
  ],
});

For all the reproduction examples: run npm i && npm run build in the terminal and check the apps/myApp/out folder for the output.

  1. Paths which are marked as external are re-written / changed (Reproduction: https://stackblitz.com/edit/node-zc1lyo):

Input:

export * from 'react';

Output:

// index.ts
export * from "../../../node_modules/react/index.js";

In this case I would expect that react is marked as external (because its resolved path matches one of the external paths).

So the expected output would be:

// index.ts
export * from "react";

  1. Symlinked package in node_modules is marked as external incorrectly (Reproduction https://stackblitz.com/edit/node-cwpdcm):
    Here I have installed a local package, which means the folder in the node_modules directory is just a symlink to the real folder.

package.json

{
  "dependencies": {
    "@repo/myLib": "file:./libs/myLib",
  }
}

Input:

export * from '@repo/myLib';

Output:

// index.ts
export * from "../../../node_modules/@repo/myLib/index.ts";

In this case the import @repo/myLib resolves to /home/projects/node-cwpdcm/libs/myLib/index.ts and not to ../../../node_modules/@repo/myLib/. (I checked that with a plugin which logs all resolved paths with the onLoad callback). Because neither the resolved nor the import path matches any of the external paths I would expect this import not to be external.

Side note: with preserveSymlinks: true the resolved path is /home/projects/node-vaswvk/node_modules/@repo/myLib/index.ts which then again should be marked as external.


These cases might only be unexpected because I don't know how the external option behaves internally. To be honest I would expect the external option to be an array of globs / regex expressions / strings instead of just an array of strings (where the strings are relative paths but still can have a wildcard, but only one)

@Septh
Copy link

Septh commented Sep 12, 2022

Why not simply write external: [ 'react' ] and external: [ '@repo/myLib' ] ?

@KingSora
Copy link
Author

@Septh the examples I gave here are just a fraction of the whole codebase. Because the dependencies are spread out accross many package.json files (its a monorepo with many packages) it would be very unconvenient and error prone to write each external package by name. The same applies to package.dependencies spread.

@ATheCoder
Copy link

ATheCoder commented Oct 31, 2022

I can confirm this issue happens for UUID as well.

I think this happens for all the packages that use the package.json's export field in order to conditionally export both an ESM and CommonJS usable package.

When you tell ESBuild to generate a commonjs bundle, you get a bundle that might include commonJS imports of ESM exports which results in a ERR_REQUIRE_ESM error.

I think this is important and needs to be investigated. I would love to make a PR for this if @evanw could give me a hint as to where to start looking.

@evanw evanw closed this as completed in 7277ffd Dec 13, 2022
@KingSora
Copy link
Author

KingSora commented Dec 14, 2022

@evanw I looked at the packages: 'external' feature you implemented, but I'm afraid that this won't solve my particular case here.

I'm using symlinked packages / dependencies:

{
  "dependencies": {
    "mypackage": "file:../mypackage"
  }
}

which would be imported as import { mypackage } from 'mypackage';. This looks like mypackage is a external package, but its actually not. Rollup solves this, because its extnernals can be filtered by the resolved path. In my case all paths resolved inside a node_modules folders are external and all outside are my own code. That works because symlinked packages are pointing to their real path (unless specified differently with e.g. preserveSymlinks option).

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

No branches or pull requests

3 participants