这是Gulp系列教程的第五部分。今天我会展示如何使用Browserify来打包JavaScript并使用CommonJS模块在浏览器中运行node模块。
Browserify
这个任务稍微复杂一些,因为我使用Browserify来打包JavaScript。如果它太复杂了超出了你的需求你也可以使用gulp-concat来把所有JavaScript文件打包成一个文件。
Browserify是一个超棒的工具,你可以在浏览器中使用node模块。超过70%的node模块可以正确运行!并且它会打包所有依赖。如果你想了解更多关于给Browserify编写CommonJS模块的内容请查阅文档。
这个任务我是在gulp-starter中发现的。它确实有点长但是很智能。它可以通过Browserify创建多个文件。我创建了两个。一个在网页头部加载包括了Modernizr并另一个包含所有其余JavaScript的文件在底部加载。
使用Browserify创建JavaScript文件
安装这个任务所需的node模块:
$ npm install --save-dev browserify@11.2.0 vinyl-source-stream@1.0.0 watchify@3.4.0 gulp-util@3.0.1 pretty-hrtime@1.0.1 gulp-notify@2.0.0
在config.js
文件中创建入口:
//gulp/config.js
browserify: {
// Enable source maps
debug: true,
// Additional file extensions to make optional
extensions: ['.coffee', '.hbs'],
// A separate bundle will be generated for each
// bundle config in the list below
bundleConfigs: [{
entries: './' + srcAssets + '/javascripts/application.js',
dest: developmentAssets + '/js',
outputName: 'application.js'
}, {
entries: './' + srcAssets + '/javascripts/head.js',
dest: developmentAssets + '/js',
outputName: 'head.js'
}]
}
//gulp/tasks/development/scripts.js
var gulp = require('gulp');
var browsersync = require('browser-sync');
var browserify = require('browserify');
var source = require('vinyl-source-stream');
var watchify = require('watchify');
var bundleLogger = require('../../util/bundleLogger');
var handleErrors = require('../../util/handleErrors');
var config = require('../../config').browserify;
/**
* Run JavaScript through Browserify
*/
gulp.task('scripts', function(callback) {
browsersync.notify('Compiling JavaScript');
var bundleQueue = config.bundleConfigs.length;
var browserifyThis = function(bundleConfig) {
var bundler = browserify({
// Required watchify args
cache: {}, packageCache: {}, fullPaths: false,
// Specify the entry point of your app
entries: bundleConfig.entries,
// Add file extentions to make optional in your requires
extensions: config.extensions,
// Enable source maps!
debug: config.debug
});
var bundle = function() {
// Log when bundling starts
bundleLogger.start(bundleConfig.outputName);
return bundler
.bundle()
// Report compile errors
.on('error', handleErrors)
// Use vinyl-source-stream to make the
// stream gulp compatible. Specifiy the
// desired output filename here.
.pipe(source(bundleConfig.outputName))
// Specify the output destination
.pipe(gulp.dest(bundleConfig.dest))
.on('end', reportFinished);
};
if(global.isWatching) {
// Wrap with watchify and rebundle on changes
bundler = watchify(bundler);
// Rebundle on update
bundler.on('update', bundle);
}
var reportFinished = function() {
// Log when bundling completes
bundleLogger.end(bundleConfig.outputName)
if(bundleQueue) {
bundleQueue--;
if(bundleQueue === 0) {
// If queue is empty, tell gulp the task is complete.
// https://github.com/gulpjs/gulp/blob/master/docs/API.md#accept-a-callback
callback();
}
}
};
return bundle();
};
// Start bundling with Browserify for each bundleConfig specified
config.bundleConfigs.forEach(browserifyThis);
});
这个任务包含一些额外的工具来处理错误并日志输出压缩过程。把这些内容放到gulp
目录的util
目录中:
//gulp/util/bundleLogger.js
/* bundleLogger
------------
Provides gulp style logs to the bundle method in browserify.js
*/
var gutil = require('gulp-util');
var prettyHrtime = require('pretty-hrtime');
var startTime;
module.exports = {
start: function(filepath) {
startTime = process.hrtime();
gutil.log('Bundling', gutil.colors.green(filepath));
},
end: function(filepath) {
var taskTime = process.hrtime(startTime);
var prettyTime = prettyHrtime(taskTime);
gutil.log('Bundled', gutil.colors.green(filepath), 'in', gutil.colors.magenta(prettyTime));
}
};
//gulp/util/handleErrors.js
var notify = require("gulp-notify");
module.exports = function() {
var args = Array.prototype.slice.call(arguments);
// Send error to notification center with gulp-notify
notify.onError({
title: "Compile Error",
message: "<%= error.message %>"
}).apply(this, args);
// Keep gulp from hanging on this task
this.emit('end');
};
使用CommonJS模块
编写CommonJS模块非常棒。你只需要输出函数,对象,字符串,整数以及任何想要作为模块或独立输出的内容。
//math.js
exports.add = function() {
var sum = 0, i = 0, args = arguments, 1 = args.length;
while (i < 1) {
sum += args[i++];
}
return sum;
};
//navigation.js
module.exports = {
toggleNavigation: function() {
...
}
};
随后你导入模块并使用:
//increment.js
var add = require('./math').add;
exports.increment = function(val) {
return add(val, 1);
};
//application.js
var navigation = require('./navigation');
var triggerNavigation = document.querySelector('.toggle- navigation');
document.addEventListener('DOMContentLoaded', function() {
triggerNavigation.addEventListener('click', navigation.toggleNavigation);
});
加载非CommonJS文件
但是还有个问题:我如何使用不含CommonJS语法的JavaScript文件?例如Modernizr或jQuery?
我需要安装browserify-shim
:
$ npm install --save-dev browserify-shim@3.8.0
打开package.son
文件并添加以下新行:
//package.json
{
"...": "...",
"browser": {
"modernizr": "./app/_bower_components/modernizr/modernizr.js",
"jquery": "./app/_bower_components/jquery/dist/jquery.js"
},
"browserify-shim": {
"modernizr": "Modernizr",
"jquery": "$"
},
"browserify": {
"transform": [
"browserify-shim"
]
},
"devDependencies": {
"...": "..."
}
}
在browser
区块中指定browserify-shim
到想要shim的资源。我使用Bower并将包安装到app/_bowser_components
中。选择的名字就是随后在JavaScripts中加载的名字。
在"browserify-shim"
中定义将依赖映射到哪里。要载入jQuery或Modernizr你需要加入以下内容:
//app/_assets/javascripts/head.js
require('modernizr');
// app/_assets/javascripts/application.js
require('jquery');
$(function() {
console.log("jQuery and Modernizr loaded");
});
一旦在package.json
文件中添加新的入口你需要运行nam install
命令。
源代码
总结
这是Gulp系列教程的第五部分的总结。我们学习了如何使用Browserify打包JavaScript文件,如何使用CommonJS模块在浏览器中运行node,以及如何使用非CommonJS的JavaScript文件。
本文根据@Stefan Imhoff的《Introduction to Gulp.js 5: Bundling JavaScript with Browserify》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://stefanimhoff.de/2014/gulp-tutorial-5-javascripts-browserify/。
如需转载,烦请注明出处:http://www.w3cplus.com/workflow/gulp-tutorial-5-javascripts-browserify.html