microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.29k stars 12.39k forks source link

Support ".mjs" input files #27957

Closed mjbvz closed 2 years ago

mjbvz commented 5 years ago

From @Sti2nd on October 7, 2018 16:17

import { timpaniSounds } from "./soundImport.mjs";

In the above example VS code will show all javascript files when writing "./", but not javascript module files. So I didn't see the above file in the list when trying to import it. Not sure if this is a bug or a feature request.

Copied from original issue: Microsoft/vscode#60103

mjbvz commented 5 years ago

I believe that #18442 tracks compiling typescript to mjs. Do we fully support working with mjs files in the editor?

weswigham commented 5 years ago

We don't lookup or include .mjs files in any way at present, since it's going to be used as a flag in node that changes module resolution and the exact behavior it switches on (W.R.T. cjs interop) is still TBD, interpreting it would be putting the cart before the horse.

weswigham commented 5 years ago

Since the other thread tracks .mjs output, I'll repurpose this one for tracking .mjs input.

vincentvictoria commented 5 years ago

I think it comes down to a standardization issue: javascript modules must have a standardized file extension.

It's causing troubles to us, and I believe everyone who are making modules targeting for both browser & node are affected.

In browser, we have to specify file name with extension: import { SuperModule } from './SuperModule.mjs';

But vscode doesn't recognize .mjs, so we resort to changing extension to .esm.js import { SuperModule } from './SuperModule.esm.js';

Then node doesn't recognize .esm.js as a module unless we specify a different loader which recognizes the extension: 'node --loader esmloader.js index.js'

This is surely uncomfortable since you have to specify a non-default loader.

Either node has to support .esm.js or vscode has to support .mjs. for short-term solution.

I personally think module javascript files gotta have a different extension since it's treated differently in both browser & node. Browsers require: <script type='module' src='script.js' /> See, browsers also need to know it's a different type of javascript before loading. I think a different extension is rightful for the purpose.

I prefer .mjs since it's funny (Hello, Michael Jackson), short and right for the purpose. I'm using .esm.js right now, but it's very cumbersome to write. And i have to specify type='module' in the browser anyway even if i already typed '.eeeessssmmmm.js'

I just hope es7/8 standard specify that javascript modules must have .mjs extension.

robertrossmann commented 5 years ago

I crafted a patch which enables tsserver to recognise, parse and provide type hints for .mjs files.

This might be useful for people who use the .mjs file extensions for JavaScript files with identical module resolution semantics as CommonJS. Note that this patch does not implement any special behaviour with regard to ES modules and might not be spec-compliant. However, editor integrations which allow using custom-built tsserver implementations will greatly increase developer productivity because suddenly everything seems to work.

vincentvictoria commented 5 years ago

Thanks for the patch, @robertrossmann!

Btw, I just realized that tsserver recognizes jsx. Then, why not mjs? Both are not ES spec, but at least industry standards.

mathiasbynens commented 5 years ago

We don't lookup or include .mjs files in any way at present, since it's going to be used as a flag in node that changes module resolution and the exact behavior it switches on (W.R.T. cjs interop) is still TBD, interpreting it would be putting the cart before the horse.

As of last October, there’s agreement on the “minimal kernel”, which states that:

  • import statements will only support files with an .mjs extension, and will import only ES modules, for now.
    • In a later phase, the intention is to move forward with format databases to map extensions and support multiple use cases.
mathiasbynens commented 5 years ago

In other words, there’s no point in waiting. .mjs signals that the file is a JavaScript module, now (in the experimental implementation) and in the future (per the acceptance of the minimal kernel).

puneetpr commented 5 years ago

is there any stop-gap workaround that we are aware of?

philipwalton commented 5 years ago

Hey @weswigham, can you please bump the priority on this issue?

This is currently preventing anyone who uses TypeScript from building a custom service worker bundle with Workbox, since Workbox's source code is published as .mjs (to disambiguate the source modules from it's built, classic scripts, which have to be .js since browsers don't currently support loading modules in workers).

Workbox users can do this with Webpack, they can do it with Rollup, and they can do it with Parcel, but they can't do it with TypeScript, and many of our users are TypeScript users.

