這裡是「Three.js學習日誌」的第21篇,這篇的內容是要講解Webpack的操作與Webpack config的編寫方法。這系列的文章假設讀者看得懂javascript,並且有Canvas 2D Context的相關知識。
首先我們要知道幾件事:
Webpack
必須要在有安裝Node.js
的環境下執行Webpack
本身需要透過CLI
介面來執行,CLI
必須要被全域安裝,或者是以devdependency
的形式安裝在node_modules
中Webpack
的CLI
會根據專案裡面的webpack.config.js
這個文件,來決定要怎麼打包專案webpack.config.js
這個檔案其實絕大多數網路上關於
Webpack
的問題討論,基本都是在討論webpack.config.js
的寫法。
所以我們接下來要簡單介紹一下怎麼樣寫一份webpack.config.js
。
webpack.config.js
的基本架構想要學習怎麼編寫webpack.config.js
,
第一步就是要先記下EOMMP這五個英文字。
E就是我們剛剛提到的Entry
O代表Output,意思是打包出來的檔案要輸出到哪裡。
第一個M代表Mode,意思是當前我們是在哪一種模式底下做打包。
第二個M就是我們剛剛提到的Module
P則代表Plugin,意思是插件。
下面這是一個常見的webpack.config.js
檔案,內容看起來的樣子。
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
//這邊是E
entry: {
main:['./src/js/index.js','./src/scss/index.scss']
},
// 這邊是O
output: {
filename: 'js/[name].[chunkhash].js', //輸出的檔案名稱格式
path: resolve(__dirname, 'build'),
},
// 這邊是M(1)
mode: 'development', // 值可以是'development'或是'production'
// 這邊是M(2)
module: {
rules: [
//...
]
},
// 這邊是P
plugins: [
new HtmlWebpackPlugin({
template: './index.html'
})
]
}
webpack.config.js
的各屬性解釋這邊請容我再解釋一下幾個關於上面這段webpack.config.js
的細節。
webpack 官方文件: 點我
entry
可以填入專案中用用到的entry files。
我們會把多個entry files構成的集合體稱為Chunk
。
這邊的main:['./src/js/index.js','./src/scss/index.scss']
換句話說就是:
「我們在這個專案中有個叫做main的chunk
,它是由index.js
和index.scss
所構成。
webpack 官方文件: 點我
我們可以在上面的output
欄位中看到path: resolve(__dirname, 'build')
這樣的寫法。
這一段的resolve
和__dirname
其實是node.js
提供的方法還有變數。
resolve
的用途是將一系列路徑或路徑段解析為絕對路徑(詳細請見文件)。
__dirname
則是代表webpack.config.js
所位於的資料夾名稱(詳細請見文件)。
webpack 官方文件: 點我
mode
表示我們當前是在哪一種模式底下做打包。
基本上可以選擇為,development(開發模式) 或 production(生產模式)。
不同的模式採用的打包方式會不同,產生的結果其細節也會不一樣。
例如我們可以選擇只在生產模式下對打包的檔案進行極小化,以減少檔案容量。
webpack 官方文件: 點我
這個部分主要是去定義當webpack
偵測到資源的時候,要怎麼去載入或編譯這個資源。
例如假設我們如果要載入.SCSS
資源。最簡單的方式就是像下面這樣設置:
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
},
]
},
我們可以注意到這邊的use
使用了三個Loader
,分別是style-loader
、css-loader
、sass-loader
。 但實際上這三個Loader
的執行順序並不是由上往下,而是由下往上。意思也就是說當webpack
偵測到SCSS
資源的時候:
sass-loader
會去把SCSS
轉譯為CSS
。CSS-loader
會去偵測CSS
內部的url()
和@import
轉換成require()
,目的是為了讓js
可以認知到CSS
內部有使用其他資源。style-loader
則是把CSS
插入DOM
中上面的寫法只是一個範例,實際上我們會因為需要應對專案的各種需求去決定module.rules
的寫法,而不同類型的資源往往也會有不同的Loader
需要使用。(而且就算同樣是要載入SCSS
資源,不同的專案需求下可能也出現好幾種寫法)
通常
Loader
會是由webpack
社群的使用者一起協力開發,不過像這樣的開源插件常常有的毛病就是:更新可能不及時(或是作者人間蒸發),所以通常要選用Loader
插件的時候,都要盡量觀察插件NPM頁面/Github Repo的更新狀況和健康程度,要升級版本時也最好都要先確認過Patch note。
webpack 官方文件: 點我
老實說plugin
這個屬性並沒有一個一定的解釋。
這個欄位就是用來讓我們導入一些插件,這些插件會在webpack
建構打包內容的時候造成影響。
這邊我們可以介紹幾個常用的插件:
webpack.DefinePlugin
: 這是一個webpack
官方內建的插件,我們可以用它來定義在不同的mode
時,產生不同的值作為環境變數。
MiniCssExtractPlugin
: 這是一個可以用來把module.rules
中偵測到的CSS
字串資源抽取出來成為獨立的CSS
檔案。
CopyPlugin
: 這是一個可以把指定資料夾裡面的內容,複製到另外一個資料夾的插件,通常會使用這個插件,大多是因為有些檔案需要在不被轉譯的情況下使用,所以必須要繞過module.rules
>Loader
的階段,直接把檔案複製到output
的路徑上。
HtmlWebpackPlugin
: 這個插件可以透過傳入Entry Chunk
的名稱,還有一個html
模板的路徑,來把Entry Chunk
的內容跟該html
模板合併輸出一個html
檔案。(意思就是可以把Entry Chunk
裡面的js
和css
塞到目標的html
裡面,變成一個有導入樣式表和JS的html
檔)。
除了上述這些以外當然還有很多其他的Plugin,狀況跟Loader一樣。
老實說 ~ 筆者其實沒有打算一步一步的去講解到底怎麼樣去寫好一個webpack
模板。
這邊可能讓大家失望了QQ
但畢竟競賽的主題不是webpack
,而是Three.js
,而且如果真的要講完「webpack-template」的開發過程,我預估大概也要講到賽程結束...
因此關於webpack
操作的細節,我只打算點到上面為止。
如果真的對如何建立自己的
webpack
模板有興趣,我很推薦你去看看這系列的影片
但是由於在接下來幾天中,筆者小弟我都會使用我自己開發的webpack
模板:「webpack-template」來進行範例的實作。所以我打算在這邊講解一下我所開發的「webpack-template」的使用方法,還有一部分的機制與原理。
Github Repository: https://github.com/mizok/webpack-template
Github
後移步至上述的Repository
地址,然後點擊畫面中的綠色"Use this template"按鈕Repository
的頁面,Github
將會直接使用筆者開發的webpack-template
作為模板來在您的帳號名下建立一個Repository
。Repository
後就可以git clone
下來。git操作的部分如果不熟悉,可以看看這邊
這個模板主要使用的技術/語言有:
webpack5
(作為主打包程序)typescript
scss
ejs
(作為主樣板語言)在Github Repo上面,您其實可以隨時檢閱英文的Readme文件,而若有問題,也歡迎隨時發布ISSUE或投遞PR ~
npm run build
: 會呼叫webpack
的 CLI
工具執行專案打包npm run dev
: 會使用內置的webpack-dev-server
來模擬專案的Hosting,用途類似VScode Live Server
npm run deploy
: 會使用gh-pages
這個插件把專案打包後部署到Github Page
在「webpack-template」中,當使用者按下Enter送出npm run build
指令後,首先會先在webpack.config.ts
裡面碰到一層判斷。
這層判斷會去根據當前每個./src/pages/
底下的EJS
檔案的命名方式,來決定要生成哪些Entry Chunks
。
例如:
index.ejs
會使程序判斷必須要生成一個被命名為index
的Entry Chunks
。index.main.ejs
會使程序判斷必須要生成一個被命名為main
的Entry Chunks
。而當如果專案備程序判定將生成了一個名為"xx"的Entry Chunks
時,我們就必須要在:
./src/ts
底下補上一個名為xx.ts
的檔案(作為ts entry
)./src/scss
底下補上一個名為xx.scss
的檔案(作為scss entry
)我們之前提到的CopyPlugin
,會把在./src/static
資料夾底下的所有檔案,一併複製到./dist/static
。
通常我們會把一些.pdf
或是.obj
、.mtl
、.gltf
等外部3D模型檔案堆放在這個資料夾,以避免它們被Loader
加載到。
其他像是有關於EJS的寫作方法、環境變數的取用之類的Tips,都可以在Repo的README進行查閱~ 這邊就不多做說明。
對於webpack
/「webpack-template」的介紹就差不多在這先打住。
明天我們將著手從一個空白的「webpack-template」模板來改造成為我們在接下來的天數會使用到的Three.js Boilerplate
!