Gulp系列教程:使用Browserify处理JavaScript
这是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/ 。
Blueed
现居上海。正在学习前端的道路上,欢迎交流。个人博客: Blueed.me ,微博:@Ivan_z3