前端构建工具从grunt、glup+fis、rollup,到现在伴随mvvm大热的webpack也迎来了4x的版本(parcel势头也很猛,将来可期~)。熟练掌握webpack也成了中高级前端的加分项,甚至是必备项。任什么时候候,无论构建工具怎么变,其本质的构建思想是不变的,例如咱们须要在开发环境有热更新,在生成环境须要压缩文件,抽离公共库等。css
本文旨在分享快速掌握webpack4的核心内容,一块儿快速通关,争取人人都是webpack配置工程师~~html
// 查看curl的命令帮助
curl --help
// 能够利用curl安装nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
复制代码
专门给OSX/Linux系统使用的,window可使用nvm-windows,具体查看github前端
// 将nvm命令写入path
source ~/.bash_profile
// 查看是否安装成功
nvm // 有输出内容则安装成功
// 若是写入命令时提示no such profile
// 则在终端中进行以下操做
cd ~ // 进入用户的home目录
open .bash_profile // 打开配置文件
// 没有该文件则执行以下命令建立一个该文件
touch .bash_profile
// 建立完成后,从新打开 open .bash_profile
// 在打开的文件中键入以下内容并保存
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
// 最后查看安装是否成功
nvm
// 查看本地已安装的node
nvm list
复制代码
// webpack4是webpack和webpack-cli分离开的
// 须要分别安装,开发使用
cnpm i webpack webpack-cli --save-dev
// 查看有没有安装成功
// 直接找到node_modules中的webpack查看版本
./node_modules/bin/webpack -v
复制代码
// package.json增长npm命令
"scripts": {
"build": "webpack"
}
// 经过npm命令进行webpack打包
npm run build
复制代码
webpack一切皆模块,entry来指定webpack打包的入口;html5
webpack根据entry入口文件,找到对应的依赖关系,造成一个依赖图,而后根据这个依赖图打包成各类文件;node
output用来告诉webpack如何将编译后的文件输出到磁盘中;react
// path用来指定输出文件的地址
// filename用来指定输出文件的名称,
// [name]表示占位符,用文件的名称来命名。
// 对于多入口文件的打包,用占位符
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
复制代码
webpack只支持js/json类型的文件,对于其余webpack不支持的文件类型(如css/ts/image/less等),须要经过loader转换成有效的模块。webpack
plugin插件,用于加强webpack的功能,例如bundle文件的优化,资源管理和环境变量注入等。基本上,loader作不到的事情,plugin能够用来处理。ios
mode,设置webpack的模式,值有development、production、none;git
// 即对应的设置process.env.NODE_ENV的值
// process.env.NODE_ENV的值为'development'
// 开启一些和本地开发相关的优化
mode: 'development'
// process.env.NODE_ENV的值为'production'
// 开启一些和生成相关的优化
mode: 'production'
// process.env.NODE_ENV的值为'none'
// 不开启任何优化
mode: 'none'
复制代码
// 本地安装
// css-loader 用于将导入的css文件解析成commonJs
// style-loader 用于将css以style标签插入head中
cnpm i css-loader style-loader -D
module: {
rules: [
test: /.css$/,
// 解析规则是从右到左的
// 因此须要先解析成commonJs模块
// 而后在以style标签形式插入到head中
use: [
'style-loader',
'css-loader'
]
]
}
复制代码
// 本地安装less和less-loader
cnpm i less less-loader -D
// 处理less文件
module: {
rules: [
test: /.less$/,
// 先将less处理成css
// 而后再按css的规则去处理
use: [
'style-loader',
'css-loader',
'less-loader'
]
]
}
复制代码
// 安装file-loader,用于解析图片
cnpm i file-loader -D
// 配置
module: {
rules: [
test: /.(jpg|jepg|png|gif)$/,
use: 'file-loader'
]
}
复制代码
// 用的也是file-loader
module: {
rules: [
test: /.(woff|woff2|eot|ttf|otf|svg)$/,
use: 'file-loader'
]
}
// 例如阿里云图表的引入
// 在css/less中引入图标
@font-face {
font-family: 'iconfont';
src: url('./font/iconfont.eot');
src: url('./font/iconfont.eot?#iefix') format('embedded-opentype'),
url('./font/iconfont.woff2') format('woff2'),
url('./font/iconfont.woff') format('woff'),
url('./font/iconfont.ttf') format('truetype'),
url('./font/iconfont.svg#iconfont') format('svg');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
// 页面内使用
<i class="iconfont"></i>
复制代码
// 方式1,经过watch命令
// 增长npm script命令
"scripts": {
"watch": "webpack --watch"
}
// 方式2,webpack.config.js中增长配置
module.exports = {
watch: true,
watchOptions: {
// 指定忽略监控的文件,能提高一些性能
ignored: /node_modules/,
// 监听到变化后,等待多长时间才去执行
aggregateTimeout: 3000,
// 监听变化是经过轮询文件系统有么有发生变化
// 这里设置每秒的轮询次数
poll: 1000
}
}
复制代码
这两种方案,都有一个弊端,就是不会自动刷新,须要咱们在浏览器手动刷新才能看到变化。
开发中,咱们更经常使用的是使用热更新。github
// 配置命令
// --open是服务启动完成后,自动打开浏览器
"script": {
"dev": "webpack-dev-server --open"
}
// 配置webpack.config.js
const webpakc = require('webpack');
moudle.exports = {
// 热更新的mode须要是开发模式
mode: 'development',
// 须要配置下面这个插件一块儿使用
// 在derServer开启了hot: true以后,其实不用手动引入
// webpack会自动引入这个插件
plugins: [
new webpack.HotModuleReplacementPlugin()
],
devServer: {
contentBase: './dist',
hot: true
}
}
复制代码
WDS不会刷新浏览器。
WDS不输出文件,只是放在内存中,所以速度更快。
watch是输出到磁盘中。
// 热更新原理:
// 1.启动阶段:
(1)文件经过webpack-complier编译后,将生成的文件传递给bundle-server,
bundle-server开启一个服务来支持文件经过相似localhsot:8080的方式在browser访问
(2)HMR-Server在生成的文件中注入一个HMR-Runtime运行时,
用来和brwoser创建链接通讯,以便在文件更新时通知browser
// 2.文件更新阶段
(1)文件经过webpack-complier编译后,将更新的内容传递给HMR-Server。
(2)HMR和HMR-Runtime通讯,将更新的内容一般以json的形式传递,
HMR-Runtime局部更新bundle.js的文件内容。
复制代码
补充:
(1)webpack-complier:将文件生成bundles.js
(2)HMR—Server:将热更新的文件传递给HMR-Runtime
(3)HMR-Runtime:被注入到bundle.js,用来更新文件的变化
(4)bundles.js是构建后输出的文件
(2)package.json中区分dev和prod的命令
mode: 'production', // prod
mode: 'development', // dev
复制代码
咱们常常看到的带有各类相似hash(例如:app.38972982.js
)的文件,这就能够简单理解为文件指纹。
生成文件指纹的方式有三种:
output: {
path: path.join(__dirname, 'dist'),
filename: '[name]_[hash].js'
},
复制代码
output: {
path: path.join(__dirname, 'dist'),
filename: '[name]_[chunkhash:8].js'
},
复制代码
output: {
path: path.join(__dirname, 'dist'),
filename: '[name]_[contenthash].js'
},
复制代码
补充:
(1)冒号后面指定生成的指纹的位数。
(2)通常咱们打包的chunk文件,即js使用chunkhash模式;css使用contenthash模式;
(3)file-loader的name设置,指定打包后的指纹策略:
[path]能够在生成的文件中生成对应的和源码文件同样 的目录。
// 安装本地插件
cnpm i mini-css-extract-plugin -D
// 引入
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 使用
plugins: [
new MiniCssExtractPlugin({
filename: '[name]_[contenthash:8].css'
})
]
// 注意,该插件不能和style-loader使用,
// 由于style-loader是用来将css以style的方式插入的
{
test: /.css$/,
use: [
// 须要将loader中css/less等文件里面的style-loader,
// 替换成该插件
MiniCssExtractPlugin.loader,
'css-loader'
]
},
复制代码
// 安装压缩css插件
cnpm i optimize-css-assets-webpack-plugin -D
// 同时须要配合cssnano插件使用
cnpm i cssnano -D
// 使用
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
plugins: [
new OptimizeCssAssetsWebpackPlugin({
assetsNameReg: /\.css$/g,
cssProcessor: require('cssnano')
})
]
复制代码
// 首先安装postcss-loader和autoprefixer
cnpm i postcss-loader autoprefixer -D
// 对样式处理文件增长autoprefixer配置
// 处理css私有前缀和兼容
// 例如,增长以下配置
{
test: /.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
// 增长autoprefixer处理
{
loader: 'postcss-loader',
options: {
plugins: () => [
require('autoprefixer')({
// 经过browsers选项指定兼容的版本
// 推荐在webpack中配置在package.json中
browsers: [
'last 2 version',
'>1%',
'ios 7'
]
})
]
}
}
]
}
复制代码
// rem的适配,引用lib-flexible,生产使用
cnpm i lib-flexible -S
// px自动转换成rem,本地安装
cnpm i px2rem-loader -D
// 配置loader,在打包时自动将px转换成rem
plugins: [
// 处理less文件
{
test: /.less$/,
use: [
// 省略其余loader
……
// 将px转换成rem
{
loader: 'px2rem-loader',
options: {
// 对应比例,750px设计稿
remUnit: 75,
// 转换成rem时保留的小数位
remPrecision: 8
}
}
]
},
]
复制代码
// 安装html-webpack-plugin插件
cnpm i html-webpack-plugin -D
// 使用
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.html'),
filename: 'index.html',
chunks: ['react'],
inject: true,
minify: {
// html5
html5: false,
// 最小化css
minifyCSS: true,
// 最小化js
minifyJS: true,
// 合并空格
collapseWhitespace: true,
// 移除注释
removeComments: true,
// 是否保留换行
preserveLineBreaks: false
}
})
]
复制代码
(1)template: 指定生成的html模板
(2)filename: 指定生成的文件名称
(3)chunks:指定将哪些chunk插入到html中
(4)inject:true/false,是否将chunk插入到html的body中;'body'表示插入到body中,'head'表示插入到head中; (5)minify:设置压缩参数。
html-webpack-plugin官网
// 终端输入
rm -rf dist
复制代码
// 安装clean-webpack-plugin
cnpm i clean-webpack-plugin -D
// 使用
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// 之前版本引入时,不须要花括号
const CleanWebpackPlugin = require('clean-webpack-plugin');
// 使用
plugins: [
new CleanWebpackPlugin()
]
复制代码
// 本地安装raw-loader,这里装的是0.5.0的版本
cnpm i raw-loader@0.5.0 -D
// 在html文件中
// 例如将公共的meta资源内联
<head>
<!-- 只须要在对应的位置插入内联代码 -->
${ require('raw-loader!../meta.html') }
</head>
// meta.html示例
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
// 内联js,例如lib-flexible.js
// 咱们须要将它内联在head中加载来保证更快
<head>
<script>
// 咱们这里先对其进行babel转译后再内联
${ require('raw-loader!babel-loader!../node_modules/lib-flexible/flexible.js') }
</script>
</head>
复制代码
内联后生成的html效果以下:
百尺竿头、日进一步。 我是愣锤,欢迎交流与分享。 若是以为喜欢,记得点赞收藏哦~~