From the above discussion it sounds like you wanted to wait to see where node landed on .mjs, but regardless of what node does, the fact is this affecting real users today. Many Workbox users are filing issues for this or complaining about it on our Slack channel or on Twitter.

It's a real blocker for a lot of people, and it's not something we can change on our end since that would break people's existing builds. There are also lots of other modules (browser modules, not just node-specific modules) that are published to npm with .mjs source files, and this is an issue for any TypeScript users wanting to consume those as well.

I don't see any downside to TypeScript recognizing .mjs as a valid JavaScript file, and I think that would be the simplest way to resolve this problem real users are having today.

TimvdLippe commented 5 years ago

Aside from the actual TS inputs, click-through in VS Code (e.g. ctrl-click on import 'foo.mjs') does not work. If I change it to import 'foo.js', VS Code correctly understands the file and correctly jumps to definition. Since the browser ignores the file extension and only requires the correct MIME-type, I am unable to author my code in .mjs (or whatever extension I would prefer) with VS Code, while it runs just fine in the browser.

Bouhtouch commented 4 years ago

Is there any news about this? I'd really enjoy having intellisense working with es modules saved as .mjs :)

rauschma commented 4 years ago

Any progress? Given that ECMAScript modules will soon be unflagged on Node.js, it would be great to have first-class support for them in TypeScript:

piotr-cz commented 4 years ago

So node 13.2 has been released with .mjs support without flag: https://github.com/nodejs/node/releases/tag/v13.2.0

philp commented 4 years ago

Like others, I've arrived here when trying to get .mjs working in VS Code. If somebody has the time, it would be useful to get some insight into why this is a typescript issue, not a vscode issue — i.e. is it because it's a dependency for processing?

weswigham commented 4 years ago

Our language service only loads files of known extensions (barring intervention from the editor), as extensions have a bearing on how module resolution is supposed to work. We do not currently recognize .mjs or any associated resolution rules, ergo, we do not load .mjs.

To anyone using .mjs: How do you stand it? Why do you not use .js and the new type: module field node supports? How do you handle jsx? Do you use .mjsx or something?

jasonwilliams commented 4 years ago

Why do you not use .js and the new type: module field node supports?

Sometimes it’s not our choice, I work on some open source projects who choose to use .mjs for whatever reason. I’m guessing now that node supports it without a flag we will only see more of this as time goes by.

Is this something you’re planning to support?

TimvdLippe commented 4 years ago

You can read several reasons in https://v8.dev/features/modules#mjs It is also used in the MDN guide on JavaScript modules: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules

Note that the browser does not look at the file extension. It is up to the developers discretion to choose their file extension. Since there are valid reasons for choosing .mjs, I would conclude that the root issue is that TypeScript has a hard-coded list of valid file extensions. Instead, TypeScript should allow any file extension to be provided in an import and properly type-check. In turn, that would fix code navigation in VS Code.

rauschma commented 4 years ago

How do you stand it?

This kind of snark is frustrating for people who’d love to use .mjs via TypeScript (see all the thumbs up among the comments).

Why do you not use .js and the new type: module field node supports?

How do you handle jsx? Do you use .mjsx or something?

I’m writing all my React in TypeScript. But for plain JavaScript, .mjsx may indeed be useful.


Suggestions:

weswigham commented 4 years ago

@TimvdLippe The mdn/v8 rationale was born from the perceived need for the extension in node, or at least that's how the discussions years ago seemed like they went. (Most all of those docs originally used .js) The recent drive in that direction came from a select group of influencers who believed modules in .js files in node would never happen, and wanted (well-meaningly) to encourage the ecosystem to move past it, so browsers could start seeing real world usage of modules. In doing so they unwitting created other major ecosystem issues (like editor support, for example), but such is life.

Instead, TypeScript should allow any file extension to be provided in an import and properly type-check.

Extensions carry semantic meaning to TS - we can't accept arbitrary extensions without choosing what "arbitrary extension" semantically means (json document? declaration file? typescript source? javascript source? commonjs module? esm module? native module?). Your local file system is more like a full browser + webserver stack than just a browser as far as we're concerned - anyone who says "browsers don't care about extensions" is ever so slightly misleading you. Yes, the browser might not read your extensions, but your webserver will, and then that will inform your browser of filetype information (in the form of MIMEs), usually derived from the extension. We, in the editor, need to use similar logic, to one degree or another, to that whole stack, not just the browser component. Moreover, our default resolution scheme is meant to imitate node, and specifically node's commonjs resolver, not browsers. Assuming that it can handle other resolvers' behaviors as a matter of course is... well, it's a lot.

Complicating all this is this: For truly arbitrary extensions, node of today will load unrecognized extensions as commonjs javascript files (barring custom require.extensions loaders), while a webserver will recognize textual file content (assuming the extension is otherwise unrecognized in its database), report a text mime, and the browser will load it as a module or a script (as text is a potentially valid module and script), depending on what API loaded it. These two competing defaults are irreconcilable for us, so it's better, in our opinion, to simply not recognize unknown extensions. Plus, you probably don't want us doing silly things like trying to read your Makefile as js, or your externs.h. File extensions do carry a lot of meaning. We choose that people be explicit with those meanings, so we don't make (as many) mistakes when checking your code.

@rauschma

This kind of snark is frustrating

I moreso meant "how do you stand it" in the context of "how do you handle all the extra configuration all of your tooling needs to make that work, if it can be configured at all". I, personally, would have prioritized by editor experience over the asks of any other tooling or convention (especially when those tools ostensibly handle any extension), so wouldn't have even considered using a different extension until it was supported in the editor. What was so compelling about the features changing your extensions gave you? What was unlocked by it?

ES modules require them and not having them in TS increases the disconnect between compilation source and compilation target.

We allow you to say foo/bar.js when referring to foo/bar.ts already for pretty much this reason (and is sort-of why moduleResolution: classic mode still exists, which doesn't support node_modules, which, as you know, browsers also don't support). New extensions or no, that won't change...

Less to configure when writing hybrid ES/CJS packages.

Our leaning, right now (as of last Friday's design meeting), is not to support checking this mode of operation, because of the incredible complexity in it (with respect to new extensions to support and hybrid emit modes to rig up). (So we'll only support loading either all esm-targeting-modules or all cjs-targeting-modules, as we do today.) You'll want to open a new issue asking for support of hybrid node-cjs and node-esm projects~

rauschma commented 4 years ago

I moreso meant "how do you stand it" in the context of "how do you handle all the extra configuration all of your tooling needs to make that work, if it can be configured at all".

OK, got it.

I, personally, would have prioritized by editor experience over the asks of any other tooling or convention (especially when those tools ostensibly handle any extension), so wouldn't have even considered using a different extension until it was supported in the editor.

At the moment I can’t really use .mjs – given that neither TS nor VSCode support it. But I’d love to be able to use it in the future.

What was so compelling about the features changing your extensions gave you? What was unlocked by it?

See answer in my previous comment. I don’t know what else to tell you.

We allow you to say foo/bar.js

Ah, good. I think I got confused by VS Code’s error message for .mjs.

Our leaning, right now (as of last Friday's design meeting), is not to support checking this mode of operation, because of the incredible complexity in it (with respect to new extensions to support and hybrid emit modes to rig up). (So we'll only support loading either all esm-targeting-modules or all cjs-targeting-modules, as we do today.) You'll want to open a new issue asking for support of hybrid node-cjs and node-esm projects~

That’s OK, I think. I’d handle these cases via two different configurations and only create the CommonJS files when uploading the Node.js package. (I don’t know if that’s going to work, but that’s what I would try to do.)

AFAICT, optionally writing files with .mjs and otherwise treating .mjs as if it were ESM-based .js is all that is needed. But I may be overlooking something.

jaydenseric commented 4 years ago

People are talking about .mjs like it's some sort of arbitrary preference; in many situations, particularly relating to native ESM that has now shipped in Node.js it's not. The package type: 'module' feature to get .js extensions to load as ESM is a bit of a hack to appease a certain crowd, it has real downsides (.js files containing CJS config for dev tools will be mistaken for ESM) and I doubt it will be used universally.

