原文地址:https://survivejs.com/webpack/appendices/comparison/javascript
在之前,是能夠將你的腳本寫在一塊兒。 時代已經改變,如今將JavaScript代碼分開來多是一個複雜的工做。 隨着單頁應用程序(SPA)的興起,這個問題已經升級。他們傾向於依靠一些有用的系統(來解決這個問題)。css
出於這個緣由,有多種策略來加載它們。您能夠當即加載它們,或者考慮須要它們時加載。Webpack支持許多這樣的策略。html
Node和npm的流行,給它的包管理器提供了更多的使用環境。在npm普及以前,很難使用依賴項。有一段時間,人們開發出了前端特定的包管理器,但npm最終贏得了勝利。如今依賴管理比之前更容易了,儘管還須要克服一些挑戰。前端
任務運行程序與打包java
歷史上,已經有不少構建工具。 Make多是最着名的,它仍然是一個可行的選擇。 專門的任務運行程序,如Grunt和Gulp,是專門爲JavaScript開發人員建立的。 經過npm提供的插件使得任務運行程序都強大並且可擴展。 甚至可使用npm腳本做爲任務運行程序。 這很常見,特別是webpack。node
任務運行程序是高水平的偉大工具。 它們容許您以跨平臺方式執行操做。 當您須要將各類資源拼接在一塊兒並生產時,問題就會開始。 出於此緣由,存在資源整合程序,如Browserify,Brunch或webpack。react
有一段時間,RequireJS很受歡迎。 它的核心是提供一個異步模塊的方法並創建在此之上。 AMD的格式在後面將會有更詳細的介紹。 幸運的是,這些標準已經遇上了,並且RequireJS彷佛是一個很好的啓發。jquery
Makewebpack
就像1977年最初發布的那樣,Make回來了。儘管它是一箇舊工具,但它仍然是相關的。 Make容許您爲各類目的編寫單獨的任務。 例如,您能夠有不一樣的任務來建立生產構建,壓縮JavaScript或運行測試。 您能夠在許多其餘工具中找到相同的方法。git
儘管Make主要用於C項目,但它並不以任何方式與C綁定。 James Coglan詳細討論了如何使用在JavaScript中使用Mark。 看一下下面的詹姆斯帖子裏介紹的壓縮代碼的方法:
Makefile
PATH := node_modules/.bin:$(PATH) SHELL := /bin/bash source_files := $(wildcard lib/*.coffee) build_files := $(source_files:%.coffee=build/%.js) app_bundle := build/app.js spec_coffee := $(wildcard spec/*.coffee) spec_js := $(spec_coffee:%.coffee=build/%.js) libraries := vendor/jquery.js .PHONY: all clean test all: $(app_bundle) build/%.js: %.coffee coffee -co $(dir $@) $< $(app_bundle): $(libraries) $(build_files) uglifyjs -cmo $@ $^ test: $(app_bundle) $(spec_js) phantomjs phantom.js clean: rm -rf build
使用Make,您可使用Make-specific語法和終端命令爲您的任務建模,使其能夠與webpack集成。
RequireJS多是第一個成爲真正受歡迎的腳本加載程序。 它首先正確地引入了模塊化JavaScript。 其最大的吸引力是AMD。 它引入了一個定義包裝器:
define(['./MyModule.js'], function (MyModule) { return function() {}; // 模塊入口 }); // 或者 define(['./MyModule.js'], function (MyModule) { return { hello: function() {...}, // 導出爲模塊函數 }; });
順便說一下,能夠在包裝器中使用require:
define(['require'], function (require) { var MyModule = require('./MyModule.js'); return function() {...}; });
後一種方法更簡潔一點。 但您仍然會遇到多餘的代碼。 ES6等標準解決了這個問題。
注意:Jamund Ferguson撰寫了一篇關於如何從RequireJS移植到webpack的優秀博客系列。
npm腳本做爲自動化構建工具
即便npm CLI(命令行界面)並不是主要用於做爲任務運行的程序,因爲有package.json的腳本字段是之成爲可能。 考慮下面的例子:
package.json
"scripts": { "stats": "webpack --env production --json > stats.json", "start": "webpack-dev-server --env development", "deploy": "gh-pages -d build", "build": "webpack --env production" },
這些腳本可使用npm run列出,而後使用npm run <script>執行。 您還可使用諸如test:watch這樣的約定命名空間。 這種方法可使它保持跨平臺。
取代使用rm -rf,您可能更但願使用諸如rimraf等實用程序。 在這裏能夠調用其餘自動化構建工具來隱藏你正在使用的具體細節。 這樣,您能夠在保持界面相同的狀況下使用重構工具。
Grunt在前端開發人員中是最受歡迎的。它的插件架構有助於它的流行,插件自己一般是複雜的,所以,當配置增長時,很難理解到底發生了什麼。
如下是Grunt文檔的示例。 在此配置中,您定義一個linting和一個觀察任務。 當watch任務運行時,它也會觸發lint任務。 這樣,當您運行Grunt時,您能夠在編輯源代碼時在終端中實時發出警告。
Gruntfile.js
module.exports = (grunt) => { grunt.initConfig({ lint: { files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'], options: { globals: { jQuery: true, }, }, }, watch: { files: ['<%= lint.files %>'], tasks: ['lint'], }, }); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.registerTask('default', ['lint']); };
在實踐中,您將有許多小的任務用於特定目的,例如構建項目。 Grunt有用的一個重要部分是它隱藏了大量的細節。
從遠來講,這可能會有問題。從Grunt的構建過程,你很難理解它引擎工做的具體狀況。
注意:grunt-webpack插件容許您在Grunt環境中使用webpack,同時將使用等級提高到Webpack。
Gulp採起不一樣的方法。 您不須要依賴每一個插件的配置,而是處理實際的代碼。 Gulp創建在管道概念之上。 若是你熟悉Unix,這裏也是同樣的。 您須要遵循如下概念:
這是一個示例的Gulpfile,可讓您更好地瞭解從項目的README中獲取的方法。 它被縮寫爲一個接口:
Gulpfile.js
const gulp = require('gulp'); const coffee = require('gulp-coffee'); const concat = require('gulp-concat'); const uglify = require('gulp-uglify'); const sourcemaps = require('gulp-sourcemaps'); const del = require('del'); const paths = { scripts: ['client/js/**/*.coffee', '!client/external/**/*.coffee'] }; // 並非全部的任務都須要使用流 // 一個gulpfile是另外一個節點程序 // 你也能夠在npm上使用全部的軟件包 gulp.task( 'clean', del.bind(null, ['build'] ); gulp.task( 'scripts', ['clean'], () => ( // 壓縮和複製全部的JavaScript(除了供應商腳本) // 源代碼一路下來 gulp.src(paths.scripts) // 管道內 .pipe(sourcemaps.init()) .pipe(coffee()) .pipe(uglify()) .pipe(concat('all.min.js')) .pipe(sourcemaps.write()) .pipe(gulp.dest('build/js')) ) ); // 文件更改時從新運行任務 gulp.task( 'watch', gulp.watch.bind(null, paths.scripts, ['scripts']) ); // 默認任務(從CLI運行`gulp`時調用) gulp.task( 'default', ['watch', 'scripts'] );
鑑於配置是代碼,若是遇到麻煩,您老是能夠將其刪除。 您能夠將現有的節點包做爲Gulp插件,等等。 與Grunt相比,您能夠更清楚地瞭解發生了什麼。 儘管如此,你仍然最終寫了不少模板做爲閒時任務。 那就是更新的方法。
注意:webpack-stream容許您在Gulp環境中使用webpack。
注意:Fly是與Gulp相似的工具。 它依賴於ES6發生器。
處理JavaScript模塊一直是一個問題。 js語言自己沒有模塊的概念,直到ES6。 Ergo,這個語言在90年代被用在瀏覽器環境中。 已經提出了包括AMD在內的各類解決方案。
Browserify是模塊問題的一個解決方案。 它能夠將CommonJS模塊捆綁在一塊兒。 您能夠將其與Gulp掛鉤,您能夠找到較小的轉換工具,使您能夠超越基本用法。 例如,watchify提供了一個在開發空閒的工做期間爲您建立捆綁包的文件監視器。
Browserify生態系統由不少小模塊組成。 這樣,Browserify就符合Unix的理念。 Browserify比webpack更容易採用,實際上它是一個很好的替代品。
注意:Splittable是一個Browserify包裝器,容許代碼分割,支持ES6開箱即用,Tree shaking等等。
使用JSPM與之前的工具大相徑庭。 它附帶了一個本身的命令行工具,用於將新的軟件包安裝到項目中,建立一個生產包,等等。 它支持SystemJS插件,能夠將各類格式加載到項目中。
與Gulp相比,Brunch在更高層次的抽象上運做。 它使用相似於webpack的聲明方法。 以示例爲例,您能夠考慮從Brunch網站改編如下配置:
module.exports = { files: { javascripts: { joinTo: { 'vendor.js': /^(?!app)/, 'app.js': /^app/, }, }, stylesheets: { joinTo: 'app.css', }, }, plugins: { babel: { presets: ['es2015', 'react'], }, postcss: { processors: [require('autoprefixer')], }, }, };
Brunch包括像brunch new, brunch watch --server, and brunch build --production。 它包含了不少創造性的功能,可使用插件擴展。
注意:Brunch有一個實驗性的熱模塊從新加載程序。
您能夠說Webpack採用比Browserify更單一的方法。 Browserify由多個小工具組成,而Webpack提供了一個核心,它提供了不少創造性的功能。
Webpack核心可使用特定的加載程序和插件進行擴展。 它能夠控制如何解決模塊,使您能夠調整您的構建以匹配特定狀況和解決沒法正常運行的軟件包。
與其餘工具相比,Webpack具備初始複雜性,但經過其普遍的功能集成能夠彌補這一點。 這是一個須要耐心的高級工具。 可是一旦瞭解了背後的基本思路,webpack就變得很強大。
其餘選項
您能夠找到更多替代品,以下所列:
結語
歷史上已經有不少JavaScript的構建工具。 每一個人都試圖以本身的方式解決一個特定的問題。 這些標準已經開始迎頭遇上,基本語義的要求也更少了。 相反,工具能夠在更高層次上競爭,並推進更好的用戶體驗。 一般,您能夠一塊兒使用幾個單獨的解決方案。
總的來講: