In the UnambiguousJavaScriptGrammar proposal, Bradley and John-David discussed the challenge of dealing with files that could successfully parse as either scripts or modules but have different execution behavior. This has a couple of issues:
- Code written with the expectation of being executed in one mode could be executed in the wrong mode, without the ability to prevent this kind of erroneous execution.
- Top-level scripts intending to be executed by Node via
node myscript.js
can't work for files that want to useimport
syntax, unless Node adds and mandates an un-ergonomic new command-line switch likenode -m myscript.js
.
In the UnambiguousJavaScriptGrammar proposal, the language would be changed to require that all module files contain at least one import
or export
declaration. The easiest way to ensure that a file is a module is to always add the (otherwise semantically meaningless) declaration:
export {};
var tmp = "blah"; // not a global!
As a variation, we could instead add a "use module";
directive, allowing modules to state their intent more directly:
"use module";
var tmp = "blah"; // not a global!
This could be useful both for top-level node scripts that want to opt in to being modules without requiring a change to command-line flags, as well as libraries that want to ensure that they are never executed in the wrong context. The semantics would require that such executions trigger an early error.
This would essentially entail a few entry points into evaluating JavaScript source:
- Definitely a script: If the source code includes a
"use strict"
directive, the source is strict mode; otherwise it's sloppy mode. If the source code includes a"use module"
directive, it's an early error. - Definitely a module: If the source code includes a
"use strict"
or"use module"
directive, it's a no-op. It's always module mode. - Unknown: If the source code includes a
"use module"
directive, it's a module. If the source code includes a"use strict"
directive and no"use module"
directive, it's a strict mode Script. Otherwise, it's a sloppy mode Script.
The web semantics would never use the Unknown mode. Node would only use the Unknown mode for top-level script files and modules that do not have associated package.json
files to indicate their mode.
As an experiment, I have prototyped a single-pass parsing algorithm that determines on the fly whether an input source is definitely a module or in the ambiguous intersection of the Script and Module grammars. Effectively, if the algorithm encounters either a "use module"
directive, an import
statement, or an export
statement, it infers that the source is a module. The primary technical challenge for parsing in this mode is to defer the reporting of strict-mode and module-mode early errors until it knows which mode the source is meant to be parsed in.
Any performance concerns around deferred error checking should be irrelevant to the web and negligible for Node, since this would only come into play for loading Node top-level scripts and modules without package.json
.
Is there any concern about existing scripts that might have
"use module"
in them, whereas there can be none that haveexport
in them?