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

ECMAScript Module for Node.js #342

Closed
ctavan opened this issue Oct 31, 2019 · 11 comments · Fixed by #423
Closed

ECMAScript Module for Node.js #342

ctavan opened this issue Oct 31, 2019 · 11 comments · Fixed by #423
Labels

Comments

@ctavan
Copy link
Member

ctavan commented Oct 31, 2019

As of 2019-10-31 ECMAScript Module (ESM) support in Node.js is still experimental and there is not yet a stable way of offering an ESM build for Node.js. The authors of the Node.js module working group even urge developers not to release dual CommonJS/ESM packages to npm yet, see: https://github.com/nodejs/modules/blob/master/doc/plan-for-new-modules-implementation.md#phase-4-further-improvements-after-unflagging which states:

  • Dual CommonJS/ESM packages: Either support packages with both CommonJS and ESM sources that can be used in either environment; or decide to specifically not support dual CommonJS/ESM packages.
    • Status quo (at time of possible unflagging): "main" points to exactly one file, and all file extensions are mandatory (by default), so there is no possibility of an import specifier pointing to different files in ESM versus CommonJS. Recommended practice for dual packages is to have "main" point to the CommonJS entry point and have users use a deep import, e.g. /module.mjs, to access ESM entry point.

There is ongoing work within Node.js to support multiple exports for npm packages which will eventually solve this issue. We will support this feature once it becomes stable in node (i.e. once it's no longer hidden behind an experimental flag).

Corresponding Node.js issues:

@ctavan
Copy link
Member Author

ctavan commented Jan 20, 2020

Current status: https://github.com/nodejs/modules/blob/master/doc/plan-for-new-modules-implementation.md#phase-4-further-improvements-after-unflagging

Status: --experimental-conditional-exports will unflag by the end of January 2020 unless consensus is reached on an alternative approach. The flag may be dropped sooner if a consensus is reached, either for an alternative solution or for --experimental-conditional-exports.

@ctavan ctavan mentioned this issue Jan 20, 2020
10 tasks
@dstaley
Copy link

dstaley commented Feb 23, 2020

@ctavan Just curious: are you planning on enabling the ES module version for Node? I'm considering doing the same in my libraries, and would love to hear your thoughts there.

@ctavan
Copy link
Member Author

ctavan commented Feb 24, 2020

@dstaley TL;DR: Yes, but not immediately.

I am planning to do this. However given the whole thing has only recently landed in Node.js, it's still flagged as experimental and there has been a lot of back and forth with the implementation details, I will likely wait a bit longer until ESM support is more stable in Node.js

Also, it will be a bit of a challenge to enable ESM for Node.js with this module since we have different code to be executed when running in Node.js vs. in Browser environments. This has to be solved with ESM as well…

@tapz
Copy link

tapz commented Feb 28, 2020

What is the correct way currently to require the module in node.js? Didn't find an answer from the docs. Or should I just ignore the deprecation warning?

@TrySound
Copy link
Member

@tapz No correct way until conditional exports (https://nodejs.org/docs/latest-v12.x/api/esm.html#esm_conditional_exports) are landed in node. Currently they are under feature flag.

@tapz
Copy link

tapz commented Feb 28, 2020

@TrySound Then I really don't understand why this change was done. Does not make any sense at all.

@ctavan
Copy link
Member Author

ctavan commented Feb 28, 2020

@tapz what are you looking for?

Do you want to use this module as a native ECMAScript Module (ESM) with Node.js' experimental ESM support? Then, as this issue describes and as mentioned by @TrySound, this is not yet supported (because this is all still experimental in Node.js).

Do you want to use this module as a classic CommonJS module with Node.js (require()-Syntax)? Then everything should be documented in https://github.com/uuidjs/uuid#deep-requires-now-deprecated

Does this answer your question? If it is still unclear it would be great to learn how we can make the docs clearer.

@TrySound
Copy link
Member

@tapz This change was done to allow bundlers like rollup and webpack build more efficient code. And later native node support can be added with less steps.

@mdodge-ecgrow
Copy link

mdodge-ecgrow commented Mar 20, 2020

I'm trying to figure out how to use this in my sequelize seed file. I'm getting the deprecation warning and it is causing it to fail seeding.
This is my relevant code:

'use strict';

const uuidv4 = require('uuid/v4');
const bcrypt = require('bcryptjs');

const saltRounds = 10;
async function hash(password) {
	return await bcrypt.hash(password, saltRounds);
}

module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.bulkInsert('users', [
      {
	id: uuidv4(),

If I switch to import, I get ERROR: Cannot use import statement outside a module

@TrySound
Copy link
Member

This will work too

const { v4: uuidv4 } = require('uuid');

ctavan added a commit that referenced this issue Apr 29, 2020
BREAKING CHANGE: Native ES Modules is still an experimental API in
Node.js 14.0.0 and has so far not officially been supported by the
`uuid` module.

Since Node.js allows importing CommonJS modules it was possible to
import the `uuid` module like this:

```js
import uuid from 'uuid';
console.log(uuid.v4()); // -> 'cd6c3b08-0adc-4f4b-a6ef-36087a1c9869'
```

This will no longer work with proper ES Module exports in place. You
can now import the `uuid` library as described in the documentation:

```js
import { v4 as uuidv4 } from 'uuid';
uuidv4(); // ⇨ '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
```

or

```js
import * as uuid from 'uuid';
console.log(uuid.v4()); // -> 'cd6c3b08-0adc-4f4b-a6ef-36087a1c9869'
```

Enabling native ES Modules for Node.js requires some special care for
the v1 algorithm which needs internal state. This makes this library
susceptible to the dual package hazard described in
https://nodejs.org/docs/latest-v14.x/api/esm.html#esm_dual_commonjs_es_module_packages

While the "isolated state" solution seems to make more sense it causes
trouble with rollup which supports CommonJS files only with an
additional plugin, see rollup/rollup#3514.

It is worth noting that webpack could deal with the "isolated state"
solution since webpack supports CommonJS sources out of the box without
further plugins and also doesn't get confused by `.cjs` file extensions
that would have to be used in the state isolation approach for
compatibility with Node.js.

The wrapper approach should however work fine. Here's what code will be
used in each case:

1. Node.js `require('uuid')`
  -> dist/index.js (CommonJS) -> dist/v1.js (CommonJS)
2. Node.js `import { v1 as uuidv1 } from 'uuid'`
  -> wrapper.mjs (ESM) -> dist/v1.js (CommonJS)
3. rollup/webpack (targeting Node.js environments)
  -> dist/esm-node/index.js (ESM) -> dist/esm-node/v1.js (ESM)
4. rollup/webpack (targeting Browser environments)
  -> dist/esm-browser/index.js (ESM) -> dist/esm-browser/v1.js (ESM)

Fixes #245
Fixes #419
Fixes #342
@ctavan
Copy link
Member Author

ctavan commented Apr 29, 2020

For everyone in this thread: we have just released [email protected] which comes with native ESM support for Node.js! Let us know if that works for you. See CHANGELOG for more info.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
5 participants