在一些簡(jiǎn)單的項(xiàng)目中我們?nèi)杂心芰Π阉蠮S依賴聯(lián)系起來(lái),但越來(lái)越復(fù)雜復(fù)雜的JS依賴很可能會(huì)成為困擾著我們。而且單頁(yè)面應(yīng)用( single-page applications, SPA, 單頁(yè)面應(yīng)用簡(jiǎn)介)依賴 many hefty libraries 。所以前輩們發(fā)明出了很多的構(gòu)建工具,這些工具能夠讓我們方便的按需加載依賴,Webpack 就提供了很多這樣的策略。而現(xiàn)在很流行的Node和他的包管理器npm讓我們能更舒服的管理依賴。還有很多工具可以自動(dòng)化地進(jìn)行代碼的語(yǔ)法檢查、壓縮等等。
Task Runners
歷史上有很多的構(gòu)建工具,其中 Make 或許是最出名的,到現(xiàn)在還是一種切實(shí)可行的選擇。而 Grunt 和 Gulp 作為專業(yè)的 Task Runner 是在特別考慮到JS開(kāi)發(fā)人員的情況下創(chuàng)建的。
通過(guò)NPM提供的插件使 Task Runner 既強(qiáng)大又可擴(kuò)展。甚至可以使用npm script作為Task Runner,這在Webpack中尤其常見(jiàn)。
從名字上可以看出 Task Runner 就是運(yùn)行一個(gè)一個(gè)的任務(wù),這些任務(wù)可以是檢查語(yǔ)法、編譯、壓縮等等。
Make
Make首次發(fā)布于1977年,主要用于C語(yǔ)言項(xiàng)目,但它與C語(yǔ)言沒(méi)有任何聯(lián)系。同樣可以用于網(wǎng)頁(yè)的構(gòu)建工具,使用 Make 構(gòu)建網(wǎng)站—阮一峰 這篇文章簡(jiǎn)單介紹了 Make 命令和使用方法,作者還分享了為什么構(gòu)建大型項(xiàng)目首選 Make ,而不是 npm script、Grunt 或 Gulp。
npm scripts as a Task Runner
盡管npm CLI的主要設(shè)計(jì)目的不是用作 Task Runner,但由于package.json腳本字段的緣故,它的工作方式也是如此。請(qǐng)考慮下面的示例:
"scripts": {
"start": "webpack-dev-server --env development",
"build": "webpack --env production",
"build:stats": "webpack --env production --json > stats.json"
},
這些腳本可以使用npm run列出,然后使用npm run <script>執(zhí)行。你還可以使用類似test:watch的約定為腳本命名。 !!#ff0000 這種方法的問(wèn)題在于它要注意保持跨平臺(tái)。!!
(您可能希望使用諸如 rimraf [ 以包的形式包裝rm -rf命令 ] 等實(shí)用程序,而不是rm-rf。這里可以調(diào)用其他Task Runner來(lái)隱藏您實(shí)際使用的那一個(gè)。通過(guò)這種方式,您可以重構(gòu)工具,同時(shí)保持接口不變。)
Grunt
這是前端開(kāi)發(fā)人員的第一個(gè)有名的 Task Runner。采用了插件架構(gòu),配置復(fù)雜,難以理解。
sample:
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-webpack plugin allows you to use webpack in a Grunt environment while you leave the heavy lifting to webpack.
Gulp
Gulp采取了不同的方法。不是依賴每個(gè)插件的配置,而是處理實(shí)際的代碼。
sample:
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"],
};
// Not all tasks need to use streams.
// A gulpfile is another node program
// and you can use all packages available on npm.
gulp.task("clean", () => del(["build"]));
gulp.task("scripts", ["clean"], () =>
// Minify and copy all JavaScript (except vendor scripts)
// with source maps all the way down.
gulp
.src(paths.scripts)
// Pipeline within pipeline
.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(paths.scripts, ["scripts"]));
// The default task (called when you run `gulp` from CLI).
gulp.task("default", ["watch", "scripts"]);
配置就是處理的代碼,因此遇到問(wèn)題時(shí)你可以隨時(shí) hack ??梢?wrap 已有的 Node 包作為 Gulp 的插件,相較于Grunt來(lái)說(shuō)你能更加清楚看到發(fā)生了什么。但是你還是需要為一些臨時(shí)任務(wù)編寫(xiě)大量的樣本文件,That is where newer approaches come in。
webpack-stream allows you to use webpack in a Gulp environment.
模塊化運(yùn)行時(shí)編譯方案
代表是Require.js/sea.js,在 前端模塊化 中已經(jīng)討論過(guò),使用預(yù)編譯會(huì)優(yōu)于運(yùn)行時(shí)編譯。
模塊化預(yù)編譯方案
代表是Browserify/Webpack,和Task Runners 不同的是他們是模塊化方案,而Gulp/Grunt是工具,webpack 因?yàn)閘oader和plugin這一配置項(xiàng)讓他可以完成一些Gulp/Grunt的工作(雖然完成的工作有重復(fù),但本質(zhì)上他們是不同的)。Gulp/Grunt完全可以同webpack結(jié)合使用。
Browserify和Webpack相比較的話各有利弊。
總結(jié)
前端需要規(guī)范代碼組織,實(shí)現(xiàn)模塊化,所以出現(xiàn)了諸如webpack之類的模塊化編譯方案。前端需要在部署上線的時(shí)候進(jìn)行檢查壓縮合并轉(zhuǎn)換,所以出現(xiàn)了諸如Gulp之類的專業(yè)構(gòu)建工具。而使用他們這一切都會(huì)是自動(dòng)進(jìn)行的。
不同的技術(shù)從不同的角度去解決問(wèn)題,我們有時(shí)候可以一起使用他們。
注:在查閱資料過(guò)程中還發(fā)現(xiàn)了很多工具,如jspm,SystemJS、Brunch、Parcel、FIS