为什么选择 webpack
- 社区生态丰富
- 配置灵活和插件化扩展
- 官方更新迭代速度快
配置文件名称
webpack 配置组成
module.exports = {
entry: ----> 打包文件的入口
output: -----> 打包的输出
mode: 'production' ----> 环境
module: {
rules: [
{ test: /\.txt$/ } -----> Loader 配置
]
},
plugins: [ -------> 插件配置
new HtmlwebpackPlugin({
template: ''
})
]
}
使用 webpack 打包文件
- 使用 webpack 小案例
准备文件及安装webapck
- 打开终端 常见文件 及 初始化项目 (注意要先安装 node)
mkdir my-webpack
cd my-webpack
npm init -y
- 安装 webpack 及 webpack-cli
npm install webpack webpack-cli --save-dev
- 新建webpack.config.js
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'main.js'
},
mode: 'production'
}
./node_modules/.bin/webpack
- 使用 npm 命令 替代 ./node_modules/.bin/webpack 打包
- 在 package.json 中的 scripts 添加 build 命令
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
- 执行 npm run build 一样可以打包
entry 和 output
单入口
entry: './src/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'build.js'
}
多入口
entry: {
app: './src/index.js'
app2: './src/main.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
Loaders
常用的 Loaders
- babel-loader
- css-loader
- less-loader
- ts-loader
- file-loader
Plugins
常见的 Plugins
- CleanWbpackPlugin 清理构建目录
- CommonsChunkPlugin 讲chunks相同的模块代码提取成公共 js
- HtmlWebpackPlugin 创建 HTML 文件去承载输出的 bundle
- UglifyjsWebpackPlugin 压缩JS
Mode
module.exports = {
mode: 'development'
};
- 或者从 cli 参数中传递
webpack --mode=development
内置函数功能
- 选项 development
会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development. 为模块和 chunk 启用有效的名。
- production
会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePlugin,FlagIncludedChunksPlugin,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin 和 TerserPlugin 。
- node
不使用任何默认优化选项
使用 babel 解析 ES6
- 安装 babel 解析文件
npm i @babel/core @babel/preset-env babel-loader -D
{
"presets": [
"@babel/press-env"
]
}
module: {
rules: [
{
test: /.js$/,
use: 'babel-loader'
}
]
}
解析 CSS 文件
module: {
rules: [
{
test: /.js$/,
use: 'babel-loader'
},
{
test: /.css$/,
use: [
'style-loader',
'css-loader'
]
}
]
}
loader 的执行顺序是 从又右到左的
url-loader 解析图片
- 安装 url-loader 和 file-loader
module: {
rules: [
{
test: /.js$/,
use: 'babel-loader'
},
{
test: /.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: { // 图片大小的限制 如果小于 10k 转成 base64 格式
limit: 10240
}
}
]
}
]
}
webpack 文件监听
- 启动 webpack 命令时,带上 --watch 参数
- 缺点是: 每次需要手动刷新浏览器
- 在配置 webpack.config.js 中设置 watch: true
watch: true,
watchOptions: {
// 默认为空,不监听文件或文件件,支持正则
ignored: /node_modules/,
// 监听发生变化后等待 xxx 毫秒去执行,默认 300
aggregateTimeout: 300,
// 判断文件是否发生变化,通过不停的询问系统指定文件有没有变化实现,默认每秒问 1000 次
poll: 1
}
热更新 webpack-dev-server
热更新 使用 webpack-dev-middleware
热更新的原理分析
- Webpack Compile
- HMR (Hot Module Replacement) Server:
- 将热更新文件传输给 HMR Rumtime
- Bundle Server:
- 提供文件在浏览器的访问 (通过服务器的方式访问,例如 127.0.0.1:8080)
- HMR Rumtime:
- 打包时会被注入到浏览器中,使浏览器和服务器建立连接,通常的连接方式是用 websocket, 用来更新文件的变化
- bundle.js
热更新的过程
- 热更新的启动阶段
- 更新阶段
- 代码通过 Webpack Compile 进行编译打包,将代码发送给 HMR Server 知道哪些 js 文件发生变动,然后通知 HMR Rumtime (HMR Server 在 服务端,HMR Rumtime 在客户端)哪些文件发生变化,通常是已JSON 的方式传输,然后 HMR Rumtime 更新代码.
文件指纹
Hash
Chunkhash
- 和 webpack 打包的 chunk 有关,不同的 entry 会生成不同的 chunkhash 值
Contenthash
module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: '[name][chunkhash:8].js'
},
module: {
rules: [
{
test: /\.(png|svg|jpg)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'img/[name][hash:8].[ext]'
}
}
]
},
{
test: /.css$/,
use: [
// 'style-loader', 这个是把 css 放到 style 里面和用 MiniCssExtractPlugin 有冲突,它是把 css 放到一个独立的文件中
MiniCssExtractPlugin.loader,
'css-loader'
]
},
]
}
mode: 'production',
plugins: [
new MiniCssExtractPlugin({
filename: '[name][contenthash:8].css'
})
]
}
:8 意思是只取前 8 位
代码压缩
JS 文件的压缩
- uglifyjs-webpack-plugin webpack4.0 后内置了
css 压缩
new OpeimizeCssAssetsPlugin({
assetNameEegExp: /\.css$/g,
cssprocessor: require('cssnano')
}),
html 压缩
- 安装
npm i html-webpack-plugin -D
new HtmlWebpackPlugin({
// 模板 所在的位置
template: path.join(__dirname, 'src/index.html'),
// 指定打包后的文件名称
filename: 'index.html',
// 声明 HTML 使用什么 chunks
chunks: ['index'],
// 把引入的 js 或 css 自动注入
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false
}
})