Webpack4 - Javascript import CSS file & CSSminify
- August 26, 2019
在這之前有介紹 Webpack 基礎設定,以及搭配 Babel 設定介紹,這次我們來介紹如何在 Javascript 引入 CSS 檔案做開發。
首先我們先來練習最基礎的引入 CSS
安裝 CSS
$ npm install css-loader style-loader --save-dev
css-loader
幫我們把 CSS 檔案透過 @import 或是 url()的方式載入到 Javascript 內style-loader
將載入好的 CSS 放置 html 讓瀏覽器可以讀取
設定 CSS
編輯 webpack.config.js
新增 module
//webpack.config.js
module.exports = {
context: path.resolve(__dirname, 'src'),
entry: './index.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'index.bundle.js',
},
module: {
rules: [
{
test: /\.(js)$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
};
注意:webpack 會從右向左執行,依據上面執行解析大概的意思是:當載入.css 檔案時,先用 css-loader 解析,再用 style-loader 將 CSS 加入到頁面中,順序要注意是否正確!!
執行編譯
新增 CSS 檔案
隨便打一些內容測試
index.js import CSS
$ npm run start
看看在網頁上呈現的效果
CSS 成功引入至 index.html 中
雖然大家都知道內聯 CSS 是優化的作法(把 CSS style 直接放入 head),可是維護上總是不方便,我希望 另外獨立出來一個 CSS 檔案引入,這時候可以使用 mini-css-extract-plugin
mini-css-extract-plugin
是用來將每個由 webpack 產生內含有 css 的 js 檔案轉成 css 檔
安裝
$ npm install mini-css-extract-plugin --save-dev
接下來我會介紹兩種設定
第一種,各別輸出在 js import css 檔案
編輯 webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
context: path.resolve(__dirname, 'src'),
entry: {
index: './index.js',
app: './app.js',
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].bundle.js',
},
plugins: [
new MiniCssExtractPlugin({
filename: './css/[name].bundle.css',
}),
],
module: {
rules: [
{
test: /\.(js)$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
};
此範例是多檔輸入輸出,可以回顧看 webpack 基礎設定
- 引入 MiniCssExtractPlugin 模組
- 加入 plugins 設定 ,輸出 CSS 檔案
- 將原本 style-loader 改成 MiniCssExtractPlugin.loader
註:filename 使用[name]變數,它會自動抓取你在 entry 裡的屬性名稱來命名檔案
執行編譯
這邊我使用兩個 js 跟兩個 css 來作範例
JS 檔案
index.js 引入了一支 CSS
app.js 引入了兩支 CSS
CSS 檔案
分別寫不同的內容
$ npm run start
編譯出來的結果
可以看到 dist 裡面多了 CSS 資料夾,並且編譯出兩支 CSS 檔案(根據 JS 裡面引入的 CSS 打成一包)
第二種,將所有在 js import css 檔案,輸出一支 CSS
編輯 webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
context: path.resolve(__dirname, 'src'),
entry: {
index: './index.js',
app: './app.js',
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].bundle.js',
},
optimization: {
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true,
},
},
},
},
plugins: [
new MiniCssExtractPlugin({
filename: './css/[name].bundle.css',
}),
],
module: {
rules: [
{
test: /\.(js)$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
};
加入 optimization.splitChunks
強制 CSS 打成一包
註:optimization.splitChunks 是在 webpack 4 新出針對模組做優化的設定( 替代了 CommonsChunkPlugin)
編譯出來的結果
會發現多了兩個檔案,CSS 是我們要的,至於那個多出來的 JS 是沒有用處的,目前查詢的結果應該算是 webpack 4 splitChunks 的小 Bug,看 Issues 上討論的結果,目前應該是沒有好的解決方法,只能手動刪除檔案 ( 算是最笨的方法 ( 笑,或忽略它不用管。
註:此問題應該會在 webpack 5 修復
Issues:
Single-file configuration emits JS assets in its own chunk group #85
Don’t output empty JS files #151
接下來介紹如何 CSS minify ,在 webpack 4 筆記(1) 有提到 webpack 有一個執行參數 --mode production
,將檔案給壓縮跟優化。但他只能壓縮 JS,卻不能壓縮 CSS 檔案。
這時候要另外使用 optimize-css-assets-webpack-plugin
optimize-css-assets-webpack-plugin
用於優化\最小化 CSS 內容
安裝
$ npm install optimize-css-assets-webpack-plugin --save-dev
設定
編輯 webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
context: path.resolve(__dirname, 'src'),
entry: {
index: './index.js',
app: './app.js',
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].bundle.js',
},
optimization: {
minimizer: [new OptimizeCSSAssetsPlugin()],
},
plugins: [
new MiniCssExtractPlugin({
filename: './css/[name].bundle.css',
}),
],
module: {
rules: [
{
test: /\.(js)$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
};
- 引入 optimize-css-assets-webpack-plugin 模組
- 設定 optimization.minimizer
執行編譯
注意這邊要執行 deploy ( npm 指令可閱 Webpack 基礎設定 )
$ npm run deploy
CSS 成功被壓縮了,可是 JS 壓縮卻失效,為什麼?
因為 optimization.minimizer
會將預設值覆蓋掉,minimizer
沒有 JS 壓縮的設定,導致 JS 壓縮並沒有執行,所以我們還要加上另一個套件。
terser-webpack-plugin
用於壓縮 JavaScript
安裝
$ npm install terser-webpack-plugin --save-dev
設定
編輯 webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
module.exports = {
context: path.resolve(__dirname, 'src'),
entry: {
index: './index.js',
app: './app.js',
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].bundle.js',
},
optimization: {
minimizer: [new TerserJSPlugin(), new OptimizeCSSAssetsPlugin()],
},
plugins: [
new MiniCssExtractPlugin({
filename: './css/[name].bundle.css',
}),
],
module: {
rules: [
{
test: /\.(js)$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
};
- 引入
terser-webpack-plugin
模組 - 設定
optimization.minimizer
執行編譯
$ npm run deploy
CSS JS 都有順利壓縮,編譯成功!!
題外話
在使用 mini-css-extract-plugin
之前,很多網站推薦使用 extract-text-webpack-plugin
,使用後卻會跳出 npm ERR!
經查詢後發現,原來
webpack 4 已棄用 extract-text-webpack-plugin
結語
寫到現在,真的覺得 webpack 比 gulp 還難學,查詢了很多文章,經過多項測試,才刪減出給大家最簡潔的使用方法,其實還有非常多小細節沒有介紹到,很多我自己也都還沒有理解 XD, 如果有說明錯誤或不明白的地方,麻煩再留言告知我,謝謝!
參考資料
optimize-css-assets-webpack-plugin
Webpack 實作入門 2:打包 CSS / SCSS 與 加入 Bootstrap