Webpack 4 學習筆記(三) - 編譯 CSS 文件
紀錄如何使用 Webpack 編譯 CSS 文件,內容包括
- 將 CSS 注入 HTML 文件
- 把 CSS 從 JavaScript 抽離,輸出獨立檔案
- 壓縮 CSS 文件
- 壓縮 JavaScript 文件
1. 將 CSS 注入 HTML 文件
安裝 CSS-loader
要使用 Webpack 編譯 CSS 需要使用以下兩個套件
npm install css-loader style-loader --save-dev
- css-loader 幫助 Webpack 讀取 CSS 檔案
- style-loader 將編譯好的 CSS 樣式整合到 HTML 文件上,因此不需要再額外連結 CSS 的檔案,難怪 Webpack 會用注入的名詞。
修改 Webpack 設定檔
編輯 webpack.config.js
檔案,在 rules 裡面新增 CSS 的規則。
// Node.js 內建用來處理路徑的模組
const path = require('path');
module.exports = {
// Webpack 的進入點
entry: './src/index.js',
// Webpack 輸出點
output: {
// 輸出的檔案名稱
filename: 'main.js',
// 輸出的檔案位置
path: path.resolve(__dirname, './dist/'),
},
module: {
rules: [
// Babel
{
test: /\.(js)$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
// CSS
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
};
Loader 的引用順序
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
注意: Webpack 的 Loader 引用順序是從右到左,很重要,順序錯誤就無法執行 先使用 css-loader 讀取檔案後 再使用 style-loader 將檔案注入 HTML 頁面中
注入 CSS 到 HTML 文件
在 src
資料夾中,新增兩個 CSS 檔案
- style.css
- reset.css
style.css 的樣式內容,簡單為 H1 標籤加上紅色
h1{
color: red;
}
reset.css 的內容,使用 Eric Meyer 的 CSS reset
在 index.js 檔案的最上面 import 這兩個 CSS 檔案
import '../src/reset.css'
import '../src/style.css'
const Name = ['Mike', 'Jacky', 'Andy', 'Scars']
Name.forEach((obj, idx)=> console.log(`${idx} => ${obj}`))
所以在 src
目錄中會有以下這些檔案
在 index.html 中,加入 H1 標籤並填寫內容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>Hello</h1>
<script src="./dist/main.js"></script>
</body>
</html>
呼叫 Webpack 進行編譯
npx webpack --mode development
使用瀏覽器檢查 Element 資訊,兩個 CSS 檔案都被注入 HTML 文件的 style 標籤裡面。
2. 抽離 CSS 輸出獨立檔案
從 Webpack 4 開始,官方推荐使用 mini-css-extract-plugin
來打包 CSS 文件,原因是extract-text-webpack-plugin
插件已經被棄用了。
如果將 CSS 抽離變成獨立的檔案,就不可以使用 style-loader 注入 CSS 到 HTML 文件中,需要自己 link 文件。
安裝 mini-css-extract-plugin 插件
npm install mini-css-extract-plugin --save-dev
修改 Webpack 設定檔
- 引入 mini-css-extract-plugin 插件
- 加入 plugins 屬性,設定 mini-css-extract-plugin 的輸出方式
修改 rules 裡面 CSS 的 loader 設定,將 style-loader 改成 MiniCssExtractPlugin.loader
// Node.js 內建用來處理路徑的模組 const path = require('path'); // 1. 引入 MiniCssExtractPlugin const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { // Webpack 的進入點 entry: './src/index.js', // Webpack 輸出點 output: { // 輸出的檔案名稱 filename: 'main.js', // 輸出的檔案位置 path: path.resolve(__dirname, './dist/'), }, // 2. 加入 plugins 屬性,設定 mini-css-extract-plugin 的輸出方式 plugins: [ new MiniCssExtractPlugin({ filename: './css/[name].bundle.css', }), ], module: { rules: [ // Babel { test: /\.(js)$/, exclude: /(node_modules)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], }, }, }, // CSS // 3. 修改 rules 裡面 CSS 的 loader 設定,將 style-loader 改成 MiniCssExtractPlugin.loader { test: /\.css$/, //use: ['style-loader', 'css-loader'], 註解掉不使用原本的設定 use: [MiniCssExtractPlugin.loader, 'css-loader'], }, ], }, };
開始編譯輸出 CSS 檔
呼叫 Webpack 進行編譯,指令與先前相同
npx webpack --mode development
準備開始編譯,目前的檔案結構是,一個 index.js 裡面引入兩個 CSS 檔案。編譯之後會將兩個 CSS 整合成一個檔案,輸出到 ./dist/css/
目錄下,檔名是 main.bundle.css
,檢查檔案內容的確包含 style.css
與 reset.css
的樣式。
在 index.html 文件 link 編譯出來的 CSS , 可以順利在瀏覽器中使用
3. 壓縮 CSS 文件
Webpack 預設的 production mode 只能壓縮 JavaScript 文件,所以需要安裝外掛來壓縮 CSS 文件。
安裝 optimize-css-assets-webpack-plugin 插件
npm install optimize-css-assets-webpack-plugin --save-dev
修改 Webpack 設定檔
- 引入 OptimizeCSSAssetsPlugin 外掛
加入 optimization 屬性,設定 minimizer 為 OptimizeCSSAssetsPlugin
// Node.js 內建用來處理路徑的模組 const path = require('path'); // 1. 引入 MiniCssExtractPlugin const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 1. const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); module.exports = { // Webpack 的進入點 entry: './src/index.js', // Webpack 輸出點 output: { // 輸出的檔案名稱 filename: 'main.js', // 輸出的檔案位置 path: path.resolve(__dirname, './dist/'), }, // 2. optimization: { minimizer: [new OptimizeCSSAssetsPlugin()], }, // 2. 加入 plugins 屬性,設定 mini-css-extract-plugin 的輸出方式 // filename 使用[name]變數,它會自動抓取你在 entry 裡的屬性名稱來命名檔案 plugins: [ new MiniCssExtractPlugin({ filename: './css/[name].bundle.css', }), ], module: { rules: [ // Babel { test: /\.(js)$/, exclude: /(node_modules)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], }, }, }, // CSS // 3. 修改 rules 裡面 CSS 的 loader 設定,將 style-loader 改成 MiniCssExtractPlugin.loader { test: /\.css$/, //use: ['style-loader', 'css-loader'], 註解掉不使用原本的設定 use: [MiniCssExtractPlugin.loader, 'css-loader'], }, ], }, };
執行編譯
呼叫 Webpack 進行編譯,由於要壓縮 CSS 檔案,因此指令要使用 production 模式
npx webpack
檢查編譯後的結果
CSS 成功被壓縮了,但是原本的 Webpack 預設的 JavaScript 壓縮卻失效,為什麼?
因為 optimization.minimizer 會將預設值覆蓋掉,變成沒有 JavaScript 的壓縮設定,很瞎吧!
所以我們還要加上另一個套件。
4. 壓縮 JavaScript 文件
安裝 terser-webpack-plugin 插件
npm install terser-webpack-plugin --save-dev
調整 Webpack 設定
- 引入 terser-webpack-plugin 模組
設定 optimization.minimizer
// Node.js 內建用來處理路徑的模組 const path = require('path'); // 抽離 CSS 檔案的套件 const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 壓縮 CSS 的套件 const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); // 壓縮 JS 的套件 const TerserJSPlugin = require('terser-webpack-plugin'); module.exports = { // Webpack 的進入點 entry: './src/index.js', // Webpack 輸出點 output: { // 輸出的檔案名稱 filename: 'main.js', // 輸出的檔案位置 path: path.resolve(__dirname, './dist/'), }, // 在生產模式會壓縮 CSS 與 JS 檔案 optimization: { minimizer: [new TerserJSPlugin(), new OptimizeCSSAssetsPlugin()], }, // 設定 CSS 的輸出方式 // 使用[name]變數,代表使用 entry 文件的檔名來命名檔案 plugins: [ new MiniCssExtractPlugin({ filename: './css/[name].bundle.css', }), ], module: { rules: [ // Babel { test: /\.(js)$/, exclude: /(node_modules)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], }, }, }, // CSS // style-loader 會將 CSS 注入 HTML // MiniCssExtractPlugin.loader 會將 CSS 抽離成獨立檔案 { test: /\.css$/, //use: ['style-loader', 'css-loader'], use: [MiniCssExtractPlugin.loader, 'css-loader'], }, ], }, };
進行編譯
呼叫 Webpack 進行編譯,指令使用 production 模式
npx webpack
檢查編譯後的結果
JavaScript 與 CSS 的檔案都順利被壓縮了!!