Skip to content

Commit 9f9efd6

Browse files
committed
add comments to explain copy-pasted cjs loader code from node core
1 parent da76779 commit 9f9efd6

File tree

2 files changed

+34
-3
lines changed

2 files changed

+34
-3
lines changed

dist-raw/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
The `dist-raw` directory contains JS sources that are distributed verbatim, not compiled nor typechecked via TS.
2+
3+
To implement ESM support, we unfortunately must duplicate some of node's built-in functionality that is not
4+
exposed via an API. We have copy-pasted the necessary code from https://github.com/nodejs/node/tree/master/lib
5+
then modified it to suite our needs.
6+
7+
Formatting may be intentionally bad to keep the diff as small as possible, to make it easier to merge
8+
upstream changes and understand our modifications. For example, when we need to wrap node's source code
9+
in a factory function, we will not indent the function body, to avoid whitespace changes in the diff.
10+
11+
One obvious problem with this approach: the code has been pulled from one version of node, whereas users of ts-node
12+
run multiple versions of node.
13+
Users running node 12 may see that ts-node behaves like node 14, for example.

dist-raw/node-cjs-loader-utils.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
// copied from https://github.com/nodejs/node/blob/master/lib/internal/modules/cjs/loader.js
1+
// Copied from several files in node's source code.
2+
// https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js
3+
// Each function and variable below must have a comment linking to the source in node's github repo.
4+
25
const path = require('path');
36
const fs = require('fs');
47

58
module.exports.assertScriptCanLoadAsCJSImpl = assertScriptCanLoadAsCJSImpl;
69

710
// copied from Module._extensions['.js']
11+
// https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js#L1211-L1217
812
function assertScriptCanLoadAsCJSImpl(filename) {
913
const pkg = readPackageScope(filename);
1014
// Function require shouldn't be used in ES modules.
@@ -15,6 +19,7 @@ function assertScriptCanLoadAsCJSImpl(filename) {
1519
}
1620
}
1721

22+
// Copied from https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js#L285-L301
1823
function readPackageScope(checkPath) {
1924
const rootSeparatorIndex = checkPath.indexOf(path.sep);
2025
let separatorIndex;
@@ -33,8 +38,10 @@ function readPackageScope(checkPath) {
3338
return false;
3439
}
3540

41+
// Copied from https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js#L249
3642
const packageJsonCache = new Map();
3743

44+
// Copied from https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js#L251-L283
3845
function readPackage(requestPath) {
3946
const jsonPath = path.resolve(requestPath, 'package.json');
4047

@@ -70,6 +77,8 @@ function readPackage(requestPath) {
7077
}
7178
}
7279

80+
// In node's core, this is implemented in C
81+
// https://github.com/nodejs/node/blob/e9f293750760d59243020d0376edf242c9a26b67/src/node_file.cc#L845-L939
7382
function internalModuleReadJSON(path) {
7483
try {
7584
return fs.readFileSync(path, 'utf8')
@@ -79,10 +88,18 @@ function internalModuleReadJSON(path) {
7988
}
8089
}
8190

91+
// Native ERR_REQUIRE_ESM Error is declared here:
92+
// https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/errors.js#L1294-L1313
93+
// Error class factory is implemented here:
94+
// function E: https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/errors.js#L323-L341
95+
// function makeNodeErrorWithCode: https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/errors.js#L251-L278
96+
// The code below should create an error that matches the native error as closely as possible.
97+
// Third-party libraries which attempt to catch the native ERR_REQUIRE_ESM should recognize our imitation error.
8298
function createErrRequireEsm(filename, parentPath, packageJsonPath) {
83-
// Attempt to create an error object that matches node's native error close enough
8499
const code = 'ERR_REQUIRE_ESM'
85100
const err = new Error(getMessage(filename, parentPath, packageJsonPath))
101+
// Set `name` to be used in stack trace, generate stack trace with that name baked in, then re-declare the `name` field.
102+
// This trick is copied from node's source.
86103
err.name = `Error [${ code }]`
87104
err.stack
88105
Object.defineProperty(err, 'name', {
@@ -94,7 +111,8 @@ function createErrRequireEsm(filename, parentPath, packageJsonPath) {
94111
err.code = code
95112
return err
96113

97-
// copy-pasted from https://github.com/nodejs/node/blob/master/lib/internal/errors.js#L1294-L1311
114+
// Copy-pasted from https://github.com/nodejs/node/blob/b533fb3508009e5f567cc776daba8fbf665386a6/lib/internal/errors.js#L1293-L1311
115+
// so that our error message is identical to the native message.
98116
function getMessage(filename, parentPath = null, packageJsonPath = null) {
99117
const ext = path.extname(filename)
100118
let msg = `Must use import to load ES Module: ${filename}`;

0 commit comments

Comments
 (0)