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

Cannot import pure ECMAScript modules in rollup.config.js #3443

Closed
haraldrudell opened this issue Mar 14, 2020 · 8 comments · Fixed by #3445
Closed

Cannot import pure ECMAScript modules in rollup.config.js #3443

haraldrudell opened this issue Mar 14, 2020 · 8 comments · Fixed by #3445

Comments

@haraldrudell
Copy link

package.json:

{
  "type": "module",
  "devDependencies": {
    "rollup": ">=2.0.6 <3",
    "rollup-plugin-thatworks": ">=1.0.3 <2"
  }
}

rollup.config.js:

import {shebang} from 'rollup-plugin-thatworks' // esm import
export default {input: 'rollup.config.js'}

Node.js: v13.6.0

Actual Behavior

yarn && yarn rollup --config
yarn install v1.21.1                                                                                           
warning package.json: No license field                                                                         
warning No license field                                                                                       
[1/4] 🔍  Resolving packages...                                                                                
success Already up-to-date.                                                                                    
✨  Done in 0.18s.
yarn run v1.21.1
warning package.json: No license field                                                                         
$ /opt/foxyboy/sw/pri/code-samples/rollup2/node_modules/.bin/rollup --config                                   
loaded rollup.config.js with warnings                                                                          
(!) Unused external imports                                                                                    
shebang imported from external module 'rollup-plugin-thatworks' but never used                                 
[!] Error: Must use import to load ES Module: /opt/foxyboy/sw/pri/code-samples/rollup2/node_modules/rollup-plugin-thatworks/lib/thatworks.js                                                                                  
require() of ES modules is not supported.                                                                      
require() of /opt/foxyboy/sw/pri/code-samples/rollup2/node_modules/rollup-plugin-thatworks/lib/thatworks.js from /opt/foxyboy/sw/pri/code-samples/rollup2/rollup.config.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.                                                                                                            
Instead rename thatworks.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /opt/foxyboy/sw/pri/code-samples/rollup2/node_modules/rollup-plugin-thatworks/package.json.

    at Module._extensions..js (internal/modules/cjs/loader.js:1160:13)
    at Object.require.extensions. [as .js] (/opt/foxyboy/sw/pri/code-samples/rollup2/node_modules/rol
lup/dist/bin/rollup:1812:17)
    at Module.load (internal/modules/cjs/loader.js:993:32)
    at Function.Module._load (internal/modules/cjs/loader.js:892:14)
    at Module.require (internal/modules/cjs/loader.js:1033:19)
    at require (internal/modules/cjs/helpers.js:72:18)
    at Object. (/opt/foxyboy/sw/pri/code-samples/rollup2/rollup.config.js:5:1)
    at Module._compile (internal/modules/cjs/loader.js:1144:30)
    at Object.require.extensions. [as .js] (/opt/foxyboy/sw/pri/code-samples/rollup2/node_modules/rol
lup/dist/bin/rollup:1809:24)
    at Module.load (internal/modules/cjs/loader.js:993:32)

Expected Behavior

rollup 2.0.6 to be able to use import of ECMAScript modules in rollup.config.js per Node.js v12.0.0+

cause: rollup has an internal transpiler that converts import to require. Node.js ESM then fails

@lukastaegert
Copy link
Member

lukastaegert commented Mar 14, 2020

I see what is happening here and this is definitely something we should support, the question is just how. The fact that Rollup transpiles its config file has been very useful in the past but with native ESM support in Node, it is facing its limitations.

I have been thinking a little about various solutions, especially solutions that do not require people to change their workflow, but it is not quite straightforward without introducing breaking changes or a complicated detection logic. Most notably it is not really easy to reliably detect if Node would think some file is an ES module based on package.json files. It is easy however to do this based on extensions. So this is my proposal to fix this:

  • If the config file has a .mjs or .cjs extension, we leave it untranspiled
  • Otherwise we transpile
  • Furthermore if no name is provided instead of just looking for rollup.config.js, rollup will by default also look for rollup.config.mjs and rollup.config.cjs in the order mjs -> cjs -> js.

I do not really love mjs but this would be an easy non-breaking way to make things work before we think about extending this in a new major version. E.g. in Rollup 3, we could decide to only transpile if we are on a Node version <= 12.

