Browserify recipe for AngularJS + source maps + minification - angularjs

I am looking for a working recipe that can minify my AngularJS code and still provide a source map. Currently I have this gulp task but minification won't work:
gulp.task('browserify', function(cb) {
var bundler = browserify({
entries: [paths.browserEntry],
globals: false,
debug: !settings.PRODUCTION
})
bundler
.bundle()
.on('error', cb)
.on('log', util.log)
.pipe(gulpif(!settings.PRODUCTION, mold.transformSourcesRelativeTo(paths.js)))
.pipe(source(paths.js))
.pipe(buffer()) // because the next steps do not support streams
.pipe(concat('bundle.js'))
.pipe(gulpif(settings.server.minify.js, rename({suffix: '.min'})))
.pipe(gulpif(settings.server.minify.js, uglify()))
.pipe(gulp.dest(paths.js))
.on('end', function() {
cb()
})
})
Any clues?

You may see an example here. The example will output a minified bundle.min.js plus a bundle.map. The crucial points which makes the example works:
Installed debowerify
Installed minifyify
package.json - added transform property
"browserify": {
"transform": [
"debowerify"
]
}
Gruntfile.js - using preBundleCB to make minifyify work
preBundleCB: function (b) {
b.plugin( minifyify,
{ output: './dist/bundle.map',
map:'bundle.map'
});
}
Hope the example is useful to you.

Related

Requirejs callback undefined on code splitting

I'm a newbie to RequireJS I have a ReactJS app with index.jsx as an entry point
// index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
export function callBackForRequirejs() {
return "testing";
}
When I load my build via RequireJS I get these callbacks
require(["/path/to/bundle"], function(callback) {
console.log(callback) // I get "callBackForRequirejs"
}, function(err){
console.log(err)
});
But when I do code splitting I'm getting undefined in the callback, for code splitting I'm using these configs
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendor",
chunks: "initial",
}
}
}
}
UPDATE:
Actually, my react app is a plugin for some external app, the external app loads my plugin via RequireJS. The code inside an external app is something like this
case 1:
require(['/pathof/my/react/plugin/bundle.js'],
function(callbackwhenpluginloads){
callbackwhenpluginloads()
})
Since the size of my bundle.js is very large so I decided to split it into two parts one which comes from node_modules and one from my code
Now the external plugin loads my react plugin something like this
case 2:
require(['/pathof/my/react/plugin/bundle.js',
'/pathof/my/react/plugin/vendor.js' ], function(callbackwhenpluginloads){
callbackwhenpluginloads() // callbackwhenpluginloads is undefined
})
I'm getting undefined callback when the external app loads my plugin in
Actually, based on RequireJS docs for starting you did the following way and it works well:
require(['/path/to/bundle.js'], function(callback) {
console.log(callback) // you get callbackForRequireJS
}, function(error) {
console.log(error)
});
And now you did a code-splitting on your project, so you should consider this the vendor.js is like a dependency to split bundle.js file. so you should follow this example to load the dependencies at the first and then run the other split code. so your code is something like below:
requirejs.config({
paths: {
reactApp: 'path/to/bundle.js'
},
deps: ['path/to/vendor.js'],
});
require(['reactApp'], function(callback) {
console.log(callback) // it should works now
}, function(error) {
console.log(error)
});
Or there is another way that I don't recommend it:
require(['path/to/vendor.js'], function() {
require(['path/to/bundle.js'], function(callback) {
console.log(callback) // it should works now
}, function(bundleError) {
console.log('bundleError', bundleError)
});
}, function(vendorError) {
console.log('vendorError', vendorError)
});
It seems, for code splitting you are using the webpack. webpack and require js don't really get along.
you should try vanilla JS instead.
<script onload="handleOnLoad()" />
Or go for a npm package.
react-load-script - npm

Gulp and wire dep not injecting file type *.*.js files

