Minifying Angular not updating templates? - javascript

Fairly new to developing in angular so please bear with me.
I happen to be developing components for AEM 6.2 using angular using gulp to minify the js for all the components by doing the following in the gulpfile:
var uglify = require('gulp-uglify');
var pump = require('pump');
var gp_concat = require('gulp-concat');
var gp_rename = require('gulp-rename');
var gp_ignore = require('gulp-ignore');
var gp_htmlmin = require('gulp-htmlmin');
var templates = require('gulp-angular-templatecache');
var paths = require('../paths');
var utils = require('../utils');
var base = [
paths.APP,
paths.ETC,
paths.DESIGN
];
gulp.task('minify', function () {
var filesToInclude = ['**/app/components/**/*.js '];
var excludeCondition = '**/*.spec*.js'
return gulp.src(filesToInclude)
.pipe(gp_ignore.exclude(excludeCondition))
.pipe(gp_concat('all.concat.js'))
.pipe(gulp.dest('dist'))
.pipe(gp_rename('all.min.js'))
.pipe(plugins.ngAnnotate())
.pipe(uglify())
.pipe(gulp.dest('dist'));
});
Now the minification of the js works perfect. However, in the templates (i.e. the html for each component), the references to the controller aren't using the minified name. For example, instead of the minified controller name, it's still using the original controller name:
<section data-ng-controller="MyController as mc" ng-cloak>
<div class="mc-name">
Hi, {{mc.userName}}
</div>
</section>
Again, I'm fairly new to angular so I'm not sure how the templates and controllers are linked in such a way that the minification knows to update all references. Could someone help shed some light on what I'm missing? Thanks!

I had a similar issue a little while back in AEM6.1 and from memory it was related to competing versions of minification IE: YUI Compressor. I'm stretching my memory, but I believe the 6.1 version of YUI Compressor was seriously outdated. I recall it being updated in 6.2, but I would still suspect it may be competing with your angular minification, probably ^latest. Essentially, you are trying to minify twice, again probably with different versions of YUI Compressor.
Now you could turn off minification in AEM, and simply run with the Angular minification (in theory), but I wouldn't suggest doing that as it would mean any AEM clientLibs are not minified.
Alternatively, don't minify with angular compiler, allow AEM to do the minification for you. Which I think is what I did at the time. Although I recall getting a hotfix through adobe daycare at some point for the same, so I can't be certain, it was a couple of years ago now.

Please try to use the controller with vm and injector syntax
`rmToolkit.controller('QuestionsCtrl', QuestionsCtrl);
QuestionsCtrl.$inject = ['$scope', '$rootScope', '$stateParams', '$state','Data_Service'];
function QuestionsCtrl($scope, $rootScope,) {
var vm = this;
}`
Hopes this syntax will resolve the minification issues

Related

ReactJS with Flux architecture generating large JS files, what is the best practice?

I've started using React with Flux architecture for full functional frontend application, and I really liked approach JSX and Flux , but the main issue is that when I'm building JSX files using Gulp, Babel and Uglyfy I'm getting about 1mb minified JS file, without minified mode it is giving almost 8mb of JS file.
And that's not the end !! for making AJAX requests React don't have built in functionality, so I need also include jQuery
I's working well, development process is faster and code is nicer than with other frameworks thanks to JSX. But how to make production files smaller ?
I'm including just a few libs Dispatcher and EventEmmiter for Flux architecture. So it's not about having unused libs in my code. I think it is because I'm writing JSX and now I have HTML+JS in one single file.
What is the best practice to split files or make JS output more smaller ?
Thanks !
There are some steps to reduce production size:
Use production version of ReactJS, which includes extra performance optimizations and strips all error messages.
You don't have to include the whole jQuery library to just use Ajax, I suggest use other lightweight library for handling ajax only e.g. reqwest or superagent.
When build for production, separate to two js files (or more), usually we will have one file called vendor.js for all libraries and app.js for just the code we made. This will leverage cache on browser as vendor.js won't change much each built.
I saw that there is a little information about using React for different pages, so I learned a lot from Gulp documentation and I found a lot of very small JS libraries MicroJS which could replace Dispatcher and EventEmmiter with just a 4-6 KB in size of course you need to do some manual work with them, but they saving about 20 times in JS file size.
Here is my Gulp file for generating minified react bundle for each page. I'm using Django for backend.
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var htmlreplace = require('gulp-html-replace');
var source = require('vinyl-source-stream');
var browserify = require('gulp-browserify');
var reactify = require('reactify');
var babelify = require('babelify');
var streamify = require('gulp-streamify');
var fs = require("fs");
var rename = require("gulp-rename");
var path = {
APP_DIR: './apps/*.jsx',
OUT_DIR: './../static/apps',
};
process.env.NODE_ENV = 'development';
gulp.task('jsx', function() {
return gulp.src([path.APP_DIR])
.pipe(browserify({
insertGlobals : true,
debug : true,
transform: [reactify, babelify.configure({
presets: ["es2015", "react"]
})],
}))
.pipe(rename({
extname: ".min.js"
}))
.pipe(gulp.dest(path.OUT_DIR));
});
gulp.task('jsx_min', function() {
return gulp.src([path.APP_DIR])
.on('error', function (error) {
console.log(error);
})
.pipe(browserify({
insertGlobals : true,
debug : false,
transform: [reactify, babelify.configure({
presets: ["es2015", "react"]
})],
}))
.pipe(streamify(uglify().on('error', function (e) {
console.log(e);
})))
.pipe(rename({
extname: ".min.js"
}))
.pipe(gulp.dest(path.OUT_DIR));
});
gulp.task('build', ['jsx_min']);
gulp.task('default', ['jsx'], function () {
return gulp.watch([path.APP_DIR], ['jsx', function () {
var current_date = new Date();
var time = current_date.getHours() + ":" + current_date.getMinutes() + ":" + current_date.getSeconds();
console.log(time, " -> Rebuilding");
}]);
});
Now for each logical page I got about 40KB minified JS file for handling all JavaScript including AJAX functionality.
So I'm marking my question answered :)
Thanks for help.

Gulp starter kit with gulp-load-plugins

I have a gulp starter kit for my project, however, I want to use gulp-load-plugins to for devDependencies of package.json file. My file structure is
ProjectName
Gulp
-Tasks
-broswerify.js
-browserSync.js
-jade.js
-lint.js
Gulpfile.js
config.json
package.json
Gulpfile.js
var requireDir = require('require-dir');
var dir = requireDir('./gulp/tasks', {recurse: true});
jade.js (Which is working as expected using gulp-load-plugins)
var gulp = require('gulp');
var config = require('../../config.json');
var plugins = require('gulp-load-plugins')();
gulp.task('jade', function(){
return gulp.src(config.jade.src)
.pipe(plugins.jade())
.pipe(gulp.dest(config.jade.build))
});
browsersync.js (which is not working using gulp-load-plugins)
var gulp = require('gulp');
var config = require('../../config.json').browsersync;
var plugins = require('browsersync'); // works
//var plugins = require('gulp-load-plugins')(); // it doesn't works.
gulp.task('browsersync', function () {
plugins.browserSync.init(config); // (browsersync required)
//plugins.browserSync.init(config) it doesn't work. (gulp-load-plugins required)
});
I would like to know that if there is a better way to do that?
Why would you wan't to use gulp-load-plugins if you have a seperate file for each plugin?
This is how i load gulp-load-plugins :
$ = require('gulp-load-plugins')({
pattern: ['gulp-*', 'gulp.*'],
replaceString: /\bgulp[\-.]/,
lazy: true,
camelize: true
}),
Here is an example of a revision plugin:
// revision styles
gulp.task('rev-styles', function () {
return gulp.src(dev.css)
.pipe($.rev())
.pipe($.cssmin())
.pipe(gulp.dest(dist.css))
.pipe($.filesize())
.pipe($.rev.manifest({merge: true}))
.pipe(gulp.dest('./'))
//rev replace
.on('end', function() {
return gulp.src(['./rev-manifest.json', 'dist/*.html'])
.pipe($.revCollector({
replaceReved: true,
dirReplacements: {
'css': 'css'
}
}))
.pipe(gulp.dest(dist.dist))
});
});
As you can see all my pipes are called .pipe($.pluginName()) meaning $ stands for gulp- . If you have a plugin named gulp-name-secondname you call it like this: .pipe($.nameSecondname()) . Top were i require gulp-load-plugins i have camelize set to true . Lazy loading loads only the plugins you use not all of them .
As a side note i strongly recommend not separating plugins in diffrent files but you can modulate them, meaning separating important tasks in separate files like compilation file , optimization file , build file, etc .
This might help you understand gulp file separation better http://macr.ae/article/splitting-gulpfile-multiple-files.html
Careful with gulp-load-plugins because it slows your tasks , for example i run gulp-webserver , when i use it with gulp-load-plugins the task finishes after 200ms versus 20ms if i use it normally. So don't use with everything, play with it see how much performance you lose on each task and prioritize.
I have used gulp-load-plugins but found that it mainly adds complexity and obscures my code. At also makes it harder to understand for people less familiar with Gulp. It looks cleaner and easier to understand to have all modules explicitly declared at the top.