Furthermore we could help the user by scanning if our import of the config file throws the error above so that we can instead show our own error message that instructs the user about using extensions.

@lukastaegert
Copy link
Member

Working on a fix in #3445

@haraldrudell
Copy link
Author

As of 3/16/2020, using the load-untranspiled-config-file branch works:

package.json:

{
  "type": "module",
  "devDependencies": {
    "allspawn": "1.0.1",
    "rollup-plugin-thatworks": "1.0.4"
  }
}

rollup.config.mjs:

import {value} from './src/esmExport.js' // in-project esm import
import {shebang} from 'rollup-plugin-thatworks' // esm import
import allspawn from 'allspawn' // CommonJS import (named exports are in default on esm)
const {SpawnAsync} = allspawn
console.log(`typeof shebang: ${typeof shebang} SpawnAsync: ${typeof SpawnAsync}`)
export default {input: 'src/index'}

src/index.mjs:

// empty

src/esmExport.js:

export const value = 2

src/testNode.js

import {shebang} from 'rollup-plugin-thatworks' // esm import
import allspawn from 'allspawn' // CommonJS import (named exports are in default on esm)
const {SpawnAsync} = allspawn
console.log(`Node.js version: ${process.versions.node}`)
console.log(`typeof shebang: ${typeof shebang} SpawnAsync: ${typeof SpawnAsync}`)

git clone --depth 1 --single-branch --branch load-untranspiled-config-file https://github.com/rollup/rollup.git && (cd rollup && yarn) && yarn add --dev ./rollupyarn && yarn rollup --config;  node src/testNode
yarn install v1.22.4
warning package.json: No license field
warning No license field
[1/4] 🔍  Resolving packages...
success Already up-to-date.
✨  Done in 0.11s.
yarn run v1.22.4
warning package.json: No license field
$ /opt/foxyboy/sw/pri/code-samples/rollupmjs/node_modules/.bin/rollup --config
(node:27371) ExperimentalWarning: The ESM module loader is experimental.
typeof shebang: function SpawnAsync: function

src/index → stdout...

(!) Generated an empty chunk
index
created stdout in 21ms
✨  Done in 0.84s.
(node:27372) ExperimentalWarning: The ESM module loader is experimental.
Node.js version: 13.11.0
typeof shebang: function SpawnAsync: function

My take on ECMAScript is Erase the PAST
The past is now anything less than Node.js v12.0.0

Can we get the load-untranspiled-config-file patch in the registry, please?

@lukastaegert
Copy link
Member

There is still quite a bit of documentation to be adjusted and written. Also, there is a feature I want to push first because it will make the current implementation nicer. Until then I would recommend installing from the branch if you rely on this.

@haraldrudell
Copy link
Author

haraldrudell commented Mar 16, 2020

I published a package rollup-esm-206 which one can use like:

yarn add --dev rollup@npm:rollup-esm-206

There is another nasty issue:

you would want to add the --experimental-json-modules option to Node.js when executing rollup so that json files can be imported in rollup.config.mjs. This would require a Node.js intermediate executable that inserts this option into argv and then execs the previous rollup executable. Ugly

quick-fix is to change:

    "build": "rollup --config config/rollup.config.mjs",

to

    "build": "node --experimental-json-modules ./node_modules/.bin/rollup --config config/rollup.config.mjs",

@lukastaegert
Copy link
Member

I will put this into the docs. Another way forward would be adding the option to the shebang but this would break Node 10 support, alas. There are two more options:

  • Create a small proxy with .cjs extension that requires the JSON file and puts it to module.exports and import this file instead:
    // load-package.cjs
    module.exports = require('./package.json');
    
    // rollup.config.mjs
    import pkg from './load-package.cjs';
    ...
  • use createRequire:
    // rollup.config.mjs
    import { createRequire } from 'module';
    const require = createRequire(import.meta.url);
    const pkg = require('./package.json');
    ...

@lukastaegert
Copy link
Member

I will not put the second option into the docs as I believe this is from an evil place.

@haraldrudell
Copy link
Author

The greatness is that the syntax:

rollup --config node:es2049package

works, too, for an ECMAScript modules exporting package. The exported file in that package, though, has to have the .mjs extension:

  "main": "lib/es2049package.mjs",

Not a single require anywhere

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

Successfully merging a pull request may close this issue.

2 participants