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

[ERROR] The entry point "./node_modules/x/y.ts" cannot be marked as external #18

Closed
Julien-Marcou opened this issue Jul 9, 2022 · 4 comments

Comments

@Julien-Marcou
Copy link

After upgrading to esrun v3.2.8, when I use esrun, I get the following error:
[ERROR] The entry point "./node_modules/x/y.ts" cannot be marked as external

When running the following command:
npx esrun ./node_modules/x/y.ts

(The TS file that I'm running only contains a console.log)

Downgrading to esrun v3.2.7 fixes the error.

@Gin-Quin
Copy link
Contributor

Gin-Quin commented Jul 11, 2022

Oh, that's because esrun does not bundle dependencies by default and its "what should I bundle?" strategy changed in 3.2.8.

The new strategy is safer and support Typescript aliases, so I still encourage to use 3.2.8 over 3.2.7.

Since 3.2.8, I delegated to esbuild the responsibility to decide what import is a dependency or not (ie whether the file comes from node_modules or not). So sadly, I'm not able to fix this bug myself.

The true fix would be that esbuild prevents any of the entry files (in your case, "./node_modules/x/y.ts") to be marked as externals.

I created an issue on esbuild and will leave this one open while the other is not resolved.

@hyrious
Copy link

hyrious commented Jul 11, 2022

I just came from the esbuild issue you just posted, and was glad to see some other project using the build api of esbuild to create ts runner. Because I developed @hyrious/esbuild-dev which does exactly bundle → run like yours. During the iteration of new features and/or behaviors of every aspects, I want to share you one thing that how I externalize third-party libraries -- that is not externalize by default! (but people still can add --external:react in their command-line.)

I used to write a simple script to find dependencies in package.json from at most 2 parent folders (which is a common pattern in monorepo). But finaly I decide to not doing this. The reason is to be compatible with libraries that can not be loaded natively. For example, if you have a CJS library does:

// node_modules/lib/index.js
// cjs-module-lexer DETECTS: NO EXPORTS
(function (e) {
  e.a = 'a';
  e['b'] = 'b';
})(exports);

This is common to see in many poorly wrapped UMD libraries. Unfortunately now even Node.js 18 cannot automatically find and add names (a and b) to that module, your code will break if you write this:

import { a, b } from "lib" // error: not found named export 'a', 'b'

I don't want people to know this tiny dark-side of ESM-CJS interop convension in Node.js and/or in esbuild (in fact, other ts runners based on transform api are facing this problem that it requires user to know how cjs-module-lexer works, not to mension that they will be hard to support tsconfig.json without plenty of code). If we bundle the lib in, esbuild will correctly create a wrapper that should does the trick.

That's it, I myself is keeping my own runner simple and stupid (KISS), it should just work at the most of the time.

@Gin-Quin
Copy link
Contributor

Hi friend Typescript runner developper :p

I've decided to not bundle dependencies after giving a lot of thought to the problem. Esrun's strategy is the following:

  1. Compile source code into ESM (not CJS).
  2. Do not bundle dependencies, so that both CJS and ESM dependencies are supported via node's resolution algorithm.

Compiling to ESM over CJS provides the advantage of unlocking the modern ESM capabilities, like top-level await (it would not be possible with CJS).

Not bundling dependencies have the following advantages:

  1. Super fast. Most of the time, most of your source code comes from your libraries.
  2. Compatible with CJS and ESM without efforts. It's up to node to execute correctly the packages.
  3. Out-of-the-box compatibility with binary dependencies like fsevents (you don't need to mark them as externals).

The other strategy (bundling everything including dependencies into CJS), has got point 2. but not 1. et 3., so I've decided to go for the no-bundle strategy. It works quite well actually!

@Gin-Quin
Copy link
Contributor

Esbuild fixed the issue, I updated Esrun to match a newer version of Esbuild.

Will work with esrun@3.2.18 or later

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