Skip to content

Commit 1d771f5

Browse files
chrisdickinsonceejbot
authored andcommitted
es modules: implement npm spec
- add -m, --module for preloading esm - Refactored startup for readability. - We can now syntax-check ESM files in addition to commonjs files. - We now handle file path resolution the way the commonjs code path does. - Removed --loader. - Removed frozen "safe" promises and maps.
1 parent 1385e1b commit 1d771f5

File tree

109 files changed

+833
-1020
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

109 files changed

+833
-1020
lines changed

.eslintrc.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ parser: babel-eslint
1212
parserOptions:
1313
sourceType: script
1414

15-
overrides:
16-
- files: ["doc/api/esm.md", "*.mjs", "test/es-module/test-esm-example-loader.js"]
17-
parserOptions:
18-
sourceType: module
19-
2015
rules:
2116
# Possible Errors
2217
# http://eslint.org/docs/rules/#possible-errors
@@ -209,3 +204,8 @@ globals:
209204
LTTNG_NET_SERVER_CONNECTION: false
210205
LTTNG_NET_STREAM_END: false
211206
internalBinding: false
207+
208+
overrides:
209+
- files: [ "esm.md" ]
210+
parserOptions:
211+
sourceType: module

lib/internal/bootstrap_node.js

Lines changed: 139 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@
108108
'ExperimentalWarning', undefined);
109109
}
110110

111-
112111
// There are various modes that Node can run in. The most common two
113112
// are running from a script and running the REPL - but there are a few
114113
// others like the debugger or running --eval arguments. Here we decide
@@ -123,8 +122,11 @@
123122
NativeModule.require('_third_party_main');
124123
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_THIRD_PARTY_MAIN_END);
125124
});
125+
return;
126+
}
126127

127-
} else if (process.argv[1] === 'inspect' || process.argv[1] === 'debug') {
128+
// Are we debugging?
129+
if (process.argv[1] === 'inspect' || process.argv[1] === 'debug') {
128130
if (process.argv[1] === 'debug') {
129131
process.emitWarning(
130132
'`node debug` is deprecated. Please use `node inspect` instead.',
@@ -135,115 +137,149 @@
135137
process.nextTick(function() {
136138
NativeModule.require('internal/deps/node-inspect/lib/_inspect').start();
137139
});
140+
return;
141+
}
138142

139-
} else if (process.profProcess) {
143+
// Are we handling profiling output?
144+
if (process.profProcess) {
140145
NativeModule.require('internal/v8_prof_processor');
146+
return;
147+
}
141148

142-
} else {
143-
// There is user code to be run
144-
145-
// If this is a worker in cluster mode, start up the communication
146-
// channel. This needs to be done before any user code gets executed
147-
// (including preload modules).
148-
if (process.argv[1] && process.env.NODE_UNIQUE_ID) {
149-
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_CLUSTER_SETUP_START);
150-
const cluster = NativeModule.require('cluster');
151-
cluster._setupWorker();
152-
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_CLUSTER_SETUP_END);
153-
// Make sure it's not accidentally inherited by child processes.
154-
delete process.env.NODE_UNIQUE_ID;
149+
// If we reach here, we have user code to run. What sort of user code?
150+
const isClusterWorker = process.argv[1] && process.env.NODE_UNIQUE_ID;
151+
const isEvalTarget = process._eval != null && !process._forceRepl;
152+
const isFileTarget = process.argv[1] && process.argv[1] !== '-';
153+
154+
// If this is a worker in cluster mode, start up the communication
155+
// channel. This needs to be done before any user code gets executed
156+
// (including preload modules).
157+
if (isClusterWorker) {
158+
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_CLUSTER_SETUP_START);
159+
const cluster = NativeModule.require('cluster');
160+
cluster._setupWorker();
161+
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_CLUSTER_SETUP_END);
162+
// Make sure it's not accidentally inherited by child processes.
163+
delete process.env.NODE_UNIQUE_ID;
164+
}
165+
166+
let loadUserFile = () => {
167+
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_START);
168+
// make process.argv[1] into a full path
169+
const path = NativeModule.require('path');
170+
process.argv[1] = path.resolve(process.argv[1]);
171+
172+
const Module = NativeModule.require('module');
173+
174+
// check if user passed `-c` or `--check` arguments to Node.
175+
if (process._syntax_check_only != null) {
176+
const fs = NativeModule.require('fs');
177+
// read the source
178+
const filename = Module._resolveFilename(process.argv[1]);
179+
var source = fs.readFileSync(filename, 'utf-8');
180+
checkScriptSyntax(source, filename);
181+
process.exit(0);
155182
}
156183

