I was about to publish a module to NPM, when I thought about rewriting it in ES6, to both future-proof it, and learn ES6. I've used Babel to transpile to ES5, and run tests. But I'm not sure how to proceed:
Do I transpile, and publish the resulting /out folder to NPM?
Do I include the result folder in my Github repo?
Or do I maintain 2 repos, one with the ES6 code + gulp script for Github, and one with the transpiled results + tests for NPM?
In short: what steps do I need to take to publish a module written in ES6 to NPM, while still allowing people to browse/fork the original code?
The pattern I have seen so far is to keep the es6 files in a src directory and build your stuff in npm's prepublish to the lib directory.
You will need an .npmignore file, similar to .gitignore but ignoring src instead of lib.
I like José's answer. I've noticed several modules follow that pattern already. Here's how you can easily implement it with Babel6. I install babel-cli locally so the build doesn't break if I ever change my global babel version.
.npmignore
/src/
.gitignore
/lib/
/node_modules/
Install Babel
npm install --save-dev babel-core babel-cli babel-preset-es2015
package.json
{
"main": "lib/index.js",
"scripts": {
"prepublish": "babel src --out-dir lib"
},
"babel": {
"presets": ["es2015"]
}
}
TL;DR - Don't, until ~October 2019. The Node.js Modules Team has asked:
Please do not publish any ES module packages intended for use by Node.js until [October 2019]
2019 May update
Since 2015 when this question was asked, JavaScript support for modules has matured significantly, and is hopefully going to be officially stable in October 2019. All other answers are now obsolete or overly complicated. Here is the current situation and best practice.
ES6 support
99% of ES6 (aka 2015) has been supported by Node since version 6. The current version of Node is 12. All evergreen browsers support the vast majority of ES6 features. ECMAScript is now at version 2019, and the versioning scheme now favors using years.
ES Modules (aka ECMAScript modules) in browsers
All evergreen browsers have been supporting import-ing ES6 modules since 2017. Dynamic imports are supported by Chrome (+ forks like Opera and Samsung Internet) and Safari. Firefox support is slated for the next version, 67.
You no longer need Webpack/rollup/Parcel etc. to load modules. They may be still useful for other purposes, but are not required to load your code. You can directly import URLs pointing to ES modules code.
ES modules in Node
ES modules (.mjs files with import/export) have been supported since Node v8.5.0 by calling node with the --experimental-modules flag. Node v12, released in April 2019, rewrote the experimental modules support. The most visible change is that the file extension needs to be specified by default when importing:
// lib.mjs
export const hello = 'Hello world!';
// index.mjs:
import { hello } from './lib.mjs';
console.log(hello);
Note the mandatory .mjs extensions throughout. Run as:
node --experimental-modules index.mjs
The Node 12 release is also when the Modules Team asked developers to not publish ES module packages intended for use by Node.js until a solution is found for using packages via both require('pkg') and import 'pkg'. You can still publish native ES modules intended for browsers.
Ecosystem support of native ES modules
As of May 2019, ecosystem support for ES Modules is immature. For example, test frameworks like Jest and Ava don't support --experimental-modules. You need to use a transpiler, and must then decide between using the named import (import { symbol }) syntax (which won't work with most npm packages yet), and the default import syntax (import Package from 'package'), which does work, but not when Babel parses it for packages authored in TypeScript (graphql-tools, node-influx, faast etc.) There is however a workaround that works both with --experimental-modules and if Babel transpiles your code so you can test it with Jest/Ava/Mocha etc:
import * as ApolloServerM from 'apollo-server'; const ApolloServer = ApolloServerM.default || ApolloServerM;
Arguably ugly, but this way you can write your own ES modules code with import/export and run it with node --experimental-modules, without transpilers. If you have dependencies that aren't ESM-ready yet, import them as above, and you'll be able to use test frameworks and other tooling via Babel.
Previous answer to the question - remember, don't do this until Node solves the require/import issue, hopefully around October 2019.
Publishing ES6 modules to npm, with backwards compatibility
To publish an ES module to npmjs.org so that it can be imported directly, without Babel or other transpilers, simply point the main field in your package.json to the .mjs file, but omit the extension:
{
"name": "mjs-example",
"main": "index"
}
That's the only change. By omitting the extension, Node will look first for an mjs file if run with --experimental-modules. Otherwise it will fall back to the .js file, so your existing transpilation process to support older Node versions will work as before — just make sure to point Babel to the .mjs file(s).
Here's the source for a native ES module with backwards compatibility for Node < 8.5.0 that I published to NPM. You can use it right now, without Babel or anything else.
Install the module:
npm install local-iso-dt
# or, yarn add local-iso-dt
Create a test file test.mjs:
import { localISOdt } from 'local-iso-dt/index.mjs';
console.log(localISOdt(), 'Starting job...');
Run node (v8.5.0+) with the --experimental-modules flag:
node --experimental-modules test.mjs
TypeScript
If you develop in TypeScript, you can generate ES6 code and use ES6 modules:
tsc index.js --target es6 --modules es2015
Then, you need to rename *.js output to .mjs, a known issue that will hopefully get fixed soon so tsc can output .mjs files directly.
#Jose is right. There's nothing wrong with publishing ES6/ES2015 to NPM but that may cause trouble, specially if the person using your package is using Webpack, for instance, because normally people ignore the node_modules folder while preprocessing with babel for performance reasons.
So, just use gulp, grunt or simply Node.js to build a lib folder that is ES5.
Here's my build-lib.js script, which I keep in ./tools/ (no gulpor grunt here):
var rimraf = require('rimraf-promise');
var colors = require('colors');
var exec = require('child-process-promise').exec;
console.log('building lib'.green);
rimraf('./lib')
.then(function (error) {
let babelCli = 'babel --optional es7.objectRestSpread ./src --out-dir ./lib';
return exec(babelCli).fail(function (error) {
console.log(colors.red(error))
});
}).then(() => console.log('lib built'.green));
Here's a last advice: You need to add a .npmignore to your project. If npm publish doesn't find this file, it will use .gitignore instead, which will cause you trouble because normally your .gitignore file will exclude ./lib and include ./src, which is exactly the opposite of what you want when you are publishing to NPM. The .npmignore file has basically the same syntax of .gitignore (AFAIK).
Following José and Marius's approach, (with update of Babel's latest version in 2019): Keep the latest JavaScript files in a src directory, and build with npm's prepublish script and output to the lib directory.
.npmignore
/src
.gitignore
/lib
/node_modules
Install Babel (version 7.5.5 in my case)
$ npm install #babel/core #babel/cli #babel/preset-env --save-dev
package.json
{
"name": "latest-js-to-npm",
"version": "1.0.0",
"description": "Keep the latest JavaScript files in a src directory and build with npm's prepublish script and output to the lib directory.",
"main": "lib/index.js",
"scripts": {
"prepublish": "babel src -d lib"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"#babel/cli": "^7.5.5",
"#babel/core": "^7.5.5",
"#babel/preset-env": "^7.5.5"
},
"babel": {
"presets": [
"#babel/preset-env"
]
}
}
And I have src/index.js which uses the arrow function:
"use strict";
let NewOneWithParameters = (a, b) => {
console.log(a + b); // 30
};
NewOneWithParameters(10, 20);
Here is the repo on GitHub.
Now you can publish the package:
$ npm publish
...
> latest-js-to-npm#1.0.0 prepublish .
> babel src -d lib
Successfully compiled 1 file with Babel.
...
Before the package is published to npm, you will see that lib/index.js has been generated, which is transpiled to es5:
"use strict";
var NewOneWithParameters = function NewOneWithParameters(a, b) {
console.log(a + b); // 30
};
NewOneWithParameters(10, 20);
[Update for Rollup bundler]
As asked by #kyw, how would you integrate Rollup bundler?
First, install rollup and rollup-plugin-babel
npm install -D rollup rollup-plugin-babel
Second, create rollup.config.js in the project root directory
import babel from "rollup-plugin-babel";
export default {
input: "./src/index.js",
output: {
file: "./lib/index.js",
format: "cjs",
name: "bundle"
},
plugins: [
babel({
exclude: "node_modules/**"
})
]
};
Lastly, update prepublish in package.json
{
...
"scripts": {
"prepublish": "rollup -c"
},
...
}
Now you can run npm publish, and before the package is published to npm, you will see that lib/index.js has been generated, which is transpiled to es5:
'use strict';
var NewOneWithParameters = function NewOneWithParameters(a, b) {
console.log(a + b); // 30
};
NewOneWithParameters(10, 20);
Note: by the way, you no longer need #babel/cli if you are using the Rollup bundler. You can safely uninstall it:
npm uninstall #babel/cli
If you want to see this in action in a very simple small open source Node module then take a look at nth-day (which I started - also other contributors). Look in the package.json file and at the prepublish step which will lead you to where and how to do this. If you clone that module you can run it locally and use it as a template for yous.
Node.js 13.2.0+ supports ESM without the experimental flag and there're a few options to publish hybrid (ESM and CommonJS) NPM packages (depending on the level of backward compatibility needed): https://2ality.com/2019/10/hybrid-npm-packages.html
I recommend going the full backward compatibility way to make the usage of your package easier. This could look as follows:
The hybrid package has the following files:
mypkg/
package.json
esm/
entry.js
commonjs/
package.json
entry.js
mypkg/package.json
{
"type": "module",
"main": "./commonjs/entry.js",
"exports": {
"./esm": "./esm/entry.js"
},
"module": "./esm/entry.js",
···
}
mypkg/commonjs/package.json
{
"type": "commonjs"
}
Importing from CommonJS:
const {x} = require('mypkg');
Importing from ESM:
import {x} from 'mypkg/esm';
We did an investigation into ESM support in 05.2019 and found that a lot of libraries were lacking support (hence the recommendation for backward compatibility):
esm package's support doesn't align with Node's which causes issues
"Builtin require cannot sideload .mjs files." https://github.com/standard-things/esm#loading, https://github.com/standard-things/esm/issues/498#issuecomment-403496745
"The .mjs file extension should not be the thing developers reach for if they want interop or ease of use. It's available since it's in --experimental-modules but since it's not fully baked I can't commit to any enhancements to it." https://github.com/standard-things/esm/issues/498#issuecomment-403655466
mocha doesn't have native support for .mjs files
Update 2020-01-13: Mocha released experimental support in mocha#7.0.0-esm1
Many high-profile projects had issues with .mjs files:
create-react-app
react-apollo
graphql-js
inferno
The main key in package.json decides the entry point to the package once it's published. So you can put your Babel's output wherever you want and just have to mention the right path in main key.
"main": "./lib/index.js",
Here's a well written article on how to publish an npm package
https://codeburst.io/publish-your-own-npm-package-ff918698d450
Here's a sample repo you can use for reference
https://github.com/flexdinesh/npm-module-boilerplate
The two criteria of an NPM package is that it is usable with nothing more than a require( 'package' ) and does something software-ish.
If you fulfill those two requirements, you can do whatever you wish.
Even if the module is written in ES6, if the end user doesn't need to know that, I would transpile it for now to get maximum support.
However, if like koa, your module requires compatibility with users using ES6 features, then perhaps the two package solution would be a better idea.
Takeaway
Only publish as much code as you need to make require( 'your-package' ) work.
Unless the between ES5 & 6 matters to the user, only publish 1 package. Transpile it if you must.
A few extra notes for anyone, using own modules directly from github, not going through published modules:
The (widely used) "prepublish" hook is not doing anything for you.
Best thing one can do (if plans to rely on github repos, not published stuff):
unlist src from .npmignore (in other words: allow it). If you don't have an .npmignore, remember: A copy of .gitignore will be used instead in the installed location, as ls node_modules/yourProject will show you.
make sure, babel-cli is a depenency in your module, not just a devDepenceny since you are indeed building on the consuming machine aka at the App developers computer, who is using your module
do the build thing, in the install hook i.e.:
"install": "babel src -d lib -s"
(no added value in trying anything "preinstall", i.e. babel-cli might be missing)
Deppending on the anatomy of your module, this solution may not work, but if your module is contained inside a single file, and has no dependencies (does not make use of import), using the following pattern you can release your code as it is, and will be able to be imported with import (Browser ES6 Modules) and require (Node CommonJS Modules)
As a bonus, it will be suittable to be imported using a SCRIPT HTML Element.
main.js :
(function(){
'use strict';
const myModule = {
helloWorld : function(){ console.log('Hello World!' )}
};
// if running in NODE export module using NODEJS syntax
if(typeof module !== 'undefined') module.exports = myModule ;
// if running in Browser, set as a global variable.
else window.myModule = myModule ;
})()
my-module.js :
// import main.js (it will declare your Object in the global scope)
import './main.js';
// get a copy of your module object reference
let _myModule = window.myModule;
// delete the the reference from the global object
delete window.myModule;
// export it!
export {_myModule as myModule};
package.json :`
{
"name" : "my-module", // set module name
"main": "main.js", // set entry point
/* ...other package.json stuff here */
}
To use your module, you can now use the regular syntax ...
When imported in NODE ...
let myModule = require('my-module');
myModule.helloWorld();
// outputs 'Hello World!'
When imported in BROWSER ...
import {myModule} from './my-module.js';
myModule.helloWorld();
// outputs 'Hello World!'
Or even when included using an HTML Script Element...
<script src="./main.js"></script>
<script>
myModule.helloWorld();
// outputs 'Hello World!'
</script>
Related
I've got an ApolloServer project that's giving me trouble, so I thought I might update it and ran into issues when using the latest Babel. My "index.js" is:
require('dotenv').config()
import {startServer} from './server'
startServer()
And when I run it I get the error
SyntaxError: Cannot use import statement outside a module
First I tried doing things to convince TPTB* that this was a module (with no success). So I changed the "import" to a "require" and this worked.
But now I have about two dozen "imports" in other files giving me the same error.
*I'm sure the root of my problem is that I'm not even sure what's complaining about the issue. I sort of assumed it was Babel 7 (since I'm coming from Babel 6 and I had to change the presets) but I'm not 100% sure.
Most of what I've found for solutions don't seem to apply to straight Node. Like this one here:
ES6 module Import giving "Uncaught SyntaxError: Unexpected identifier"
Says it was resolved by adding "type=module" but this would typically go in the HTML, of which I have none. I've also tried using my project's old presets:
"presets": ["es2015", "stage-2"],
"plugins": []
But that gets me another error: "Error: Plugin/Preset files are not allowed to export objects, only functions."
Here are the dependencies I started with:
"dependencies": {
"#babel/polyfill": "^7.6.0",
"apollo-link-error": "^1.1.12",
"apollo-link-http": "^1.5.16",
"apollo-server": "^2.9.6",
"babel-preset-es2015": "^6.24.1",
Verify that you have the latest version of Node.js installed (or, at least 13.2.0+). Then do one of the following, as described in the documentation:
Option 1
In the nearest parent package.json file, add the top-level "type" field with a value of "module". This will ensure that all .js and .mjs files are interpreted as ES modules. You can interpret individual files as CommonJS by using the .cjs extension.
// package.json
{
"type": "module"
}
Option 2
Explicitly name files with the .mjs extension. All other files, such as .js will be interpreted as CommonJS, which is the default if type is not defined in package.json.
If anyone is running into this issue with TypeScript, the key to solving it for me was changing
"target": "esnext",
"module": "esnext",
to
"target": "esnext",
"module": "commonjs",
In my tsconfig.json. I was under the impression "esnext" was the "best", but that was just a mistake.
For those who were as confused as I was when reading the answers, in your package.json file, add
"type": "module"
in the upper level as show below:
{
"name": "my-app",
"version": "0.0.0",
"type": "module",
"scripts": { ...
},
...
}
According to the official documentation:
import statements are permitted only in ES modules. For similar functionality in CommonJS, see import().
To make Node.js treat your file as an ES module, you need to (Enabling):
add "type": "module" to package.json
add "--experimental-modules" flag to the Node.js call
I ran into the same issue and it's even worse: I needed both "import" and "require"
Some newer ES6 modules works only with import.
Some CommonJS works with require.
Here is what worked for me:
Turn your js file into .mjs as suggested in other answers
"require" is not defined with the ES6 module, so you can define it this way:
import { createRequire } from 'module'
const require = createRequire(import.meta.url);
Now 'require' can be used in the usual way.
Use import for ES6 modules and require for CommonJS.
Some useful links: Node.js's own documentation. difference between import and require. Mozilla has some nice documentation about import
I had the same issue and the following has fixed it (using Node.js 12.13.1):
Change .js files extension to .mjs
Add --experimental-modules flag upon running your app.
Optional: add "type": "module" in your package.json
More information: https://nodejs.org/api/esm.html
First we'll install #babel/cli, #babel/core and #babel/preset-env:
npm install --save-dev #babel/cli #babel/core #babel/preset-env
Then we'll create a .babelrc file for configuring Babel:
touch .babelrc
This will host any options we might want to configure Babel with:
{
"presets": ["#babel/preset-env"]
}
With recent changes to Babel, you will need to transpile your ES6 before Node.js can run it.
So, we'll add our first script, build, in file package.json.
"scripts": {
"build": "babel index.js -d dist"
}
Then we'll add our start script in file package.json.
"scripts": {
"build": "babel index.js -d dist", // replace index.js with your filename
"start": "npm run build && node dist/index.js"
}
Now let's start our server.
npm start
I Tried with all the methods, but nothing worked.
I got one reference from GitHub.
To use TypeScript imports with Node.js, I installed the below packages.
1. npm i typescript --save-dev
2. npm i ts-node --save-dev
Won't require type: module in package.json
For example,
{
"name": "my-app",
"version": "0.0.1",
"description": "",
"scripts": {
},
"dependencies": {
"knex": "^0.16.3",
"pg": "^7.9.0",
"ts-node": "^8.1.0",
"typescript": "^3.3.4000"
}
}
Step 1
yarn add esm
or
npm i esm --save
Step 2
package.json
"scripts": {
"start": "node -r esm src/index.js",
}
Step 3
nodemon --exec npm start
Node v14.16.0
For those who've tried .mjs and got:
Aviator#AW:/mnt/c/Users/Adrian/Desktop/Programming/nodejs_ex$ node just_js.mjs
file:///mnt/c/Users/Adrian/Desktop/Programming/nodejs_ex/just_js.mjs:3
import fetch from "node-fetch";
^^^^^
SyntaxError: Unexpected identifier
and who've tried import fetch from "node-fetch";
and who've tried const fetch = require('node-fetch');
Aviator#AW:/mnt/c/Users/Adrian/Desktop/Programming/nodejs_ex$ node just_js.js
(node:4899) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/mnt/c/Users/Adrian/Desktop/Programming/nodejs_ex/just_js.js:3
import fetch from "node-fetch";
^^^^^^
SyntaxError: Cannot use import statement outside a module
and who've tried "type": "module" to package.json, yet continue seeing the error,
{
"name": "test",
"version": "1.0.0",
"description": "to get fetch working",
"main": "just_js.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "MIT"
}
I was able to switch to axios without a problem.
import axios from 'axios'; <-- put at top of file.
Example:
axios.get('https://www.w3schools.com/xml/note.xml').then(resp => {
console.log(resp.data);
});
I found the 2020 update to the answer in this link helpful to answering this question as well as telling you WHY it does this:
Using Node.js require vs. ES6 import/export
Here's an excerpt:
"Update 2020
Since Node v12, support for ES modules is enabled by default, but it's still experimental at the time of writing this. Files including node modules must either end in .mjs or the nearest package.json file must contain "type": "module". The Node documentation has a ton more information, also about interop between CommonJS and ES modules."
I'm new to Node.js, and I got the same issue for the AWS Lambda function (using Node.js) while fixing it.
I found some of the differences between CommonJS and ES6 JavaScript:
ES6:
Add "type":"module" in the package.json file
Use "import" to use from lib.
Example: import jwt_decode from jwt-decode
Lambda handler method code should be define like this
"exports.handler = async (event) => { }"
CommonJS:
Don't add "type":"module" in the package.json file
Use "require" to use from lib.
Example: const jwt_decode = require("jwt-decode");
The lambda handler method code should be defines like this:
"export const handler = async (event) => { }"
In my case. I think the problem is in the standard node executable. node target.ts
I replaced it with nodemon and surprisingly it worked!
The way using the standard executable (runner):
node target.ts
The way using the nodemon executable (runner):
nodemon target.ts
Do not forget to install nodemon with npm install nodemon ;P
Note: this works amazing for development. But, for runtime, you may execute node with the compiled js file!
To use import, do one of the following.
Rename the .js file to .mjs
In package.json file, add {type:module}
If you are using ES6 JavaScript imports:
install cross-env
in package.json change "test": "jest" to "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest"
more in package.json, add these:
...,
"jest": {
"transform": {}
},
"type": "module"
Explanation:
cross-env allows to change environment variables without changing the npm command. Next, in file package.json you change your npm command to enable experimental ES6 support for Jest, and configure Jest to do it.
This error also comes when you run the command
node filename.ts
and not
node filename.js
Simply put, with the node command we will have to run the JavaScript file (filename.js) and not the TypeScript file unless we are using a package like ts-node.
If you want to use BABEL, I have a simple solution for that!
Remember this is for nodejs example: like an expressJS server!
If you are going to use react or another framework, look in the babel documentation!
First, install (do not install unnecessary things that will only trash your project!)
npm install --save-dev #babel/core #babel/node
Just 2 WAO
then config your babel file in your repo!
file name:
babel.config.json
{
"presets": ["#babel/preset-env"]
}
if you don't want to use the babel file, use:
Run in your console, and script.js is your entry point!
npx babel-node --presets #babel/preset-env -- script.js
the full information is here; https://babeljs.io/docs/en/babel-node
I had this error in my NX workspace after upgrading manually. The following change in each jest.config.js fixed it:
transform: {
'^.+\\.(ts|js|html)$': 'jest-preset-angular',
},
to
transform: {
'^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular',
},
I had this issue when I was running migration
Its es5 vs es6 issue
Here is how I solved it
I run
npm install #babel/register
and add
require("#babel/register")
at the top of my .sequelizerc file my
and go ahead to run my sequelize migrate.
This is applicable to other things apart from sequelize
babel does the transpiling
Just add --presets '#babel/preset-env'.
For example,
babel-node --trace-deprecation --presets '#babel/preset-env' ./yourscript.js
Or
in babel.config.js
module.exports = {
presets: ['#babel/preset-env'],
};
To make your import work and avoid other issues, like modules not working in Node.js, just note that:
With ES6 modules you can not yet import directories. Your import should look like this:
import fs from './../node_modules/file-system/file-system.js'
For people coming to this thread due to this error in Netlify functions even after adding "type": "module" in package.json file, update your netlify.toml to use 'esbuild'. Since esbuild supports ES6, it would work.
[functions]
node_bundler = "esbuild"
Reference:
https://docs.netlify.com/functions/build-with-javascript/#automated-dependency-bundling
The documentation is confusing. I use Node.js to perform some local task in my computer.
Let's suppose my old script was test.js. Within it, if I want to use
import something from "./mylocalECMAmodule";
it will throw an error like this:
(node:16012) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
SyntaxError: Cannot use import statement outside a module
...
This is not a module error, but a Node.js error. Forbid loading anything outside a 'module'.
To fix this, just rename your old script test.js into test.mjs.
That's all.
My solution was to include babel-node path while running nodemon as follows:
nodemon node_modules/.bin/babel-node index.js
You can add in your package.json script as:
debug: nodemon node_modules/.bin/babel-node index.js
NOTE: My entry file is index.js. Replace it with your entry file (many have app.js/server.js).
I had the same problem when I started to use Babel... But later, I
had a solution... I haven't had the problem any more so far...
Currently, Node.js v12.14.1, "#babel/node": "^7.8.4", I use babel-node and nodemon to execute (Node.js is fine as well..)
package.json: "start": "nodemon --exec babel-node server.js "debug": "babel-node debug server.js"!! Note: server.js is my entry
file, and you can use yours.
launch.json. When you debug, you also need to configure your launch.json file "runtimeExecutable":
"${workspaceRoot}/node_modules/.bin/babel-node"!! Note: plus
runtimeExecutable into the configuration.
Of course, with babel-node, you also normally need and edit another file, such as the babel.config.js/.babelrc file
In case you're running nodemon for the Node.js version 12, use this command.
server.js is the "main" inside package.json file, replace it with the relevant file inside your package.json file:
nodemon --experimental-modules server.js
I recently had the issue. The fix which worked for me was to add this to file babel.config.json in the plugins section:
["#babel/plugin-transform-modules-commonjs", {
"allowTopLevelThis": true,
"loose": true,
"lazy": true
}],
I had some imported module with // and the error "cannot use import outside a module".
If you are using node, you should refer to this document. Just setup babel in your node app it will work and It worked for me.
npm install --save-dev #babel/cli #babel/core #babel/preset-env
When I used sequelize migrations with npx sequelize db:migrate, I got this error, so my solution for this was adding the line require('#babel/register'); into the .sequelizerc file as the following image shows:
Be aware you must install Babel and Babel register.
Wrong MIME-Type for JavaScript Module Files
The common source of the problem is the MIME-type for "Module" type JavaScript files is not recognized as a "module" type by the server, the client, or the ECMAScript engine that process or deliver these files.
The problem is the developers of Module JavaScript files incorrectly associated Modules with a new ".mjs" (.js) extension, but then assigned it a MIME-type server type of "text/javascript". This means both .js and .mjs types are the same. In fact the new type for .js JavaScript files has also changed to "application/javascript", further confusing the issue. So Module JavaScript files are not being recognized by any of these systems, regardless of Node.js or Babel file processing systems in development.
The main problem is this new "module" subtype of JavaScript is yet known to most servers or clients (modern HTML5 browsers). In other words, they have no way to know what a Module file type truly is apart from a JavaScript type!
So, you get the response you posted, where the JavaScript engine is saying it needs to know if the file is a Module type of JavaScript file.
The only solution, for server or client, is to change your server or browser to deliver a new Mime-type that trigger ES6 support of Module files, which have an .mjs extension. Right now, the only way to do that is to either create a HTTP content-type on the server of "module" for any file with a .mjs extension and change your file extension on module JavaScript files to ".mjs", or have an HTML script tag with type="module" added to any external <script> element you use that downloads your external .js JavaScript module file.
Once you fool the browser or JavaScript engines into accepting the new Module file type, they will start doing their scripting circus tricks in the JS engines or Node.js systems you use.
I don't understand what is wrong.
Node v5.6.0
NPM v3.10.6
The code:
function (exports, require, module, __filename, __dirname) {
import express from 'express'
};
The error:
SyntaxError: Unexpected token import
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:387:25)
at Object.Module._extensions..js (module.js:422:10)
at Module.load (module.js:357:32)
at Function.Module._load (module.js:314:12)
at Function.Module.runMain (module.js:447:10)
at startup (node.js:140:18)
at node.js:1001:3
Node 13+ Since Node 13, you can use either the .mjs extension, or set {"type": "module"} in your package.json. You don't need to use the --experimental-modules flag. Modules is now marked as stable in node.js
Node 12 Since Node 12, you can use either the .mjs extension, or set "type": "module" in your package.json. And you need to run node with the --experimental-modules flag.
Node 9 In Node 9, it is enabled behind a flag, and uses the .mjs extension.
node --experimental-modules my-app.mjs
While import is indeed part of ES6, it is unfortunately not yet supported in NodeJS by default, and has only very recently landed support in browsers.
See browser compat table on MDN and this Node issue.
From James M Snell's Update on ES6 Modules in Node.js (February 2017):
Work is in progress but it is going to take some time — We’re currently looking at around a year at least.
Until support shows up natively (now marked stable in Node 13+), you'll have to continue using classic require statements:
const express = require("express");
If you really want to use new ES6/7 features in NodeJS, you can compile it using Babel. Here's an example server.
Unfortunately, Node.js doesn't support ES6's import yet.
To accomplish what you're trying to do (import the Express module), this code should suffice
var express = require("express");
Also, be sure you have Express installed by running
$ npm install express
See the Node.js Docs for more information about learning Node.js.
I'm shocked esm hasn't been mentioned. This small, but mighty package allows you to use either import or require.
Install esm in your project
$ npm install --save esm
Update your Node Start Script to use esm
node -r esm app.js
esm just works. I wasted a TON of time with .mjs and --experimental-modules only to find out a .mjs file cannot import a file that uses require or module.exports. This was a huge problem, whereas esm allows you to mix and match and it just figures it out... esm just works.
As mentioned in other answers Node JS currently doesn't support ES6 imports.
(As of now, read EDIT 2)
Enable ES6 imports in node js provides a solution to this issue. I have tried this and it worked for me.
Run the command:
npm install babel-register babel-preset-env --save-dev
Now you need to create a new file (config.js) and add the following code to it.
require('babel-register')({
presets: [ 'env' ]
})
// Import the rest of our application.
module.exports = require('./your_server_file.js')
Now you can write import statements without getting any errors.
Hope this helps.
EDIT:
You need to run the new file which you created with above code. In my case it was config.js. So I have to run:
node config.js
EDIT 2:
While experimenting, I found one easy solution to this issue.
Create .babelrc file in the root of your project.
Add following (and any other babel presets you need, can be added in this file):
{
"presets": ["env"]
}
Install babel-preset-env using command npm install babel-preset-env --save, and then install babel-cli using command npm install babel-cli -g --save
Now, go to the folder where your server or index file exists and run using:
babel-node fileName.js
Or you can run using npm start by adding following code to your package.json file:
"scripts": {
"start": "babel-node src/index.js"
}
Error: SyntaxError: Unexpected token import or SyntaxError: Unexpected token export
Solution: Change all your imports as example
const express = require('express');
const webpack = require('webpack');
const path = require('path');
const config = require('../webpack.config.dev');
const open = require('open');
And also change your export default = foo; to module.exports = foo;
In case that you still can't use "import" here is how I handled it:
Just translate it to a node friendly require. Example:
import { parse } from 'node-html-parser';
Is the same as:
const parse = require('node-html-parser').parse;
babel 7 proposal
can you add dev dependencies
npm i -D #babel/core #babel/preset-env #babel/register
and add a .babelrc in the root
{
"presets": [
[
"#babel/preset-env",
{
"targets": {
"node": "current"
}
}
]
]
}
and add to the .js file
require("#babel/register")
or if you run it in the cli, you could use the require hook as -r #babel/register, ex.
$node -r #babel/register executeMyFileWithESModules.js
When I was started with express always wanted a solution to use import instead require
const express = require("express");
// to
import express from "express"
Many time go through this line:- Unfortunately, Node.js doesn't support ES6's import yet.
Now to help other I create new two solutions here
1) esm:-
The brilliantly simple, babel-less, bundle-less ECMAScript module loader.
let's make it work
yarn add esm / npm install esm
create start.js or use your namespace
require = require("esm")(module/*, options*/)
// Import the rest of our application.
module.exports = require('./src/server.js')
// where server.js is express server start file
Change in your package.josn pass path of start.js
"scripts": {
"start": "node start.js",
"start:dev": "nodemon start.js",
},
"dependencies": {
+ "esm": "^3.2.25",
},
"devDependencies": {
+ "nodemon": "^1.19.2"
}
2) Babel js:-
This can be divide into 2 part
a) Solution 1 thanks to timonweb.com
b) Solution 2
use Babel 6 (older version of babel-preset-stage-3 ^6.0)
create .babelrc file at your root folder
{
"presets": ["env", "stage-3"]
}
Install babel-preset-stage-3
yarn add babel-cli babel-polyfill babel-preset-env bable-preset-stage-3 nodemon --dev
Change in package.json
"scripts": {
+ "start:dev": "nodemon --exec babel-node -- ./src/index.js",
+ "start": "npm run build && node ./build/index.js",
+ "build": "npm run clean && babel src -d build -s --source-maps --copy-files",
+ "clean": "rm -rf build && mkdir build"
},
"devDependencies": {
+ "babel-cli": "^6.26.0",
+ "babel-polyfill": "^6.26.0",
+ "babel-preset-env": "^1.7.0",
+ "babel-preset-stage-3": "^6.24.1",
+ "nodemon": "^1.19.4"
},
Start your server
yarn start / npm start
Oooh no we create new problem
regeneratorRuntime.mark(function _callee(email, password) {
^
ReferenceError: regeneratorRuntime is not defined
This error only come when you use async/await in your code.
Then use polyfill that includes a custom regenerator runtime and core-js.
add on top of index.js
import "babel-polyfill"
This allow you to use async/await
use Babel 7
Need to upto date every thing in your project
let start with babel 7
.babelrc
{
"presets": ["#babel/preset-env"]
}
Some change in package.json
"scripts": {
+ "start:dev": "nodemon --exec babel-node -- ./src/index.js",
+ "start": "npm run build && node ./build/index.js",
+ "build": "npm run clean && babel src -d build -s --source-maps --copy-files",
+ "clean": "rm -rf build && mkdir build",
....
}
"devDependencies": {
+ "#babel/cli": "^7.0.0",
+ "#babel/core": "^7.6.4",
+ "#babel/node": "^7.0.0",
+ "#babel/polyfill": "^7.0.0",
+ "#babel/preset-env": "^7.0.0",
+ "nodemon": "^1.19.4"
....
}
and use import "#babel/polyfill" on start point
import "#babel/polyfill"
import express from 'express'
const app = express()
//GET request
app.get('/', async (req, res) {
// await operation
res.send('hello world')
})
app.listen(4000, () => console.log('🚀 Server listening on port 400!'))
Are you thinking why start:dev
Seriously. It is good question if you are new. Every change you are boar with start server every time
then use yarn start:dev as development server every change restart server automatically for more on nodemon
if you can use 'babel', try to add build scripts in package.json(--presets=es2015) as below. it make to precompile import code to es2015
"build": "babel server --out-dir build --presets=es2015 && webpack"
As of Node.js v12 (and this is probably fairly stable now, but still marked "experimental"), you have a couple of options for using ESM (ECMAScript Modules) in Node.js (for files, there's a third way for evaling strings), here's what the documentation says:
The --experimental-modules flag can be used to enable support for
ECMAScript modules (ES modules).
Once enabled, Node.js will treat the following as ES modules when passed to
node as the initial input, or when referenced by import statements within
ES module code:
Files ending in .mjs.
Files ending in .js, or extensionless files, when the nearest parent
package.json file contains a top-level field "type" with a value of
"module".
Strings passed in as an argument to --eval or --print, or piped to
node via STDIN, with the flag --input-type=module.
Node.js will treat as CommonJS all other forms of input, such as .js files
where the nearest parent package.json file contains no top-level "type"
field, or string input without the flag --input-type. This behavior is to
preserve backward compatibility. However, now that Node.js supports both
CommonJS and ES modules, it is best to be explicit whenever possible. Node.js
will treat the following as CommonJS when passed to node as the initial input,
or when referenced by import statements within ES module code:
Files ending in .cjs.
Files ending in .js, or extensionless files, when the nearest parent
package.json file contains a top-level field "type" with a value of
"commonjs".
Strings passed in as an argument to --eval or --print, or piped to
node via STDIN, with the flag --input-type=commonjs.
I'm going to address another problem within the original question that no one else has. After recently converting from CommonJS to ESM in my own NodeJS project, I've seen very little discussion about the fact that you cannot place imports wherever you want, like you could with require. My project is working great with imports now, but when I use the code in the question, I first get an error for not having a named function. After naming the function, I receive the following...
import express from 'express'
^^^^^^^
SyntaxError: Unexpected identifier
at Loader.moduleStrategy (internal/modules/esm/translators.js:88:18)
You cannot place imports inside functions like you could require. They have to be placed at the top of the file, outside code blocks. I wasted quite a bit of time on this issue myself.
So while all of the above answers are great at helping you get imports to work in your project, none address the fact that the code in the original question cannot work as written.
import statements are supported in the stable release of Node since version 14.x LTS.
All you need to do is specify "type": "module" in package.json.
In my case it was looking after .babelrc file, and it should contain something like this:
{
"presets": ["es2015-node5", "stage-3"],
"plugins": []
}
My project uses node v10.21.0, which still does not support ES6 import keyword. There are multiple ways to make node recognize import, one of them is to start node with node --experimental-modules index.mjs (The mjs extension is already covered in one of the answers here). But, this way, you will not be able to use node specific keyword like require in your code. If there is need to use both nodejs's require keyword along with ES6's import, then the way out is to use the esm npm package. After adding esm package as a dependency, node needs to be started with a special configuration like: node -r esm index.js
I've been trying to get this working. Here's what works:
Use a recent node version. I'm using v14.15.5. Verify your version by running: node --version
Name the files so that they all end with .mjs rather than .js
Example:
mod.mjs
export const STR = 'Hello World'
test.mjs
import {STR} from './mod.mjs'
console.log(STR)
Run: node test.mjs
You should see "Hello World".
Simply install a higher version of Node. As till Node v10 es6 is not supported. You need to disable a few flags or use
I am trying to upgrade my Angular 9 app to Angular 10 version, but getting below warning after the upgrade
WARNING in calendar.reducer.ts depends on lodash/keys. CommonJS or AMD dependencies can cause optimization bailouts.
I have added below line to my angular.json file but issue is not resolved
"allowedCommonJsDependencies": ["lodash"]
How can I fix above issue.
The npm package lodash itself is not an ECMAScript module and therefore produces the warning.
There are multiple ways to fix this:
Replace with ES modulized library (recommended)
Some libraries offer ES modulized builds. In case of lodash, you can replace it with lodash-es.
Run npm install --save lodash-es.
Now replace all imports from lodash with lodash-es.
Also make sure to import the library with ES import statements:
import { keys } from 'lodash-es';
Whitelist CommonJS dependency
If there is no ES modulized build available for your library, or if you for some reason don't care, you can allow specific CommonJS dependencies in the angular.json file:
"architect": {
"build": {
"builder": "#angular-devkit/build-angular:browser",
"options": {
"allowedCommonJsDependencies": ["lodash"]
}
}
}
Since Angular CLI Version 10.0.1 you can use globs in allowedCommonJsDependencies.
This means that if you pass lodash, the sub-paths (e.g. lodash/keys) will also be allowed.
Docs reference: https://angular.io/guide/build#configuring-commonjs-dependencies
I don't understand what is wrong.
Node v5.6.0
NPM v3.10.6
The code:
function (exports, require, module, __filename, __dirname) {
import express from 'express'
};
The error:
SyntaxError: Unexpected token import
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:387:25)
at Object.Module._extensions..js (module.js:422:10)
at Module.load (module.js:357:32)
at Function.Module._load (module.js:314:12)
at Function.Module.runMain (module.js:447:10)
at startup (node.js:140:18)
at node.js:1001:3
Node 13+ Since Node 13, you can use either the .mjs extension, or set {"type": "module"} in your package.json. You don't need to use the --experimental-modules flag. Modules is now marked as stable in node.js
Node 12 Since Node 12, you can use either the .mjs extension, or set "type": "module" in your package.json. And you need to run node with the --experimental-modules flag.
Node 9 In Node 9, it is enabled behind a flag, and uses the .mjs extension.
node --experimental-modules my-app.mjs
While import is indeed part of ES6, it is unfortunately not yet supported in NodeJS by default, and has only very recently landed support in browsers.
See browser compat table on MDN and this Node issue.
From James M Snell's Update on ES6 Modules in Node.js (February 2017):
Work is in progress but it is going to take some time — We’re currently looking at around a year at least.
Until support shows up natively (now marked stable in Node 13+), you'll have to continue using classic require statements:
const express = require("express");
If you really want to use new ES6/7 features in NodeJS, you can compile it using Babel. Here's an example server.
Unfortunately, Node.js doesn't support ES6's import yet.
To accomplish what you're trying to do (import the Express module), this code should suffice
var express = require("express");
Also, be sure you have Express installed by running
$ npm install express
See the Node.js Docs for more information about learning Node.js.
I'm shocked esm hasn't been mentioned. This small, but mighty package allows you to use either import or require.
Install esm in your project
$ npm install --save esm
Update your Node Start Script to use esm
node -r esm app.js
esm just works. I wasted a TON of time with .mjs and --experimental-modules only to find out a .mjs file cannot import a file that uses require or module.exports. This was a huge problem, whereas esm allows you to mix and match and it just figures it out... esm just works.
As mentioned in other answers Node JS currently doesn't support ES6 imports.
(As of now, read EDIT 2)
Enable ES6 imports in node js provides a solution to this issue. I have tried this and it worked for me.
Run the command:
npm install babel-register babel-preset-env --save-dev
Now you need to create a new file (config.js) and add the following code to it.
require('babel-register')({
presets: [ 'env' ]
})
// Import the rest of our application.
module.exports = require('./your_server_file.js')
Now you can write import statements without getting any errors.
Hope this helps.
EDIT:
You need to run the new file which you created with above code. In my case it was config.js. So I have to run:
node config.js
EDIT 2:
While experimenting, I found one easy solution to this issue.
Create .babelrc file in the root of your project.
Add following (and any other babel presets you need, can be added in this file):
{
"presets": ["env"]
}
Install babel-preset-env using command npm install babel-preset-env --save, and then install babel-cli using command npm install babel-cli -g --save
Now, go to the folder where your server or index file exists and run using:
babel-node fileName.js
Or you can run using npm start by adding following code to your package.json file:
"scripts": {
"start": "babel-node src/index.js"
}
Error: SyntaxError: Unexpected token import or SyntaxError: Unexpected token export
Solution: Change all your imports as example
const express = require('express');
const webpack = require('webpack');
const path = require('path');
const config = require('../webpack.config.dev');
const open = require('open');
And also change your export default = foo; to module.exports = foo;
In case that you still can't use "import" here is how I handled it:
Just translate it to a node friendly require. Example:
import { parse } from 'node-html-parser';
Is the same as:
const parse = require('node-html-parser').parse;
babel 7 proposal
can you add dev dependencies
npm i -D #babel/core #babel/preset-env #babel/register
and add a .babelrc in the root
{
"presets": [
[
"#babel/preset-env",
{
"targets": {
"node": "current"
}
}
]
]
}
and add to the .js file
require("#babel/register")
or if you run it in the cli, you could use the require hook as -r #babel/register, ex.
$node -r #babel/register executeMyFileWithESModules.js
When I was started with express always wanted a solution to use import instead require
const express = require("express");
// to
import express from "express"
Many time go through this line:- Unfortunately, Node.js doesn't support ES6's import yet.
Now to help other I create new two solutions here
1) esm:-
The brilliantly simple, babel-less, bundle-less ECMAScript module loader.
let's make it work
yarn add esm / npm install esm
create start.js or use your namespace
require = require("esm")(module/*, options*/)
// Import the rest of our application.
module.exports = require('./src/server.js')
// where server.js is express server start file
Change in your package.josn pass path of start.js
"scripts": {
"start": "node start.js",
"start:dev": "nodemon start.js",
},
"dependencies": {
+ "esm": "^3.2.25",
},
"devDependencies": {
+ "nodemon": "^1.19.2"
}
2) Babel js:-
This can be divide into 2 part
a) Solution 1 thanks to timonweb.com
b) Solution 2
use Babel 6 (older version of babel-preset-stage-3 ^6.0)
create .babelrc file at your root folder
{
"presets": ["env", "stage-3"]
}
Install babel-preset-stage-3
yarn add babel-cli babel-polyfill babel-preset-env bable-preset-stage-3 nodemon --dev
Change in package.json
"scripts": {
+ "start:dev": "nodemon --exec babel-node -- ./src/index.js",
+ "start": "npm run build && node ./build/index.js",
+ "build": "npm run clean && babel src -d build -s --source-maps --copy-files",
+ "clean": "rm -rf build && mkdir build"
},
"devDependencies": {
+ "babel-cli": "^6.26.0",
+ "babel-polyfill": "^6.26.0",
+ "babel-preset-env": "^1.7.0",
+ "babel-preset-stage-3": "^6.24.1",
+ "nodemon": "^1.19.4"
},
Start your server
yarn start / npm start
Oooh no we create new problem
regeneratorRuntime.mark(function _callee(email, password) {
^
ReferenceError: regeneratorRuntime is not defined
This error only come when you use async/await in your code.
Then use polyfill that includes a custom regenerator runtime and core-js.
add on top of index.js
import "babel-polyfill"
This allow you to use async/await
use Babel 7
Need to upto date every thing in your project
let start with babel 7
.babelrc
{
"presets": ["#babel/preset-env"]
}
Some change in package.json
"scripts": {
+ "start:dev": "nodemon --exec babel-node -- ./src/index.js",
+ "start": "npm run build && node ./build/index.js",
+ "build": "npm run clean && babel src -d build -s --source-maps --copy-files",
+ "clean": "rm -rf build && mkdir build",
....
}
"devDependencies": {
+ "#babel/cli": "^7.0.0",
+ "#babel/core": "^7.6.4",
+ "#babel/node": "^7.0.0",
+ "#babel/polyfill": "^7.0.0",
+ "#babel/preset-env": "^7.0.0",
+ "nodemon": "^1.19.4"
....
}
and use import "#babel/polyfill" on start point
import "#babel/polyfill"
import express from 'express'
const app = express()
//GET request
app.get('/', async (req, res) {
// await operation
res.send('hello world')
})
app.listen(4000, () => console.log('🚀 Server listening on port 400!'))
Are you thinking why start:dev
Seriously. It is good question if you are new. Every change you are boar with start server every time
then use yarn start:dev as development server every change restart server automatically for more on nodemon
if you can use 'babel', try to add build scripts in package.json(--presets=es2015) as below. it make to precompile import code to es2015
"build": "babel server --out-dir build --presets=es2015 && webpack"
As of Node.js v12 (and this is probably fairly stable now, but still marked "experimental"), you have a couple of options for using ESM (ECMAScript Modules) in Node.js (for files, there's a third way for evaling strings), here's what the documentation says:
The --experimental-modules flag can be used to enable support for
ECMAScript modules (ES modules).
Once enabled, Node.js will treat the following as ES modules when passed to
node as the initial input, or when referenced by import statements within
ES module code:
Files ending in .mjs.
Files ending in .js, or extensionless files, when the nearest parent
package.json file contains a top-level field "type" with a value of
"module".
Strings passed in as an argument to --eval or --print, or piped to
node via STDIN, with the flag --input-type=module.
Node.js will treat as CommonJS all other forms of input, such as .js files
where the nearest parent package.json file contains no top-level "type"
field, or string input without the flag --input-type. This behavior is to
preserve backward compatibility. However, now that Node.js supports both
CommonJS and ES modules, it is best to be explicit whenever possible. Node.js
will treat the following as CommonJS when passed to node as the initial input,
or when referenced by import statements within ES module code:
Files ending in .cjs.
Files ending in .js, or extensionless files, when the nearest parent
package.json file contains a top-level field "type" with a value of
"commonjs".
Strings passed in as an argument to --eval or --print, or piped to
node via STDIN, with the flag --input-type=commonjs.
I'm going to address another problem within the original question that no one else has. After recently converting from CommonJS to ESM in my own NodeJS project, I've seen very little discussion about the fact that you cannot place imports wherever you want, like you could with require. My project is working great with imports now, but when I use the code in the question, I first get an error for not having a named function. After naming the function, I receive the following...
import express from 'express'
^^^^^^^
SyntaxError: Unexpected identifier
at Loader.moduleStrategy (internal/modules/esm/translators.js:88:18)
You cannot place imports inside functions like you could require. They have to be placed at the top of the file, outside code blocks. I wasted quite a bit of time on this issue myself.
So while all of the above answers are great at helping you get imports to work in your project, none address the fact that the code in the original question cannot work as written.
import statements are supported in the stable release of Node since version 14.x LTS.
All you need to do is specify "type": "module" in package.json.
In my case it was looking after .babelrc file, and it should contain something like this:
{
"presets": ["es2015-node5", "stage-3"],
"plugins": []
}
My project uses node v10.21.0, which still does not support ES6 import keyword. There are multiple ways to make node recognize import, one of them is to start node with node --experimental-modules index.mjs (The mjs extension is already covered in one of the answers here). But, this way, you will not be able to use node specific keyword like require in your code. If there is need to use both nodejs's require keyword along with ES6's import, then the way out is to use the esm npm package. After adding esm package as a dependency, node needs to be started with a special configuration like: node -r esm index.js
I've been trying to get this working. Here's what works:
Use a recent node version. I'm using v14.15.5. Verify your version by running: node --version
Name the files so that they all end with .mjs rather than .js
Example:
mod.mjs
export const STR = 'Hello World'
test.mjs
import {STR} from './mod.mjs'
console.log(STR)
Run: node test.mjs
You should see "Hello World".
Simply install a higher version of Node. As till Node v10 es6 is not supported. You need to disable a few flags or use
I just started to use Babel to compile my ES6 javascript code into ES5. When I start to use Promises it looks like it's not working. The Babel website states support for promises via polyfills.
Without any luck, I tried to add:
require("babel/polyfill");
or
import * as p from "babel/polyfill";
With that I'll get the following error on my app bootstrapping:
Cannot find module 'babel/polyfill'
I searched for the module but it seems I'm missing some fundamental thing here. I also tried to add the old and good bluebird NPM but it looks like it's not working.
How to use the polyfills from Babel?
This changed a bit in babel v6.
From the docs:
The polyfill will emulate a full ES6 environment. This polyfill is automatically loaded when using babel-node.
Installation:
$ npm install babel-polyfill
Usage in Node / Browserify / Webpack:
To include the polyfill you need to require it at the top of the entry point to your application.
require("babel-polyfill");
Usage in Browser:
Available from the dist/polyfill.js file within a babel-polyfill npm release. This needs to be included before all your compiled Babel code. You can either prepend it to your compiled code or include it in a <script> before it.
NOTE: Do not require this via browserify etc, use babel-polyfill.
The Babel docs describe this pretty concisely:
Babel includes a polyfill that includes a custom regenerator runtime
and core.js.
This will emulate a full ES6 environment. This polyfill is
automatically loaded when using babel-node and babel/register.
Make sure you require it at the entry-point to your application, before anything else is called. If you're using a tool like webpack, that becomes pretty simple (you can tell webpack to include it in the bundle).
If you're using a tool like gulp-babel or babel-loader, you need to also install the babel package itself to use the polyfill.
Also note that for modules that affect the global scope (polyfills and the like), you can use a terse import to avoid having unused variables in your module:
import 'babel/polyfill';
For Babel version 7, if your are using #babel/preset-env, to include polyfill all you have to do is add a flag 'useBuiltIns' with the value of 'usage' in your babel configuration. There is no need to require or import polyfill at the entry point of your App.
With this flag specified, babel#7 will optimize and only include the polyfills you needs.
To use this flag, after installation:
npm install --save-dev #babel/core #babel/cli #babel/preset-env
npm install --save #babel/polyfill
Simply add the flag:
useBuiltIns: "usage"
to your babel configuration file called "babel.config.js" (also new to Babel#7), under the "#babel/env" section:
// file: babel.config.js
module.exports = () => {
const presets = [
[
"#babel/env",
{
targets: { /* your targeted browser */ },
useBuiltIns: "usage" // <-----------------*** add this
}
]
];
return { presets };
};
Reference:
usage#polyfill
babel-polyfill#usage-in-node-browserify-webpack
babel-preset-env#usebuiltins
Update Aug 2019:
With the release of Babel 7.4.0 (March 19, 2019) #babel/polyfill is deprecated. Instead of installing #babe/polyfill, you will install core-js:
npm install --save core-js#3
A new entry corejs is added to your babel.config.js
// file: babel.config.js
module.exports = () => {
const presets = [
[
"#babel/env",
{
targets: { /* your targeted browser */ },
useBuiltIns: "usage",
corejs: 3 // <----- specify version of corejs used
}
]
];
return { presets };
};
see example: https://github.com/ApolloTang/stackoverflow-eg--babel-v7.4.0-polyfill-w-core-v3
Reference:
7.4.0 Released: core-js 3, static private methods and partial
application
core-js#3, babel and a look into the future
If your package.json looks something like the following:
...
"devDependencies": {
"babel": "^6.5.2",
"babel-eslint": "^6.0.4",
"babel-polyfill": "^6.8.0",
"babel-preset-es2015": "^6.6.0",
"babelify": "^7.3.0",
...
And you get the Cannot find module 'babel/polyfill' error message, then you probably just need to change your import statement FROM:
import "babel/polyfill";
TO:
import "babel-polyfill";
And make sure it comes before any other import statement (not necessarily at the entry point of your application).
Reference: https://babeljs.io/docs/usage/polyfill/
First off, the obvious answer that no one has provided, you need to install Babel into your application:
npm install babel --save
(or babel-core if you instead want to require('babel-core/polyfill')).
Aside from that, I have a grunt task to transpile my es6 and jsx as a build step (i.e. I don't want to use babel/register, which is why I am trying to use babel/polyfill directly in the first place), so I'd like to put more emphasis on this part of #ssube's answer:
Make sure you require it at the entry-point to your application,
before anything else is called
I ran into some weird issue where I was trying to require babel/polyfill from some shared environment startup file and I got the error the user referenced - I think it might have had something to do with how babel orders imports versus requires but I'm unable to reproduce now. Anyway, moving import 'babel/polyfill' as the first line in both my client and server startup scripts fixed the problem.
Note that if you instead want to use require('babel/polyfill') I would make sure all your other module loader statements are also requires and not use imports - avoid mixing the two. In other words, if you have any import statements in your startup script, make import babel/polyfill the first line in your script rather than require('babel/polyfill').
babel-polyfill allows you to use the full set of ES6 features beyond
syntax changes. This includes features such as new built-in objects
like Promises and WeakMap, as well as new static methods like
Array.from or Object.assign.
Without babel-polyfill, babel only allows you to use features like
arrow functions, destructuring, default arguments, and other
syntax-specific features introduced in ES6.
https://www.quora.com/What-does-babel-polyfill-do
https://hackernoon.com/polyfills-everything-you-ever-wanted-to-know-or-maybe-a-bit-less-7c8de164e423
Like Babel says in the docs, for Babel > 7.4.0 the module #babel/polyfill is deprecated, so it's recommended to use directly core-js and regenerator-runtime libraries that before were included in #babel/polyfill.
So this worked for me:
npm install --save core-js#3.6.5
npm install regenerator-runtime
then add to the very top of your initial js file:
import 'core-js/stable';
import 'regenerator-runtime/runtime';