Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix: Add globalPreload to ts-node/esm for node 20
As of node v20, loader hooks are executed in a separate isolated thread
environment.  As a result, they are unable to register the
`require.extensions` hooks in a way that would (in other node versions)
make both CJS and ESM work as expected.

By adding a `globalPreload` method, which *does* execute in the main
script environment (but with very limited capabilities), these hooks can
be attached properly, and `--loader=ts-node/esm` will once again make
both cjs and esm typescript programs work properly.
  • Loading branch information
isaacs committed Sep 7, 2023
commit afbd4b69fc039864c73fd5de60a33eb58fc8d699
10 changes: 10 additions & 0 deletions esm.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,13 @@ const require = createRequire(fileURLToPath(import.meta.url));
/** @type {import('./dist/esm')} */
const esm = require('./dist/esm');
export const { resolve, load, getFormat, transformSource } = esm.registerAndCreateEsmHooks();

// Affordance for node 20, where load() happens in an isolated thread
export const globalPreload = () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this hook be included in the return value of https://typestrong.org/ts-node/api/index.html#createEsmHooks?

That API is meant for anyone wanting to wrap our loader in their own logic. They'd do --loader my-loader.mjs with their my-loader.mjs exporting all the functions they get from calling createEsmHooks(), perhaps wrapping them to implement new behavior.

This API predates support for multiple loaders, but also it should be possible to compose loaders in code so that end-users don't have to pass --loader twice.

Copy link
Contributor Author

@isaacs isaacs May 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything is just as composable as it was, with the exception that globalPreload is a bit weird to stack. (You have to append all the strings together wrapped in IIFE's so they don't clobber each others' vars.)

But multiple loaders have been supported longer than globalPreload was needed, so that might not matter.

const self = fileURLToPath(import.meta.url);
return `
const { createRequire } = getBuiltin('module');
const require = createRequire(${JSON.stringify(self)});
require('./dist/esm').registerAndCreateEsmHooks();
`;
};