I have a Vue.js Application with the following excerpt of code:
(function() {
initApp();
})();
function initApp() {
window.myApp = new Vue({
el: '#wrapper',
data() {
return {
somedata: []
}
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
When I try to minify it, it fails with the error Error : Unexpected token: punc (() but the application runs successfully. I'm not sure why?
Those compressors simply only support an old version of JavaScript. Their support is restricted to at most ES5. To make your code work, convert it:
(function() {
initApp();
})();
function initApp() {
window.myApp = new Vue({
el: '#wrapper',
data: function() { // changed this line
return {
somedata: []
}
}
});
}
And it should compress.
Details:
They use uglify-js: "^3.3.10", that is known for not supporting ES6(uglify-es does) .
From their repo (emphasis mine):
UglifyJS 3
UglifyJS is a JavaScript parser, minifier, compressor and beautifier
toolkit.
Note:
(...)
uglify-js only supports JavaScript (ECMAScript 5).
To minify ECMAScript 2015 or above, transpile using tools like Babel.
Your compressor isn’t ES6 compliant
You’re getting that error because, like pacdcjunior's said, your compressor isn’t ES6 compliant. (I got your same error when I switched from jQuery to Vue.js—using ES6 syntax.)
Solution: Use Terser instead.
It’s ES6 compliant, in active development (at the time of writing), and is a direct replacement for Uglifyjs.
Bonus: How to minify lots of files in one pass with Terser
You can minify a single file in Terser from the command line like this:
$ terser file.js -m -o file.min.js
But if you have a load of files to minify in one go, that will be tedious. I found this excellent answer and modified it just a little. Add this to your .bash_profile:
alias renderjs='rm *.min.js; for f in *.js; do short=${f%.js}; terser $f -m -o $short.min.js; done'
Navigate to your js directory and run renderjs. Now all your *.js files have a minified version. Nice!
Do you mean the compiled js file (app.js)? If that case you just compile for production "npm run production".
Related
I've downloaded the most recent version of compiler and i've tried to optimize js code with these flags:
java -jar closure-compiler-v20211006.jar -W VERBOSE -O WHITESPACE_ONLY
--language_out ECMASCRIPT5 $script_path_in --js_output_file $script_path_tmp
closure compiler has optimized this lines of code:
for(var extraProperty of extraProperties){
option.setAttribute(extraProperty,initialOption[extraProperty]);
}
into
for (var $jscomp$iter$0 = $jscomp.makeIterator(extraProperties), $jscomp$key$extraProperty = $jscomp$iter$0.next(); !$jscomp$key$extraProperty.done; $jscomp$key$extraProperty = $jscomp$iter$0.next()) {
var extraProperty = $jscomp$key$extraProperty.value;
{
option.setAttribute(extraProperty, initialOption[extraProperty])
}
}
And as a result i receive such error in browser:
all_compressed.js Uncaught ReferenceError: $jscomp is not defined
Is there a way to change language spec with this compiler without adding side dependencies into the project, or maybe it's a bug?
Git bug tracker
The best option for white space only mode is to set the language out to the latest ECMASCRIPT version used by the source code (or later) to avoid runtime dependencies.
I am writing in Javascript using classes. Example:
'use strict';
class MyClassName
{
myGame;
constructor(game)
{
this.myGame = game;
}
startGame()
{
this.startActions();
}
startActions()
{
//
}
}
When i try to compress it in PhpStorm by using Assets Compressor, i get error:
[ERROR] 3:6:identifier is a reserved word
How i can make correct compressing my code in PhpStorm? Are there any ways to compress JS code that uses classes?
Assets Compressor plugin only supports ECMAScript 2015, it will throw errors on new syntax.
Please try following the instructions from https://www.jetbrains.com/help/idea/minifying-javascript.html: install either UglifyJS or the Closure Compiler and set it up as a file watcher to run from the IDE
I have a TypeScript library that I've created. I need to know how to import and use this library in a browser. First, I am using tsc v2.1.4; I am also using gulp's TypeScript plugins to help with the development process. I have a gulp task that compiles my *.ts files to *.js files as follows.
gulp.task('dist', function() {
var tsResult =
gulp.src(['src/**/*.ts'])
.pipe(sourcemaps.init())
.pipe(tsc({ out: 'mylib.js', noImplicitAny: true, target: 'es6', sourceMap: true, module: 'system' }));
return tsResult.js
.pipe(sourcemaps.write())
.pipe(gulp.dest('dist'));
});
The generated mylib.js file looks something like the following.
System.register("vehicle/car",[], function(exports_1, context_1) {
"use strict";
var __moduleName = context_1 && context_1.id;
var Car;
return {
execute: function() {
Car = class Car {
constructor(make, model) {
this.make = make;
this.model = model;
}
};
exports_1("Car", Car);
};
});
I then attempt to follow the documentation on SystemJS and create a index.html to test usage.
<html>
<head>
<title>Test MyLib</title>
</head>
<body onload="start()">
<script src="node_modules/systemjs/dist/system.js"></script>
<script>
function start() {
SystemJS.import('dist/mylib.js')
.then(function(lib) {
console.log(lib);
//what do i do here? how do i use my classes/objects here?
});
}
</script>
</body>
</html>
Looking at the JavaScript console, I see no errors. Where I log the lib out, it is just an Object with a bunch of functions that I'm not sure how to use to instantiate the classes/objects from my library.
I'm continuing to read more on how this TypeScript to ES6 to ES5 stuff works. Apparently, even though I've generated a JavaScript file (e.g. mylib.js) I just can't simply reference it like
<script src="dist/mylib.js"></script>"
and then use it. I have to go through SystemJS (which I'm new to and is a part of the confusion). Apparently, it seems like I can just reference my *.ts files directly and use other plugins (babel) with SystemJS to transpile on the fly. It doesn't help that the documentation on babel systemjs plugin is out of date (the usage instructions is out of date it seems).
The SystemJS usage instructions are a bit confusing too. In some cases I see SystemJS.config({...}) and in some cases I see System.config({...}). I'm speculating they changed SystemJS from System, but I'm really not sure.
I'd appreciate clarification on how to go from a TypeScript library project all the way browser usage; any online examples or guidance on here is appreciated (and I'm continuing to search as well).
I have a Typescript+Node+Angular2+Electron app and currently trying to run tests for node classes, written also in Typescript.
For building the application and running it within electron I use following tsconfig:
"compilerOptions": {
"module": "system",
"target": "es6",
...
}
So as you can see, it's using systemjs and compiling TS into JS-es6. It works fine, application itself is working.
Now I need Jasmine to come on board. I installed this npm package, updated my gulp tasks to run gulp-jasmine for just 1 file:
gulp.task('jasmine', function() {
gulp.src('./test/test.js')
.pipe(jasmine())
});
This is how my test.js looks like:
System.register(["./models-src/app/models/pathWatch/pathWatch"], function(exports_1, context_1) {
"use strict";
var __moduleName = context_1 && context_1.id;
var pathWatch_1;
return {
setters:[
function (pathWatch_1_1) {
pathWatch_1 = pathWatch_1_1;
}],
execute: function() {
describe("Run Application:", () => {
it("starts", () => {
var pw1 = new pathWatch_1.PathWatch();
expect(true).toEqual(true);
});
});
}
}
});
So, nothing special, 1 import-1test-1assert, wrapped with SystemJs stuff.
When I try to run this test, I have an error: "System is not defined".
My questions are:
1) Is it possible to run jasmine tests, using systemjs loader inside?
2) If it's possible, do I need to install/configure some additional stuff?
3) I tried to compile TS using Module="commonjs" and it's working. But I don't want to compile my source differently for tests and build. Why it's working fine with commonjs without any additional manipulations?
4) Also I tried to compile TS using Module="es6". It's not working, I have an error "Unexpected reserved word". Is it possible to run jasmine tests written in js es6 without transpiling them into es5?
Thanks a lot!
1) Is it possible to run jasmine tests, using systemjs loader inside?
2) If it's possible, do I need to install/configure some additional
stuff?
You mean, run jasmine tests in node using systemjs as a loader? I don't think jasmine supports using systemjs instead of require for loading modules. So your tests need to be in commonjs, but test code can use SystemJS to load and test application code. Something like this in test.js could work, provided that systemjs is configured properly and can find pathWatch module:
describe("Run Application:", () => {
it("starts", (done) => {
var system = require('systemjs');
system.config({
// systemjs config here
//
});
system.import('path-to-path-watch-module').then(pathWatch => {
var pw = new pathWatch.PathWatch();
expect(true).toEqual(true);
done();
});
});
});
system.import is asynchronous, so all jasmine tests need to be async too.
3) I tried to compile TS using Module="commonjs" and it's working. But
I don't want to compile my source differently for tests and build. Why
it's working fine with commonjs without any additional manipulations?
Because then there is no reference to System in the compiled code - it uses module.exports like any other node module and can be loaded as is by jasmine.
4) Also I tried to compile TS using Module="es6". It's not working, I
have an error "Unexpected reserved word". Is it possible to run
jasmine tests written in js es6 without transpiling them into es5?
Module="es6" requires a runtime that supports es6 import and export, so it needs a transpiler and module loader before it can run on current version of node.
I have an existing application where I have AMD modules defined using RequireJS. I use "text" and "i18n" plugins for requirejs extensively in my project.
I have been experimenting with ES6 modules lately and would like to use them while creating new modules in my application. However, I want to reuse the existing AMD modules and import them while defining my ES6 modules.
Is this even possible? I know Traceur and Babel can create AMD modules from ES6 modules, but that only works for new modules with no dependency on existing AMD modules, but I could not find an example of reusing the existing AMD modules.
Any help will be appreciated. This is a blocker for me right now to start using all ES6 goodies.
Thanks
Yes, it can be done. Create a new application with the following structure:
gulpfile.js
index.html
js/foo.js
js/main.es6
node_modules
Install gulp and gulp-babel. (I prefer to install gulp locally but you may want it globally: that's up to you.)
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Something</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.20/require.js"></script>
<script>
require.config({
baseUrl: "js",
deps: ["main"]
});
</script>
</head>
<body>
</body>
</html>
gulpfile.js:
"use strict";
var gulp = require('gulp');
var babel = require('gulp-babel');
gulp.task("copy", function () {
return gulp.src(["./js/**/*.js", "./index.html"], { base: '.' })
.pipe(gulp.dest("build"));
});
gulp.task("compile-es6", function () {
return gulp.src("js/**/*.es6")
.pipe(babel({"modules": "amd"}))
.pipe(gulp.dest("build/js"));
});
gulp.task("default", ["copy", "compile-es6"]);
js/foo.js:
define(function () {
return {
"foo": "the value of the foo field on module foo."
};
});
js/main.es6:
import foo from "foo";
console.log("in main: ", foo.foo);
After you've run gulp to build the application, open the file build/index.html in your browser. You'll see on the console:
in main: the value of the foo field on module foo.
The ES6 module main was able to load the AMD module foo and use the exported value. It would also be possible to have a native-AMD module load an ES6 module that has been converted to AMD. Once Babel has done its work, they are all AMD modules as far as an AMD loader is concerned.
In addition to #Louis's answer, assuming you already have a bunch of third party libraries specified in require.js configuration, in your new ES6 modules, whenever you are importing a module, be it amd or es6, you'll be fine as long as you keep the imported module name consistent. For example:
Here is the gulpfile:
gulp.task("es6", function () {
return gulp.src("modules/newFolder//es6/*.js")
.pipe(babel({
"presets": ["es2015"],
"plugins": ["transform-es2015-modules-amd"]
// don't forget to install this plugin
}))
.pipe(gulp.dest("modules/newFolder/build"));
});
Here is the es6 file:
import d3 from 'd3';
import myFunc from 'modules/newFolder/es6module'
// ...
This will be compiled to sth like this:
define(['d3', 'modules/newFolder/es6module'], function (_d, _myFunc) {
'use strict';
// ...
});
as long as the module in define(['d3', 'modules/newFolder/es6module'], ... of the compiled file is fine in a original AMD file, it should work with under existing require.js setup, such as compress files etc.
In terms of #coderC's question about require.js loaders, I was using i18n!nls/lang in AMD modules, at first I thought it would be a really tricky thing to find an alternative of AMD plugin loaders in ES6 modules, and I switched to other localization tools such as i18next. But it turned out that it's okay to do this:
import lang from 'i18n!nls/lang';
// import other modules..
because it will be compiled by gulp task to sth like:
define(['d3', 'i18n!nls/lang'], function (_d, _lang) {
// ....
This way, we don't have to worry about the require.js loader.
In a nutshell, in ES6 modules, if you want to use existing AMD plugin/modules, you just need to ensure the compiled file is conformed with the existing setup. Additionally, you can also try the ES6 module bundler Rollup to bundle all the new ES6 files.
Hope this can be helpful for those who are trying to integrate ES6 syntax in project.
A few changes for the latest version of babel:
First, babel({"modules": "amd"}) doesn't work with the latest version of babel. Instead, use babel({"plugins": ["#babel/plugin-transform-modules-amd"]}). (You'll need to install that plugin as a separate module in npm, i.e. with npm install --save-dev #babel/plugin-transform-modules-amd.)
Second, the syntax for gulp.task no longer accepts arrays as its second argument. Instead, use gulp.parallel or gulp.series to create a compound task.
Your gulpfile will end up looking like this:
"use strict";
var gulp = require('gulp');
var babel = require('gulp-babel');
gulp.task("copy", function () {
return gulp.src(["./js/**/*.js", "./index.html"], { base: '.' })
.pipe(gulp.dest("build"));
});
gulp.task("compile-es6", function () {
return gulp.src("js/**/*.es6")
.pipe(babel({"plugins": ["#babel/plugin-transform-modules-amd"]}))
.pipe(gulp.dest("build/js"));
});
gulp.task("default", gulp.parallel("copy", "compile-es6"));