# webpack的进阶用法(一)
# 清理构建目录:clean-webpack-plugin
由于每次构建项目前并不会自动的清理目录,会造成输出文件越来越多。这时 我们就得手动清理输出目录的文件的麻烦。
一般情况下也可以通过npm scripts设置命令行的方式进行构建目录的清理。
//package.json "scripts": { "build": "rm -rf ./dist && webpack" }
但是这样实现的方式给人感觉就不太优雅,这是,我们可以借助clean-webpack-plugin
插件的形式清除构建目录,默认会执行删除output值得的输出目录。
安装clean-webpack-plugin插件并配置
npm i clean-webpack-plugin -D
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.export = {
plugins: [
new CleanWebpackPlugin()
]
}
# CSS3前缀补全:autoprefixer
由于浏览器标准并没有统一,例如Chrome对应的webkit,Firfox对应的Geko,IE对应的 Trident和Opera对应的Presto。所以部分的CSS3特性需要补全前缀已实现浏览器的兼容。
通过autoprefixer后处理的方式实现自动的CSS前缀补全。
安装postcss-loader和autoprefixer并配置。
npm i postcss-loader autoprefixer -D
通过package.json中browsersList字段配置需要兼容的浏览器版本号。
"browserslist": [
"last 2 version",
">1%",
"IOS 7"
]
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
}
]
}
}
根目录新建postcss.config.js使用autoprefixer插件。
module.exports = {
plugins: [
require('autoprefixer')
]
}
# px自动转rem:px2rem-loader
由于移动端设备的普及及尺寸的不一致,所以需要实现不同尺寸的适配就需要 通过CSS媒体查询等方式实现响应式布局。但是这样就需要为不同的尺寸设置样式, 相对繁琐,而随着W3C对移动设备尺寸的推进,提出了rem,其实现了页面渲染时 能根据根元素font-size值进行相对大小的设置。
通过px2rem-loader就能实现将px转换为rem实现移动端设备尺寸的适配。
1、安装px2rem-loader和lib-flexible(计算根元素font-size)
npm i px2rem-loader -D
npm i lib-flexible -S
2、配置webpack
module.exports = {
module: {
rules: [
{
loader:'px2rem-loader',
options: {
remUnit: 75, //rem相对px的转换,1rem = 75px
remPrecesion:8 // rem后的小数位数
}
}
]
}
}
# 静态资源内联
资源内联可以实现页面框架的初始化脚本,首屏css内联可以避免页面闪动; 小图片或者字体内联可以减少HTTP网络请求数量等。
HTML和JS内联可借助raw-loader实现内联。
安装raw-loader@0.5.1并设置内联
在index.html页面引入meta标签
// html-webpack-plugin默认是ejs模板的
${ require('raw-loader!./meta.html') }
在index.html引入flexible.js文件
<script>${ require('raw-loader!babel-loader!../node_modules/lib-flexible/flexible.js') }</script>
CSS内联可借助style-loader或者html-inline-css-webpack-plugin。
module.exports = {
module: {
rules: [
{
test:/\.less$/,
use: [
{
loader: 'style-loader',
options: {
insertAt: 'top',//样式插入到head
singleton: true //将所有style标签合并一个
},
},
'css-loader',
'less-loader'
]
}
]
}
}
# 多页面打包
多页面的优势可以做到页面间解耦,因为会单独打包成独立的入口文件;并且对seo更加友好(传闻,有待考究, 个人觉得除了可以多配置meta关键字暂时没有觉得seo的其他优势)。
多页面打包的通用方案一般通过设置entry多入口结合html-webpack-plugin动态获取入口文件。并借助glob 库实现动态匹配规则获取匹配的目录,一般按照一定的源码项目规则,例如每个页面对应的入口文件 为src对应的文件夹下的index.js,模板为src对应的文件夹下的index.html。
安装glob并配置webpack
npm i glob -D
const glob = require('glob')
const setMPA = () => {
const entry = {}
const htmlWebpackPlugins= []
// 获取entry入口文件
const entryFiles = glob.sync(path.join(__dirname,'./src/*/index.js'))
console.log(entryFiles)
Object.keys(entryFiles).map(
(index) => {
const entryFile = entryFiles[index]
const match = entryFile.match(/src\/(.*)\/index\.js/)
const pageName = match && match[1]
entry[pageName] = entryFile
htmlWebpackPlugins.push(
new HtmlWebpackPlugin({
template: path.join(__dirname, `src/${pageName}/index.html`),
filename: `${pageName}.html`,
chunks: [pageName],
inject: true,
minify: {
html5: true,
collapsableWhitespace: true,
preserveLineBreaks: false,
minifyJS: true,
minifyCSS: true,
removeComments: true
}
})
)
}
)
return {
entry,
htmlWebpackPlugins
}
}
const { entry, htmlWebpackPlugins } = setMPA()
module.exports = {
entry: entry,
plugins: [
htmlWebpackPlugins
]
}
# sourcemap
通过source map可以定位到源代码并进行代码调试;通过开发环境开启source map,线上 环境关闭可以实现开发调试和避免源代码泄漏。
启动source map配置
// webpack.dev.js
module.exports = {
devtool: 'source-map'
}
# source map 类型
devtool | 首次构建 | 二次构建 | 是否适合生产环境 | 可以定位的代码 |
---|---|---|---|---|
(none) | 非常快速 | 非常快速 | yes | 打包后的代码 |
eval | 非常快速 | 非常快速 | no | webpack生产的一个个模块代码 |
cheap-source-map | 比较快 | 中等 | no | 经过loader转换过的代码(仅限行) |
source-map | 慢 | 慢 | no | 原始源代码 |
更多可参看devtool:https://www.webpackjs.com/configuration/devtool/
# 公共资源提取:SplitChunksPlugin
通过公共资源的提取和一些基础库分离,可以把通用资源打包成一个来实现 减少加载资源,并且基础库的分离并通过cdn方式引入,也进一步减少资源加载。
通过html-webpack-externals-plugin进行基础库的分离,并且通过模板引入
npm i html-webpack-externals-plugin -D
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin')
module.exports = {
plugins: [
new HtmlWebpackExternalsPlugin({
externals: [
{
module:'react',
entry:'https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/cjs/react.production.min.js',
global:'React'
},
{
module:'react-dom',
entry:'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/cjs/react-dom.production.min.js',
global:'ReactDOM'
}
]
})
]
}
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
${ require('raw-loader!./meta.html') }
<title>index</title>
<script>${ require('raw-loader!babel-loader!../../node_modules/lib-flexible/flexible.js') }</script>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
</body>
</html>
其中提到,webpack4.x版本后就剔除了之前一直使用的CommonsChunksPlugin进行 模块抽取的插件,这个插件存在的原因就有由于共用模块较多的时候会致使代码包 过大,不利于首次加载等。因而,webpack4.x就内置了SplitChunksPlugin进行公共 脚本的分离和基础包的分离,该插件实现了懒加载模块的通用模块单独抽取,而并不会抽取到父级 上等优化性能。
利用SplitChunksPlugin进行基础包分离,分离react和react-dom,并引入到对应的模板中
//webpack配置
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /(react|react-dom)/,
name: 'vendors',
chunks: 'all'
}
}
}
}
}
webpack配置HtmlWebpackPlugin插件添加chunks包名
new HtmlWebpackPlugin({
template: path.join(__dirname, `src/${pageName}/index.html`),
filename: `${pageName}.html`,
chunks: ['vendors', pageName],
inject: true,
minify: {
html5: true,
collapsableWhitespace: true,
preserveLineBreaks: false,
minifyJS: true,
minifyCSS: true,
removeComments: true
}
})
利用SplitChunksPlugin进行公共脚本的分离,并添加到模板中
//webpack配置
module.exports = {
optimization: {
splitChunks: {
minSize: 0, // 设置最小size多少是才进行通用分离
cacheGroups: {
name:'commons',
chunks: 'all', // all:所有引入的库进行分离;async:异步引入的库进行分离(默认);initial:同步引入的库进行分离
minChunks:2//设置默认最少多少个引入才进行通用分离
}
}
}
}
//webpack配置
new HtmlWebpackPlugin({
chunks: ['commons', pageName],
})
更多配置可参考:https://www.webpackjs.com/plugins/split-chunks-plugin/
demo代码可查看:https://github.com/PCAaron/blogCode/tree/master/webpack/webpack-improve
# 推荐阅读
什么是source map?:http://www.ruanyifeng.com/blog/2013/01/javascript_source_map.html
CommonsChunksPlugin与SplitChunksPlugin:https://www.jianshu.com/p/a1ccd6d1b4ba