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

Ability to output mjs extension when -d is specified #6222

Closed
tbranyen opened this issue Sep 9, 2017 · 18 comments · Fixed by #9144
Closed

Ability to output mjs extension when -d is specified #6222

tbranyen opened this issue Sep 9, 2017 · 18 comments · Fixed by #9144
Labels
area: modules outdated A closed issue/PR that is archived due to age. Recommended to make a new issue

Comments

@tbranyen
Copy link

tbranyen commented Sep 9, 2017

Feature request:

Recommendation from Node core is to output mjs alongside js files so that the package.json main field can be ambiguous. Since babel only outputs .js files when used with the -d directory flag, it becomes complicated to make this work. I'd like to see an option available to specify the extension the same as with parsing/consuming mjs.

Current Behavior

This is the most elegant solution I've found so far, which involves building all files into a temporary directory, renaming all the files to mjs, copying them into the dist/node destination, and then removing the temp directory.

"build-node-esm": "babel lib -d dist/node-es && rename -v .js .mjs dist/node-es/*.js && rename -v .js .mjs dist/node-es/**/*.js && cp -R dist/node-es/* dist/node && rm -rf dist/node-es",

Possible Solution

My suggestion would be to add a new CLI flag option to specify the output extension. This will allow developers to easily support both Node-based ESM/CJS.

babel lib -d dist/node --ext ".mjs"

Context

I'm trying to figure out how to build a library that will be ready to take advantage of the new Node ESM semantics.

Your Environment

software version(s)
node v9.0.0-pre
@babel-bot
Copy link
Collaborator

Hey @tbranyen! We really appreciate you taking the time to report an issue. The collaborators
on this project attempt to help as many people as possible, but we're a limited number of volunteers,
so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant Slack
community that typically always has someone willing to help. You can sign-up here
for an invite.

@nicolo-ribaudo
Copy link
Member

Would #6221 work for you?

@tbranyen
Copy link
Author

tbranyen commented Sep 9, 2017

No, my source isn't .mjs, it's .js, but I'm trying to output .mjs specifically for Node.

@jridgewell
Copy link
Member

jridgewell commented Sep 10, 2017

Are you trying to have two copies of every file? In that case, a find and copy would probably be better than running babel twice:

babel lib -d dist/node && find ./dist/node -name "*.js" -exec bash -c 'cp "$1" "${1/.js/.mjs}"' -- {} \;

I'm cool with having an --ext and --keep-file-extension, though.

@tbranyen
Copy link
Author

Two copies of every file is the only way to support new Node ESM and legacy CJS. Unfortunate and hopefully temporary.

@hzoo
Copy link
Member

hzoo commented Nov 13, 2017

