隨著網頁技術不斷翻新,前端需要處理的事也就越來越繁雜。在這樣龐雜豐富且迅速更迭的技術環境之下,將開發流程自動化、工程化就成了必需,開發者也自然會需要一些工具來協助優化這些流程。
今天就來聊聊前端的模組打包工具(Module Bundler)。
前端工程化#
工程化的起點,自然是從 Node.js 問世,套件管理工具 npm 誕生開始。透過 npm,開發者便能快速且輕易的從 NPM Registry 下載到其他開發者提交的套件,並加在自己的專案中。
除此之外,npm 也提供了 script 的功能,將 shell script 封裝成別名快速使用:
{
"scripts": {
"dev": "node app.js"
}
}例如上例,當開發者輸入 npm run dev,就等同於執行了 node app.js 這行指令。透過這樣簡短的 script 設定,確實可以解決一些基本的需求。
Grunt#
但其實大部分需求在開發過程中,重複性是非常高的。例如將 SASS、SCSS 編譯成 CSS,透過 npm script,就需要修改完、輸入指令進行編譯、Reload,開發者的開發體驗便會大打折扣。要解決這樣的情況,Grunt 是一個不錯的解決方案。
Grunt 提供了更大的程式化空間,讓開發者能更自由地控制自動化流程。藉由大量的插件(plugin),以及高度客製化的設定,開發者可以輕易地完成一些常見的任務。
Gulp#
但 Grunt 的設定大多是每個插件個別設定,一旦專案中的插件數量增加,設定跳來跳去,同一支原始檔案的去向很容易就變得難以追蹤。Gulp 透過管道(Pipes)及串流(Streams)的概念,便能有效避免前述的情況發生。
例如想要將 LESS 編譯成 CSS,再將檔案進行最小化(minify)處理,Gulp 中的設定可能會這樣寫:
function css() {
return src("assist/style/*.less")
.pipe(less())
.pipe(minifyCSS())
.pipe(dest("dist/css"));
}藉由 pipe 函式,將任務結果依序往後傳遞,同檔案類型會經過什麼處理,也就變得一目了然。除此之外,Gulp 相較於 Grunt 還多了檔案監看、檔案讀寫等功能,將許多繁雜的基礎功能都得以自動化。
Webpack#
但隨著前端的演進,開發流程又更加複雜,針對檔案類型做處理已經不能滿足開發者的需求。加上資源量越來越多,在 HTTP/1.1 有單一網域請求數上限的情況下,勢必需要將前端的程式分開包裝,才能夠將資源傳遞給使用者。
熱門套件 Webpack 則給出了一個全新的思考模式:藉由定義專案的 entry 及 output,Webpack 便會從 entry 開始解析專案,最後將相依的檔案打包成指定的 output。除此之外,也可以在過程中間加上 loader、plugins,對需要的檔案做進一步的處理。
同樣拿 CSS 來看看,這次將 SCSS 依序處理成 CSS:
rules: [
{
test: /\.(scss)$/,
include: [path.resolve(__dirname, "app")],
loader: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [
{
loader: "css-loader",
options: {
modules: false,
minimize: true,
sourceMap: true,
importLoaders: 3,
},
},
{
loader: "postcss-loader",
options: {
sourceMap: true,
config: {
path: path.resolve(__dirname, "postcss.config.js"),
},
},
},
{
loader: "resolve-url-loader",
options: {
sourceMap: true,
},
},
{
loader: "sass-loader",
options: {
sourceMap: true,
},
},
],
}),
},
//...
];透過上述設定,將會依序透過 sass-loader、resolve-url-loader、postcss-loader、css-loader、style-loader 對副檔名為 .scss 的檔案做處理,其餘檔案類型也能夠設定、搭配相對應的 loader,將前端的內容封裝、打包。
更多打包工具#
看到一堆設定,這也是 Webpack 最讓人詬病的問題:Webpack 提供開發者更高的自由度,同時卻也帶來更多的複雜度。但在一般的中小型專案,可能根本不需要那些繁雜的設定,這時候用 Webpack 就有點殺雞用牛刀。
開源社群中有一些新的打包工具,都能讓開發者可以減少撰寫龐大設定的痛苦,並享用自動化流程的便利:
- Backpack:專注在 Node.js 後端專案
- Rollup:號稱是新一代打包工具
- Parcel:完全無設定便能直接使用
打包工具的用途#
說了那麼多打包工具,用途到底是什麼?不外乎以下幾點。
轉譯#
前端三大框架是不少開發者接觸打包工具的起點。由於前端框架提供了許多額外的語法,但瀏覽器只能解讀 JavaScript,中間必須要經過一個轉換的步驟,將開發者撰寫的程式,轉譯成瀏覽器引擎(Browser Engine)能解讀的內容。
例如 LESS、SASS 會透過 postcss 做相對應的處理;React 用的 JSX 語法、Vue 的 .vue 檔、ES6+ 的語法等等,則會透過 Babel,做程式碼的轉譯。
優化程式#
針對程式進行效能優化是非常重要的一環,也因為其繁瑣的流程設定,打包工具在優化程式這塊能充分的給予協助。
打包工具可以幫忙完成的事情包含:
- minify
- uglify
- 切分 chunk
- 樹搖(Tree Shaking)
加速開發#
例如為了減少前端請求數目的 CSS Sprite,比起用 Photoshop 慢慢對齊、計算 CSS 屬性,還不如透過打包工具的套件例如 Webpack Spritesmith,來完成圖檔合併的工作。其他像是 Webpack 的 Dev Server 內建的 Hot Reload 功能,網頁開發者就不用一直手動重新整理頁面。
加上前面的轉譯及優化程式,將原本需要手動處理的事情全部交給打包工具處理,再透過設定妥當的自動化流程,讓開發者寶貴的時間不用再去做週期性的繁瑣雜事。
結語#
在網站內容不斷增加,開發流程逐漸趨近工程化的現在,嘗試去使用、理解這些能協助建置自動化開發流程的套件,可以讓開發者有效地省下大量的時間。
原文出處#
- 原書/iThome:https://ithelp.ithome.com.tw/articles/10225915