RequireJS: Uglification Not Working - gulp

I must be making a mistake somewhere, but it's not being written to stdout during optimization. I'm trying to optimize a file via requirejs, but the output isn't being minified. According to the documentation, UglifyJS should minify the code.
At any rate, the following code is trivial, but it isolates the problem.
src/index.js:
require(['config'], function () {
require(['myMod'], function (myMod) {
console.log(myMod.x());
})
})
src/myMod.js:
define(function () {
let myMod = {
x: 5
};
return myMod;
})
src/config.js:
define(function () {
require.config({
baseUrl: 'src'
});
})
And here's the gulp task that is performing the optimization:
gulp.task('optimize', function (cb) {
let config = {
appDir: 'src',
dir: 'dist/src',
generateSourceMaps: true,
preserveLicenseComments: false,
removeCombined: true,
baseUrl: './',
modules: [{
name: 'index',
include: ['myMod']
}]
}
let success = function (buildResponse) { console.log(buildResponse); cb() },
error = function (err) { console.log(err); cb(err) }
rjs.optimize(config, success, error)
})
After running the task, dist/src/index.js has all of the other modules included in it. However, it's not minified, and none of the variables have been renamed. Instead, it's as if the files were just concatenated, nothing more. Could someone tell me (1) why is it not being minified? (2) is UglifyJS throwing an error? If so, is there a way to see it when the gulp task is being run?
EDIT Here's a link to RequireJS docs where it talks about using the optimizer in node, which is done in the gulp task mentioned above. It's at the bottom under "Using the optimizer as a node module".
http://requirejs.org/docs/node.html

RequireJS' optimizer bundles UglifyJS2. UglifyJS2 does not handle ES6 or higher. If I take the options you use in your gulpfile, and plunk them into a separate file that I name options.js, and issue this command:
$ ./node_modules/.bin/r.js -o options.js
Then I get this output:
Tracing dependencies for: index
Uglify file: /tmp/t33/dist/src/index.js
Error: Cannot uglify file: /tmp/t33/dist/src/index.js. Skipping it. Error is:
SyntaxError: Unexpected token: name (myMod)
If the source uses ES2015 or later syntax, please pass "optimize: 'none'" to r.js and use an ES2015+ compatible minifier after running r.js. The included UglifyJS only understands ES5 or earlier syntax.
index.js
----------------
config.js
index.js
myMod.js
As you can see, UglifyJS does fail to minify your file, and RequireJS just skips the minification step for that file. Since this is not an outright error, the file is still output, just not minified.
If you change let to var in myMod.js, then the issue disappears.
Unfortunately, since this is not an execution failure (r.js still runs, it just does not minify the file), the error is not signaled to the errback handler you pass to rjs.optimize. I don't see a way to catch such error in a Gulpfile. The safe thing to do is to set optimize: "none" and perform the minification as an additional build step after running rjs.optimize.

I had also run into the same issue where require.js's optimizer (r.js) was combining different modules, but, it was not minify-ing the merged file. Although my run time environment is different from yours (using Java's Nashorn engine), this error was visible on my console :
If the source uses ES2015 or later syntax, please pass "optimize: 'none'" to r.js and use an ES2015+ compatible minifier after running r.js. The included UglifyJS only understands ES5 or earlier syntax.
Also, this error does not stop the optimizer from combining the files, it's just that the optimizer will not be able to mini-fy the merged file.

Related

Updated to Gulp 4.0 and now have a task build error