@ljharb said we should support multi-build so maybe we figure out a way to incorporate these ideas together somehow. (Like if you wanted to output a es5, mjs/modules, esnext folder(s)

@loganfsmyth
Copy link
Member

I think a whole tool built around multiple build targets could be really cool. Not sure it'd make sense for babel-cli to be that tool.

My vote for this would probably be to do #6242 and default sourceType: script, then add a --mjs-modules flag on here, so that anything that was a module gets written with a .mjs extension. That way you could have sourceType: "module" set in some configs or based on env or something, and just the babel command worries about how to save the files and add extensions.

Thoughts?

@hzoo
Copy link
Member

hzoo commented Nov 13, 2017

I think it should be babel-cli since the main use case of cli is to publish modules/packages to npm (not for the browser), and that's where I think it's fine to make it built-in? Shouldn't have to install another package to do a multi build where it seems like a lot of libraries are doing all the logic for this already in package.json?

Although some libraries use rollup, so we could add it to rollup/ the rollup plugin too
https://github.com/reactjs/redux/blob/master/package.json#L22-L26

    "build:commonjs": "cross-env BABEL_ENV=commonjs babel src --out-dir lib",
    "build:es": "cross-env BABEL_ENV=es babel src --out-dir es",
    "build:umd": "cross-env BABEL_ENV=es NODE_ENV=development rollup -c -i src/index.js -o dist/redux.js",
    "build:umd:min": "cross-env BABEL_ENV=es NODE_ENV=production rollup -c -i src/index.js -o dist/redux.min.js",
    "build": "npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min",

Ok although we also added that --keep-file-extension flag too

@jaydenseric
Copy link

jaydenseric commented Nov 13, 2017

Here is how I have it working with the CLI:

{
  "build": "npm run build:main && npm run build:module",
  "build:main": "babel src --out-dir lib/main --config-file ./babelrc.main.json",
  "build:module": "babel src --out-dir lib/module --config-file ./babelrc.module.json --keep-file-extension"
}

The source files have .mjs. The main build automatically generates .js, while the module build preserves .mjs thanks to --keep-file-extension.

The only difference between babelrc.main.json and .babelrc.module.json is that preset-env has "modules": false in ./babelrc.module.json. I tried to make the config more DRY by having both extend babelrc.common.json, but there is still some duplication in the preset-env config 🙁

IMO Rollup is the wrong tool for packages; dependencies should be imported not bundled. It would be great if the Babel CLI handled this common use case with less complex config.

@ljharb
Copy link
Member

ljharb commented Nov 13, 2017

The primary use case for babel-cli is indeed "i have a package and i want to prepare it for being properly published".

"Properly", currently, means that your package.json main points to a CJS + ES5 file (ideally with extension omitted). You can choose what else to include as you like, and individual entry points need to be documented, along with their module format if applicable.

The instant node supports .mjs unflagged (in a hypothetical version X), "properly" will mean that your package.json main will omit the extension, and point to a path that has a .js file that's CJS + ES5, and an .mjs file that's ESM + "whatever syntax node X supports" (even as future versions support more things). Anything that's an entry point should also have paired .js/.mjs files, and the extensionless path needs to be documented (but the module format of these no longer needs specifying).

It's very important that prior to this point, it be easy for babel-cli to handle this use case by default.

@loganfsmyth
Copy link
Member

I think it should be babel-cli since the main use case of cli is to publish modules/packages to npm

That's fair. I should clarify that my concern is more that the babel command as it is is pretty simple. Expanding it to more complex usecases seems likely to be a breaking change, and I feel like there's a lot of existing code out there using the babel command that is probably perfectly happy as-is. Perhaps if we consider a more complex CLI tool, we give it a clearer name to go alongside the existing commands?

@tunnckoCore
Copy link

tunnckoCore commented May 3, 2018

The --keep-file-extension is good. But in case that your scenario is to use typescript files (intentionally, because the ide support) and compiles typescript through the Babel7, that flag can't help.

@donaldpipowitch
Copy link

donaldpipowitch commented May 9, 2018

We use TypeScript as well. Multiple build targets sound really nice. I really want to use the same config everywhere and just change the module format and I would like to use --watch easily and still output multiple formats. It would be nice to specify the output extension (e.g. I heard .mjs is currently not the best fit for webpack, but .esm.js like Inferno currently does) and it would be actually really nice to be able to output them in the same directory, just with different extensions (in case you used --copy-files to copy assets and you want to keep the references).

@conartist6
Copy link
Contributor

I too think this use case (foo.js => babel => foo.jsm) is so core as to be a pretty sensible thing to support even if the babel cli does not support more generalized functionality like multiple build targets or arbitrary file renaming.

@conartist6
Copy link
Contributor

Here's what I'm doing right now, utilizing https://www.npmjs.com/package/renamer:

"scripts": {
"build:commonjs": "cross-env BABEL_ENV=commonjs babel src --out-dir lib",
"build:es": "cross-env BABEL_ENV=es babel src --out-dir lib",
"build":
"npm run build:es && renamer --regex --find '\.js$' --replace '.mjs' 'lib/**' && npm run build:commonjs",
}

An earlier poster did something similar with find, but Windows isn't going to have find.

@AaronNGray
Copy link

AaronNGray commented Aug 21, 2018

from looking at the code I have found using --keep-file-extension solves this issue for my use case at least.

@tbranyen
Copy link
Author

@AaronNGray that flag was brought up last year, you'll find it in the very comments you're responding to. The use case is taking any input and outputting as mjs, for instance TypeScript...

@eps1lon
Copy link
Contributor

eps1lon commented Dec 7, 2018

PR open at #9144

@github-actions github-actions bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Apr 10, 2020
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 10, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: modules outdated A closed issue/PR that is archived due to age. Recommended to make a new issue
Projects
None yet