I'm getting below error running this command
gulp.task('minify', function () {
return gulp
.src('public/app/js/myapp.bundle.js')
.pipe(uglify())
.pipe(gulp.dest('public/app/js/myapp.bundle.min.js'));
});
GulpUglifyError: unable to minify JavaScript Caused by: SyntaxError: Unexpected token: name (MenuItem) (line: 1628, col: 18, pos: 53569)
Code on that location is this
setters: [],
execute: function () {
class MenuItem { // <-- line 1628
What's wrong?
UglifyJS does not currently support EcmaScript 6 structures like classes.
You'll probably need to run your JavaScript through a transpiler step first, or find a minifier that knows what to do with ES6 code.
Update 2017-06-17
The branch of UglifyJS that is designed to work with ES6 is now published as uglify-es on npm.
Update 2018-09-10
terser is the new uglify-es, uglify-es is no longer maintained.
If using gulp both npmjs gulp-uglify-es and npmjs gulp-terser packages support terser.
npm install gulp-terser --save-dev
const gulp = require('gulp');
const terser = require('gulp-terser');
function es(){
return gulp.src('./src/index.js')
.pipe(terser())
.pipe(gulp.dest('./build'))
}
gulp.task('default', es);
If you run into this problem and you have in fact a transpiler step like Babel, make sure that you include the proper Babel preset in you .babelrc file. Otherwise Babel will simply leave your code as is.
E.g.
{
"presets": ["es2015"]
}
Related
Is there any way to precompile riot.js tag that includes ES6 import syntax like below?
<riot-tag>
<script>
import Foo from './foo'
new Foo();
</script>
</riot-tag>
I use gulp and gulp-riot to build tags.
gulp.task('tags', () => {
return gulp.src([`${srcDir}/*`])
.pipe($.riot({
type: 'es6'
}))
.pipe(gulp.dest(`${destDir}/`));
});
You're going to need gulp to transform your ES2015 code into something the riot compiler can understand.
Start by adding an ES2015 compiler to you app:
npm install babel-core babel-preset-es2015 --save-dev
Then add your .babelrc file, to tell babel what presets to use:
{
"presets": ["es2015"]
}
Then gulp should be able to handle it ok from there:
import gulp from 'gulp';
import riot from 'gulp-riot';
gulp.task('tags', () => {
return gulp.src([`${srcDir}/*`])
.pipe(riot({
type: 'es6'
}))
.pipe(gulp.dest(`${destDir}/`));
});
Hope this helps!
I am trying to use gulp in order to minify a folder containing JS files. However, one of the files has the above error, preventing it from being minified.
I managed to catch and print the error, which I've partially printed here:
JS_Parse_Error {
message: 'SyntaxError: Unexpected token: punc ())',
filename: 'ex.js',
line: 189,
col: 25,
pos: 6482,
stack: Error\n at new JS_Parse_Error (eval at <anonymous> ... )
plugin: 'gulp-uglify',
fileName: '.../js/ex.js',
showStack: false
}
The file in question contains the following, shortened:
function() {
...
$.confirm({
buttons: {
confirm: function() {
$.post('/ajax-handler', {
...
})
.done( function(response) {
var data = filterResponse(response);
if (data['status'] == 'success') {
sleep(1000).then(() => {
* ...
});
sleep(5000).then(() => {
...
});
} else {
console.log('Oops!');
}
})
.fail( function(err, status, response) {
...
});
},
cancel: function() {}
}
});
...
}
I added the "*" above in order to indicate the exact position listed by JS_Parse_Error.
// Update
From the comments ~ #imolit
v2.0.0 (2018-09-14) - BREAKING CHANGES (link)
Switch back to uglify-js (uglify-es is abandoned, if you need uglify ES6 code please use terser-webpack-plugin).
Original answer before the update...
I hope you can get inspired by this solution which works with webpack. (link below)
Simply teach UglifyJS ES6
There are two versions of UglifyJS - ES5 and ES6 (Harmony), see on git
ES5 version comes by default with all the plugins, but if you install a Harmony version explicitly, those plugins will use it instead.
package.json
"uglify-js": "git+https://github.com/mishoo/UglifyJS2.git#harmony"
or
npm install --save uglify-js#github:mishoo/UglifyJS2#harmony
yarn add git://github.com/mishoo/UglifyJS2#harmony --dev
Webpack
To use it with webpack install also the webpack plugin
npm install uglifyjs-webpack-plugin --save-dev
yarn add uglifyjs-webpack-plugin --dev
then import the manually installed plugin
var UglifyJSPlugin = require('uglifyjs-webpack-plugin');
and replace it in code
- new webpack.optimize.UglifyJsPlugin({ ... })
+ new UglifyJSPlugin({ ... })
For more webpack info (Installation/Usage) see https://github.com/webpack-contrib/uglifyjs-webpack-plugin#install
npm install uglifyjs-webpack-plugin --save-dev is not enough
The main problem is "uglifyjs-webpack-plugin": "^0.4.6" in webpack's package.json
According to semver, ^0.4.6 := >=0.4.6 <0.5.0. Because of the leading zero, webpack will never use the 1.0.0-beta.2.
So after running npm i -D uglifyjs-webpack-plugin#beta, you need to do one more step which is rm -rf node_modules/webpack/node_modules/uglifyjs-webpack-plugin. Then webpack will pick up the version from node_modules/uglifyjs-webpack-plugin instead of node_modules/webpack/node_modules/uglifyjs-webpack-plugin
Update on 2018-04-18: webpack v4 does not have this issue
Add the babel-preset-es2015 dependency to fix this.
And also add 'es2015' in .babelrc file.
json
{
"presets": ["es2015"]
}
I am having the same issue, i found a great answers here that helped me to reach the the file that was causing the error.
Go to Rails Console and Paste:
JS_PATH = "app/assets/javascripts/**/*.js";
Dir[JS_PATH].each do |file_name|
puts "\n#{file_name}"
puts Uglifier.compile(File.read(file_name))
end
Hope it helps someone!
If you got this error using Grunt (grunt-contrib-uglify) the solution is to install ES6 version of the plugin:
npm install grunt-contrib-uglify-es --save-dev
For me it had nothing to do with Uglify not working correctly, but rather a dependency (in this case empty-promise) that has not been compiled to ES5 yet. As we just imported the raw source file, but babel is only transpiling files outside of node_modules, uglify got confused by the ES6 syntax.
Simply check if any dependency you've recently added might not have a "dist" build.
Add stage-3 to presets in .babelrc file.
{
"presets": [
"stage-3"
]
}
I try to write these code
gulp.task('script', function() {
'use strict'
return gulp.src(['app.js', 'components/**/*.jsx'])
.pipe(babel())
.pipe(browserify())
.pipe(gulp.dest("dist"));
});
but it shows some error:
SyntaxError:
/Users/Zizy/Programming/learn-react-js/components/CommentBox.jsx:58
<div className="commentBox">
^
ParseError: Unexpected token
at wrapWithPluginError (/Users/Zizy/Programming/learn-react-js/node_modules/gulp-browserify/index.js:44:10)
It seems that before .pipe(browserify()) the gulp did't transform the jsx code. But if I just remove .pipe(browserify()) I find that did transform, just cannot let babel and browserify work together.
I know maybe I can use like babelify or browserify plugin for babel though, I just want figure out the reason.
gulp-browserify doesn't quite work like that. You don't give it a bunch of buffers to collect and bundle.
You give it one file—the entry file—which it passes into Browserify. Browserify checks to see what other files the entry file references, then loads those files directly from the file system, meaning that you can't modify them with gulp plugins beforehand.
So, really, if we pretend you don't want to use Babel on your source files, your gulpfile should look like this, only passing in the entry file:
gulp.task('script', function() {
'use strict'
return gulp.src('app.js')
.pipe(browserify())
.pipe(gulp.dest("dist"));
});
However, note that gulp-browserify is no longer maintained, and this is exactly why. gulp plugins aren't supposed to read directly from the file system. That's why you're supposed to use Browserify (or, in your case, Babelify) directly with vinyl-source-stream as recommended in the gulp recipes. It's more idiomatic and less confusing.
That wraps up my answer to your question, but I'd like to add: if you're using the ES2015 module syntax (and you probably should be), there's a better way to do this. Browserify wraps all your modules separately in a bunch of code to make the programmatic CommonJS API work properly, but ES2015 modules have a declarative syntax, which makes it much easier for tools to operate on them statically. There's a tool called Rollup that takes advantage of this, allowing it to produce bundles that are smaller, faster, and more minfication-friendly than Browserify's.
Here's how you might use it with gulp:
var gulp = require('gulp'),
rollup = require('rollup-stream'),
babel = require('gulp-babel'),
source = require('vinyl-source-stream'),
buffer = require('vinyl-buffer');
gulp.task('script', function() {
return rollup({entry: 'app.js'})
.pipe(source('app.js'))
.pipe(buffer())
.pipe(babel())
.pipe(gulp.dest('dist'));
});
Starting from Babel 6 you need to declare the presets manually, check this.
Basically, in the root of your project you need a .babelrc with the following content:
{
"presets": [ "es2015", "react" ]
}
And the corresponding npm modules in package.json:
// package.json
{
"devDependencies": {
...
"babel-preset-es2015": "^6.1.18",
"babel-preset-react": "^6.1.18",
...
}
}
Here is a sample repository with gulp, babel and browserify
Following is the code snippet
gulp.task("js", (done) => {
const bundler = browserify({ entries: paths.js.source }, { debug: true }).transform(babel);
bundler.bundle()
.on("error", function (err) { console.error(err); this.emit("end"); })
.pipe(source(paths.build.destMinJSFileName))
.pipe(buffer())
.pipe(sourcemaps.init({ loadMaps: true }))
.pipe(uglify())
.pipe(sourcemaps.write(paths.js.destMapFolder))
.pipe(gulp.dest(paths.build.destBuildFolder));
done();
});
I have a piece of code:
'use strict';
class ArticleModel {
constructor(options = {}) {
this.options = options
}
}
module.exports = ArticleModel
which results in the error Unexpected token = - I don't believe Babel is parsing this. Which babel 6 plugin is needed to parse default parameters in a function?
Edit 1 - this is my .babelrc file
{
"presets": [
"es2015",
"stage-0"
]
}
Edit 2 - I am not running babel from the same directory as .babelrc. I'm running babel from inside test/ where the structure looks like this:
/app
/test
/test/runner.js < -- this is what calls babel-core/register
.babelrc
Do I need to explicitly tell babel-core/register where .babelrc is? I assumed it rolled up a directory for it.
Edit 3 - changed babel/register to babel-core/register. Still get the same issue.
npm install babel-preset-es2015 --save-dev
Add the following line to your .babelrc file:
{
"presets": ["es2015"]
}
Did you try this?
How are you importing the module into the test? I had a similar problem when my tests started to break after upgrading from Babel 5 to 6. In my case it turned out that the problem was because the import has to referenced the default property in the imported lib.
The initiator of this Babel issue gives a good example: https://github.com/babel/babel/issues/2679
I'm new to Gulp and the concept of task runners. I am wanting to write some javascript using es6 and have gulp run it through jscs, jshint and finally use babel to convert it to es5.
The part I'm confused about is the order I should have these tasks in my gulp pipeline. If I run jshint first I get warnings about how I can't use let and arrow functions. However, if I convert my code using babel first the babel output then fails validation as well.
What I'm looking for is a correct way of ordering my gulp task so it validates and converts my code to es5.
This is my current gulp task.
gulp.task('js-validation', function() {
$.util.log('**Starting js validation**');
return gulp
.src(config.alljs)
.pipe($.print())
.pipe($.jshint())
.pipe($.jscs())
.pipe($.babel())
.pipe($.jshint.reporter('jshint-stylish', {verbose: true}))
.pipe($.jshint.reporter('fail'))
.pipe(gulp.dest(config.temp));
});
This work for me:
.pipe(jshint({
esnext: true
}))
First, if possible, consider moving to ESLint; I'm not saying that because it's a subjective opinion, I'm saying that because it's modular and supports ES6, and even React+JSX if that's where you want to go with it.
You aren't going to have a lot of luck with JSHint, yet, if ES6 is where you're going.
If/when I'm wrong, please let me know, but I believe they have yet to replace their parser, to support all of ES6, and unless you're going to include the entirety of the browser polyfill+library in the pipeline (just for sake of having no missing methods, for validate to work), you may well be at a loss, here.
With ESLint in place, you could use the following config options (in .eslintrc, in the package.json, et cetera), to get ES6 support:
{
"env": {
"browser": true,
"node": true,
"es6": true
},
"ecmaFeatures": {
"modules": true,
"jsx": true
}
}
Of course, if you don't need node globals, JSX or ES6 modules, feel free to rip those out.
The one other caveat there is that ESLint has no support for ES7 (ES2016), yet (but will, when it's standardized).
So array/generator comprehensions, async/await, trailing commas in function argument lists, et cetera, are not supported and will cause explosions.
There is a babel-eslint version of eslint which will validate these, if that's your requirement.
You can put that in place by installing "babel-eslint" and then in your eslint config, setting { "parser": "babel-eslint" } to the root object, along with all of your other config preferences.
But typically, you would lint the code that you are putting into the system, pre-compile, using ESLint and Babel:
// ...
.pipe( eslint() )
.pipe( babel() )
// ...
To lint the source code (rather then the compiled code) you have to call the linter before babel, so the order is correct.
However, you have to use a linter that really understands ES6. With JSHint, you have to set the esnext option, but I'm not sure whether it supports all ES6 features. I recommend to have a look at eslint with babel-eslint instead.
Instead of JSHint, you can use ESLint, which will have support for numerous ES6 functions:
http://eslint.org/docs/user-guide/configuring
You are correct that you want your linting to occur prior to transpilation, also.
gulp.task('jshint', function () {
gulp.src('js/**/*.js')
.pipe(cache('jshint'))
.pipe(jshint({esnext:true}))
.pipe(jshint.reporter('default'));
});
.pipe(jshint({esnext:true}))
You have the correct order, but as suggested from other answers to use ESLint. You should also have a function to handle errors when linting. Here is my gulpfile.js (not a perfect example, but it's working for me):
const gulp = require("gulp"),
babel = require("gulp-babel"),
eslint = require("gulp-eslint");
gulp.task("babel", () => {
gulp.src("src/*.js")
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError())
.on("error", onError) // handle error for eslint
.pipe(babel())
.on("error", onError) // handle error for babel
.pipe(gulp.dest("dist"));
});
gulp.task("watch", () => {
process.chdir(process.env.INIT_CWD);
gulp.watch("src/*.js", ["babel"]);
});
// ignore if error is from babel, eslint error message is enough
if (err.plugin != "gulp-babel" && err.message) {
console.log("Message: ", err.message);
}