Having actually used CJS .js and ESM .mjs files side by side by side in real projects and packages for a while now, the distinction is great. You can lint each separately with their correct mode, e.g. banning require() in ESM files and banning import in CJS:

https://github.com/jaydenseric/eslint-config-env/blob/cd3f596d4571c0e4f89cd7ec7e13c42b3ecdcbca/index.js#L244

philipwalton commented 4 years ago

Having actually used CJS .js and ESM .mjs files side by side by side in real projects and packages for a while now, the distinction is great.

I completely agree.

If you've ever tried actually building a web application that uses real ES modules (along with a <script nomodule> fallback) it becomes immediately clear how helpful the distinction can be. Not only can you tell immediately by looking at a filename whether it's a module script or a classic script, but you can also configure your tooling and infrastructure to do that as well:

For example:

It's also the case that many web APIs don't yet support native modules (e.g. Service Worker), so until that changes, web developers will have to deploy JavaScript in module and non-module formats—and being able to easily differentiate them by filename is extremely useful (as many people in this thread have said...over and over again).

@weswigham you laid out the clear argument above that extensions carry semantic meaning:

Extensions carry semantic meaning to TS - we can't accept arbitrary extensions without choosing what "arbitrary extension" semantically means (json document? declaration file? typescript source? javascript source? commonjs module? esm module? native module?). Your local file system is more like a full browser + webserver stack than just a browser as far as we're concerned - anyone who says "browsers don't care about extensions" is ever so slightly misleading you. Yes, the browser might not read your extensions, but your webserver will, and then that will inform your browser of filetype information (in the form of MIMEs), usually derived from the extension

