之前写的都是js 代码分割,下面来看看css 代码分割。
先看看webpack.config.js 如下
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
mode: 'development',
devtool: "cheap-module-source-map",
devServer: {
contentBase: './bundle',
open: true
},
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /\.(png|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
outputPath: 'imgs/',
limit: 20480
}
}
}, {
test: /\.scss$/,
use: ['style-loader', {
loader: 'css-loader',
options: {
importLoaders: 2,
// modules: true
}
},
'sass-loader',
'postcss-loader']
}, {
test: /\.(eot|ttf|svg)$/,
use: {
loader: 'file-loader'
}
}, {
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}]
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'bundle')
},
optimization: {
splitChunks: {
chunks: 'async'
}
},
plugins: [new HtmlWebpackPlugin({
template: 'src/index.html'
}),new CleanWebpackPlugin()]
}
output 中配置了filename 与 path 。output 中还有一个常配置项 chunkFilename。如下。
output: {
filename: '[name].js',
chunkFilename: '[name].chunk.js',
path: path.resolve(__dirname, 'bundle')
},
那么filename 与 chunkFilename 有什么区别呢。
我们先把项目的src/index.js 改成下面这样
async function getComponent () {
const {default: _} = await import(/* webpackChunkName:"lodash" */ 'lodash')
const element = document.createElement('div');
element.innerHTML = _.join(['h','e'], '**');
return element;
}
document.addEventListener('click', () => {
getComponent().then(element => {
document.body.appendChild(element);
})
})
然后,运行打包命令。发现现在我们的文件名是这样的。js 文件分别是main.js 与 vendors~lodash.chunk.js。
入口文件(entry 中配置的文件),它对应到的是output 中的filename,因此得到的是main.js
main.js 中会引入lodash,而lodash 又被单独打包生成了一个文件。打包生成的这个文件,在整个代码的运行中,main.js 先执行,然后异步加载lodash,因此这个js 并不是个入口的js,而是一个被main.js 异步加载的间接js 文件。
那么打包生成这种间接js 文件,就会在output 中走 chunkFilename。
下面正式来讲解,如何在webpack 中进行css 代码的分割。这个得借助webpack 官网提供的一个插件 MiniCssExtractPlugin
webpack 官网 documentation > plugins > MiniCssExtractPlugin
这个插件就可以实现在webpack 中,对引入的 css 文件进行代码分割
我们改一下src/index.js 中代码,如下
import './style.css';
console.log('hello world')
再新建一个文件src/style.css,如下。
body {
background: pink;
}
再在webpack 中配置一下.css 文件的loader,如下。
{
test: /\.css$/i,
use: ['style-loader', {
loader: 'css-loader',
options: {
importLoaders: 1,
// modules: true
}
},
'postcss-loader'],
}
然后,打包代码。运行页面,会发现,页面已经有背景色了。
我们来看看打包生成的文件,只有html 与 js 文件。而html 中是没有刚刚的样式的。也就是说,webpack 在打包的时候会把我们的css 文件代码打包进 js 文件中。(CSS in JS)
那么,我们希望在打包css 文件的时候,单独将其打包在打包目录下的css 文件中,而不是打包进js 文件中。这个时候,就要借助插件 MiniCssExtractPlugin 。
我们先按照官网介绍下载,使用命令
npm install --save-dev mini-css-extract-plugin
下载好后,我们去配置webpack, 进入webpack.config.js,先require 引入这个插件,然后在plugins 中添加这个插件,再在module 中添加配置(之前我们在解析css 时最后一步是style-loader,现在不可以使用它了,将它替换为这个插件提供的loader),如下。
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: 'development',
devtool: "cheap-module-source-map",
devServer: {
contentBase: './bundle',
open: true
},
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /\.(png|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
outputPath: 'imgs/',
limit: 20480
}
}
}, {
test: /\.css$/i,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 1,
// modules: true
}
},
'postcss-loader'
],
}, {
test: /\.scss$/,
use: ['style-loader', {
loader: 'css-loader',
options: {
importLoaders: 2,
// modules: true
}
},
'sass-loader',
'postcss-loader']
}, {
test: /\.(eot|ttf|svg)$/,
use: {
loader: 'file-loader'
}
}, {
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}]
},
output: {
filename: '[name].js',
chunkFilename: '[name].chunk.js',
path: path.resolve(__dirname, 'bundle')
},
optimization: {
splitChunks: {
chunks: 'async'
}
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({})
]
}
好,我们运行打包命令。可以发现,现在生成了单独的css 文件。如下。
我们还可以给这个 plugin 配置一些参数, filename,chunkFilename 。
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[name].chunk.css'
})
]
运行打包命令,我们发现css文件的名字还是main.css 。这是因为这个css 文件是被html 直接引用的,这种情况在filename 与chunkFilename 中,它会走前者。而如果它是间接的被引用的话,它走的就是后者。
下面,我们新建一个css 文件 src/style1.css ,如下
body {
font-size: 50px;
}
然后同样在index.js 中引入
import './style.css';
import './style1.css';
console.log('hello world')
打包,会发现,webpack 将他们打包放入了同一个css文件,如下。
刚刚我们看到了,生成的css 文件没有做压缩,如果我们想生成压缩的css 代码,那么我们还需要一个插件“optimize-css-assets-webpack-plugin” :
先下载这个插件:
npm install --save-dev optimize-css-assets-webpack-plugin
下好后,我们先引入它。然后在optimization中添加minimizer ,如下。
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
mode: 'development',
devtool: "cheap-module-source-map",
devServer: {
contentBase: './bundle',
open: true
},
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /\.(png|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
outputPath: 'imgs/',
limit: 20480
}
}
}, {
test: /\.css$/i,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 1,
// modules: true
}
},
'postcss-loader'
],
}, {
test: /\.scss$/,
use: ['style-loader', {
loader: 'css-loader',
options: {
importLoaders: 2,
// modules: true
}
},
'sass-loader',
'postcss-loader']
}, {
test: /\.(eot|ttf|svg)$/,
use: {
loader: 'file-loader'
}
}, {
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}]
},
output: {
filename: '[name].js',
chunkFilename: '[name].chunk.js',
path: path.resolve(__dirname, 'bundle')
},
optimization: {
splitChunks: {
chunks: 'async'
},
minimizer: [new OptimizeCSSAssetsPlugin({})]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[name].chunk.css'
})
]
}
Done.
以上是基本的配置,还有一些复杂配置主要针对多入口的打包,请参考官方文档 https://webpack.js.org/plugins/mini-css-extract-plugin/