I am facing below issue -
I have Yeomen generator and wiredep to inject bower dependencies in index.html file.
I have installed angular tree view by bower then noticed that lib files and css file of angular tree view are not getting injected in index file.
After debugging for while found that the lib file of angular tree view has one extras dot (angular.treeview.js) same with the css file as well
So how to inject that file in index.html
i have below task in inject.js file in gulp folder to inject file in index.html which is generated by yoemen
gulp.task('inject', ['scripts'], function () {
var injectStyles = gulp.src([
path.join(conf.paths.src, '/app/**/*.css')
], { read: false });
var injectScripts = gulp.src([
path.join(conf.paths.src, '/app/**/*.module.js'),
path.join(conf.paths.src, '/app/**/*.js'),
path.join('!' + conf.paths.src, '/app/**/*.spec.js'),
path.join('!' + conf.paths.src, '/app/**/*.mock.js')
])
.pipe($.angularFilesort()).on('error',conf.errorHandler('AngularFilesort'));
var injectOptions = {
ignorePath: [conf.paths.src, path.join(conf.paths.tmp, '/serve')],
addRootSlash: false
};
return gulp.src(path.join(conf.paths.src, '/*.html'))
.pipe($.inject(injectStyles, injectOptions))
.pipe($.inject(injectScripts, injectOptions))
.pipe(wiredep(_.extend({}, conf.wiredep)))
.pipe(gulp.dest(path.join(conf.paths.tmp, '/serve')));
}
I am using Yeomen and gulp.
Any help would be appreciated.
It doesn't have to do anything with your gulp task.
Wiredep uses bower.json file to inject dependency in your index file.
I case of any issue, like in your current scenario you just need to override your package, like you do for bootstrap.
add below code in bower.json
"overrides": {
"bootstrap": {
"main": [
"dist/css/bootstrap.css",
"dist/fonts/glyphicons-halflings-regular.eot",
"dist/fonts/glyphicons-halflings-regular.svg",
"dist/fonts/glyphicons-halflings-regular.ttf",
"dist/fonts/glyphicons-halflings-regular.woff",
"dist/fonts/glyphicons-halflings-regular.woff2"
]
},
"angular-treeview":{
"main":[
"angular.treeview.js",
"css/angular.treeview.css"
]
}
}
I hope it will help you.
Happy coding :)

Building Typescript for Angular using Gulp

