(翻譯)前端構(gòu)建工具的比較

原文地址:https://survivejs.com/webpack/appendices/comparison/

在以前,是可以將你的腳本寫在一起。 時(shí)代已經(jīng)改變,現(xiàn)在將JavaScript代碼分開來可能是一個(gè)復(fù)雜的工作。 隨著單頁應(yīng)用程序(SPA)的興起,這個(gè)問題已經(jīng)升級(jí)。他們傾向于依靠一些有用的系統(tǒng)(來解決這個(gè)問題)。

出于這個(gè)原因,有多種策略來加載它們。您可以立即加載它們,或者考慮需要它們時(shí)加載。Webpack支持許多這樣的策略。

Node和npm的流行,給它的包管理器提供了更多的使用環(huán)境。在npm普及之前,很難使用依賴項(xiàng)。有一段時(shí)間,人們開發(fā)出了前端特定的包管理器,但npm最終贏得了勝利?,F(xiàn)在依賴管理比以前更容易了,盡管還需要克服一些挑戰(zhàn)。

任務(wù)運(yùn)行程序與打包

歷史上,已經(jīng)有很多構(gòu)建工具。 Make可能是最著名的,它仍然是一個(gè)可行的選擇。 專門的任務(wù)運(yùn)行程序,如Grunt和Gulp,是專門為JavaScript開發(fā)人員創(chuàng)建的。 通過npm提供的插件使得任務(wù)運(yùn)行程序都強(qiáng)大而且可擴(kuò)展。 甚至可以使用npm腳本作為任務(wù)運(yùn)行程序。 這很常見,特別是webpack。

任務(wù)運(yùn)行程序是高水平的偉大工具。 它們?cè)试S您以跨平臺(tái)方式執(zhí)行操作。 當(dāng)您需要將各種資源拼接在一起并生產(chǎn)時(shí),問題就會(huì)開始。 出于此原因,存在資源整合程序,如Browserify,Brunch或webpack。

有一段時(shí)間,RequireJS很受歡迎。 它的核心是提供一個(gè)異步模塊的方法并建立在此之上。 AMD的格式在后面將會(huì)有更詳細(xì)的介紹。 幸運(yùn)的是,這些標(biāo)準(zhǔn)已經(jīng)趕上了,而且RequireJS似乎是一個(gè)很好的啟發(fā)。

Make

就像1977年最初發(fā)布的那樣,Make回來了。盡管它是一個(gè)舊工具,但它仍然是相關(guān)的。 Make允許您為各種目的編寫單獨(dú)的任務(wù)。 例如,您可以有不同的任務(wù)來創(chuàng)建生產(chǎn)構(gòu)建,壓縮JavaScript或運(yùn)行測(cè)試。 您可以在許多其他工具中找到相同的方法。

盡管Make主要用于C項(xiàng)目,但它并不以任何方式與C綁定。 James Coglan詳細(xì)討論了如何使用在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語法和終端命令為您的任務(wù)建模,使其可以與webpack集成。

RequireJS

RequireJS可能是第一個(gè)成為真正受歡迎的腳本加載程序。 它首先正確地引入了模塊化JavaScript。 其最大的吸引力是AMD。 它引入了一個(gè)定義包裝器:

define(['./MyModule.js'], function (MyModule) {
  return function() {}; // 模塊入口
});
 
// 或者
define(['./MyModule.js'], function (MyModule) {
  return {
    hello: function() {...}, // 導(dǎo)出為模塊函數(shù)
  };
});

順便說一下,可以在包裝器中使用require:

define(['require'], function (require) {
  var MyModule = require('./MyModule.js');
 
  return function() {...};
});

后一種方法更簡(jiǎn)潔一點(diǎn)。 但您仍然會(huì)遇到多余的代碼。 ES6等標(biāo)準(zhǔn)解決了這個(gè)問題。

注意:Jamund Ferguson撰寫了一篇關(guān)于如何從RequireJS移植到webpack的優(yōu)秀博客系列。

npm腳本作為自動(dòng)化構(gòu)建工具

即使npm CLI(命令行界面)并非主要用于作為任務(wù)運(yùn)行的程序,由于有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>執(zhí)行。 您還可以使用諸如test:watch這樣的約定命名空間。 這種方法可以使它保持跨平臺(tái)。

取代使用rm -rf,您可能更希望使用諸如rimraf等實(shí)用程序。 在這里可以調(diào)用其他自動(dòng)化構(gòu)建工具來隱藏你正在使用的具體細(xì)節(jié)。 這樣,您可以在保持界面相同的情況下使用重構(gòu)工具。

Grunt


Grunt在前端開發(fā)人員中是最受歡迎的。它的插件架構(gòu)有助于它的流行,插件本身通常是復(fù)雜的,因此,當(dāng)配置增加時(shí),很難理解到底發(fā)生了什么。

以下是Grunt文檔的示例。 在此配置中,您定義一個(gè)linting和一個(gè)觀察任務(wù)。 當(dāng)watch任務(wù)運(yùn)行時(shí),它也會(huì)觸發(fā)lint任務(wù)。 這樣,當(dāng)您運(yùn)行Grunt時(shí),您可以在編輯源代碼時(shí)在終端中實(shí)時(shí)發(fā)出警告。

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']);
};

在實(shí)踐中,您將有許多小的任務(wù)用于特定目的,例如構(gòu)建項(xiàng)目。 Grunt有用的一個(gè)重要部分是它隱藏了大量的細(xì)節(jié)。

從遠(yuǎn)來說,這可能會(huì)有問題。從Grunt的構(gòu)建過程,你很難理解它引擎工作的具體情況。

注意:grunt-webpack插件允許您在Grunt環(huán)境中使用webpack,同時(shí)將使用等級(jí)提升到Webpack。

Gulp


Gulp采取不同的方法。 您不需要依賴每個(gè)插件的配置,而是處理實(shí)際的代碼。 Gulp建立在管道概念之上。 如果你熟悉Unix,這里也是一樣的。 您需要遵循以下概念:

  • 來源匹配文件。
  • 對(duì)來源執(zhí)行操作的過濾器(例如,轉(zhuǎn)換為JavaScript)
  • 接收模塊庫(例如,您的構(gòu)建目錄)在哪里管理構(gòu)建結(jié)果。

這是一個(gè)示例的Gulpfile,可以讓您更好地了解從項(xiàng)目的README中獲取的方法。 它被縮寫為一個(gè)接口:

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']
};
 
// 并不是所有的任務(wù)都需要使用流
// 一個(gè)gulpfile是另一個(gè)節(jié)點(diǎn)程序
// 你也可以在npm上使用所有的軟件包
gulp.task(
  'clean',
  del.bind(null, ['build']
);
 
gulp.task(
  'scripts',
  ['clean'],
  () => (
    // 壓縮和復(fù)制所有的JavaScript(除了供應(yīng)商腳本)
    // 源代碼一路下來
    gulp.src(paths.scripts)
      // 管道內(nèi)
      .pipe(sourcemaps.init())
        .pipe(coffee())
        .pipe(uglify())
        .pipe(concat('all.min.js'))
      .pipe(sourcemaps.write())
      .pipe(gulp.dest('build/js'))
  )
);
 
// 文件更改時(shí)重新運(yùn)行任務(wù)
gulp.task(
  'watch',
  gulp.watch.bind(null, paths.scripts, ['scripts'])
);
 
// 默認(rèn)任務(wù)(從CLI運(yùn)行`gulp`時(shí)調(diào)用)
gulp.task(
  'default',
  ['watch', 'scripts']
);

鑒于配置是代碼,如果遇到麻煩,您總是可以將其刪除。 您可以將現(xiàn)有的節(jié)點(diǎn)包作為Gulp插件,等等。 與Grunt相比,您可以更清楚地了解發(fā)生了什么。 盡管如此,你仍然最終寫了很多模板作為閑時(shí)任務(wù)。 那就是更新的方法。

注意:webpack-stream允許您在Gulp環(huán)境中使用webpack。

注意:Fly是與Gulp類似的工具。 它依賴于ES6發(fā)生器。

Browserify


處理JavaScript模塊一直是一個(gè)問題。 js語言本身沒有模塊的概念,直到ES6。 Ergo,這個(gè)語言在90年代被用在瀏覽器環(huán)境中。 已經(jīng)提出了包括AMD在內(nèi)的各種解決方案。

Browserify是模塊問題的一個(gè)解決方案。 它可以將CommonJS模塊捆綁在一起。 您可以將其與Gulp掛鉤,您可以找到較小的轉(zhuǎn)換工具,使您可以超越基本用法。 例如,watchify提供了一個(gè)在開發(fā)空閑的工作期間為您創(chuàng)建捆綁包的文件監(jiān)視器。

Browserify生態(tài)系統(tǒng)由很多小模塊組成。 這樣,Browserify就符合Unix的理念。 Browserify比webpack更容易采用,實(shí)際上它是一個(gè)很好的替代品。

注意:Splittable是一個(gè)Browserify包裝器,允許代碼分割,支持ES6開箱即用,Tree shaking等等。

JSPM


使用JSPM與以前的工具截然不同。 它附帶了一個(gè)自己的命令行工具,用于將新的軟件包安裝到項(xiàng)目中,創(chuàng)建一個(gè)生產(chǎn)包,等等。 它支持SystemJS插件,可以將各種格式加載到項(xiàng)目中。

Brunch


與Gulp相比,Brunch在更高層次的抽象上運(yùn)作。 它使用類似于webpack的聲明方法。 以示例為例,您可以考慮從Brunch網(wǎng)站改編以下配置:

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。 它包含了很多創(chuàng)造性的功能,可以使用插件擴(kuò)展。

注意:Brunch有一個(gè)實(shí)驗(yàn)性的熱模塊重新加載程序

Webpack


您可以說Webpack采用比Browserify更單一的方法。 Browserify由多個(gè)小工具組成,而Webpack提供了一個(gè)核心,它提供了很多創(chuàng)造性的功能。

Webpack核心可以使用特定的加載程序和插件進(jìn)行擴(kuò)展。 它可以控制如何解決模塊,使您可以調(diào)整您的構(gòu)建以匹配特定情況和解決無法正常運(yùn)行的軟件包。

與其他工具相比,Webpack具有初始復(fù)雜性,但通過其廣泛的功能集成可以彌補(bǔ)這一點(diǎn)。 這是一個(gè)需要耐心的高級(jí)工具。 但是一旦了解了背后的基本思路,webpack就變得很強(qiáng)大。

其他選項(xiàng)

您可以找到更多替代品,如下所列:

  • pundle宣傳自己作為下一代打包工具,并特別注意其性能。
  • Rollup重點(diǎn)關(guān)注打包es6的代碼。Tree shaking是其賣點(diǎn)之一。您可以使用Rollup與webpack的加載程序rollup-loader。
  • AssetGraph采用完全不同的方法,建立在HTML語義之上,使其成為超鏈接分析結(jié)構(gòu)分析的理想選擇。webpack-assetgraph-plugin將webpack和AssetGraph結(jié)合在一起。
  • FuseBox是一個(gè)專注于速度的打包工具。 它采用零配置方式,旨在開箱即用。
  • StealJS是一個(gè)依賴加載器,一個(gè)專注于性能和易用性的構(gòu)建工具。
  • Flipbox將多個(gè)捆綁包裹在一個(gè)統(tǒng)一的界面后面。

結(jié)語

歷史上已經(jīng)有很多JavaScript的構(gòu)建工具。 每個(gè)人都試圖以自己的方式解決一個(gè)特定的問題。 這些標(biāo)準(zhǔn)已經(jīng)開始迎頭趕上,基本語義的要求也更少了。 相反,工具可以在更高層次上競(jìng)爭(zhēng),并推動(dòng)更好的用戶體驗(yàn)。 通常,您可以一起使用幾個(gè)單獨(dú)的解決方案。

總的來說:

  • 自動(dòng)化構(gòu)建工具和打包工具解決不同的問題。 您可以通過兩者實(shí)現(xiàn)類似的結(jié)果,但通常最好將它們一起使用來相互補(bǔ)充。
  • 較早的工具(如Make或RequireJS)仍然具有影響力,即使它們?cè)谇岸碎_發(fā)中不如以往那樣受歡迎。
  • Bundinner如Browserify或webpack解決了一個(gè)重要的問題,并幫助您管理復(fù)雜的Web應(yīng)用程序。
  • 一些新興技術(shù)從不同的角度解決問題。 有時(shí)候它們建立在其他工具之上,有時(shí)它們可以一起使用。

原博客備份

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容