AngularJS + RequireJS Module Definitions

I've got a fairly large project that uses both RequireJS and AngularJS. Everything works fine but looking at my code its kind of a mess with module definitions. For example here is the 'main' app file:
define(['angular',
'jquery',
'ui-router',
'angular-restmod',
'angular-cookies',
'angular-animate',
'angular-sanitize',
'angular-touch',
'angular-moment',
'angular-ui-select2',
'bower_components/jquery-ui/ui/resizable',
'bower_components/jquery-ui/ui/draggable',
'bower_components/jquery-ui/ui/sortable',
'bower_components/jquery-ui/ui/droppable',
'angularui',
'angular-hotkeys',
'splitter',
'angular-loading-bar',
'common/components/chart/chart',
'common/utils/confirmLeave',
'common/utils/listener',
'common/components/toolbar/toolbar',
'common/components/anchor/anchor',
'common/utils/print',
'common/components/notifications/notifications',
'angular-shims-placeholder'], function (angular, $) {
var app = angular.module('myapp', ['restmod', 'ngCookies', 'ui.router', 'oc.lazyLoad', 'ngAnimate', 'ngSanitize', 'angularMoment',
'ui.bootstrap', ui.select2', 'utils.listener', 'ng.shims.placeholder', 'interceptors.exceptions', 'interceptors.security', 'cfp.hotkeys', 'utils.offline', 'components.notifications', 'angular-loading-bar']);
return module;
});
if you notice I define both the the amd module and the angular module twice. Its pretty nasty looking ( even though it does work fine ).
My question is has anyone found a better approach for this? I've seen this ngDefine project but I have my reservations about it.
I ended up writing my own little utility to handle this...
define(['angular'], function(angular){
angular.defineModule = function dm(name, modules){
var pargs = dm.caller.arguments;
var filtered = Array.slice(pargs)
.filter(function (m) { return m && m.name; })
.map(function (mm) { return mm.name; });
modules && (filtered = filtered.concat(modules));
return angular.module(name, filtered);
};
});
then you can use it like:
define(['angular',
'core',
'common/services/users',
'common/services/account',
'common/components/toolbar/toolbar',
'common/components/multi-select/multi-select',
'./change-avatar',
'./change-password',
'less!app/admin/users/detail/detail'], function (angular) {
var module = angular.defineModule('admin.users.detail');
// fun code here //
return module;
});
the caveat is all your require modules have to return the angular module at the end. If they don't, then I created a 'shim' technique where you can pass it in manually like:
var module = angular.defineModule('admin.roles.settings', ['textAngular']);
Interested to get others feedback...
You're not loading the modules twice; you are loading the modules once so that it can be found when you declare your application-module's dependencies. As AMD module you depend on them the first time at which time they are physically loaded and as AngularJS module you depend on them but that's only possible when they are already visible.
What we do to cut away some of this boilerplate code is have a generic core.js AMD module which loads all the libraries we are going to need always anyway (jquery, plugins, angular etc.). Then our main app file would simply depend on the core module.
You can take this further, by defining an AngularJS 'core' module as well. Then all you need is:
define(['core'], function (angular, $) {
return angular.module('myapp', ['core']);
});
You moved it out, but also made it reusable over multiple modules for both RequireJS and AngularJS.
Regarding ngDefine, it seems like syntactical sugar. Considering mixing AngularJS with RequireJS already provides the necessary learning curve, alienating the syntax more while not gaining a significant advantage seems like a choice you can skip. Ask yourself: "Our current approach is ugly, but do I do this a lot? Is it a real problem worth another library and a new way of defining angular apps?". Probably not!

How to add a broccoli plugin to ember-cli app with live-reload?

When I run ember build, the broccoli plugin runs correctly,
and outputs the sprite CSS file and sprite PNG file into the assets directory.
When I run ember serve, the same thing happens initially too.
However, when I save any file, causing Broccoli to rebuild its tree,
the sprite CSS and PNG files are no longer merged into the main app tree,
and when the page refreshes from live-reload the page no longer displays the sprited images.
Why does this happen?
How do I ensure that the outputs from my plugin get merged every time?
Details:
After asking this question,
and getting no responses despite putting a bounty on it,
I decided to write my own broccoli plugin for CSS image sprite generation:
broccoli-sprite
What I have tried so far:
#1
I am merging the output from my plugin with that of the main app using this in Brocfile.js
var app = new EmberApp(/* ... */);
/* other ember-cli init for app */
var broccoliSprite = require('broccoli-sprite');
var spritesTree = broccoliSprite(/* ... */);
var appTree = app.toTree();
var broccoliMergeTrees = require('broccoli-merge-trees');
module.exports = broccoliMergeTrees([spritesTree, appTree]);
I understand that this might not be the way to go, and I am fairly new to both ember-cli and broccoli, so pardon the newbie error, if this is one.
#2
In Brocfile.js, extend EmberApp to include a new tree for sprites:
var EmberApp = require('ember-cli/lib/broccoli/ember-app');
var broccoliSprite = require('broccoli-sprite');
EmberApp.prototype.sprites = function() {
console.log('EmberApp.prototype.sprites');
var spritesTree = broccoliSprite('public', this.options.sprite);
return spritesTree;
};
var originalEmberAppToArray = EmberApp.prototype.toArray;
EmberApp.prototype.toArray = function() {
var sourceTrees = originalEmberAppToArray.apply(this, arguments);
sourceTrees.push(this.sprites());
return sourceTrees;
};
The next release of Ember CLI will have first class support for add-ons. Thanks to Robert Jackson.
Take a look at https://github.com/rjackson/ember-cli-esnext to get an idea of how to package up broccoli-sprite for Ember CLI.
I look forward to using it in future apps :)

gulp-filter not filtering out excluded files correctly

I'm experimenting with using gulpjs instead of grunt for a project. I'm attempting to use gulp filter to ignore vendor libraries when running jsHint on my code. I've based my code off of the code from the readme's example, but the files have not been filtered.
I'm running node 0.10.26, gulp 3.8.0,and gulp filter 0.4.1
I'm trying to run jshint on a directory wcui/app/js that contains many other directories of JS files, with about 120 js files total. I want to exclude the vendor directory only.
My code looks like this:
var gulp = require('gulp');
var gulpFilter = require('gulp-filter');
var jshint = require('gulp-jshint');
var srcs = {
scripts: ['wcui/app/js/**/*.js'],
styles: ['wcui/app/css/**/*.less','wcui/app/css/**/*.css']
};
var dests = {
scripts: 'wcui/static/js/',
styles: 'wcui/static/css/'
};
gulp.task('scripts', function() {
var filter = gulpFilter('!wcui/app/js/vendor');
return gulp.src(srcs.scripts)
.pipe(filter)
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish'))
.pipe(filter.restore)
.pipe(gulp.dest(dests.scripts));
});
gulp.task('styles', function() {
return gulp.src(srcs.styles)
.pipe(gulp.dest(dests.styles));
});
gulp.task('dev',['scripts','styles']);
Right now running gulp dev does the same thing it did before I added the filter, linting every js file. How can I change this to make it filter correctly? The gulp example had the src in the format 'wcui/app/js/*.js' but when I admit the ** glob, I don't get subdirectories at all. Other than that I think I'm following the readme to the letter (with changes for my particular task).
For readers that have a more up-to-date version of gulp-filter (release at the time of writing is 1.0.0)
The release of version 0.5.0 of gulp-filter introduced multimatch 0.3.0 which come with a breaking change.
Breaking change
Using a negate ! as the first pattern no longer matches anything.
Workaround: ['*', '!cake']
Basically, what it means is you need to replace
var filter = gulpFilter('!wcui/app/js/vendor');
with
var filter = gulpFilter(['*', '!wcui/app/js/vendor']);
and you are good to go.
Also, as noted in the comment by MildlySerious, you should have .pipe(filter.restore()) instead of .pipe(filter.restore)
Use filter like this gulpFilter(['*', '!app/vendor'])

Categories

Resources