I'm trying to setup an angularjs project according to Johnpapa's Angular Style Guide whilst using TypeScript and Gulp as a build tool. I believe Gulp is currently recommended over Grunt but I'm not very experienced with Gulp.
What I have:
My project currently looks like this:
src/
+- ts/ # contains .ts source files
+- typings/ # contains .d.ts typing definitions
+- html/ # contains .html files
dist/
+- bundle.js # single .js file containing compiled typescript and sourcemaps
Following the angular style guide I have created a separate .ts file for each angular element.
my-app.module.ts
----------------
angular.module('myApp', []);
for initialization of the module and another for a simple implementation of a controller:
my-controller.controller.ts
----------------------------
export class MyController {
testString = 'test';
}
angular
.module('myApp')
.controller('MyController', MyController);
typescript is configured using a simple tsconfig.json. (Note that filesGlob is not active yet - it will become available from TypeScript 2.0)
tsconfig.json
-------------
{
"exclude" : [
"node_modules"
],
"filesGlob" : [
"./src/typings/index.d.ts",
"./src/ts/**/*.ts",
"!./node_modules/**/*.ts"
],
"compilerOptions": {
"noImplicitAny": true,
"target": "es5",
"sourceMap" : true,
"outFile" : "./dist/bundle.js",
"removeComments": false
}
}
What I want:
I would ideally like to
Have Gulp monitor new or updated .ts files in ./src/ts/**/*.ts
Concatenate all the files from ./src/ts/**/*.ts. This is required for angular to work properly. Other methods I've tried using requirejs or browserify can't find the other .ts files without having to manually input references to these files.
Compile using the definitions from tsconfig.json. This would take into consideration the typings in ./src/typings/index.d.ts (for external modules including 'angular'). Also sourcemaps.
Possibly an uglify or babelify step to finish it.
What I tried:
I've tried following the manual from the typescriptlang handbook but this uses browserify and won't work with angular.
Gulp-typescript also has a note on concatenating files but the out option doesn't work like this:
var gulp = require('gulp');
var ts = require('gulp-typescript');
var tsProject = ts.createProject('tsconfig.json');
gulp.task('default', function () {
var tsResult = tsProject.src().pipe(ts(tsProject));
return tsResult.js.pipe(gulp.dest('dist'));
});
This configuration will output an empty file with only comments.
Another method mentioned in this question:
gulp.task('ts', function () {
gulp.src('./src/ts/**/*.ts')
.pipe(ts({
noImplicitAny: true,
out: 'output.js'
}))
.pipe(gulp.dest('./tmp/ts'));
});
gulp.task('default', ['ts'], function() {
gulp.src(['./tmp/ts/output.js'])
.pipe(sourcemaps.init())
.pipe(uglify())
.pipe(sourcemaps.write('/'))
.pipe(gulp.dest('./dist/'));
});
But this gave two issues: 1. Even though I only pointed at the .ts files in ./src/ts the typescript compiler started spewing errors from .ts in ./node_modules. 2. It still didn't manage to concatenate everything.
I'm at quite a loss here. Can anyone help me set up this build script? I'm surprised I couldn't find a similar working demo anywhere.
Solution:
I've configured the gulp environment based on the solution in this answer and removed the 'export' statement for classes / objects that are not inside a typescript module.
If that helps, here is a Angular Typescript Gulp Tutorial that has a basic TypeScript, Angular, Gulp, etc. setup that concatenate the app and the vendor/nodes files. There is the demo code on github.
/* File: gulpfile.js */
// grab our gulp packages
var gulp = require('gulp');
// Include plugins
var plugins = require("gulp-load-plugins")({
pattern: ['gulp-*', 'gulp.*', 'main-bower-files', 'del'],
replaceString: /\bgulp[\-.]/
});
var browserSync = require('browser-sync').create();
var reload = browserSync.reload;
// create a default task to build the app
gulp.task('default', ['jade', 'typescript', 'bowerjs', 'bowercss', 'appcss'], function() {
return plugins.util.log('App is built!')
});
In my example, we use Jade to HTML:
// Jade to HTML
gulp.task('jade', function() {
return gulp.src('src/**/*.jade')
.pipe(plugins.jade()) // pip to jade plugin
.pipe(gulp.dest('dist')) // tell gulp our output folder
.pipe(reload({stream: true}))
;
});
For TypeScript, we compiled into one single app.js file:
// TYPESCRIPT to JavaScript
gulp.task('typescript', function () {
return gulp.src('src/**/*.ts')
.pipe(plugins.typescript({
noImplicitAny: true,
out: 'app.js'
}))
.pipe(gulp.dest('dist/js/'))
.pipe(reload({stream: true}))
;
});
For bower, we merge all the js files in vendor.js and CSS in vendor.css:
// BOWER
gulp.task('bowerjs', function() {
gulp.src(plugins.mainBowerFiles())
.pipe(plugins.filter('**/*.js'))
.pipe(plugins.debug())
.pipe(plugins.concat('vendor.js'))
.pipe(plugins.uglify())
.pipe(gulp.dest('dist/js'));
});
gulp.task('bowercss', function() {
gulp.src(plugins.mainBowerFiles())
.pipe(plugins.filter('**/*.css'))
.pipe(plugins.debug())
.pipe(plugins.concat('vendor.css'))
.pipe(gulp.dest('dist/css'));
});
Custom CSS:
// APP css
gulp.task('appcss', function () {
return gulp.src('src/css/**/*.css')
.pipe(gulp.dest('dist/css/'))
.pipe(reload({
stream: true
}));
});
// CLEAN
gulp.task('clean', function(done) {
var delconfig = [].concat(
'dist',
'.tmp/js'
);
// force: clean files outside current directory
plugins.del(delconfig, {
force: true
}, done);
});
This is what reloads the browser when changes occur:
// Watch scss AND html files, doing different things with each.
gulp.task('serve', ['default'], function () {
// Serve files from the root of this project
browserSync.init({
server: {
baseDir: "./dist/"
}
});
gulp.watch("src/**/*.jade", ['jade']).on("change", reload);
gulp.watch("src/**/*.ts", ['typescript']).on("change", reload);
gulp.watch("src/**/*.css", ['appcss']).on("change", reload);
});
My tsconfig.json looks like this... I put the JS files that are automatically compiled from the text editor (Atom) into .tmp/js/atom ... some people put the .js in the same directory as the .ts but I find it confusing... less files is better for me:
{
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"outDir": ".tmp/js/atom"
},
"exclude": [
"node_modules",
"typings"
]
}