But then your conclusion seems to be that the semantic meaning carried by .mjs is unimportant (and the rationale seems to be based on folk's personal feelings toward .mjs).

I hope we can prevent this issue from becoming a war of ideologies or personal preferences. If node applies semantic meaning to .mjs files, then I don't see an argument against TS supporting it.

weswigham commented 4 years ago

But then your conclusion seems to be that the semantic meaning carried by .mjs is unimportant (and the rationale seems to be based on folk's personal feelings toward .mjs).

My conclusion isn't that .mjs is meaningless - it's that it's implied semantic meaning doesn't mesh well with what we already accept, and we're moving cautiously regarding it. Say we added the ability to read in both .mjs and .js files as input... Whap happens to each? Do we have to transpile both? Do they behave differently? If they don't, then why have both? Is .js only for commonjs modules? It can't be, since there exists esm written with a .js extension. Is .mjs only for es modules? It can't be, because there exists esm written that's intended to be compiled to cjs with a js extension in the output. (Rather than left as-is). It's not synonymous with .js (where anything goes provided it's some kind of JS and intent must be encoded elsewhere) and its meaning is overloaded already - it has semantic baggage. We need to shake out which resolver modes it matters in and what workflows we want to support, to have a consistent story in developing both modules for transpilation to cjs, and modules that arent transpiled. Plus the potentially common scenario of wanting both kinds of output (esm and cjs) from a single input. Patching the existing node module resolution to support mjs amounts to supporting a mixed-mode world (akin to node itself), where some inputs are es modules, and some as cjs modules, and they are handled differently. That's something that we have a rough sketch of, if daunting to us in scope. (Since to maintain full expressivity across both extensions, we'd need to add support and handling for way more than just one new extension). Moreover, how do we encode all these preferences into declaration output? Do we alter declaration file resolution to support more chains of extensions? (foo.mts.d.ts) Do we add a source pragma? Do we hope and pray that there aren't name conflicts and just continue dropping extensions and erasing input formats as we do today? (Spoiler: in the mixed mode type resolver, we can't, as if we don't, then we can't get accurate resolution failures involving declaration files) And then on the input side there's the question of how jsx extensions should layer that adds yet more complexity... Ungh.

Plus, like, lemme ask you this. A question driving at the heart if the original request: If you have an input.mts file, and you have a import "./input.mjs" in that file, what should happen when you compile targeting cjs modules? If we output .mjs, node'll refuse to load it as cjs (because that extension is esm), however if we output as .js, the input won't work (and we categorically will not rewrite your imports). Should we error on the import? This implies that resolver behavior needs to be tied to target module format, assuming it affects extension, and not just the moduleResolution setting. Do note that with implicit extensions, this was much cleaner for us - we could say "just write './input'" and brush the problem under the rug; but without that ability, solving those problems is much more important.

There are answers to these questions and designs that could work (the questions are mostly rhetorical), but the complexity of "how do we emit modules" grows very quickly, and has been growing yet more, - which is why we're very much trying to see just how little we can get by with, for now. That's why I'm asking. What, exactly is forcing everyone to use the mjs extension, what does it get them, and how does it fit into their workflows. What's it's real common use, in practice, rather than in theory. Where can't TS's current model be adapted to work, or the project adapted to work with TS.

Plus, since all the new resolver features aren't even in node yet - if/when the currently flagged features unflag (which will probably be before January's end), we'll need to update much related to this yet again. That we're moving slowly here is very intentional - what we have today can work in many cases (or can be made to work if your project structure is flexible), and is compatible with what we've already been doing (ofc). We have the ability to muck things up quite a bit with the wrong design. We've seen plenty of patches/PRs that just make mjs extensions an output option or an input option, but none go so far as to answer semantic questions like these on the implications of the change.

Plus plus, it's the holidays now, stuff's slower~ Happy (impending) Thanksgiving to everyone in the USA.

TL;DR: If the fact that I keep replying to people here doesn't clue everyone in: we're looking at it - despite the surface level simplicity of the requests, there's actually a lot going on.

robertrossmann commented 4 years ago

I would like to provide some clues about What, exactly is forcing everyone to use the mjs extension question.

I believe that people watching this thread can be categorised into several groups:

Personally I belong into that last group. All I really want is for VS Code to get ES modules supported at the LSP level, which, I think, means to:

Full stop after that (barring I did not forget something important). I understand that in the long term some TypeScript users might want to also emit ESM files or even consume ES modules in their TS files but for me that's a stretch goal at this time given the complexity involved. Right now, however, VS Code lacks support for a major Node.js feature and its cornerstone feature, the intellisense features, do not work at all for anything with .mjs extension in its filename. Personally, getting this supported at the LSP level so non-TS users can start using ES modules in VS Code would be a huge win for the community.

My current usage for ES modules is that I write primarily .mjs files and compile them down to commonJS targets with Babel. The problem with that setup is that the ES modules I write implicitly use CommonJS module resolution mechanism, not the Node's ESM resolution, but I am willing to ditch that and refactor the hell out of it as soon as VS Code gets ESM support into it. Other tools will follow suit soon, I am sure.

weswigham commented 4 years ago

My current usage for ES modules is that I write primarily .mjs files and compile them down to commonJS targets with Babel.

If you're compiling to commonjs, why would you not use the commonjs resolver? We're not going to intervene at runtime and provide a mapping layer between the two resolvers, so you're relying on one resolver being a strict subset of the other - moreover, what benefit do you gain by having your input follow the subset resolver if you're always compiling to a target using the commonjs resolver?

robertrossmann commented 4 years ago

@weswigham I would like to ditch the Babel compilation part altogether now that Node.js supports ES modules natively. I only mentioned my current usage to explain my workflow at this time, not the intended workflow in the future.

TimvdLippe commented 4 years ago

@weswigham As @robertrossmann pointed out, this issue is about the issue in VS Code where code traversal of JavaScript does not work. The points you mentioned about TypeScript itself are valid, but these are tracked in #18442

Admittedly, we should discuss issues with VS Code code traversal in VS Code, but this issue was explicitly moved to the TypeScript repository. The fact that VS Code uses TypeScript for its intellisense is an implementation detail to the end-user imo.

I want the following to work in VS Code (note that I don't use TypeScript at all):

index.js

import { Foo } from './foo.js';
import { Bar } from './bar.mjs';

foo.js

export const Foo = 5;

bar.mjs

export const Bar = 42;

If you ctrl + hover over the imports in index.js, you can see that VS Code detects that foo.js is indeed an exporting module and click-through works as expected. However, the same is not true for bar.mjs. VS Code does not allow click-through, does not provide intellisense and general type warnings. (Note that I wrote the file bar.mjs here, but it could be a third_party project that I want to use that ships .mjs and thus I have no control over its file extension choices)

I understand that the implications for the TypeScript language semantics result in a complex solution that requires a lot of maintenance work. If that is the case, maybe VS Code should use a different LSP backend for providing JavaScript compatibility, as "TypeScript as a language" then creates unfortunate limitations on "TypeScript as a LSP backend for intellisense of JavaScript projects".

piotr-cz commented 4 years ago

Let's not forget that this issue has been created as an VS Code issue.

For example I'm not interested in compiling .mjs files to TypeScript, I just would like intellisense to work properly with these

TimvdLippe commented 4 years ago

I see this issue was mentioned in the meeting notes of 22 November, which spurred additional discussion in this issue on November 27th.

Could this issue be included in a new design meeting, but then focused on the "TypeScript as a language server requires an allowlist of file extensions, which is problematic for VS Code as an editor for generic JavaScript files loaded in a browser, where file extensions don't matter"? Any update on the status of this issue would be greatly appreciated, thanks!

philp commented 4 years ago

Just a small note on the use of the .mjs extension in codebases.

Although the file extension might not have any bearing on how the file is served to or interpreted by the browser, it is important when managing a codebase which spans client and server code. Here's a note from Google on the subject:

You may have noticed we’re using the .mjs file extension for modules. On the Web, the file extension doesn’t really matter, as long as the file is served with the JavaScript MIME type text/javascript. The browser knows it’s a module because of the type attribute on the script element.

Still, we recommend using the .mjs extension for modules, for two reasons:

  1. During development, the .mjs extension makes it crystal clear to you and anyone else looking at your project that the file is a module as opposed to a classic script. (It’s not always possible to tell just by looking at the code.) As mentioned before, modules are treated differently than classic scripts, so the difference is hugely important!
  2. It ensures that your file is parsed as a module by runtimes such as Node.js and d8, and build tools such as Babel. While these environments and tools each have proprietary ways via configuration to interpret files with other extensions as modules, the .mjs extension is the cross-compatible way to ensure that files are treated as modules.

Just thought it worth raising, as the use of .mjs isn't just a cosmetic preference.

justinfagnani commented 4 years ago

Please note that there are many people at Google who disagree with that note. .mjs is almost never necessary, and definitely causes problems with lots of tools. I personally strongly recommend against it.

dandv commented 4 years ago

I believe that people watching this thread can be categorised into several groups:

  • TypeScript users hoping to consume .mjs files in their .ts files

I'm in this camp. Is there a way to import { Foo } from './Foo.mjs' in a .ts file? That would allow gradually migrating ECMAScript Modules code to TypeScript.

frank-dspeed commented 4 years ago

@justinfagnani i promote exactly the opsit you at google should switch now everything to MJS! and i would even prefer if you switch to mjs + jsdocs and check that with typescript and not ts it self but we will all see where we end up i think the force of @guybedford me and others who are pushing the new standards will win at the end because its logic! Sure thanks to some oldschool people we will need much patience but thats a none blocker at all with codemods and existing Tool Chains lol its not so much overhead to compile away not needed tooling like ts.

We have now a shared standard module system and it will get used as its simply working. No Tooling that exists will block that.

I remember that you want to try to force every one into tooling and go away from standards this can't be the Future.

Future

I can see a lot of guides about how to fork a ts projects and maintain that fork automated :). the performance of testing and the expirence as also iteration overall speed is simply better with using mjs directly in a project and no additional build chain for that. it ends up in directly import able code in the browser and other environments.

philp commented 4 years ago

Please note that there are many people at Google who disagree with that note. .mjs is almost never necessary, and definitely causes problems with lots of tools. I personally strongly recommend against it.

Thanks for the input @justinfagnani — it's useful to get a more diverse range of perspectives on these sorts of things.

I think where this all becomes frustrating is when some tools and technologies are promoting a progression to more cohesive working practices, but other tools put a block on their adoption. I wouldn't want to pick sides, it's just an observation from the frontlines, and as a seasoned developer.

A real-world example: I have some JS modules, using a .js extension so that they play nicely with VS Code linting, refactoring, etc. But when I come to write some benchmarking tests, which will run through Node, I have to jump through hoops, because Node expects my modules to have an .mjs extension for modules to be recognised. I don't really want to run them through a preprocessor, because I want to test native ECMAScript syntax.

As a developer, I'm left to make a decision: use .mjs but lose the convenience of my dev tool; or use .js but put a hacky config, a preprocessor or some polyfills in place to make Node play nicely. As a selfish, bratty developer: I just want VS Code to play nicely with .mjs with zero config on my part.

Really just throwing this out there as another niche perspective. Hope it's useful in some way.

rauschma commented 4 years ago

@philp Have you tried "type": "module"? https://nodejs.org/api/esm.html#esm_package_json_type_field

But I agree that being able to use .mjs is important when working with Node.js. Especially in projects that have a mix of JS script files (.js), CommonJS files (.cjs), and ES modules (.mjs).

piotr-cz commented 4 years ago

I've decided to write short comment in top of every .js file to describe whether it's CommonJs or ES module, so for quick peeks I don't have to analyse syntax first.

It feels odd please don't judge me

frank-dspeed commented 4 years ago

@philp for you i have a extra solution put "type": "module" into your package.json and node will handle .js as .mjs maybe it helps you this also works with sub directorys you can put a package.json with that content into all dirs with .js files that should be .mjs

the current loader implamentation reads always package.json relativ to the imported file

frank-dspeed commented 4 years ago

@piotr-cz usage of top level import or export signals esm already really well

frank-dspeed commented 4 years ago

and about the .mjs .js extensions can any one in here tell me a reason why its a good idea to have 2 diffrent processed languages share the same extension ?

why is there a .ts ??? why did they not share the .js extension when that is such a great idea?

piotr-cz commented 4 years ago

@frank-dspeed yes unless there is no import/ require in the file just export/ module.exports somewhere in the middle or at the bottom

philp commented 4 years ago

@rauschma Yes, that type config is something I've tried. Unfortunately, I've been unsuccessful in getting it to work when there are dependencies which implement CommonJS. It's frustrating, and I've kind of given up.

At the risk of appearing to be snarky: lots of chat here about the rights and wrongs of .mjs since Oct `18, but it feels like nothing much will really happen any time soon. The use of transpilation has caused a few difficult knots in the soup of module standards. Would love to find time to contribute, but looking at 16+ month long "quickfix" PRs does not encourage me.

That sounds really sour, but I honestly want to find a way to contribute, rather than discuss the pros and cons of a (seemingly?) established standard.

piotr-cz commented 4 years ago

@philp I think that with the adoption of esm in node, more and more people will find out about this problem and build pressure to have this issue resolved.

If you submit solution, you'll get support at least from most developers in this issue.

frank-dspeed commented 4 years ago

@piotr-cz i do at present a fork of typescript that emits and handels .mjs as js and it works for my usecase as my main goal is to fix typescript for vscode and use it only for typechecking of jsdoc typedef.

later goals are production of codemods to follow the development here and produce pure .mjs builds of typescript it self. that will get typedef via jsdoc and so be more fast fix and iter able.

wxs77577 commented 4 years ago

Any updates on this issue?

frank-dspeed commented 4 years ago

@wxs77577 a update is not even planned i think they want to block transition for the vscode users that are using typescript + jsdoc comments for type interfaces checked with typescript because that will stop usage of the .ts extension.

frank-dspeed commented 4 years ago

i created an example of the current issue so it can be easier replicated.

https://github.com/frank-dspeed/example-typechecking-mjs

exse2 commented 4 years ago

I just want to ctrl-click on the filename in 'import from "./a.mjs"' and it's not working. Is this a embrace, extend, exterminate issue to bring people over to typescript?

NemoStein commented 4 years ago

I just want to ctrl-space on an identifier imported from a .mjs file and have intellisense to auto-complete...

TimvdLippe commented 4 years ago

Chrome DevTools just ran into this again. Acorn (https://github.com/acornjs/acorn) ships a acorn.mjs distribution, but we can't import it in TS. I am not sure what option we have, other than to choose between Acorn or TS with regards to ES modules.