How can I minify an ExtJs 5 project without Sencha? - javascript

I have been researching the ability to minify an ExtJS application without Sencha and the closest I have come to is this link:
Is there a way to minify an ExtJS application without Sencha CMD?
However, I am not sure how to execute the file in one of the later comments. I am using the minify-maven-plugin with com.samaxes.maven and the CLOSURE engine. I was able to generate the minified js file of the entire project but I get errors when I try to load the web page.
I was able to verify the web page was calling the correct file. I received the error "TypeError: q is undefined"...not helpful at all. Without the minified file, the web application runs perfectly. So, the generated minified file must have something wrong with it.
The suggestion at the bottom of the link above indicates the sequence of files that I should include but I have no idea how to actually implement this. Also, there are probably over a hundred javascript files that need to be minified so I would rather not have to type each file in the jsb file.
Are there any suggestions on how to minify my entire project at build time with maven?

I'm using Grunt to build the project, but it doesn't really matter as all you need is to combine files, so maven should be more than capable.
I wanted my dev version to still rely on Extjs dynamic class loader so I don't have to rebuild the project whenever I modify one file, and only production version to be minified into a single file. There were a few pitfalls before I got it working, here is what I ended up with. Also this is for ExtJS6, but it probably still should be the same.
It is all controlled by backend variable dev, which when set to false will use minified sources.
index.html (I'm using some meta templating language as example)
<html>
<head>
{{if dev}}
<script src="/ext/ext-all-debug.js"></script>
{{else}}
<script src="/ext/ext-all.js"></script>
{{/if}}
<script>
var dev = {{dev}};
Ext.Loader.setConfig({enabled: dev});
</script>
{{if dev}}
<script src="/app.min.js"></script>
{{else}}
<script src="/app.js"></script>
{{/if}}
</head>
<body></body>
<html>
app files, requires directive doesn't work well when the dynamic loader is disabled, so I had to add conditions like this everywhere:
Ext.define('MyApp.view.Panel', {
extend: 'MyApp.view.GenericPanel',
requires: dev ? [
'MyApp.view.AnotherView',
] : [],
...
});
Gruntfile.js (if you need only concatenation replace uglify with concat everywhere)
module.exports = function(grunt) {
grunt.initConfig({
pkg : grunt.file.readJSON('package.json'),
uglify : {
build: {
files: {
'../app.min.js': ['../app/view/GenericPanel.js', '../app/**/*.js', '../app.js'],
}
}
},
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('default', [ 'uglify' ]);
};
grunt's project.json:
{
"name": "My App",
"version": "1.0.0",
"devDependencies": {
"grunt": "~0.4.5",
"grunt-contrib-concat": "^1.0.1",
"grunt-contrib-uglify": "^1.0.1"
}
}
The order of files matter, by default grunt will use alphabetic order. If you extend some class, the parent class has to be included higher. app.js should be at the end. Other than that it is working well in a single mixed file, so I didn't have to customize the file order further. Grunt has pretty powerful path patterns, so if you need to make sure some file is included first you just list it before other path patterns and it will be smart enough to not include it twice.
I recommend you start with simple concatenation without minification, and only if that works try minifying it. When minifying you might need to be careful with global functions and variables as they can be renamed if minifier is too aggressive. Grunt's minifier almost worked for me with the default settings, I just had to made couple small changes to my code (related to global functions).

While I am not sure why you would want this, the main thing you need is the so-called dependency tree - which tells you the order in which to include the source files.
Then you can put all the files (ExtJS source, libraries if applicable and also your own views) into one big file, in the correct order. This file should then work exactly as the 500 distinct files. (It did for me.)
That done, you can search for a working minifier. Not every minifier can minify ExtJS code, and I don't remember my last results before we finally decided to switch to Sencha Cmd, but I think Microsoft Javascript Minifier was one that worked for us.
Apart from that, minified JavaScript is really legible. You should provide the source of the error, with 200 characters before and 200 characters after the error, and I guess someone here can tell what's going on there.

Related

Building a Webpack 4 Config for SASS (Compilation, Minification in Prod), JS (Concat + Minification), and Multiple Vue Single Page Applications

Trying to setup a webpack setup for my entire resource generation workflow in our app. I don't need any hot reloading, browsersync, etc. Just needs to watch for changes, and rebuild depedent objects when changes are made. File structure looks like this:
(I apologize for the image I seriously looked up other methods to post structure, but nothing was working on the preview, I can post a fiddle-or-codepen with this output in a comment afterwards)
The only areas of note are:
1) Each folder underneath vue-spas each Single-Page Mini App (SPAs) generates it's own output file of the app.
2) All items in constructs underneath js are concat and minified into one output file (/dist/js/main.min.js) but every item underneath js/components/ just renders a minified and mangled version of that file
Lastly, I understand this is probably a difficult question to wrap around, but I have Gulp doing some of it now, and Webpack doing the Vue compilation, just trying to see if it's possible to consolidate into just webpack and let it do the work.
Thanks for any assistance.
There are a few approaches. The simplest would be to add a key for each app in the entry point configuration in your webpack.config.js file.
That would look like this in your webpack.config.js file:
module.exports = {
entry: {
app1: './vue-spa/vue-spa1/app.js',
app2: './vue-spa/vue-spa2/app.js'
// etc
}
};
This will output individual directories in your dist for each with a nicely bundled app file.
By default, if you pass in a production variable to your webpack build command it'll apply all the optimizations you're looking for. If it's lacking out-of-the-box, there's likely a loader that can handle whatever optimization you need.
For Sass, you can add sass-loader to your webpack file:
https://github.com/webpack-contrib/sass-loader
Your devServer can just watch your vue-spa directory recursively for changes.
Another approach is to use lerna -- though that would require additional configuration, and is only necessary in your situation if you're in an enterprise environment where each individual app is being shipped out to a private NPM registry, and require individual semver.

Configure karma to load test files last

I'm following John Papa's Style Guide and am having problems getting all of my Jasmine specs to load after everything else. The problem is that the directory structure of my app is flat, and thus the spec files are included in the same directory as the files they are testing.
files: [
'app/vendor/js/jquery.js',
'app/vendor/js/angular.js',
'app/vendor/js/*.js',
'bower_components/angular-mocks/angular-mocks.js',
'app/app.js',
'app/app.constants.js',
'app/app.config.js',
'app/**/*.app.js',
'app/**/*.js',
'app/**/*.spec.js',
'app/**/*.html'
]
The other problem is that in the Karma configuration file, it's including all of the .spec.js files in with the plain old .js files. So the second to last string in the above array is redundant, but it's there to illustrate what I am trying to do.
How do I get my spec files to load after all of the other JavaScript files?
EDIT: By following JP's style guide, your files should be named with a chaining syntax: the.directive.js, the.directive.spec.js. So, you can solve my problem by just including all all directives (.directive.js), controllers (.controller.js), etc. before the specs instead of using the universal .js. However, I want to see if someone comes up with a more robust solution.
Try with
files: [
'app/**/!(*spec).js',
'app/**/*spec.js',
...
]

Visual Studio 2015 compiles ALL typescript files when SINGLE file is changed

I am using Visual Studio 2015 with Typescript 1.5.4 and Resharper 9
This is the buggy scenario:
I have about 180 typescript files
I change single .ts file
VS shows message "Generation of XXX.ts file complete. Remaining files still compiling"
after that ALL my .ts files are compiled to .js
2 things were changed in those .js files: formatting is slightly different and reference for .js.map was removed
When I build the whole project, then the .js files are generated again but with original formatting and with link to .js.map present
This is annoying because it generates too much noise in Git
and it prevents me from debugging typescript files directly in browser. (because of that missing .js.map file)
The desired behaviour is of course that the only changed .ts file should be compiled on save. How to do it?
It seems that R# has nothing to do with this, because it continues to happen with R# disabled.
My current project settings:
-------------UPDATE-------------
I've tried to update to Typescript version 1.6.
The PATH variable pointed to C:\Program Files (x86)\Microsoft SDKs\TypeScript\1.4\ so I've updated that to point to 1.6
So when I now type tsc -v it says message TS6029: Version 1.6.2
But because of historical reasons (the project I work on is about 2 years old) I have to use version 1.4 inside VisualStudio. So in the .csproj is <TypeScriptToolsVersion>1.4</TypeScriptToolsVersion>
After this change the compile on safe stopped working completely.
Now I have to rebuild the whole solution :(
It seems that Visual Studio does not support watch mode properly (i.e. incremental compilation):
Just to be clear, --watch does work on Windows if you're using
node.js/io.js, but the tsc.exe program distributed with VS does not
support it; you still have Compile on Save for similar functionality
anyhow.
https://github.com/Microsoft/TypeScript/issues/2375#issuecomment-100812347
I'm not sure why this was closed. Supporting --watch for our tsc.exe
host would both be possible and desirable. Right now the limiting
factor is that our tsc.exe host is a bit of ugly C++, that uses some
ancient COM interfaces for Chakra that we haven't spent much effort
on. Our options are: [...]
https://github.com/Microsoft/TypeScript/issues/2375#issuecomment-100949019
As a workaround, could you run
tsc --watch
in the folder where tsconfig.json is located?
Edit: https://github.com/Microsoft/TypeScript/issues/5638 - Visual Studio 2015 compiles ALL typescript files when SINGLE file is changed
Starting with VS 2015 RTM, Compile-on-Save, every time you save a file
we need to generate all files in the project to ensure consistent
output. We have got numerous issues related to inconsistent output
when saving files in different orders. Building all files is the only
way we can guarantee correct and consistent output given all the
language constructs and how they interact across files (e.g.
namespaces/internal modules can be augmented, and that affects the
shape of emitted code, also const enms are in lined as constants,
etc..).
Try "ECMAScript 5" instead of "ECMAScript 3" in "ECMAScript version
I had a similar issue, but since we were handling TS compilation on our own, I wanted to avoid auto-compilation at all...
The fix was to force the TypeScriptCompileOnSaveEnabled flag to false inside the project:
<PropertyGroup>
<TypeScriptCompileOnSaveEnabled>false</TypeScriptCompileOnSaveEnabled>
</PropertyGroup>
in my case this effectively stopped VS2015 from automatically compiling the .ts files on save, without VS getting into the way every time and messing up outputs...
Another work around: You could use Gulp to generate your compiled js files and maps. With Gulp you can also create a watch task to compile at a save of a ts file. You can even create clean tasks to clean up the project.
Example of a build task:
var tsProject = ts.createProject(paths.typescriptRoot + 'tsConfig.json'); // use tsconfig.json
gulp.task("tsbuild", function () {
var tsResult = tsProject.src()
.pipe(sourcemaps.init()) // needed to create sourcemaps
.pipe(ts(tsProject)); // use tsconfig.json
return tsResult.js
.pipe(concat(paths.concatTsFileName)) // concat all output files into a sings js files
.pipe(sourcemaps.write()) // write the sourcemap to be able to debug the ts files
.pipe(gulp.dest(paths.typescriptOut)); // output the result on specific path
});
Example of a cleanup task :
gulp.task("clean:tsout", function (cb) {
rimraf(paths.typescriptOut + paths.concatTsFileName, cb); // rimraf is used to delete a folder
});
gulp.task("clean:scriptjs",
function () {
return gulp.src(paths.typescriptJs, { read: false }) // to clean up multiple files we need to use gulp-rimraf
.pipe(gulpRimraf());
});
Example of a Watch task:
gulp.task("watch:tsbuild", ['tsbuild'], function () {
gulp.watch(paths.typescriptRoot + '**/*.ts', ['tbbuild']);
});

After modularizing an AngularJS app, how do you include the entire project in the index.html without having to type a ton of <script> tags

I've been learning Angular for awhile now and am looking into the best ways to modularize the application. I think my understanding of that is going pretty well, but I've looked around for awhile and can't seem to get a good answer as to how all of these .js files get included inside of the index.html without just manually typing out a bunch of tags. I've been looking into Grunt/Gulp and get how those are combining the entire app into one .js file, but for development I'm guessing you don't want to have to re-run grunt or gulp every time you want to update the app.
There are many different options: gulp, grunt, or webpack seem to be the most popular. I tend to use webpack the most these days.
A good setup will typically run a local node server, which will refresh the browser automatically every time you make a change to a file.
There are many yeoman generators that will set this all up for you, or you can find simple examples on github.
The basic idea is to
concatenate all your js files (in proper order so the module definitions go before controllers/services)
minify if for production
copy to a fixed path
include this single js file in your html
during development have your grunt/gulp script watch for changes in js files and re-run the above steps so you don't have to run the grunt/gulp task manually.
Now if you are using gulp here is how you would typically handle above steps
gulp.task('process-js', function () {
return gulp.src(jsFiles, {base: './'})
.pipe(gulpif(isProd, concat('all.min.js'), concat('all.js')))
.pipe(gulpif(isProd, uglify({mangle: true, preserveComments: 'some'})))
.pipe(gulp.dest(deployFolder + '/static/js'))
});
where jsFiles is an array of files/folders that contain your angular app js files
var jsFiles = [
'!static/js/**/*.js',
'!static/js/plugin/**/*.*',
'app/index/**/*module.js',
'app/index/**/*config.js',
'app/index/**/*ctrl.js'
];
Note: use ! prefix to exclude certain files/folders from processing.
isProd is just a flag that indicates whether you are preparing for production or development.
During development I also use BrowserSync to watch any changes to my js files and re-run the gulp task to prepare all.js. It also refreshes the page in browser automatically.
gulp.task('run', function () {
browserSync({
server: {
baseDir: deployFolder
},
open: true,
browser: ['google chrome'],
files: deployFolder + '/**/*',
watchOptions: {
debounceDelay: 2000
}
});
gulp.watch(jsFiles, ['process-js']);
});
gulp.task('default', function () {
runSequence(
'clean',
'run'
);
});
Gulp/Grunt to concat all your angular files.
Create 2 tasks :
a dev build task
concat to one file BUT don't uglify.
a distribution/production task which is the same as dev one but this one uglify the concatenated file.

Using Flow for browser apps

I want to use Flow (the static type checker for JavaScript by Facebook) for browser apps. How do you get Flow to follow the other .js files which are being used by a given .js file? In Node.js, the use of the require function makes Flow follow other modules and check for type errors, and I want a similar functionality for browser apps too.
Say I have a Classroom.js file which uses a module Student.js. When I run Flow, it will throw the error identifier Student Unknown global name.
Facebook uses browserify to do this in their Flux Chat example. Browserify inlines the require statements in node-style JavaScript to produce code that can be run in the browser.
Here are the relevant bits of their package.json:
{
"scripts": {
"build": "NODE_ENV=production browserify . | uglifyjs -cm > js/bundle.min.js",
},
"browserify": {
"transform": [
["reactify", { "stripTypes": true }],
"envify"
]
}
}
I have run into this problem myself, just now.
As you have a single, simple dependency (Classroom --> Student, this link contains a workaround that might help in your case. http://flowtype.org/docs/third-party.html
It says, create a new directory, put an "interface file" inside (this is basically a stub. pick any name for the file), and include everything with
flow check --lib /abs/path/to/my/interfacefiledir/ Classroom.js
For more complex scenarios, like secondary dependencies, third-party-libraries (like including jQuery with its full API), I don't have a strategy.
I think the facebook-flow team has put "add more interface files" on their to-do list. http://flowtype.org/docs/coming-soon.html#_

Categories

Resources