Starting protractor through gulp

I'm trying to run protractor as a gulp task but I can't get it to work.
I've tried the gulp-protractor plugin like this:
gulp.task('protractor-server', function (done) {
var called = false;
nodemon({
script: 'test/e2e/server/server.js',
stdout: true,
ignore: ['app/**', 'node_modules'],
watch: 'test/e2e/**/*.js'
})
.on('start', function () {
if (!called) {
done();
}
called = true;
});
});
gulp.task('run-protractor', ['protractor-server'], function (done) {
return gulp.src(['test/e2e/**/*.js'])
.pipe(protractor({
configFile: __dirname + '/protractor.conf.js'
}))
.on('error', function (error) {
console.log('gulp error: ', error);
throw error;
});
});
However, firstly why do I need to use gulp.src(['test/e2e/**/*.js']) and then pipe protractor? Is it not possible to run protractor by it self since i have specified the spec files in the protractor.conf-file. (fyi I did try that but it didn't work).
Secondly, when I try and run like specified in the above snippet I keep getting errors like this: WARNING - pattern C:\[absolutepath]\test\e2e\[subfolder]\[filename].js did not match any files. for all files that exist in the e2e folder and sub-folders. What could be the reason for this?
this is my protractor conf file:
exports.config = {
specs: [
'test/e2e/[subfolder]/*.page.js',
'test/e2e/[subfolder]/*.spec.js'
],
baseUrl: 'http://localhost:3000'
};
If I start the server separately and the run protractor from the command prompt it works fine. I was thinking to use child_process.spawn and start a protractor child process but i haven't gotten that to work either. Any suggestions on how to start protractor from a gulp task?
No need to use 'test/e2e/**/*.js']
Provide all configuration in protractor.conf.js file it self.
You can use task like
gulp.task('run-protractor', ['run-server','run-webdriver'], function (done) {
//run protractor conf here
})
create run-server and run-webdriver gulp taks, test them separately once they are working, utilize them into run-protractor task.

Why can't I view source maps with Angular and Browserify?

I am trying to step into the Browserify world. I am using a this tutorial as a starter. The source maps work fine. As soon as I require in angular the source maps disappear. Here is my browserify task.
gulp.task('browserify', function(){
return browserify({
entries: ['./src/javascript/app.coffee'],
extensions: ['.coffee', '.hbs']
})
.bundle({debug: true})
.on('error', handleErrors)
.pipe(source('app.js'))
.pipe(gulp.dest('./build/'));
});
I am passing in the debug: true flag. Is it even possible to make source maps with angular?
I believe you have the debug flag in the wrong location, try moving it into the call to browserify().
gulp.task('browserify', function(){
return browserify({
entries: ['./src/javascript/app.coffee'],
extensions: ['.coffee', '.hbs'],
debug: true //moved to here
})
.bundle()
.on('error', handleErrors)
.pipe(source('app.js'))
.pipe(gulp.dest('./build/'));
});

Resources