How to use ES modules within gulpfile.js? [duplicate] - javascript

Question: How can I write my gulp file in ES6 so I can use import instead of require and use => syntax over function()?
I can use io.js or node any version.
gulpfile.js:
import gulp from "./node_modules/gulp/index.js";
gulp.task('hello-world', =>{
console.log('hello world');
});
Errors:
import gulp from "./node_modules/gulp/index.js";
^^^^^^
SyntaxError: Unexpected reserved word
gulp.task('hello-world', =>{
^^
SyntaxError: Unexpected token =>
Inside the node_modules/gulp/bin/gulp.js i've changed the first line to #!/usr/bin/env node --harmony as asked in this stack

Yes, you can by using babel.
Make sure you've got the latest version of the gulp-cli.
npm install -g gulp-cli
Install babel as a dependency of the project.
npm install --save-dev babel
Rename gulpfile.js to gulpfile.babel.js
Your gulpfile might look something like this:
import gulp from 'gulp';
gulp.task('default', () => {
// do something
});
Update for Babel 6.0+
As correctly pointed out by Eric Bronniman, there are a few extra steps involved in getting this to work with the latest version of babel. Here are those instructions:
Again, make sure you've got the latest version of gulp-cli
npm install -g gulp-cli
Then install gulp, babel core, and the es2015 presets
npm install --save-dev gulp babel-core babel-preset-es2015
Then, either add the following to a .babelrc file or to your package.json
"babel": {
"presets": [
"es2015"
]
}
Your gulpfile.js should be named gulpfile.babel.js

Note you can now use many/most ES6 features in Node.js v4.0.0 without babel. However apparently 'import' is still not supported. See: https://nodejs.org/en/docs/es6/
Edit: Most of the popular ES6 features (including destructuring and spread) are supported by default in NodeJS 5.0 (see above link.) The only major missing feature appears to be ES6 modules as far as I can tell.

If you have the latest versions of gulp & node, you can simply create a gulpfile as gulpfile.mjs instead of gulpfile.js and it should work without needing to use Babel or any other transpiler.
.mjs is a special format used by node which allows usage of ES Modules.
References :-
https://nodejs.org/api/esm.html#esm_enabling
https://nodejs.org/api/packages.html#packages_determining_module_system
Example :-
// Filename: gulpfile.mjs
import gulp from 'gulp';
export default task;
function task()
{
return (
gulp.src(`./src/js/**/*.js`)
.pipe(gulp.dest(`./dist/Static/js`)
);
}

I use babel-node and native gulp.
Install babel and gulp as devDependencies.
Write gulpfile.js with ES6 syntax.
Use command ./node_modules/.bin/babel-node ./node_modules/.bin/gulp to run gulp
In package.json scripts section, you can skip the first ./node_modules/.bin/ part - as babel-node ./node_modules/.bin/gulp.
The advantage of this appoach is, one day when the node.js support all ES6 features one day, all you need to opt-out babel runtime is to replace babel-node with node. That is all.

If you're using the most modern version of Gulp and the Gulp CLI, you can just do Gulpfile.babel.js and it will understand and transpile your ES6 gulpfile with BabelJS by default.
It is also important to have the BabelJS transpiler installed under devDependencies as is Gulp:
npm install --save-dev babel
Also note that to require gulp in this context, you do not have to import the index.js, you can just:
import gulp from 'gulp';

Basically, what you need to install using npm is gulp, gulp-babel and babel-resent-env, add "env" to your .babelrc presets array, and use a gulpfile.babel.js file.
npm install gulp-babel --save-dev
Some of the answers mentioned babel-core, babel-preset-es2015, etc. The Babel official setup guide with Gulp is to use gulp-babel only, while gulp-babel has dependencies modules including babel-core so you don't need to install it separately.
About preset, you need to use a preset to make Babel actually do something, which is called Preset Env that automatically determines the Babel plugins you need based on your supported environments.
npm install babel-preset-env --save-dev
and in .babelrc file
{
"presets": ["env"]
}

/*
* Steps
* 1. Rename your gulpfile.js to gulpfile.babel.js
* 2. Add babel to your package.json (npm install -D babel)
* 3. Start writing ES6 in your gulpfile!
*/
import gulp from 'gulp'; // ES6 imports!
import sass from 'gulp-sass';
const sassOpts = { outputStyle: 'compressed', errLogToConsole: true }; // "let" and "const"!!
gulp.task('sass', () = > { // Arrow functions!!
gulp.src('./**/*.scss')
.pipe(sass(sassOpts))
.pipe(gulp.dest('./'));
});
gulp.task('default', ['sass'], () => { // Arrow functions!!
gulp.watch('./src/sass/**/*.scss', ['sass'])
.on('change', (e) => { // Arrow functions!!
console.log(`File ${e.path} was ${e.type}, running Sass task...`); // Template strings and interpolation!!
});
});

Steps I followed for developing the code for gulpfile in es6:
npm install gulp && sudo npm install gulp -g.
Please make sure that you you are using the updated version of Gulp.
The current version at the time of writing this answer was 3.9.1. To check which version of gulp is installed, type gulp -v
npm install babel-core babel-preset-es2015-without-strict --save-dev
Type touch .babelrc in the terminal
In the .babelrc file, add this code
{
"presets": ["es2015-without-strict"]
}
Created the gulp config file with the name gulpfile.babel.js
Voila!!! You can now write the config code for gulp in ES6.
Source: Using ES6 with Gulp - Mark Goodyear

I have just had the same problem and
solved as following:
Windows 10
node version: 14.15.4
npm version: 6.14.10
gulp version: 4.0.2
using yarn v1
Renamed gulpfile.js as gulpfile.babel.js
Added these packages as devdependency:
"#babel/cli": "^7.12.10",
"#babel/core": "^7.12.10",
"#babel/preset-env": "^7.12.11",
"#babel/register": "^7.12.10",
"gulp-babel": "^8.0.0",
Added babel.config.json
{
"presets": [
[
"#babel/preset-env",
{
"targets": {
"ie": "10",
"edge": "17",
"firefox": "60",
"chrome": "70",
"safari": "11.1"
}
}
]
]
}
Finally I deleted yarn.lock file and node_modules folder and installed all packages.
yarn install
This is how my gulpfile.babel.js file looks like:
import { src, dest, parallel, series, watch } from 'gulp';
import autoprefixer from 'autoprefixer';
import cssnano from 'cssnano';
import concat from 'gulp-concat';
import postcss from 'gulp-postcss';
import replace from 'gulp-replace';
import sass from 'gulp-sass';
import { init, write } from 'gulp-sourcemaps';
import uglify from 'gulp-uglify';
import babel from "gulp-babel";
//....
const _default = series(
parallel(scssTask, jsTask),
cacheBustTask,
watchTask
);
export { _default as default };
Note:
yarn gulp command runs properly but I still have that warning:
Requiring external module #babel/register

Related

I want Babel to transpile JSX but not async/await

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

Import Class in Nodejs fail [duplicate]

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

Use Babelify with Browserify Globally / Global in WebStorm

Background:
I have several vanilla JS projects with files up to 25 000 lines / single file in which I would like to use ES6 capabilities + require so I can make the code more readable. OS X guy by the way
Possible solution:
I could make up a package.json and use a webpack for each project, but I would prefer if I do not do that.
What I have done so far:
Install browserify globally
sudo npm install -g browserify
setup a watcher in PhpStorm
global browserify path
/usr/local/lib/node_modules/browserify/bin/cmd.js
arguments
$FilePath$
-o
$FileDir$/$FileNameWithoutAllExtensions$.js
all works fine, and if I have a require in my code
var foo = require('./inc/_dependency-functionality');
โœ… it will bundle just right and the required external files will get bundle inside a single file
BUT, ideally, I would like to have it so that I can use ES6 import / export functions, which may say I need babelify
doing this
sudo npm install -g browserify
and using
$FilePath$
-o
$FileDir$/$FileNameWithoutAllExtensions$.js
-t [ /usr/local/lib/node_modules/babelify --presets [/usr/local/lib/node_modules/#babel/preset-env ] ]
โŒ will not actually babelify the script
I'm kind of stuck
Ok, I managed to do it
$FilePath$
-o
$FileDir$/$FileNameWithoutAllExtensions$.js
-t [ /usr/local/lib/node_modules/babelify/index.js --presets [/usr/local/lib/node_modules/#babel/preset-env ] ]
Babelify should be appended by /index.js
and then you can actually lose the presets, if you have .babelrc in the home of your user library ( babel searches for .babelrc recursively on top )
$FilePath$
-o
$FileDir$/$FileNameWithoutAllExtensions$.js
-t [ /usr/local/lib/node_modules/babelify/index.js ]
Also, make sure your files are named file.source.js not file.babel as I had them, as the transpiling will not start for unknown files

ES6 import for 'ava' test not working

I followed the docs to create my first test using ava but it doesn't seem to run properly. I get the error below. I tried adding import 'babel-register'; at the top of the file, and it works, but only if I run one specific test file. e.g. ava ./test/helpers/test_helper.js. Running ava on its own though... results in the import error below. Does anyone else know how to fix this? The getting started guide uses ES6 import and I have no idea why mine doesn't just work.
(function (exports, require, module, __filename, __dirname) { import
test from 'ava';
^^^^^^ SyntaxError: Unexpected token import
test.js
import test from 'ava';
test(t => {
t.deepEqual([1, 2], [1, 2]);
});
there is a far easier way to work with ES module for AVA
$ npm install esm --save-dev
Then in your package.json add
{
"ava": {
"require": [
"esm"
]
}
}
Babel never works correctly, I spend more time on debugging the tool then my code with all this pile of CS everyday!
Add to your package.json
"ava": {
"files": [
"test/**/*.js"
],
"require": [
"babel-register"
],
"babel": "inherit"
},
Your .babelrc
{
"presets": ["es2015"]
}
And then your imports should work.
add this to your package.json
"ava": {
"babel": true
}
e.g.
https://github.com/e2e-boilerplate/selenium-webdriver-es-modules-babel-ava/blob/master/package.json
https://github.com/e2e-boilerplate/puppeteer-es-modules-babel-ava/blob/master/package.json
For me it was enough to just add
"type": "module",
to my package.json
in order to make
import test from 'ava';
test('foo', t => {
t.pass();
});
run correctly.
After you have yarm/npm installed it, did you run ava --init?
In package.json, what does the command say?
If you run (if you use npm) npm run test, it should execute the command in your package.json.
If you then have any .js (ES6) in your test directory, it should execute it (example is also on their github page https://github.com/avajs/ava).
You don't need to add all of that which is mentioned in the above comment.
These commands should get you a working run:
mkdir avatest
cd avatest
npm init
npm install --global ava (you probably did this already)
npm install --save-dev ava
ava --init
touch test/test.js
atom test/test.js (pasted your script)
npm run test
> 1 passed

Do I need require js when I use babel?

Im experimenting with ES6, and Im using gulp to build and babel to transpile to ES5. The output is not being run in node, just linked to from a .htm file with a tag. Im thinking I need to add
<script src='require.js'></script>
or something like that.
Im trying to import / export.
////////////////scripts.js
import {Circle} from 'shapes';
c = new Circle(4);
console.log(c.area());
/////////////////shapes.js
export class Circle {
circle(radius) {
this.radius = radius;
}
area() {
return this.radius * this.radius * Math.PI;
}
}
Error is
Uncaught ReferenceError: require is not defined
Refers to this (after .pipe(babel()) in gulp)
var _shapes = require('shapes');
Do I need require js when I use babel?
You might need some module loader, but it is not necessary RequireJS. You have several options. The following will help you to get started.
rollup.js with rollup-plugin-babel
Rollup is a next-generation JavaScript module bundler. It understands ES2015 modules natively, and will produce a bundle that doesn't need any module loader to operate. Unused exports will be trimmed from the output, it's called tree-shaking.
Now I personally recommend using rollupjs, as it produces the clearest output, and is easy to setup, however, it gives a different aspect to the answer. All the other approaches do the following:
Compile the ES6 code with babel, use the module format of your choice
Concatenate the compiled modules alongside with a module loader OR use a bundler that will traverse the dependencies for you.
With rollupjs things doesn't really work this way. Here, rollup is the first step, instead of babel. It only understands ES6 modules by default. You must give an entry module of which the dependencies will be traversed and concatenated. As ES6 allows multiple named exports in a module, rollupjs is smart enough to strip unused exports, thus shrinking bundle size. Unfortunately rollupjs-s parser doesn't understand >ES6 syntax, so ES7 modules have to be compiled before rollup parses them, but the compilation should not affect the ES6 imports. It is done by using the rollup-plugin-babel plugin with the babel-preset-es2015-rollup preset (this preset is the same as the es2015 one, except the module transformer and the external-helpers plugin). So rollup will do the following with your modules if correctly set up:
Reads your ES6-7 module from the filesystem
The babel plugin compiles it to ES6 in memory
rollup parses the ES6 code for imports and exports (using acorn parser, compiled into rollup)
it traverses the whole graph, and creates a single bundle (which still might have external dependencies, and the entry's exports might be exported, in a format of your choice)
Example nodejs build:
// setup by `npm i rollup rollup-plugin-babel babel-preset-es2015 babel-plugin-external-helpers --save-dev`
// build.js:
require("rollup").rollup({
entry: "./src/main.js",
plugins: [
require("rollup-plugin-babel")({
"presets": [["es2015", { "modules": false }]],
"plugins": ["external-helpers"]
})
]
}).then(bundle => {
var result = bundle.generate({
// output format - 'amd', 'cjs', 'es6', 'iife', 'umd'
format: 'iife'
});
require("fs").writeFileSync("./dist/bundle.js", result.code);
// sourceMaps are supported too!
}).then(null, err => console.error(err));
Example grunt build with grunt-rollup
// setup by `npm i grunt grunt-rollup rollup-plugin-babel babel-preset-es2015 babel-plugin-external-helpers --save-dev`
// gruntfile.js
module.exports = function(grunt) {
grunt.loadNpmTasks("grunt-rollup");
grunt.initConfig({
"rollup": {
"options": {
"format": "iife",
"plugins": [
require("rollup-plugin-babel")({
"presets": [["es2015", { "modules": false }]],
"plugins": ["external-helpers"]
})
]
},
"dist": {
"files": {
"./dist/bundle.js": ["./src/main.js"]
}
}
}
});
}
Example gulp build with gulp-rollup
// setup by `npm i gulp gulp-rollup rollup-plugin-babel babel-preset-es2015 babel-plugin-external-helpers --save-dev`
// gulpfile.js
var gulp = require('gulp'),
rollup = require('gulp-rollup');
gulp.task('bundle', function() {
gulp.src('./src/**/*.js')
// transform the files here.
.pipe(rollup({
// any option supported by Rollup can be set here.
"format": "iife",
"plugins": [
require("rollup-plugin-babel")({
"presets": [["es2015", { "modules": false }]],
"plugins": ["external-helpers"]
})
],
entry: './src/main.js'
}))
.pipe(gulp.dest('./dist'));
});
Babelify + Browserify
Babel has a neat package called babelify. It's usage is simple and straightforward:
$ npm install --save-dev babelify babel-preset-es2015 babel-preset-react
$ npm install -g browserify
$ browserify src/script.js -o bundle.js \
-t [ babelify --presets [ es2015 react ] ]
or you can use it from node.js:
$ npm install --save-dev browserify babelify babel-preset-es2015 babel-preset-react
...
var fs = require("fs");
var browserify = require("browserify");
browserify(["./src/script.js"])
.transform("babelify", {presets: ["es2015", "react"]})
.bundle()
.pipe(fs.createWriteStream("bundle.js"));
This will transpile and concatenate your code at once. Browserify's .bundle will include a nice little CommonJS loader, and will organize your transpiled modules into functions. You can even have relative imports.
Example:
// project structure
.
+-- src/
| +-- library/
| | \-- ModuleA.js
| +-- config.js
| \-- script.js
+-- dist/
\-- build.js
...
// build.js
var fs = require("fs");
var browserify = require("browserify");
browserify(["./src/script.js"])
.transform("babelify", {presets: ["es2015", "react"]})
.bundle()
.pipe(fs.createWriteStream("dist/bundle.js"));
// config.js
export default "Some config";
// ModuleA.js
import config from '../config';
export default "Some nice export: " + config;
// script.js
import ModuleA from './library/ModuleA';
console.log(ModuleA);
To compile just run node build.js in your project root.
Babel + WebPack
Compile all your code using babel. I recommend you to use the amd module transformer (called babel-plugin-transform-es2015-modules-amd in babel 6). After that bundle your compiled sources with WebPack.
WebPack 2 is out! It understands native ES6 modules, and will perform (or rather simulate) tree shaking using babili-s builtin dead code elimination. For now (September 2016) I would still suggest to use rollup with babel, although my opinion might change with the first release of WebPack 2. Feel free to discuss your opinions in the comments.
Custom compilation pipeline
Sometimes you want to have more control over the compilation process. You can implement your own pipeline like this:
First, you have to configure babel to use amd modules. By default babel transpiles to CommonJS modules, which is a little complicated to handle in the browser, although browserify manages to handle them in a nice way.
Babel 5: use { modules: 'amdStrict', ... } option
Babel 6: use the es2015-modules-amd plugin
Don't forget to turn on the moduleIds: true option.
Check the transpiled code for generated modul names, there are often mismatches between defined and required modules. See sourceRoot and moduleRoot.
Finally, you have to have some kind of module loader, but it isn't necessairy requirejs. There is almondjs, a tiny require shim that works well. You can even implement your own:
var __modules = new Map();
function define(name, deps, factory) {
__modules.set(name, { n: name, d: deps, e: null, f: factory });
}
function require(name) {
const module = __modules.get(name);
if (!module.e) {
module.e = {};
module.f.apply(null, module.d.map(req));
}
return module.e;
function req(name) {
return name === 'exports' ? module.e : require(name);
}
}
At the end, you can just concatenate the loader shim and the compiled modules together, and running an uglify on that.
Babel's boilerplate code is duplicated in every module
By default, most of the above methods compile each module with babel individually, and then concatenate them together. That's what babelify does too. But if you look at the compiled code, you see that babel inserts lots of boilerplate at the beginning of each file, most of them are duplicated across all files.
To prevent this you can use the babel-plugin-transform-runtime plugin.
barebones webpack 2
1) If this is your root directory:
index.html
<html>
...
<script src="./bundle.js"></script>
...
</html>
scripts.js
import { Circle } from './shapes.js';
...
shapes.js
export class Circle {
...
}
2) have node installed node
3) run the following command in your terminal:
$ npm install -g webpack
5) in your root directory run the following:
$ webpack scripts.js bundle.js
You should now have a file called bundle.js in your root directory which will be the file your index.html will consume. This is a minimalistic bundling feature from webpack. You can learn more here
require does not exist in the browser, so this error is expected. You need to use something like require.js or Browserify.

Categories

Resources