I'm writing ES6 JavaScript modules and using Babel to transpile them to ES5. Babel generates sourcemaps that point back to the original ES6 code. I then use r.js to take those ES5 AMD modules and combine and uglify them. r.js creates a sourcemap that shows the ES5 files. I want the ES6 ones from the first step. My grunt file looks like this:
module.exports = function(grunt) {
require('load-grunt-tasks')(grunt); // npm install --save-dev load-grunt-tasks
// Project configuration.
grunt.initConfig({
babel: {
options: {
modules: "amd",
sourceMap: true
},
dist: {
files: {
"es5/editor.js": "src/editor.js",
"es5/editor-events.js": "src/editor-events.js"
}
}
},
requirejs: {
production: {
options: {
baseUrl: "es5",
mainConfigFile: "es5/require.config.js",
name: "../node_modules/almond/almond",
include: ["editor"],
out: "dist/ed.js",
optimize: "uglify2",
generateSourceMaps: true,
preserveLicenseComments: false
}
}
}
});
// Default task(s).
grunt.registerTask('default', ['babel', 'requirejs']);
};
It compiles everything perfectly. But it loses the nice ES6 sourcemaps. Any way to keep them? Is there a better build process that'll get me to a single, browser-friendly JavaScript file?
you shouldn't use two different steps for building your app. one for transpiling and an other one for bundling. you should have one step instead.
you could use browserify to bundle them and babelify as transpiler. the command would look like this:
browserify app.js -t babelify -d -o bundle.js
Note: -d (debug) will enable the sourcemaps. they will point to the es6 files.
Related
I would like to use the features of ES2016 for my front end development. Especially import and decorators are interesting for me.
I’ve started a small test project and created some different files with classes which I include with import. Babel generates the correct files but includes an require statement which does not work in a browser (as far as I know).
Are there any good tools to concat all files into a single javascript file ordered by their require? Or some libraries for gulp which do this for me?
You get the error because Babel translates your ES2016 code into CommonJS format, browser does not support it. You need some module bundler for creating bundle that can be used in browser:
Browserify
Webpack
Rollup
Example gulp build with gulp-rollup
// setup by `npm i gulp gulp-rollup rollup-plugin-babel babel-preset-es2016 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": [["es2016", { "modules": false }]],
"plugins": ["external-helpers"]
})
],
entry: './src/main.js'
}))
.pipe(gulp.dest('./dist'));
});
TL;DR
minifyify (the Browserify plugin) makes use of uglify-js but appears to be unable to handle Conditional compilation:
compression works
uglifyjs alone works for conditional compilation
minifyify provides additional compilation optimization but I have been unable to use conditional compilation with it
I'm using Browserify with the babelify transformer and the minifyify plugin. Here is the cmd, broken down in readable parts:
browserify
src/scripts/app/index.js
-o
build/prod/public/assets/js/appBundle.min.js
-t
[ babelify --presets [ es2015 ] ]
-p
[ minifyify --no-map --uglify [ --compress [ --drop_console --dead_code --conditionals --unused --if_return ] --mangle --screw-ie8 --define [ DEBUG=false ] ] ]
I've gotten every setting/option to work. However, I am unable to get conditional compilation to work.
Minifyify uses uglifyjs' minify method. The fact I'm passing by minifyify shouldn't really change anything.
Building directly through uglifyjs works
uglifyjs input.js --compress --dead_code --define DEBUG=false -o output.js
But then I lose the additional compressions/optimizations provided by minifyify.
I'm also open to another build process. My needs are resumed in the settings of the current process:
CommonJS required modules
transpiling of ES6 to ES5
advanced minification/compression
It turns out that the culprit was, more or less, uglifyjs. The property name for global definition in the task is different between CMD and Programmatic API.
cmd line: --define VARNAME=VALUE
programmatic: compress: {global_defs: { varname: value } }
That being said, it also seems that minifyify or browserify isn't passing the cmd-line options properly for global definitions - we're still investigating this
programmatic solution
By using the Browserify & minifyify programmatic API, the build task works. Below is the same task as the one in OP, but it works:
"use strict";
var browserify = require("browserify"),
fs = require("fs");
browserify("src/scripts/app/index.js")
.transform("babelify", {presets: ["es2015"], plugins: ["transform-object-assign"]})
.plugin("minifyify", {map: false, uglify: {
compress: {
drop_console: true,
dead_code: true,
conditionals: true,
unused: true,
if_return: true,
global_defs: {
DEBUG: false
}
},
mangle: true,
"screw-ie8": true
}})
.bundle()
.pipe(fs.createWriteStream("build/prod/public/assets/js/appBundle.js"));
update in uglifyjs docs
I've proposed a modification to the current uglifyjs docs, providing an example using the programmatic API as above, so as to avoid this issue for others in the future.
I want to use both Browserify and Babel with my JavaScript. For this I created a gulp task
gulp.task('babel', function() {
return gulp.src('_babel/*.js')
.pipe(browserify({ insertGlobals : true }))
.pipe(babel({ presets: ['es2015'] }))
.pipe(gulp.dest('_dev/js'));
});
Unfortunately, when I want to use import within my code, I am getting an error:
ParseError: 'import' and 'export' may only appear at the top level
My main js file is very simple:
import 'directives/toggleClass';
I'm guessing that it is because of Babel (and it's use strict addition), but what can I do?
Babel maintains an official transform for Browserify called babelify and it should be used wherever possible if using babel and browserify.
Drop the use of babel directly and place babelify as a transform plugin for browserify. There are many ways to configure browserify but specifying config in your package.json would probably be easiest.
"browserify": {
"transform": [["babelify", { "presets": ["es2015"] }]]
}
Your gulp task will then be simplified
gulp.task('babel', function() {
return gulp.src('_babel/*.js')
.pipe(browserify({ insertGlobals : true }))
.pipe(gulp.dest('_dev/js'));
});
Browserify also exposes methods to do this programmatically so you will be able to configure the bundler from inside your gulp task (dropping the package config, although using the package is perfectly fine for this), check their documentation and experiment, I've done it before but its been a long time since I used gulp (using gulp here is just a complication you dont need, but I expect you are using it elsewhere in your build pipeline where it might be more helpful).
I'm trying to automate .jsx template compiling. I'm using grunt to achieve this goal. But at the moment my grunt task for .jsx compiling just hangs and nothing happens...
I added NPM package grunt-react. Then I added configuration for it:
module.exports = function( grunt ){
grunt.loadNpmTasks('grunt-react');
grunt.initConfig({
react: {
dynamic_mappings: {
files: [
/* ui-components compiling */
{
expand: true,
cwd: './scripts/components',
src: ['**/**.jsx'],
dest: './scripts/components/dest',
ext: '.js'
}
]
}
}
});
grunt.registerTask('react', ['react']);
};
Then I trying to run this task using grunt grunt react and the task is hangs... and nothing happens. It's looks like some process running, but in reality nothing happens.
Grunt versions:
grunt-cli v0.1.13
grunt v0.4.5
Operating system Windows 7.
I learned the issue and got the solution. On June 12th, 2015, the React team has deprecated JSTransform and react-tools, which grunt-react package uses. Instead this module author recomend to use Babel.
I installed Babel and related packages using command:
npm install --save-dev grunt-babel babel-preset-es2015 babel-plugin-transform-react-jsx babel-preset-react
Then I configured my Gruntfile.js to use Babel for compiling .jsx files to .js:
module.exports = function( grunt ){
grunt.loadNpmTasks('grunt-babel');
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
babel: {
options: {
plugins: ['transform-react-jsx'],
presets: ['es2015', 'react']
},
jsx: {
files: [{
expand: true,
cwd: './scripts/components',
src: ['*.jsx'],
dest: './scripts/components',
ext: '.js'
}]
}
}
});
grunt.registerTask('react', ['babel']);
};
And now, when I run the command grunt react my react .jsx components is compiling.
I have this code:
"use strict";
import browserSync from "browser-sync";
import httpProxy from "http-proxy";
let proxy = httpProxy.createProxyServer({});
and I have installed babel-core and babel-cli globally via npm. The point is when I try to compile with this on my terminal:
babel proxy.js --out-file proxified.js
The output file gets copied instead of compiled (I mean, it's the same as the source file).
What am I missing here?
Babel is a transformation framework. Pre-6.x, it enabled certain transformations by default, but with the increased usage of Node versions which natively support many ES6 features, it has become much more important that things be configurable. By default, Babel 6.x does not perform any transformations. You need to tell it what transformations to run:
npm install babel-preset-env
and run
babel --presets env proxy.js --out-file proxified.js
or create a .babelrc file containing
{
"presets": [
"env"
]
}
and run it just like you were before.
env in this case is a preset which basically says to compile all standard ES* behavior to ES5. If you are using Node versions that support some ES6, you may want to consider doing
{
"presets": [
["env", { "targets": { "node": "true" } }],
]
}
to tell the preset to only process things that are not supported by your Node version. You can also include browser versions in your targets if you need browser support.
Most of these answers are obsolete. #babel/preset-env and "#babel/preset-react are what you need (as of July 2019).
I had the same problem with a different cause:
The code I was trying to load was not under the package directory, and Babel does not default to transpiling outside the package directory.
I solved it by moving the imported code, but perhaps I could have also used some inclusion statement in the Babel configuration.
First ensure you have the following node modules:
npm i -D webpack babel-core babel-preset-es2015 babel-preset-stage-2 babel-loader
Next, add this to your Webpack config file (webpack.config.js) :
// webpack.config.js
...
module : {
loaders : [
{
test : /\.js$/,
loader : 'babel',
exclude : /node_modules/,
options : {
presets : [ 'es2015', 'stage-2' ] // stage-2 if required
}
}
]
}
...
References:
https://gist.github.com/Couto/6c6164c24ae031bff935
https://github.com/babel/babel-loader/issues/214
Good Luck!
As of 2020, Jan:
STEP 1: Install the Babel presets:
yarn add -D #babel/preset-env #babel/preset-react
STEP 2: Create a file: babelrc.js and add the presets:
module.exports = {
// ...
presets: ["#babel/preset-env", "#babel/preset-react"],
// ...
}
STEP 3:- Install the babel-loader:
yarn add -D babel-loader
STEP 4:- Add the loader config in your webpack.config.js:
{
//...
module: [
rules: [
test: /\.(js|mjs|jsx|ts|tsx)$/,
loader: require.resolve('babel-loader')
]
]
//...
}
Good Luck...
npm install --save-dev babel-preset-node5
npm install --save-dev babel-preset-react
...and then creating a .babelrc with the presets:
{
"presets": [
"node5",
"react"
]
}
...resolved a very similar issue for me, with babel 3.8.6, and node v5.10.1
https://www.npmjs.com/package/babel-preset-node5
https://www.npmjs.com/package/babel-preset-react
Same error, different cause:
Transpiling had worked before and then suddenly stopped working, with files simply being copied as is.
Turns out I opened the .babelrc at some point and Windows decided to append .txt to the filename. Now that .babelrc.txt wasn't recognized by babel. Removing the .txt suffix fixed that.
fix your .babelrc
{
"presets": [
"react",
"ES2015"
]
}
In year 2018:
Install following packages if you haven't yet:
npm install babel-loader babel-preset-react
webpack.config.js
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['es2015','react'] // <--- !`react` must be part of presets!
}
}
],
}
Ultimate solution
I wasted 3 days on this
import react from 'react' unexpected identifier
I tried modifying webpack.config.js and package.json files, and adding .babelrc, installing & updating packages via npm, I've visited many, many pages but nothing has worked.
What worked? Two words: npm start. That's right.
run the
npm start
command in the terminal to launch a local server
...
(mind that it might not work straight away but perhaps only after you do some work on npm because before trying this out I had deleted all the changes in those files and it worked, so after you're really done, treat it as your last resort)
I found that info on this neat page. It's in Polish but feel free to use Google translate on it.