157-
if (process._eval != null && !process._forceRepl) {
184+
return Module;
185+
};
186+
187+
if (isEvalTarget || !isFileTarget) {
188+
loadUserFile = () => {
158189
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_START);
159190
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_END);
160-
// User passed '-e' or '--eval' arguments to Node without '-i' or
161-
// '--interactive'
191+
};
192+
}
162193

163-
perf.markMilestone(
164-
NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_START);
165-
preloadModules();
166-
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_END);
194+
const MaybeModule = loadUserFile();
167195

196+
if (isEvalTarget) {
197+
// User passed '-e' or '--eval' arguments to Node without '-i' or
198+
// '--interactive'
199+
preloadModules(() => {
168200
const internalModule = NativeModule.require('internal/module');
169201
internalModule.addBuiltinLibsToObject(global);
170202
evalScript('[eval]');
171-
} else if (process.argv[1] && process.argv[1] !== '-') {
172-
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_START);
173-
// make process.argv[1] into a full path
174-
const path = NativeModule.require('path');
175-
process.argv[1] = path.resolve(process.argv[1]);
203+
});
204+
} else if (isFileTarget) {
205+
preloadModules(() => MaybeModule.runMain());
206+
} else {
207+
preloadModules(() => runRepl());
208+
}
176209

177-
const Module = NativeModule.require('module');
210+
// This is the end of the startup code.
178211

179-
// check if user passed `-c` or `--check` arguments to Node.
180-
if (process._syntax_check_only != null) {
181-
const fs = NativeModule.require('fs');
182-
// read the source
183-
const filename = Module._resolveFilename(process.argv[1]);
184-
var source = fs.readFileSync(filename, 'utf-8');
185-
checkScriptSyntax(source, filename);
186-
process.exit(0);
212+
// Load preload modules
213+
function preloadModules(next) {
214+
perf.markMilestone(
215+
NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_START);
216+
if (process._preload_modules) {
217+
NativeModule.require('module')
218+
._preloadModules(process._preload_modules);
219+
}
220+
221+
if (process._preload_es_modules) {
222+
NativeModule.require('module')
223+
._preloadESModules(process._preload_es_modules).then(() => {
224+
perf.markMilestone(
225+
NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_END);
226+
next();
227+
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
228+
}).catch((err) => {
229+
process._rawDebug(err.stack);
230+
process.exit(1);
231+
});
232+
return;
233+
}
234+
235+
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_END);
236+
next();
237+
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
238+
}
239+
}
240+
241+
function runRepl() {
242+
// If -i or --interactive were passed, or stdin is a TTY.
243+
if (process._forceRepl || NativeModule.require('tty').isatty(0)) {
244+
// REPL
245+
const cliRepl = NativeModule.require('internal/repl');
246+
cliRepl.createInternalRepl(process.env, function(err, repl) {
247+
if (err) {
248+
throw err;
187249
}
188-
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_END);
189-
perf.markMilestone(
190-
NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_START);
191-
preloadModules();
192-
perf.markMilestone(
193-
NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_END);
194-
Module.runMain();
195-
} else {
196-
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_START);
197-
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_END);
198-
perf.markMilestone(
199-
NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_START);
200-
preloadModules();
201-
perf.markMilestone(
202-
NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_END);
203-
// If -i or --interactive were passed, or stdin is a TTY.
204-
if (process._forceRepl || NativeModule.require('tty').isatty(0)) {
205-
// REPL
206-
const cliRepl = NativeModule.require('internal/repl');
207-
cliRepl.createInternalRepl(process.env, function(err, repl) {
208-
if (err) {
209-
throw err;
210-
}
211-
repl.on('exit', function() {
212-
if (repl._flushing) {
213-
repl.pause();
214-
return repl.once('flushHistory', function() {
215-
process.exit();
216-
});
217-
}
250+
repl.on('exit', function() {
251+
if (repl._flushing) {
252+
repl.pause();
253+
return repl.once('flushHistory', function() {
218254
process.exit();
219255
});
220-
});
221-
222-
if (process._eval != null) {
223-
// User passed '-e' or '--eval'
224-
evalScript('[eval]');
225256
}
226-
} else {
227-
// Read all of stdin - execute it.
228-
process.stdin.setEncoding('utf8');
257+
process.exit();
258+
});
259+
});
229260

230-
var code = '';
231-
process.stdin.on('data', function(d) {
232-
code += d;
233-
});
261+
if (process._eval != null) {
262+
// User passed '-e' or '--eval'
263+
evalScript('[eval]');
264+
}
265+
} else {
266+
// Read all of stdin - execute it.
267+
process.stdin.setEncoding('utf8');
234268

235-
process.stdin.on('end', function() {
236-
if (process._syntax_check_only != null) {
237-
checkScriptSyntax(code, '[stdin]');
238-
} else {
239-
process._eval = code;
240-
evalScript('[stdin]');
241-
}
242-
});
269+
var code = '';
270+
process.stdin.on('data', function(d) {
271+
code += d;
272+
});
273+
274+
process.stdin.on('end', function() {
275+
if (process._syntax_check_only != null) {
276+
checkScriptSyntax(code, '[stdin]');
277+
} else {
278+
process._eval = code;
279+
evalScript('[stdin]');
243280
}
244-
}
281+
});
245282
}
246-
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
247283
}
248284

