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