前端構建工具對比
title: 前端構建工具對比
toc: true
date: 2018-10-17 19:41:31
categories:
- Web
tags:
- 前端構建工具
- grunt
- gulp
- webpack
前端技術發展之快,各種可以提高開發效率的新思想和框架層出不窮。但是它們都有一個共同點:
原始碼無法直接執行,必須通過轉換後才可以正常執行。
構建就是做這件事情,將原始碼轉換成可執行的JavaScript、CSS、HTML程式碼,包括如下內容:
程式碼轉換:將TypeScript編譯成JavaScript、將SCSS編譯成CSS等。
檔案優化:壓縮JavaScript、CSS、HTML程式碼,壓縮合並圖片等。
程式碼分割:提取多個頁面的公共程式碼,提取首屏不需要執行部分的程式碼讓其非同步載入。
模組合併:在採用模組化的專案裡會有很多個模組和檔案,需要通過構建功能將模組分類合併成一個檔案。
自動重新整理:監聽本地原始碼的變化,自動重新構建、重新整理瀏覽器。
程式碼校驗:在程式碼被提交到倉庫前需要校驗程式碼是否符合規範,以及單元測試是否通過。
自動釋出:更新程式碼後,自動構建出線上釋出程式碼並傳輸給釋出系統。
構建其實是工程化、自動化思想在前端開發中的體現,將一系列流程用程式碼去實現,讓程式碼自動化地執行這一系列複雜的流程。構建為前端開發注入了更大的活力,解放了我們的生產力。
Npm Scripts
Npm是在安裝Node. js時附帶的包管理器,
Npm Script則是Npm內建的一個功能,允許在package.json檔案裡面使用scripts欄位定義指令碼命令:
{
// ...
"scripts": {
"build": "node build.js",
"dev": "node dev.js",
"pub": "node build.js"
}
}
優點:內建,無須安裝其他依賴。
缺點:功能太簡單,雖然提供了pre和post兩個鉤子,但不能方便地管理多個任務之間的依賴。
Grunt
Grunt相當於進化版的Npm Script,它的誕生其實是為了彌補Npm Script的不足。
Grunt有大量現成的外掛封裝了常見的任務,
也能管理任務之間的依賴關係,自動化地執行依賴的任務,
每個任務的具體執行程式碼和依賴關係寫在配置檔案Gruntfile.js
裡,
例如:
module.exports = function(grunt) {
// 所有外掛的配置資訊
grunt.initConfig({
// uglify外掛的配置資訊
uglify: {
app_task: {
files: {
'build/app.min.js': ['lib/index.js', 'lib/test.js']
}
}
},
// watch外掛的配置資訊
watch: {
another: {
files: ['lib/*.js'],
}
}
});
// 告訴Grunt我們將使用這些外掛
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
// 告訴Grunt我們在終端中啟動Grunt時需要執行哪些任務
grunt.registerTask('dev', ['uglify','watch']);
};
在專案根目錄下執行命令grunt dev
,就會啟動JavaScript檔案壓縮和自動重新整理功能。
優點:
靈活,它只負責執行我們定義的任務;
大量的可複用外掛封裝好了常見的構建任務。
缺點:
整合度不高,要寫很多配置後才可以用,無法做到開箱即用。
Gulp
Gulp 是一個基於流的自動化構建工具。
除了可以管理和執行任務,還支援監聽檔案、讀寫檔案。
Gulp被設計得非常簡單,
只通過下面5種方法就可以支援幾乎所有構建場景:
- 通過gulp.task註冊一個任務
- 通過gulp.run執行任務
- 通過gulp.watch監聽檔案的變化
- 通過gulp.src讀取檔案
- 通過gulp.dest寫檔案
Gulp的最大特點是引入了流的概念,
同時提供了一系列常用的外掛去處理流,
流可以在外掛之間傳遞,大致使用如下:
// 引入 Gulp
var gulp = require('gulp');
// 引入外掛
var jshint = require('gulp-jshint');
var sass = require('gulp-sass');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
// 編譯SCSS任務
gulp.task('sass', function() {
// 讀取檔案,通過管道餵給外掛
gulp.src('./scss/*.scss')
// SCSS 外掛將 scss 檔案編譯成 CSS 檔案
.pipe(sass())
// 輸出檔案
.pipe(gulp.dest('./css'));
});
// 合併壓縮JavaScript檔案
gulp.task('scripts', function() {
gulp.src('./js/*.js')
.pipe(concat('all.js'))
.pipe(uglify())
.pipe(gulp.dest('./dist'));
});
// 監聽檔案的變化
gulp.task('watch', function(){
// 當 scss 檔案被編輯時執行 SCSS 任務
gulp.watch('./scss/*.scss', ['sass']);
gulp.watch('./js/*.js', ['scripts']);
});
優點:好用又不失靈活,既可以單獨完成構建,也可以和其他工具搭配使用。
缺點:整合度不高,要寫很多配置後才可以用,無法做到開箱即用。
可以將Gulp看作Grunt的加強版。
相對於Grunt,Gulp增加了監聽檔案、讀寫檔案、流式處理的功能。
Fis3
Fis3 是一個來自百度的優秀國產構建工具。
相對於Grunt、Gulp這些只提供了基本功能的工具,
Fis3集成了Web開發中的常用構建功能。
讀寫檔案:通過fis.match讀檔案,release配置檔案的輸出路徑。
資源定位:解析檔案之間的依賴關係和檔案位置。
檔案指紋:在通過useHash配置輸出檔案時為檔案URL加上md5戳,來優化瀏覽器的快取。
檔案編譯:通過parser配置檔案解析器做檔案轉換,例如將ES6編譯成ES5。
壓縮資源:通過optimizer配置程式碼壓縮方法。
圖片合併:通過spriter配置合併CSS裡匯入的圖片到一個檔案中,來減少HTTP請求數。
大致使用如下:
// 加md5
fis.match('*.{js,css,png}', {
useHash: true
});
// 通過fis3-parser-typescript外掛可將TypeScript檔案轉換成JavaScript檔案
fis.match('*.ts', {
parser: fis.plugin('typescript')
});
// 對CSS進行雪碧圖合併
fis.match('*.css', {
// 為匹配到的檔案分配屬性useSprite
useSprite: true
});
// 壓縮JavaScript
fis.match('*.js', {
optimizer: fis.plugin('uglify-js')
});
// 壓縮CSS
fis.match('*.css', {
optimizer: fis.plugin('clean-css')
});
// 壓縮圖片
fis.match('*.png', {
optimizer: fis.plugin('png-compressor')
});
優點:集成了各種Web開發所需的構建功能,配置簡單、開箱即用。
缺點:目前官方已經不再更新和維護,不支援最新版本的Node.js。
Fis3是一種專注於Web開發的完整解決方案,如果將Grunt、Gulp比作汽車的發動機,則可以將Fis3比作一輛完整的汽車。
Webpack
Webpack 是一個打包模組化JavaScript的工具,
在Webpack裡一切檔案皆模組,
通過Loader
轉換檔案,
通過Plugin
注入鉤子,
最後輸出由多個模組組合成的檔案。
Webpack專注於構建模組化專案。
一切檔案,如JavaScript、CSS、SCSS、圖片、模板,
對於Webpack來說都是一個個模組,
這樣的好處是能清晰地描述各個模組之間的依賴關係,以方便Webpack對模組進行組合和打包。
經過Webpack的處理,最終會輸出瀏覽器能使用的靜態資源。
Webpack具有很大的靈活性,能配置處理檔案的方式,使用方法大致如下:
module.exports = {
// 所有模組的入口,Webpack從入口開始遞迴解析出所有依賴的模組
entry: './app.js',
output: {
// 將入口所依賴的所有模組打包成一個檔案bundle.js輸出
filename: 'bundle.js'
}
}
優點:
- 專注於處理模組化的專案,能做到開箱即用、一步到位
- 可通過Plugin擴充套件,完整好用又不失靈活
- 使用場景不侷限於Web開發
- 社群龐大活躍,經常引入緊跟時代發展的新特性,能為大多數場景找到已有的開源擴充套件
- 良好的開發體驗。
缺點:
- 只能用於採用模組化開發的專案。
Rollup
Rollup是一個和Webpack很類似但專注於ES6的模組打包工具。
它的亮點在於,能針對ES6原始碼進行Tree Shaking(搖樹優化),以去除那些已被定義但沒被使用的程式碼並進行Scope Hoisting(作用域提升),以減小輸出檔案的大小和提升執行效能。
然而Rollup的這些亮點隨後就被Webpack模仿和實現。
由於Rollup的使用方法和Webpack差不多,所以這裡就不詳細介紹如何使用Rollup了。
它們的差別:
- Rollup是在Webpack流行後出現的替代品
- Rollup生態鏈還不完善,體驗不如Webpack
- Rollup的功能不如Webpack完善,但其配置和使用更簡單
- Rollup不支援Code Spliting,但好處是在打包出來的程式碼中沒有Webpack那段模組的載入、執行和快取的程式碼
- Rollup在用於打包JavaScript庫時比Webpack更有優勢,因為其打包出來的程式碼更小、更快。但它的功能不夠完善,在很多場景下都找不到現成的解決方案。
為什麼選擇Webpack
上面介紹的構建工具是按照它們誕生的時間排序的,
它們是時代的產物,側面反映出Web開發的發展趨勢,如下所述:
- 在Npm Script和Grunt時代,Web開發要做的事情變多,流程複雜,自動化思想被引入,用於簡化流程
- 在Gulp時代,開始出現一些新語言用於提高開發效率,流式處理思想的出現是為了簡化檔案轉換的流程,例如將ES5轉換成ES6
- 在Webpack時代,由於單頁應用的流行,網頁的功能和實現程式碼變得複雜、龐大,Web開發向模組化改進
- 這些構建工具都有各自的定位和專注點,它們之間既可以單獨完成任務,也可以相互搭配來彌補各自的不足。在瞭解這些常見的構建工具後,我們需要根據自己的需求去判斷應該如何選擇和搭配它們才能更好地滿足自己的需求。
經過多年的發展,Webpack已經成為構建工具中的首選,這是有原因的:
- 大多數團隊在開發新專案時會採用緊跟時代的技術,這些技術幾乎都會採用“模組化+新語言+新框架”,Webpack可以為這些新專案提供一站式的解決方案
- Webpack有良好的生態鏈和維護團隊,能提供良好的開發體驗並保證質量
- Webpack被全世界大量的Web開發者使用和驗證,能找到各個層面所需的教程和經驗分享。
參考連結:https://blog.csdn.net/broadview2006/article/details/79091719