拆分配置文件
将 webpack.config.js 按实际需要进行拆分,分成公用部分和特定用途部分
核心内容:
- 按照用途,将原配置文件拆分为多个配置文件
- 通过
webpack-merge合并配置 - 运行 webpack 时使用指定配置文件进行打包
步骤大纲
- 安装
webpack-merge - 将
build/webpack.config.js拆分成:公用配置、开发配置、生成配置 - 为快捷命令指定相应的 webpack 配置文件
具体步骤
1、安装 webpack-merge
npm i webpack-merge -D
2、将 build目录下的 webpack.config.js 拆分为以下3个文件
- 公用配置:
webpack.config.default.js - 开发配置:
webpack.config.dev.js - 生产配置:
webpack.config.prod.js
webpack.config.default.js
const path = require('path')const { CleanWebpackPlugin } = require('clean-webpack-plugin')const HtmlWebpackPlugin = require('html-webpack-plugin')const MiniCssExtractPlugin = require('mini-css-extract-plugin')const { VueLoaderPlugin } = require('vue-loader')module.exports = {// 入口文件entry: './src/main.js',// 打包输出output: {path: path.join(__dirname, '../dist'),filename: 'app.bundle.js'},module: {rules: [// 处理纯 css 样式文件{test: /\.css$/i,use: [MiniCssExtractPlugin.loader, 'css-loader']},// 处理 sass|scss 样式文件{test: /\.(scss|sass)$/i,use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']},// 处理图片和字体文件{test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/i,type: "asset"},// 处理 ES6+ 语法{test: /\.m?js$/i,exclude: /(node_modules|bower_components)/,use: {loader: 'babel-loader',options: {presets: ['@babel/preset-env'],plugins: ['@babel/plugin-transform-runtime']}}},{test: /\.vue$/i,use: 'vue-loader'}]},plugins: [// 生成 index.htmlnew HtmlWebpackPlugin({template: './public/index.html'}),// 抽取样式new MiniCssExtractPlugin(),// 打包清理new CleanWebpackPlugin(),// 处理 Vue 组件new VueLoaderPlugin()],}
webpack.config.dev.js
const path = require('path')const { merge } = require('webpack-merge')const defaultConfig = require('./webpack.config.default')module.exports = merge(defaultConfig, {// 开发模式mode: 'development',// 开发服务器devServer: {// host 公共wifi下可以访问本地项目host:'0.0.0.0',static: {directory: path.join(__dirname, '../dist')},port: 9000}})
webpack.config.prod.js
const { merge } = require('webpack-merge')const defaultConfig = require('./webpack.config.default')module.exports = merge(defaultConfig, {// 生产模式(打包后的文件会作压缩处理)mode: 'production',// 生成更高质量的 Source Map 文件devtool: 'source-map',output: {// 生成的文件带 hash 版本信息filename: 'app.[fullhash].js'}})
3、为 package.json 中的快捷命令指定对应的 webpack 配置文件
{"scripts": {"serve": "webpack serve -c ./build/webpack.config.dev.js --open","build": "webpack -c ./build/webpack.config.prod.js"},// ...}
解决跨域问题
解决开发时,因调用不同源的 API 接口而产生的跨域问题
核心内容:
- 在项目中请求非同源的后端接口
- 通过
webpack-dev-server的devServer配置项启用代理服务,解决跨域问题
步骤大纲
- 安装 axios
- 在任意页面发起请求(URL:https://www.uinav.com/api/public/v1/home/swiperdata)
- 配置 devServer.proxy 代理
- 修改请求 URL 路径为相对路径
具体步骤
1、安装网络请求库 axios
npm i axios -D
2、在 src/views/Home/index.vue中发起网络请求
async created() {const url = 'https://www.uinav.com/api/public/v1/home/swiperdata'const result = await axios.get(url)console.log(result)}
当前该请求不会成功,会报跨域错误:

3、在开发环境的配置文件 build/webpack.config.dev.js中配置代理服务
// ...module.exports = merge(defaultConfig, {// ...devServer: {// ...// 配置代理proxy: {//配置多个代理,{'/api1': {target: 'https://www.uinav1.com',//secure 不检查 https 的证书secure: false,}},{'/api2': {target: 'https://www.uinav2.com',secure: false,}},...}}})
4、修改后端接口路径
const url = '/api/public/v1/home/swiperdata'
重启开发服务器,即可成功调用。
定义环境变量
让 webpack 通过读取环境变量的数据,达到在执行打包时能指定参数的功能
本章节将实现:通过环境变量的方式,指定开发服务器的端口号
核心内容:
- 了解
操作系统环境变量和webpack 环境变量 - 在 webpack 中使用以上两种环境变量的方法
1、webpack 能使用的环境变量:
- 改造三个 webpack 配置文件:导出函数而不是对象,并通过函数参数获取 webpack 环境变量
- 在快捷命令中添加 webpack 环境变量:
--env port=xxxx - 在开发配置文件中使用 webpack 环境变量来设置开发服务器的端口号
- 在开发配置文件中使用系统环境变量来设置开发服务器的端口号
具体步骤
1、将三个 webpack 的配置文件做如下改造
webpack.config.default.js
module.exports = env => {return {// ...}}
webpack.config.dev.js 和 webpack.config.prod.js
module.exports = env => {return merge(defaultConfig(env), {// ...})}
改造后即可通过 env 参数获取 webpack 环境变量。
2、在 webpack.config.dev.js 中读取 webpack 环境变量 port,设置为开发服务器的端口号
// ...module.exports = env => {return merge(defaultConfig(env), {// ...devServer: {// ...port: env.port || 9000,// ...}})}
配置完毕后,就能用下列方式指定启动服务器时的端口号:
- 以
npm run serve启动:使用默认端口 9000 - 以
npm run serve --env port=8888启动:使用指定的端口 8888
3、更进一步:读取操作系统环境变量,设置为开发服务器端口号
// ...
module.exports = env => {
return merge(defaultConfig(env), {
// ...
devServer: {
// ...
port: env.port || process.env.PORT || 9000,
// ...
}
})
}
配置后,如以 PORT=7777 npm run serve 启动服务器,端口就会被指定为 7777。
设置路径别名
为项目的 src 目录设置别名 @,让路径变得更简短易读
核心内容:
- 配置 webpack 路径别名
- 改写项目代码中的路径
步骤大纲
- 通过 webpack 配置项
resolve.alias设置别名 - 使用别名改写代码中的相关路径
具体步骤
1、在 webpack.config.default.js 中添加别名解析配置
// ...
module.exports = env => {
return {
// ...
resolve: {
alias: {
// 为 src 目录设置别名 @
'@': path.resolve(__dirname, '../src')
}
}
}
}
2、使用别名 @ 改写代码中的路径,比如:
import Home from '@/views/Home/index.vue'
import About from '@/views/About/index.vue'
生命周期钩子介绍
了解 webpack 生命周期的概念,以及生命周期各阶段的事件通知处理
生命周期钩子函数只能在插件plugin中使用,不能在加载器loader中使用
生命周期:Webpack 程序从开始启动到运行结束,期间经过一系列节点并触发事件所形成的一套完整事件流。
生命周期钩子:以注册监听函数的方式,来在事件发生时执行指定逻辑
Webpack 中一些较为重要的生命周期节点:
**before-run**- 即将开始构建**run**- 已开始构建**before-compile**- 即将开始编译**compile**- 已开始编译**make**- 正在从入口开始,分析直接和间接依赖模块,并创建出 webpack 模块对象**build-module**- 正在构建 webpack 模块**seal**- 封装构建结果**after-compile**- 已完成构建**emit**- 输出构建结果
开发自定义 Loader
自己开发 webpack loader 来解析和处理特定文件
核心内容:
- loader 的作用和原理
- 开发一个自己的
style-loader
1、loader 的作用:
webpack只认识 js 和 json 格式的代码,其他类型的文件需要借助 loader 资源加载器来转换,简单的说,loader 就是进行文件资源的转换
2、loader 的原理:
loader 就是一个函数,该函数接收一个参数,这个参数就是目标要处理的文件的源代码,例如 css-loader 里的函数参数就是css-loader 读取的css文件内容,在函数体内可以做一个逻辑操作,loader 的函数最后返回值是字符串格式的js代码
为什么需要 Loader
因为 webpack 只能直接处理 js/json 代码,其他文件都必须先转换成 js 后,才能参与打包。
而 loader 就是这样的文件转换器:它以原始文件内的数据为参数,对这些数据加工处理后,最终输出 js (及可选的 source map)
编写 loader 的语法
1、在 js 文件中通过 module.exports 导出一个函数即可:
- 参数:要进行处理的资源内容(二进制、或字符串格式)
- 返回值:一段代表 JS 代码的字符串
module.exports = function (source) {
return '... 要输出的 JS 代码 ...'
}
步骤大纲
- 编写一个页面,并在主入口js中引用一个自定义后缀名的文件(内容就是普通css)
- 配置基本的 webpack 文件
- 创建 loaders 目录,用于存放自定义 loader
- 编写自定义的 loader:my-style-loader (功能和 style-loader 一样,往页面head中插入 style 样式代码)
- 配置
resolveLoader.modules解析自定义 loader 的路径,并配置用 my-style-loader 处理 css 文件
具体步骤
1、创建一个新项目,并创建以下文件
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="box"></div>
<script src="./dist/app.bundle.js"></script>
</body>
</html>
index.css
.box {
width: 100px;
height: 100px;
border: 1px solid red;
background-color: pink;
}
index.js
import './index.css'
2、创建自定义 Loader 代码文件: loaders/my-style-loader.js
module.exports = function (source) {
console.log('>>>>原始文件内容>>>>', source)
// 要输出的 JS 代码
const newSource = `
const style = document.createElement('style');
style.innerHTML = \`${source}\`;
document.head.appendChild(style);
`
console.log('>>>>转换后的内容>>>>', newSource)
// 返回转换后的内容
return newSource
}
3、创建 webpack 配置文件 webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
// 解析 Loader 的路径
resolveLoader: {
modules: [
path.resolve(__dirname, 'loaders')
]
},
module: {
rules: [
// 使用 my-style-loader 处理 css 文件
{
test: /\.css$/i,
use: 'my-style-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'index.html'
})
]
}
运行 webpack build 运行index.html文件查看效果
开发自定义 Plugin
自己开发一个 webpack 插件,用它来在打包工作进行到某个环节时,执行额外的逻辑
核心内容:
- 插件的作用和原理
- 编写一个用于在打包结束后生成包含此次打包描述信息的文件
1、插件的作用
在 webpack 运行期间,会广播出许多生命周期事件,而 plugin 能监听它们并执行指定逻辑
- 通过 webpack API 改变资源内容,达到改变最终输出内容的目的
- 其他的任何事情,比如:将打包后的文件上传到某台服务器
编写插件的语法
插件使用 class 语法编写,它是一个带有 apply() 的类。该方法会被 webpack 编译器调用,并在整个编译周期中都有效
class MyPlugin {
apply(compiler) {
// 注册生命周期钩子的处理函数
//使用 tap 给compiler.hooks.done注册函数
compiler.hooks.done.tap('MyPlugin',(stats) => {
console.log('Test Done!');
});
}
}
module.exports = MyPlugin;
tap 方法的第一个参数理论上可传任意值,但推荐传驼峰方式命名的字符串(最好就是当前类名)。
步骤大纲
- 在之前项目的基础上,在 loaders 下创建插件 my-plugin
- 在插件中通过
stats.compilation.assets获取打包后的资源信息 - 在插件中通过
compiler.options.output.path获取打包的配置信息 - 对以上信息进行处理后,输出到 dist 目录中的一个文件
- 在 webpack 配置文件中配置 my-plugin
具体步骤
1、在之前项目的基础上,创建插件代码文件: loaders/my-plugin.js
const fs = require('fs')
const path = require('path')
class MyPlugin {
apply(compiler) {
// 触发打包结束事件时执行
compiler.hooks.done.tap('MyPlugin', (stats) => {
// 获取生成的资源信息
const assets = stats.compilation.assets
const arr = Object.entries(assets).map(item => {
// 文件名字
const filename = item[0]
// 文件大小
const size = item[1].size()
return `${filename}的文件大小是${size / 1024}KB`
})
// 获取打包所用时间
const timeUsed = stats.endTime - stats.startTime
// 生成要输入的字符串
const res = `****** 本次构建信息 ******,
- 构建时间:${timeUsed}毫秒,
- 资源列表:${arr.join('\n')},
************************`
// 写入文件
const distPath = compiler.options.output.path
fs.writeFileSync(path.join(distPath, 'report.txt'), res)
})
}
}
module.exports = MyPlugin
2、在 webpack 配置中启用插件
// ...
module.exports = {
// ...
plugins: [
new MyPlugin()
]
}
打包后查看 dist/report.txt 文件:

