core-decorators icon indicating copy to clipboard operation
core-decorators copied to clipboard

Support Node 10 ECMAScript Modules

Open dantman opened this issue 6 years ago • 1 comments

Node has implemented native support for ES2015 modules with an .mjs extension. True modules that function according to the spec.

One limitation of the spec differences between real ES modules and CommonJS modules is that imports from CommonJS modules cannot use named imports, the entire exports/module.exports object is just exposed as the default export.

For core-decorators this results in the following: https://github.com/dantman/core-decorators-esm-test

core-decorators-modules daniel$ npm start

> [email protected] start /private/tmp/core-decorators-modules
> npm run run:babel && npm run run:esm


> [email protected] run:babel /private/tmp/core-decorators-modules
> babel test.js > babel-test.js && node babel-test.js

{ override: [Getter],
  deprecate: [Getter],
  deprecated: [Getter],
  suppressWarnings: [Getter],
  memoize: [Getter],
  autobind: [Getter],
  readonly: [Getter],
  enumerable: [Getter],
  nonenumerable: [Getter],
  nonconfigurable: [Getter],
  debounce: [Getter],
  throttle: [Getter],
  decorate: [Getter],
  mixin: [Getter],
  mixins: [Getter],
  lazyInitialize: [Getter],
  time: [Getter],
  extendDescriptor: [Getter],
  profile: [Getter],
  applyDecorators: [Getter] }

> [email protected] run:esm /private/tmp/core-decorators-modules
> node --experimental-modules test.mjs

(node:22402) ExperimentalWarning: The ESM module loader is experimental.
{ default:
   { override: [Getter],
     deprecate: [Getter],
     deprecated: [Getter],
     suppressWarnings: [Getter],
     memoize: [Getter],
     autobind: [Getter],
     readonly: [Getter],
     enumerable: [Getter],
     nonenumerable: [Getter],
     nonconfigurable: [Getter],
     debounce: [Getter],
     throttle: [Getter],
     decorate: [Getter],
     mixin: [Getter],
     mixins: [Getter],
     lazyInitialize: [Getter],
     time: [Getter],
     extendDescriptor: [Getter],
     profile: [Getter],
     applyDecorators: [Getter] } }

You cannot import {autobind} from 'core-decorators'; inside of ESM code. Your only option is to import CD from 'core-decorators'; const {autobind} = CD;.

To make it possible to use named imports from core-decorators I think it would be a good idea to support Node 10's ES modules.

Doing this should be pretty simple for core-decorators, as core-decorators is a leaf package (a package with no dependencies). We just need to export another build in the package that uses ES modules like es/ does but uses the .mjs file extension. Also ESM modules use the same main as normal Node modules, you just specify main without an extension and Node 9- will get your CommonJS .js and Node 10/--experimental-modules will get the ESM .mjs. So either the .mjs build will need to be in lib/ or you'll need an index.js and index.mjs in the package root to switch between module.exports = require('./lib'); and export * from './esm';.

Given how ESM works, I think the ecosystem would adapt to ESM easiest if leaf packages like core-decorators are the first to support ESM. (Then packages with dependencies on leaf packages don't need to worry about importing CommonJS versions of leaf packages)

dantman avatar Apr 09 '18 21:04 dantman