Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

actually discuss `.cjs` extension #293

Open
ljharb opened this Issue Mar 13, 2019 · 16 comments

Comments

Projects
None yet
8 participants
@ljharb
Copy link
Contributor

ljharb commented Mar 13, 2019

The .cjs extension imo never received explicit consensus - it seems to have been discussed solely in side channels, and merged as part of a much larger PR that achieved consensus without mentioning this aspect of it.

Let's please discuss it, have it either reach consensus to keep it, or remove it.

@jkrems

This comment has been minimized.

Copy link

jkrems commented Mar 13, 2019

@targos

This comment has been minimized.

Copy link
Member

targos commented Mar 13, 2019

I haven't made up my mind yet, but to me it just seems like nobody will actually use this extension.

@WebReflection

This comment has been minimized.

Copy link
Contributor

WebReflection commented Mar 14, 2019

FWIW

I haven't made up my mind yet, but to me it just seems like nobody will actually use this extension.

I would, and others have already expressed their preference for an explicit .cjs over .mjs.

The .cjs extension is also one of the best ways to migrate older projects/dependencies or keep these as such.

// modern JS
import legacy from './module-name.cjs';

// module-name.cjs
module.exports = require('module-name');

That will disambiguate without needing any change to already published CJS modules.

@adrianhelvik

This comment has been minimized.

Copy link

adrianhelvik commented Mar 15, 2019

I don't see how this would change anything. Okay, allow it if you like it, but we'll still need mjs to determine which parser to use. To me, this would just mean .js == .cjs. Which I have absolutely no opinion about. Is that the purpose?

@WebReflection

This comment has been minimized.

Copy link
Contributor

WebReflection commented Mar 16, 2019

we'll still need mjs to determine which parser to use

if the code is executed as ESM, regardless the .mjs extension, .cjs determines the parse goal of the legacy/intermediate imported file.

To me, this would just mean .js == .cjs

to me this mean .js can be the present and the future, and .cjs imported at any time though a single, intermediate, file, for any legacy module that doesn't offer an ESM counterpart.

Is that the purpose?

the purpose is to disambiguate .cjs from ESM, same way you'd use .mjs to disambiguate from CJS.
I'd personally write everything as ESM using .js extension and explicit import legacy dependencies without an ESM counter part through an intermediate .cjs file.

@adrianhelvik

This comment has been minimized.

Copy link

adrianhelvik commented Mar 16, 2019

Then you would have to use --module or something to determine the parse goal, or break all legacy apps.

@WebReflection

This comment has been minimized.

Copy link
Contributor

WebReflection commented Mar 17, 2019

@adrianhelvik alias node='node -m' would work great for me 👋

@adrianhelvik

This comment has been minimized.

Copy link

adrianhelvik commented Mar 17, 2019

Okay. So the proposal is that:

  • By default .js == .cjs
  • With -m/--module, project files will default to being interpreted as modules unless they use the extension .cjs or come from external packages.

Okay, get it. :)

@WebReflection

This comment has been minimized.

Copy link
Contributor

WebReflection commented Mar 17, 2019

By default .js == .cjs

AFAIK that won't be the case since there are multiple ways to disambiguate .js, but the proposal is that .cjs will disambiguate CJS no matter what, same as .mjs disambiguate ESM no matter what.

Every argument made for .mjs is valid for .cjs too.

@ljharb

This comment has been minimized.

Copy link
Contributor Author

ljharb commented Mar 17, 2019

That’s not exactly accurate; the argument for .mjs is that .js means cjs already. The argument for .cjs, as i understand it, only exists when a mode is enabled that changes the meaning of .js to mean ESM.

@WebReflection

This comment has been minimized.

Copy link
Contributor

WebReflection commented Mar 18, 2019

.js means cjs already

not necessarily, accordingly to the current state, flags etc. .js can be parsed as ESM and mean ESM.

In such context, .cjs will disambiguate CJS no matter what, same as .mjs disambiguate ESM no matter what.

In such context, every argument made for .mjs is valid for .cjs too, so there's no reason to not have it.

@adrianhelvik

This comment has been minimized.

Copy link

adrianhelvik commented Mar 18, 2019

.mjs is the future. .js interpreted as esm on a per project basis is good for interop and .cjs fills in the little edge case of someone needing CommonJS, but not wanting to change the extension of all their files.

To me, .js as esm on a per package basis sounds like a small feature that would ease the transition for a lot of people in the short run. (before .mjs becomes widespread) .cjs is a natural extension of that.

@weswigham

This comment has been minimized.

Copy link

weswigham commented Mar 18, 2019

.mjs is the future

audible gagging noises heard from twitter

Most would see .mjs as vestigial and hope that at some point in the future .js as esm could become the default. Take this reasoned transition plan, for example:

  1. type field is available unflagged in node 12. npm --init starts to generate package.json files with "type": "module" set.
  2. node 13 - warn on packages without "type": set to a known value ("module" or "commonjs"). npm automatically adds "type": "commonjs" to packages missing the field on installation, so most people don't actually notice the change.
  3. node 14 - "type": "module" or "type": "commonjs" is now a required package.json field.
  4. node 15 - Packages missing a "type": field are now assumed to be "type": "module" by default. npm now automatically only appends "type": "commonjs" to packages last updated prior to a specified cutoff date (and does nothing to modern packages).

This would advance the ecosystem default in a relatively easy-to-handle way, IMO, with npm's coordination. Many would argue that .mjs is a technical crutch - not the future.

@adrianhelvik

This comment has been minimized.

Copy link

adrianhelvik commented Mar 18, 2019

Okay, that does not sound too bad to me. But why is .mjs so bad? Have you actually tried it. It's quite simple really. Just use the mjs extension.

Try it out on two pet projects and get back to me.

@GeoffreyBooth

This comment has been minimized.

Copy link
Contributor

GeoffreyBooth commented Mar 18, 2019

Okay, that does not sound too bad to me. But why is .mjs so bad? Have you actually tried it. It’s quite simple really. Just use the mjs extension.

Try it out on two pet projects and get back to me.

Yes, I tried it: #151 (comment)

@shannon

This comment has been minimized.

Copy link

shannon commented Mar 18, 2019

.js means cjs already

This is only true for Node. As a passive observer of this discussion I just felt like this needs to be stated.

There are still other module systems besides commonjs. .js means JavaScript. It doesn't unamibiguously mean any module system at all. Commonjs needs disambiguation just as much as ESM outside of the context of Node.

Normally I would use .cjs.js or .amd.js or .umd.js, etc as a matter of convention. When writing modern standard JavaScript I never assume Commonjs as the default. It's what I transpile to from the standard format (ESM).

Personally I use .js extensions in my source files because I'm writing standard JavaScript and I never write non-module scripts in the browser any more. In the browser I've moved on to this format and there is no need for disambiguation. I'd like to do the same in Node. Adding .cjs just makes this transition easier as @WebReflection described. It also gives me an official extension to transpile my code to Commonjs with for users that aren't ready for this step. Just as I would use .umd.js for legacy browser.

I'm not sure but it seems like opposition to this extension might stem from a code for Node first mentality. I think there are a lot of developers who code for other environments first and transpile to add support for Node.

To me it's not all about making a single codebase run in both environments. It's about being able to use the same conventions universally. So there is less supefluous context switching between projects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.