add .mjs to list of well known extensions#4691
Conversation
this is to conform to the plan of the Node.js EP
|
I am unclear on how to ensure the extension is only ever an ES Module. |
|
We could build the same kind of automatic loader support like we did for json and only just test for the extension, and thus turn off all the other parser features for those modules. Otherwise, I'm not sure if theres a really "GREAT" way to do it because we determine the module based on the lexical tokens used etc. |
|
@TheLarkInn I think only the target source type needs to change, are there other parser features that need to change? |
|
Any thoughts on what you'd expect if someone runs |
|
well if webpack sees it is still a .mjs extension it would error. Is it possible to give it a new filename/specify the language goal when handing it off? |
sokra
left a comment
There was a problem hiding this comment.
Is the order correct? Does it really prefer .js over .mjs?
It would be great to have some simple test here, which tests the preferences for extensions.
|
@sokra I've left things unchanged in this PR, but .mjs would probably be preferred if that seems an ok breaking change. I will add tests for that as well. |
|
@loganfsmyth after some thought, ideally |
|
@bmeck Yeah, that seems like the ideal to me too. I guess that will have to wait to see if Webpack could add logic to make the parse goal explicit. |
|
Thank you for your pull request! The most important CI builds succeeded, we’ll review the pull request soon. |
| return callback(); | ||
| } | ||
|
|
||
| const isMJS = this._source._name && /.mjs$/.test(this._source._name); |
There was a problem hiding this comment.
/.mjs$/ should be /\.mjs$/ 😁
@sokra is there a common name property on all possible sources? Accessing the private _name property is not ideal here.
jhnns
left a comment
There was a problem hiding this comment.
Thanks @mbeck! 👍
As I already commented on the diff, passing an array as sourceType does not work. We need to change the Parser.prototype.parse implementation for that.
In the long term, I would like to achieve feature parity with Node.js, as this encourages to write code that works potentially in both environments (actually, we did it already with CJS).
Feature parity means for me:
.jsmust contain CJS.mjsmust contain ESM- More controversial: Importing "named exports" from CJS will raise an error
I think, the last one is more controversial since importing named exports does already work for us. However, I think it's more important to provide a consistent and unified environment. That's why I would deliberately remove this feature.
In the short term, the transition should be as painless as possible. For now, we should preserve the old behavior for .js files and just enforce the module parser goal for .mjs. This means that for .js files, the parser would still just try the module parser goal first and then back off to script. Importing named exports from CJS should still work for now.
Once we agreed on this, we should publish guidelines in order to write code that works in Node.js and Webpack.
Any thoughts @sokra @TheLarkInn @bebraw ?
| this.options = options; | ||
| options.type = options.type || "require"; | ||
| options.extensions = options.extensions || ["", ".js"]; | ||
| options.extensions = options.extensions || ["", ".mjs", ".js", ]; |
There was a problem hiding this comment.
Is that trailing comma by accident? 😁
(It does no harm here, but we usually do not use trailing commas in one-liners)
| try { | ||
| this.parser.parse(this._source.source(), { | ||
| this.parser.parse(source, { | ||
| sourceTypes: sourceTypes, |
There was a problem hiding this comment.
Passing an array as sourceType is not supported. These options are not passed to acorn anyway (@sokra could you clarify the purpose of this second argument initialState)?
|
@loganfsmyth in the long term, parsing a |
Yeah, soft deprecation (a warning before dropping the feature) would be a good way to go. 👍 |
|
@jhnns One example would be if you still wanted to try to preserve the named exports behavior to ease the transition to Node's behavior, it could be nice to compile your es6 syntax with Babel, so the import would still behave like CommonJS. Or say there is some feature that is hard to compile to ES6 but is easy to do if you can convert it to CommonJS. In a more general case, if I have a loader for some extension that isn't |
Mhmm... I think, once one of your dependencies have been translated to ES modules, you will probably have a hard time with still using CommonJS because now you need to convert your synchronous let someEs6Module;
require.import("some-es6-module").then(module => someEs6Module = module);Actually, this means that every function inside your module that uses You can ease the transition for people who are using bundlers by providing different entry points ( I just realized that this change is more nuanced than I thought. If we want to have feature parity with Node.js, we also need to adapt this asynchronous import behavior from ES to CJS... |
|
@jhnns this is in part why in the EP https://github.com/bmeck/node-eps/blob/a1eab9bf023bbe13a79ddb18f0622a5d57215f9b/002-es-modules.md you can't |
|
this has grown in scope quite a bit and I probably don't have bandwidth to draw it to completion anytime soon if someone else wants to take it up |
That's a fair point, I forgot there were limitations there then. Then ignoring that part, the other question for me is if a loader for a non .js/.mjs extension wants to output ESM, how will Webpack handle it? And separately, if there are other loaders in the chain, how should they decide which grammar to use? |
|
@sokra is there someone who could take this over since it expanded in scope so much? |
| return callback(); | ||
| } | ||
|
|
||
| const isMJS = this._source._name && /\.mjs$/.test(this._source._name); |
|
w/e this becomes should not land until it can be forced to be a Module as per the new Internet Draft: |
|
@sokra can this be merged now that Node is shipping mjs support under a flag? |
|
Why not let |
|
@pierreneter |
|
done on |
What kind of change does this PR introduce?
feature, compliance w/ Node.js EP
Did you add tests for your changes?
No
If relevant, link to documentation update:
Summary
this is to conform to the plan of the Node.js EP.
Does this PR introduce a breaking change?
No
Other information