249285
function setupProcessObject() {
@@ -487,26 +523,27 @@
487523
process._tickCallback();
488524
}
489525

490-
// Load preload modules
491-
function preloadModules() {
492-
if (process._preload_modules) {
493-
NativeModule.require('module')._preloadModules(process._preload_modules);
494-
}
495-
}
496-
497526
function checkScriptSyntax(source, filename) {
527+
// We need to determine the kind of module this is (commonjs or esm)
528+
// and load it the right way.
529+
498530
const Module = NativeModule.require('module');
499531
const vm = NativeModule.require('vm');
500532
const internalModule = NativeModule.require('internal/module');
533+
const { ModuleWrap } = NativeModule.require('internal/loader/ModuleWrap');
501534

502-
// remove Shebang
535+
const mode = Module.guessModuleMode(filename, source);
503536
source = internalModule.stripShebang(source);
504-
// remove BOM
505537
source = internalModule.stripBOM(source);
506-
// wrap it
507-
source = Module.wrap(source);
508-
// compile the script, this will throw if it fails
509-
new vm.Script(source, { displayErrors: true, filename });
538+
if (mode === 'esm') {
539+
new ModuleWrap(source, filename);
540+
// this throws if a syntax error
541+
} else {
542+
// We are legacy commons.
543+
source = Module.wrap(source);
544+
// Compile the script. This will throw if it fails.
545+
new vm.Script(source, { displayErrors: true, filename });
546+
}
510547
}
511548

512549
// Below you find a minimal module system, which is used to load the node

lib/internal/errors.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ E('ERR_ASYNC_TYPE', 'Invalid name for async "type": %s');
263263
E('ERR_BUFFER_OUT_OF_BOUNDS', bufferOutOfBounds);
264264
E('ERR_BUFFER_TOO_LARGE',
265265
`Cannot create a Buffer larger than 0x${kMaxLength.toString(16)} bytes`);
266+
E('ERR_CANNOT_IMPORT_LEGACY_MODULE',
267+
'Cannot import module previously loaded as legacy module: %s');
268+
E('ERR_CANNOT_REQUIRE_ESM', 'Cannot require module previously loaded as ES module: %s');
266269
E('ERR_CANNOT_WATCH_SIGINT', 'Cannot watch for SIGINT signals');
267270
E('ERR_CHILD_CLOSED_BEFORE_REPLY', 'Child closed before reply received');
268271
E('ERR_CHILD_PROCESS_IPC_REQUIRED',

0 commit comments

Comments
 (0)