Im updating to Gulp 4.0 but I get an error when running gulp watch, that states:
AssertionError [ERR_ASSERTION]: Task never defined: build
The relevant code block in my Gulp file looks like this. What am i doing wrong?
gulp.task('server', gulp.series('build', function () {
browserSync.init(["css/*.css", "js/*.js"], {
server: { baseDir: "./" , port: 80}
// If you use vhosts use the line below and comment out the line above.
//proxy: "demo.local"
});
}));
You have at least this error in your code:
browserSync.init(["css/*.css", "js/*.js"], {
should be:
browserSync({
files: ["css/*.css", ""js/*.js"]
});
browserSync.init takes an options object as its first argument.
Secondly, the error Task never defined: xxxx I have seen this when, in your case, you call the build task - in your 'server' task before it has been defined/registered. So put the gulp.task('build'...) definition ( a registration of the task) before your 'server' task.
Your gulpfile is erroring for this reason before getting to the other error in browserSync.init mentioned above.

Webpack 4 - JSON module not found

I have some JSON files in my Webpack application that I want to import. They have names such as 0.json, 1.json, 2.json, and so on and are inside of the directory src/res/level/. When I try to require() them in my code, it does not work:
private loadWorld() {
// load the level
// duplicate the object to avoid modifying the actual instance
// that json-loader created
this.state.level = JSON.parse(JSON.stringify(require(`#res/level/${this.level}.json`))) as LevelData;
// ...
}
This line in my method always throws an error:
Error: Cannot find module "#res/level/1.json".
at webpackContextResolve (webpack-internal:///9:16:11)
at webpackContext (webpack-internal:///9:9:11)
However, I cannot figure out why. And to make things more confusing, if I run Webpack in watch mode, and I edit this line before my program tries to run it, then the JSON files are suddenly loaded properly.
I have configured my alias for #res properly:
resolve: {
extensions: [".ts", ".js", ".glsl", ".json"],
alias: {
"#res": path.join(__dirname, "src/res"),
"#lib": path.join(__dirname, "src/lib"),
"#shader": path.join(__dirname, "src/shader"),
"#control": path.join(__dirname, "src/control"),
"#scene": path.join(__dirname, "src/scene"),
"#util": path.join(__dirname, "src/util"),
}
}
And because this is Webpack 4, I simply did not include a loader for JSON.
So why is this not working?
Additionally, I notice that when I inspect the generated code, I see this:
Which suggests that the JSON files are being loaded, but not under the directory that I expect.
The compiler began to load the JSON files consistently when I used string concatenation instead of a template string:
this.state.level = JSON.parse(JSON.stringify(require("#res/level/" + this.level.toString() + ".json"))) as LevelData;

"this" in underscore is undefined after compiling with browserify and debowerify

So first.. I have next gulp task:
gulp.task('js', function() {
browserify('./src/js/main.js')
.bundle()
.on('error', onError)
.pipe( source('main.js') )
.pipe( gulp.dest(path.build.js) );
});
and package.json:
{
"browserify": {
"transform": [
["babelify", { "presets": ["es2015"] }],
"debowerify"
]
},
}
I am importing Backbone in main.js (or only underscore... it doesn't matter)
import Backbone from 'backbone';
And in console I am getting error
Uncaught TypeError: Cannot read property '_' of undefined
I checked code and found that in underscore sources at start of library root is undefined
// Establish the root object, `window` in the browser, or `exports` on the server.
var root = this;
// Save the previous value of the `_` variable.
var previousUnderscore = root._;
I think the problem is that debowerify or babelfy is wrapping code in some function. But also if I use node modules without debowerify all works fine. But I want to use bower.
So how to fix this problem?
To any future visitors to this question,
this is similar to Underscore gives error when bundling with Webpack
The gist of the issue is that babel is probably running the underscore.js code, since underscore.js uses this, and in es6 this is undefined when outside of a function, naturally this._ fails.
In code I've fixed the issue by ensuring that babel does not run on node_modules.
In my case the same error arose when using just browserify with underscore. I've workarounded issue by switching from underscore to lodash. They are in general (surely not fully) compatible, but at the worst I'd rather copy some missing function from underscore sources than live with its deisolated load approach.

Babel not transforming decorators

Forgive me if I'm missing something obvious, I'm relatively new to javascript, ES2015, etc.
I have a gulp task to run gulp-babel over my Aurelia application. Everything runs and works, except the files containing decorators (Aurelia's #inject)
those files spit out the same error in gulp-notify:
Error: (path-to-file)/nav-bar.js: Property right of AssignmentExpression expected node to be of a type ["Expression"] but instead got "Decorator"
I'm not really sure how to begin resolving this. My task looks like:
gulp.task('build-system', function () {
return gulp.src(paths.source)
.pipe(plumber({errorHandler: notify.onError("Error: <%= error.message %>")}))
.pipe(changed(paths.output, {extension: '.js'}))
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(babel(compilerOptions))
.pipe(sourcemaps.write({includeContent: true}))
.pipe(gulp.dest(paths.output));
});
and my compilerOptions:
module.exports = {
moduleIds: false,
comments: false,
compact: false,
presets: ['es2015'],
plugins: ['syntax-decorators', 'transform-decorators']
};
any insight would be greatly appreciated!
I believe this is a babel v6 issue. (which is implied by your presets: ['es2015'])
If you drop back to babel v5.x (as included with the skeleton) it should work.
Here's the decorator issue in the Babel Phabricator instance. It may be some time before it's fixed based on this reply.

Passing karma configuration object from gulpfile

I have a karma.conf.js file that exports a function that takes a config object and applies a bunch of configurations to that object.
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['jasmine'],
...
If I start karma from the command line like this: karma start, it runs correctly. Clearly the karma start function is inserting the required config object when it calls the function exported by karma.conf.js.
I am trying to start it with a gulp task that looks like this:
gulp.task('test', function (done) {
var karma = require('karma').server;
var karmaConf = require('./karma.conf.js')();
karma.start(karmaConf, done);
});
This gives me an error because the config parameter is missing.
Two questions:
How can I get the karma config object to include as a parameter, and
Is there a better way to do this?
try this:
gulp.task('test', function(done) {
var Server = require('karma').Server;
new Server({
configFile: __dirname + '/karma.conf.js',
singleRun: true
}, done).start();
});
I am aware this question is a little old, but I found it when I was about to post my own q/a to something similar. The main difference being that I'm not working with gulp, but am just using Karma's public API directly. I'm still stuck using Karma v0.12, but it doesn't look like the spec has changed in this regard. It still requires an ordinary object, and my config file exports a function, just like in the OP's situation.
The main problem with the sample in the question is it tries calling the config function without providing any arguments. That is probably what is throwing the error. In particular, the config function expects a single input config, and calls config.set(actualConfigObject). What I did was write a function of my own that provides a minimally suitable object.
All that is needed is to ensure that what is passed in to the config function has a set function that in some way captures its first argument for later use. I actually ended up wrapping all that in a function that returns the argument for convenience:
function extractConfig(configFunction) {
var last;
var shell = {
set: function (input) { last = input; }
};
configFunction(shell);
return last;
}
Then I can call this with my required config file:
var config = extractConfig(require('./local-karma.conf.js'));
Which got my tests running. I have noticed that something is slightly off, since I override the logging level in my config, but the API seems to be using config.LOG_DEBUG regardless. But that's the only problem I've had so far. Though this unanswered question seems to also be doing something similar, but with less successful results.