[note] Webpack 學習筆記
此篇為各筆記之整理,非原創內容,內容主要參考自 webpack 官方網站:Webpack Guides。
$ npm install webpack webpack-cli --save-dev
$ npx webpack # 預設會以 ./src/index.js 為 entry;以 ./dist/main.js 為 output。
# 預設就會吃 webpack.config.js,因此除非檔名有不同,否則可以省略
$ npx webpack --config webpack.config.js
$ npx webpack -p # build in production
$ npx webpack-dev-server --open # run in dev-server
$ npm run build -- --mode production --display-used-exports # 顯示有用到的 exports
- webpack-cli options @ github
- webpack-template @ pjchender github
- Webpack 4 常用設定 @ PJCHENder gist
概念(Concept)
過去我們會將套件直接從 <head></head>
中透過 <script src="">
載入,這種做法稱作「隱式依 賴關係(implicit dependency)」,因為在 index.js
中沒有宣告它需要使用什麼套件,而是預期它會在全域載入。但這麼做有幾個缺點:
- 沒辦法清楚看到程式碼依賴外部的函式庫。
- 如果依賴不存在,或者引入順序錯誤,應用程序將無法正常運行。
- 如果依賴被引入但是並沒有使用,瀏覽器將被迫下載無用代碼。
因此,我們可以用 webpack 來管理我們的程式碼。
Webpack 包含幾個核心部分:
- Entry
- Output
- Loaders
- Plugins
- Mode
- Browser Compatibility
Concepts @ Webpack Concept
Entry
告訴 webpack 要使用的進入點是哪隻檔案,預設會使用 ./src/index.js
。
Output
要把 bundle 過的檔案放在哪裡及其檔名,預設會使用 /dist/main.js
。
Loaders(modules)
雖然 webpack 本來就可以了解 JavaScript 和 JSON 檔,但實際的應用程式中仍包含許多其他類型的檔案(例如,圖檔),這時候會需要透過 loader 來處理 JS / JSON 以外的檔案類型。在設定時,是透過 module.rules
的屬性來設定。
// https://webpack.js.org/concepts/
module.exports = {
// ...
module: {
rules: [{ test: /\.txt$/, use: 'raw-loader' }],
},
};
特別留意使用 regex 來選擇要套用該 loader 的檔案類型是,不要加上單引號或雙引號,也就是使用 /\.txt$/
,而不是 '/\.txt$/'
或 "/\.txt$/"
。
Plugins
Loaders 是用來處理特定類型的檔案,而 plugins 則可以用來執行某些功能更廣泛的任務,像是打包最佳化(bundle optimization)、資源管理(asset management)和注入環境變數。
// https://webpack.js.org/concepts/
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
module.exports = {
module: {
rules: [{ test: /\.txt$/, use: 'raw-loader' }],
},
plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
};
由於你可以根據需求在設定檔的不同位置重複使用該 plugin,因此在使用 plugin 是需使用 new
來確保每個 plugin 是獨立的 instance。
Mode
預設值是 production
,還可以是 development
或 none
。
透過這個設定,webpack 會自動啟用最佳化的策略。
Module, chunk, and bundle
Module: Discrete chunks of functionality that provide a smaller surface area than a full program. Well-written modules provide solid abstractions and encapsulation boundaries which make up a coherent design and clear purpose.
Chunk: This webpack-specific term is used internally to manage the bundling process. Bundles are composed out of chunks, of which there are several types (e.g. entry and child). Typically, chunks directly correspond with the output bundles however, there are some configurations that don't yield a one-to-one relationship.
Bundle: Produced from a number of distinct modules, bundles contain the final versions of source files that have already undergone the loading and compilation process.
chunk 是在 webpack process 中的許多 modules;bundle 則是射出的 chunk 或許多 chunks。
注意:在 Webpack 4 中有部分 API 有變動,若下面文章有無法使用的,可以參考 webpack 4 announcement @ GitHub issues 查看更新項目。
載入與執行設定檔
Webpack 的設定檔(configuration file)就是一個匯出為物件的 JS 檔案。
Configuration @ Webpack Concept
安裝
$ npm install webpack webpack-cli webpack-dev-server --save-dev
可以在 package.json
中加入設定檔:
// package.json
"scripts": {
"build:dev": "webpack --config webpack.config.js",
"start": "webpack-dev-server --config webpack.config.js"
}
使用
# 使用 npm
$ npm run start
# 使用 npx
$ npx webpack
Entry and Output
在 webpack 的設定檔中,有兩個最基本的必填屬性,分別是 entry
和 output
。
- 在
context
中,可以設定要讀取檔案的根資料夾(base directory),預設是使用設定檔放置的資料夾。 - 在
entry
中,我們可以放相對路徑。預設是src/index.js
。 - 在
output
的path
中,我們則是一點要放絕對路徑, 在這裡我們可以使用 Node 提供的 path module 來取得當前資料夾的絕對路徑,慣例上會使用build
或dist
。預設是dist/
。[name]
,它會被 entry 中的 key 換掉[chunkhash]
則可讓瀏覽器知道是否需要重新載入檔案[filename]
在慣例上則是會使用bundle.js
// webpack.config.js
const path = require('path');
const config = {
mode: 'development',
context: path.resolve(__dirname, 'src'),
entry: './index.js', // 若沒設定 context 則要寫 `./src/index.js`
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'foo.bundle.js',
},
};
module.exports = config;
- Entry Points @ Webpack Concept
- Output @ Webpack Concept
- Entry and Context @ Webpack Configuration
多個 entry 和多個 output bundles
Output Management @ Webpack > Guides
設定兩個 entry,會根據 entry 的 Key 產生兩隻檔案:app.bundle.js
和 print.bundle.js
// webpack.config.js
const path = require('path');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
// publicPath: path.resolve(__dirname, 'dist')
},
};
清除 dist 資料夾
在 Webpack 5 中,只需要 output
項目中加上 clean: true
即可,不需要在額外安裝 plugin:
diff --git a/webpack.config.js b/webpack.config.js
index 3a50e6d..0ac5f88 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -10,6 +10,7 @@ const config = {
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
+ clean: true,
},
devServer: {
contentBase: './dist',
Loader
Loader @ Webpack Concept
在 webpack 中可以套用許多不同的 modules
,最常用的 modules 是各種 loaders
, loader
的功用就是告訴 webpack 該如何處理匯入的檔案,通常是 Javascript(例如,babel-loader),但 webpack 不限於處理 Javascript,其他資源檔像是 Sass(sass-loader),圖片等也都可以處理,只要提供對應的 loader。
同時 loader 也可以串連使用,概念上類似於 Linux 中的 pipe,A Loader 處理完之後把結果交給 B Loader 繼續轉換,以此類推,但要特別留意,串連的時候則是以反方向執行(由右至左)。
Loader 執行的順序是從陣列最後一個元素開始,往第一個元素的方向執行。
Loading CSS(單純載入 CSS)
如果希望能在 JavaScript 中 import CSS 檔的話,需要安裝與設定對應的 loader。
安裝
npm install --save-dev style-loader css-loader
css-loader
是讓我們可以在 JavaScript 中使用import
載入 CSS 檔style-loader
是把 CSS 樣式載入 HTML 中
使用
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.css$/i, // 記得不用加上雙引號
// loader 的順序很重要,會先執行 css-loader 接著才是 style-loader
use: [
'style-loader', // 是把 CSS 樣式載入 HTML 中
'css-loader', // 在 JavaScript 中可以 `import` 載入 CSS 檔
],
},
],
},
};
效果
從 inspector 中,我們可以看到所撰寫的 CSS 樣式會被注入到 index.html
的 <head>
中:
Loading SCSS / SASS
- 不需要使用 SASS:只是要打包 CSS 檔案的話,只需透過
style-loader
和css-loader
,做法可參考 Asset Management - Loading CSS @ Webpack Guide,如此 webpack 會在該頁面將特定的 CSS 灌入<head></head>
內。 - 需要使用 SASS :則須再透過
sass-loader
和node-sass
。
- 需要安裝 file-loader 並進行相關設定後才能處理圖片資源。
- 若希望抽成 css 檔,須透過 extract-text-webpack-plugin ,但目前 webpack 4 仍不支援。
安裝
# 安裝和 sass/scss 有關的 loader
npm install --save-dev sass-loader node-sass
# 有需要的話也需要搭配 css-loader 和 style-loader
npm install --save-dev css-loader styled-loader
sass-loader
讓我們可以在 JS 檔中使用import
匯入 SCSS 檔- 可能會需要搭配
style-loader
或mini-css-extract-plugin
- 一定要先執行
sass-loader
才能執行css-loader
,最後才是styled-loader
(或mini-css-extract-plugin
)。由於 loader 載入的順序是逆轉的,因此sass-loader
會放在陣列的最後面。
設定
// webpack.config.js
module: {
rules: [
{
test: /\.(scss|css)$/i,
// loader 的順序很重要,一定要先從 sass-loader 開始,接著 css-loader,最後 style-loader
use: ['style-loader', 'css-loader', 'sass-loader'],
},
];
}