I am following the instructions in this React Doc.
https://reactjs.org/docs/add-react-to-a-website.html#run-jsx-preprocessor
I have installed the dependencies as instructed:
npm install babel-cli#6 babel-preset-react-app#3
And to watch / transpile my source I use:
npx babel --watch src --out-dir dist --presets react-app/prod
This works great BUT, it not only transpiles JSX but also aysnc/await. Which all browsers I support (December 2020) already support async/await and therefore I would like to not transpile it. Is there another preset I should be using that would transpile JSX but not Async/Await?
What's causing async/await to be transformed is plugin-transform-regenerator.
You can enable/disable it in this REPL to demonstrate its effects. On the sidebar, scroll all the way down to plugins and click the x next to plugin-transform-regenerator.
You'd have to remove that preset and manually add all of the plugins and presets inherited from that preset to a babel config. I'm afraid it isn't possible to disable a specific plugin from a preset at the moment, as far as I know.
You can find all of the plugins and presets that preset is using here, under dependencies:
https://github.com/facebook/create-react-app/blob/master/packages/babel-preset-react-app/package.json
Here's documentation on putting together a babel config: https://babeljs.io/docs/en/configuration
I think you're able to achieve your role by using 2 common babel presets: #babel/preset-env & #babel/preset-react with latest version.
The key thing you might need to change to keep async/await (a2) is the target option of preset-env. As long as you set a browser to support (a2) such as chrome: 80, babel would keep them for you. Of course #babel/preset-react is all about for transform jsx.
Here's a step you need to do:
Install deps:
npm i -D #babel/core #babel/cli #babel/preset-env #babel/preset-react
Create a babel.config.js:
const presets = [
[
"#babel/preset-env",
{
"targets": {
"chrome": 80, // this version to support `async/await`
},
// "modules": false, // you might want it to native support esm in browser
}
],
"#babel/preset-react"
];
module.exports = { presets };
Finally, run your test code:
npx babel --watch src --out-dir dist
NOTE: No need to specify presets here since it's configured via the file
So, I'm dabbling a bit with Typescript and Grunt at the moment to see if it's worth it for me. The thing is: Typescript does not compile to *.mjs files but only regular *.js files. Node does support ES6 Modules but only if you either mark them as '*.jsm' files or by setting "type": "module". Setting this top-level field in package.json however has global scope for any *.js file in the same directory and any following ones.
This breaks the Gruntfile.js file as it seems since it uses CommonJS modules, see my very basic Gruntfile as example:
module.exports = function (grunt) {
grunt.initConfig({
ts: {
default: {tsconfig: "./tsconfig.json"}
}
})
grunt.loadNpmTasks("grunt-ts");
grunt.registerTask("default", ["ts"]);
}
Without expecting much success I naively changed the export syntax from module.exports = to export default which expectedly did no work since it didn't make much sense.
Questions
Is there any option to use Grunt with ES6 modules enabled in node?
Is there a proper way to tell TypeScript to compile to *.mjs files?
If you set "type": "module" in your package.json, you need to rename Gruntfile.js to Gruntfile.cjs, and run it with grunt --gruntfile Gruntfile.cjs.
The suggested approach with Babel running before Grunt makes Grunt a bit redundant. Since TypeScript does not yet support exporting ES6 modules to *.mjs files (and you have to use the *.mjs suffix in your import when node should still be running with its CommonJS system) and will probably never fully (see Design Meeting Notes 11/22/2019) I have to conclude that ES6 modules still have serious implications and issues. Changing the file extension is not enough since the extension-less imports fail with node. You'd need to go through every compiled file and change the import to specifically load *.mjs files.
However, the TypeScript Compiler can be set up in a way that it does understand ES6 module syntax and to compile to CommonJS (see TS handbook).
{
"compilerOptions": {
"module": "CommonJS",
// [...]
},
}
This way the TypeScript code be written with ES6 module syntax and the output can be CommonJS compatible without braking other code. As a bonus you can skip the Babel approach and grunt can run TS compiler.
You can using babel-node to compile first. Which will resolve ES6 export and import problem.
npm install --save-dev #babel/core #babel/node
npx babel-node server.js
This question already has answers here:
Node.js - SyntaxError: Unexpected token import
(16 answers)
Closed 3 years ago.
I'm trying to get the hang of ES6 imports in Node.js and am trying to use the syntax provided in this example:
Cheatsheet Link
I'm looking through the support table, but I was not able to find what version supports the new import statements (I tried looking for the text import/require). I'm currently running Node.js 8.1.2 and also believe that since the cheatsheet is referring to .js files it should work with .js files.
As I run the code (taken from the cheatsheet's first example):
import { square, diag } from 'lib';
I get the error:
SyntaxError: Unexpected token import.
Reference to library I'm trying to import:
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
What am I missing and how can I get node to recognize my import statement?
Node.js has included experimental support for ES6 support.
Read more about here: https://nodejs.org/docs/latest-v13.x/api/esm.html#esm_enabling.
TLDR;
Node.js >= v13
It's very simple in Node.js 13 and above. You need to either:
Save the file with .mjs extension, or
Add { "type": "module" } in the nearest package.json.
You only need to do one of the above to be able to use ECMAScript modules.
Node.js <= v12
If you are using Node.js version 9.6 - 12, save the file with ES6 modules with .mjs extension and run it like:
node --experimental-modules my-app.mjs
You can also use npm package called esm which allows you to use ES6 modules in Node.js. It needs no configuration. With esm you will be able to use export/import in your JavaScript files.
Run the following command on your terminal
yarn add esm
or
npm install esm
After that, you need to require this package when starting your server with node. For example if your node server runs index.js file, you would use the command
node -r esm index.js
You can also add it in your package.json file like this
{
"name": "My-app",
"version": "1.0.0",
"description": "Some Hack",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node -r esm index.js"
},
}
Then run this command from the terminal to start your node server
npm start
Check this link for more details.
I just wanted to use the import and export in JavaScript files.
Everyone says it's not possible. But, as of May 2018, it's possible to use above in plain Node.js, without any modules like Babel, etc.
Here is a simple way to do it.
Create the below files, run, and see the output for yourself.
Also don't forget to see Explanation below.
File myfile.mjs
function myFunc() {
console.log("Hello from myFunc")
}
export default myFunc;
File index.mjs
import myFunc from "./myfile.mjs" // Simply using "./myfile" may not work in all resolvers
myFunc();
Run
node --experimental-modules index.mjs
Output
(node:12020) ExperimentalWarning: The ESM module loader is experimental.
Hello from myFunc
Explanation:
Since it is experimental modules, .js files are named .mjs files
While running you will add --experimental-modules to the node index.mjs
While running with experimental modules in the output you will see: "(node:12020) ExperimentalWarning: The ESM module loader is experimental.
"
I have the current release of Node.js, so if I run node --version, it gives me "v10.3.0", though the LTE/stable/recommended version is 8.11.2 LTS.
Someday in the future, you could use .js instead of .mjs, as the features become stable instead of Experimental.
More on experimental features, see: https://nodejs.org/api/esm.html
Using Node.js v12.2.0, I can import all standard modules like this:
import * as Http from 'http'
import * as Fs from 'fs'
import * as Path from 'path'
import * as Readline from 'readline'
import * as Os from 'os'
Versus what I did before:
const
Http = require('http')
,Fs = require('fs')
,Path = require('path')
,Readline = require('readline')
,Os = require('os')
Any module that is an ECMAScript module can be imported without having to use an .mjs extension as long as it has this field in its package.json file:
"type": "module"
So make sure you put such a package.json file in the same folder as the module you're making.
And to import modules not updated with ECMAScript module support, you can do like this:
// Implement the old require function
import { createRequire } from 'module'
const require = createRequire(import.meta.url)
// Now you can require whatever
const
WebSocket = require('ws')
,Mime = require('mime-types')
,Chokidar = require('chokidar')
And of course, do not forget that this is needed to actually run a script using module imports (not needed after v13.2):
node --experimental-modules my-script-that-use-import.js
And that the parent folder needs this package.json file for that script to not complain about the import syntax:
{
"type": "module"
}
If the module you want to use has not been updated to support being imported using the import syntax then you have no other choice than using require (but with my solution above that is not a problem).
I also want to share this piece of code which implements the missing __filename and __dirname constants in modules:
import {fileURLToPath} from 'url'
import {dirname} from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
If you are using the modules system on the server side, you do not need to use Babel at all. To use modules in Node.js ensure that:
Use a version of node that supports the --experimental-modules flag
Your *.js files must then be renamed to *.mjs
That's it.
However and this is a big however, while your shinny pure ES6 code will run in an environment like Node.js (e.g., 9.5.0) you will still have the craziness of transpilling just to test. Also bear in mind that Ecma has stated that release cycles for JavaScript are going to be faster, with newer features delivered on a more regular basis. Whilst this will be no problems for single environments like Node.js, it's a slightly different proposition for browser environments. What is clear is that testing frameworks have a lot to do in catching up. You will still need to probably transpile for testing frameworks. I'd suggest using Jest.
Also be aware of bundling frameworks. You will be running into problems there.
Use:
"devDependencies": {
"#babel/core": "^7.2.0",
"#babel/preset-env": "^7.2.0",
"#babel/register": "^7.0.0"
}
File .babelrc
{
"presets": ["#babel/preset-env"]
}
Entry point for the Node.js application:
require("#babel/register")({})
// Import the rest of our application.
module.exports = require('./index.js')
See How To Enable ES6 Imports in Node.js
You may try esm.
Here is some introduction: esm
Using the .mjs extension (as suggested in the accepted answer) in order to enable ECMAScript modules works. However, with Node.js v12, you can also enable this feature globally in your package.json file.
The official documentation states:
import statements of .js and extensionless files are treated as ES modules if the nearest parent package.json contains "type": "module".
{
"type": "module",
"main": "./src/index.js"
}
(Of course you still have to provide the flag --experimental-modules when starting your application.)
Back to Jonathan002's original question about
"... what version supports the new ES6 import statements?"
based on the article by Dr. Axel Rauschmayer, there is a plan to have it supported by default (without the experimental command line flag) in Node.js 10.x LTS. According to node.js's release plan as it is on 3/29, 2018, it's likely to become available after Apr 2018, while LTS of it will begin on October 2018.
Solution
https://www.npmjs.com/package/babel-register
// This is to allow ES6 export syntax
// to be properly read and processed by node.js application
require('babel-register')({
presets: [
'env',
],
});
// After that, any line you add below that has typical ES6 export syntax
// will work just fine
const utils = require('../../utils.js');
const availableMixins = require('../../../src/lib/mixins/index.js');
Below is definition of file *mixins/index.js
export { default as FormValidationMixin } from './form-validation'; // eslint-disable-line import/prefer-default-export
That worked just fine inside my Node.js CLI application.
I don't know if this will work for your case, but I am running an Express.js server with this:
nodemon --inspect ./index.js --exec babel-node --presets es2015,stage-2
This gives me the ability to import and use spread operator even though I'm only using Node.js version 8.
You'll need to install babel-cli, babel-preset-es2015, and babel-preset-stage-2 to do what I'm doing.
What is the quick way to fix the error
Unexpected token => .
I wrote below code and it only runs in higher version of chrome but not on lower version and ie11.
var result = aIndice.filter(obj => {
return obj.Type === "E"
})
You are using an arrow function obj => { } which will not work in Internet Explorer 11. You need to either use tools like Babel to compile your ES6 code to ES5, or simply avoid using any modern features.
You can also write your function like this:
var result = aIndice.filter(function(obj) {
return obj.Type === "E"
})
Arrow functions are an es2015 feature, therefore they will not run on older browsers.
Some features can be implemented by using different polyfills like modernizr, but arrow functions are a language expression and thus can't be polyfilled.
You can tell what features are available in what browsers by using caniuse.
The solution to this problem is transpiling the code with a tool like babel.
To transpile your script with babel, you will need to install npm and node.js, and then initiate an npm project:
$ npm init
And install the dependencies we need, the babel-cli and a preset for it to use babel-preset-env.
$ npm install --save-dev babel-cli babel-preset-env
Now you need a settings file for babel, you can define your target browsers there using browserlist, so create a file named ".babelrc" and in it write:
{
"presets": [
["env", {
"targets": {
"ie": "11",
"chrome": 41
}
}]
]
}
Add a new npm script to package.json (created by calling npm init)
"script.js" is the source script, and "script-transpiled.js" is the output script.
"scripts": {
"transpile": "babel script.js --o script-transpiled.js"
}
And call
npm run transpile
Now your script will be transpiled into a new file script-transpiled.js and you can run it the targeted browsers.
To work with a large scale project it is recommended to use babel-loader with webpack.
I have a legacy project which uses Gulp to compile SASS and minify JS etc. (based on Drupal).
I'd like to use ES6 style imports and also be able to import modules that are located in node_modules without referencing the full path (for example import the lodash.debounce module as
import throttle from 'lodash.throttle'
What do I need to achieve that? (besides Gulp and NPM). Babel? Browserify? Lost with all the tooling.
I'd like to avoid webpack as it would increase the complexity of my project (and I don't know if I can use it in parallel with the way Drupal 7 is doing things)
Yep, you want babel. The documentation to set it up in your gulpfile is here: http://babeljs.io/docs/setup/#installation
You'll want to use the es2015 preset to enable the import syntax.
var gulp = require("gulp");
var babel = require("gulp-babel");
gulp.task("default", function () {
return gulp.src("src/app.js")
.pipe(babel({
presets: ['es2015']
}))
.pipe(gulp.dest("dist"));
});
To use import you need a transpiler, for example babel.
Assuming you are building code for the browser then to use import (transpiled to require) you need webpack or browserify which will also allow you to import from node_modules (there are other module builders too, jspm and systemjs, however I know next-to-nothing about them).
For either of these you will also need something to enable babel to be used in the build process. I use webpack with babel-loader.
I found a useful reference here specifically on using ES6 modules with webpack.