在上一篇文章中我給大家分享了預處理器(loader),裏面講到了style-loader 和css-loader,有關樣式引入的問題,但是上面的樣式文件只是引入到style標籤裏面,並不是我想要的樣式文件獨立分離。
如果想了解有關css-loader和style-loader可以參考以下地址:
Webpack實戰(四):教教你如何輕鬆搞定-預處理器(loader)
通過js引入樣式文件只是把樣式添加到style標籤內,而不是引入一個獨立的css文件,一般來說,在生產環境下,我們希望樣式存在於CSS文件中而不是style標籤中,因爲文件更有利於客戶端進行緩存。
Webpack社區有專門的插件:extract-text-webpack-plugin(適用於Webpack 4之前版本)和mini-css-extract-plugin(適用於Webpack 4及以上版本),它們就是專門用於提取樣式到CSS文件的。
- extract-text-webpack-plugin
extract-text-webpack-plugin安裝命令代碼如下:
# for webpack 3
npm install --save-dev extract-text-webpack-plugin
# for webpack 2
npm install --save-dev extract-text-webpack-plugin@2.1.2
# for webpack 1
npm install --save-dev extract-text-webpack-plugin@1.0.1
由於webpack版本不一樣,extract-text-webpack-plugin安裝的出來版本的也不一樣。
配置代碼如下:
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const path = require('path')
module.exports = {
context: path.join(__dirname, './src'),
entry: {
index: './index.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: 'index.js'
},
mode: 'development',
module: {
rules: [
{
test: /\.css$/i,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
}),
exclude: /node_modules/
},
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: [
[
'env', {
modules: false
}
]
]
}
}
}
],
},
plugins: [
new ExtractTextPlugin("styles.css") //提取後css文件名稱
]
}
在module.rules中我們設置了處理CSS文件和js文件的規則,其中css配置的use字段並沒有直接傳入loader,而是使用了插件的extract方法包了一層。內部的fallback屬性用於指定當插件無法提取樣式時所採用的loader,use(extract方法裏面的)用於指定在提取樣式之前採用哪些loader來預先進行處理。除此之外,還要在Webpack的plugins配置中添加該插件,並傳入提取後的資源文件名。
由於我電腦項目裏裝的4.0以上的webpack版本,這裏不再做打包測試。
樣式的提取是以資源入口開始的整個chunk爲單位的。比如我們的應用從index.js開始引入了幾百個模塊,這些模塊都引入了它們各自的樣式文件,但是最終生成的c s s文件只有一個,因爲它們都來自同一個入口模塊。上面我們講styles.css作爲文件名傳給extract-text-webpack-plugin,但是當項目有多個入口的時候就會發生重名問題。就像我們前面動態配置的output.filename一樣。這裏我們也將要對插件提取的css文件使用類似模版的命名方式。
下面是入口的index.js和about.js
// index.js
import './index.css'
// about.js
import './about.css'
we bpack.config.js配置部分代碼如下
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const path = require('path')
module.exports = {
context: path.join(__dirname, './src'),
entry: {
index: './index.js',
about: './about.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
mode: 'development',
module: {
rules: [
{
test: /\.css$/i,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
}),
exclude: /node_modules/
},
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: [
[
'env', {
modules: false
}
]
]
}
}
}
],
},
plugins: [
new ExtractTextPlugin("[name].css") //提取後css文件名稱
]
}
我們使用[name].css來動態生成c s s文件名,name爲即entry中我們爲每一個入口分配的名字(index、about),由此可以推出[name]指的是chunk(chunk是對一組有依賴關係的模塊的封裝)的名字。
- mini-css-extract-plugin
mini-css-extract-plugin 是 extract-text-webpack-plugin的升級版本,它擁有更多的特性和更好的性能。最突出的一條就是 mini-css-extract-plugin支持按需加載css,舉個例子,a.js通過import()函數異步加載了b.js,b.js裏面加載了style.css,那麼style.css最終只能被同步加載(通過HTML的link標籤)。但是現在mini-css-extract-plugin會單獨打包出一個0.css(假設使用默認配置),這個CSS文件將由a.js通過動態插入link標籤的方式加載。
首先安裝mini-css-extract-plugin
npm install --save-dev mini-css-extract-plugin
下面是入口的index.js和index2.js
// index.js
import './common.css'
// index2.js
import './style.css'
web pack.config.js配置如下:
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
context: path.join(__dirname, './src'),
entry: {
index: './index.js',
index2: './index2.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
mode: 'development',
module: {
rules: [
{
test: /\.css$/i,
use: [{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
},
}, 'css-loader'],
exclude: /node_modules/
},
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: [
[
'env', {
modules: false
}
]
]
}
}
}
],
},
plugins: [new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css'
})],
}
打包效果如下:
可以發現最後輸出兩個c s s文件名分別爲chunk 名,index.css,index2.css
在配置上mini-css-extract-plugin與extract-text-webpack-plugin有以下幾點不同
- loader規則設置的形式不同,並且mini-css-extract-plugin支持配置publicPath,用來指定異步CSS的加載路徑。
- 不需要設置fallback。
- 在plugins設置中,除了指定同步加載的CSS資源名(filename),還要指定異步加載的CSS資源名(chunkFilename)。
總結
Webpack樣式文件分離,主要用兩個插件mini-css-extract-plugin與extract-text-webpack-plugin,它們有着各自的特點,但是如果webpack版本4.0以上建議用mini-css-extract-plugin,它擁有更多的特性,特別是按需加載cs s,解決了一些性能問題。
如果想了解更多,請掃描二維碼: