Webpack
1. webapck打包流程
entry、output、loader、plugin、Mode......
- 从入口文件开始递归分析,调用配置的loader对模块进行编译(css-loader、vue-loader....)
- 借助babel-parser将js代码转为ast抽象语法树,对ast进行遍历(babel-traverse),通过import引用节点查找文件的依赖关系,生成最终的依赖关系图谱(dependency graph)(每个模块都有一个唯一的id标识)
- 递归遍历依赖图谱的所有模块,组装成一个个包含多个模块的 Chunk(块)
- 最终将生成的内容打包输出
module.exports = {
mode: 'production',
plugins: [...],
module: {
rules: [...],
},
entry: '...',
output: ...,
devServer: {},
};
2. 热更新(HMR)
websocket、webpack-dev-server, 用于开发阶段
- 启动server服务,再启动socket服务,建立本地服务和浏览器的双向通信
- webpack每次编译后生成一个hash值作为此次编译的标识,也是下一次热更新的标识(每次代码修改后,会生成新的文件(生成的新文件的文件名标识为上次编译生成的hash值))
- webpack监听文件变化,重新编译
- 编译结束,通知浏览器请求变化的资源(例如修改的js、css等文件),同时将新生成的hash值传给浏览器,用于下次热更新使用
- 浏览器将获取的新模块替换旧模块,实现局部刷新
3. 常用plugin/loader
// plugins
HtmlWebpackPlugin // 生成html文件,注入生成的bundle
SplitChunksPlugin // CommonsChunkPlugin的替代品,将公共的依赖模块提取到已有的入口 chunk 中,或者提取到一个新生成的 chunk
webpack-bundle-analyzer // 对打包后的文件进行分析,生成资源分析图
terser-webpack-plugin
-----------------------------------------------------------------------------------------------
// loaders
style-loader // 用于将css编译完成的样式,挂载到页面style标签上
postcss-loader // 用于补充css样式各种浏览器内核前缀
vue-loader // 用于编译.vue文件
-----------------------------------------------------------------------------------------------
// loader和plugins的区别
plugins: 扩展webpack功能,采用发布-订阅模式
loaders: 将(除js、json之外的文件)转为webpack能处理的有效模块,以供应用程序使用,以及被添加到依赖图中;
相同优先级的loader链,执行顺序为:`从右到左,从下到上`
4. MF(Module Federation)
webpack && rollup
webpack: 代码拆分(及异步加载chunk等)、静态资源处理(支持任意格式,使用loader处理为模块依赖)、运行时动态导入,一般用于打包应用
rollup: ESM支持,模块静态解析(有助于tree-shaking和作用域提升之类的优化工作),一般用于打包js类库
Vue-cli
基于插件的架构; 基于webpack
1. 组成
- CLI(@vue/cli):全局安装,终端命令
- CLI服务:项目局部安装,开发环境依赖;
基于webpack;加载cli插件,提供优化过的webpack配置
// 常用
vue-cli-service serve --open // 启动开发服务器且在浏览器打开并附带热重载模块HMR
vue-cli-service build --report
// 打包且生成 report.html报告以帮助分析包内容(包依赖关系和包的体积大小), 内部借助webpack-bundle-analyzer插件实现
// vue-cli打包所做的优化:
vue-cli-service inspect // 查看webpack配置
yorkie // 类同husky, 支持git hooks实现代码风格自动化
- CLI插件:@vue/cli-plugin- (内建插件) 或 vue-cli-plugin- (社区插件), 可修改webpack的内部配置
2. html && 静态资源 && css模块化
- public/index.html: 会被HtmlWebpackPlugin处理的模板,打包后资源链接(通常会配置preload、prefetch)会被注入该文件; 可将环境变量作为插值使用,例如
// 引入网站logo
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
- 静态资源处理: 放置于public目录(特殊情况使用)或者以绝对路径引用,不会经过webpack处理;使用相对路径引入会作为一个模块依赖被解析,会经过webpack处理(借助Assets Modules确定最终的资源路径)
// 资源被作为模块依赖的方式引入经过webpack处理的好处
1. 生成文件名hash, 避免缓存的影响
2. 压缩、打包脚本样式,减少http请求
// 使用public场景
1. 构建输出中使用指定的文件名
2. 使用与webapck不兼容的类库,避开webpack的打包处理
实际项目public目录下的文件类别:
模板文件、日志文件(Changelog.md)、网站logo、一些模拟数据/公共配置文件(例如子系统配置数据)
----------------
// assets目录
一些静态文件如fonts, images放置该目录;
// 以下两种方式图片被解析为模块依赖
<img src="../assets/logo.png" title="assets中的图片">
<!-- 或, imgSrc动态绑定时,使用import/require导入 -->
<img :src="imgSrc" title="assets中的图片">
import imgSrc from '../assets/logo.png';
3. Css:
Vue CLI 内部使用了 PostCSS, 默认开启了autoprefixer
- 全局样式自动化导入
// 安装 style-resources-loader 与 vue-cli-plugin-style-resources-loader
module.exports = {
...
pluginOptions: {
'style-resources-loader': {
preProcessor: 'less',
patterns: [path.resolve(__dirname, 'src/css/main.less')],
},
},
}
// OR, 安装 style-resources-loader
// 针对特定目标文件引入该样式文件
vue中引入css的几种方式
<script>
import '@/assets/dark-theme/index.scss';
<script/>
<style lang='scss' scoped src='./index.scss'></style>
<style lang='scss' scoped>
@import '~@/assets/index.scss';
@import url('https://csdnimg.cn/release/bl.css');
@import './index.scss';
</style>
4. 环境变量
需要针对不同的环境,使用不同的配置
两个默认可用的变量:
NODE_ENV(默认:production/test/development): 指定应用运行的模式、决定创建的webpack配置BASE_URL
// 环境文件分类
.env // 所有模式载入
.env[mode] // 指定模式载入
.env[mode].local // 指定模式载入且忽略git提交
// 能被客户端访问的环境变量
NODE_ENV、BASE_URL、VUE_APP_xxx
// 解析的环境变量可以在public/index.html中以[HTML 插值]的方式使用
// 例如引入网站图标
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
环境变量优先级:
package.json 中scripts中定义的 --mode > .env[mode]文件指定模式 > .env文件指定模式
使用场景:根据环境配置不同的接口地址
5. 打包部署
打包为应用模式:
- 小于 8KiB 的静态资源会被内联在js中
public中的静态资源会被原样输出
打包目录包含如下文件:js、css、fonts、img、public目录下的文件
6. 插件
7. 常用配置
// publicPath
// outputDir
// assetsDir 静态资源的打包路径
// filenameHashing
// runtimeCompiler 是否包含运行时编译器
// productionSourceMap
// configureWebpack 修改webpack配置
// css...
// devServer
// pluginOptions
// transpileDependencies 转义第三方依赖
Vite
基于rollup
1. Css相关
- vite不需要使用less-loader、css-loader等处理相关样式
2. 插件
vite-plugin-pages: 基于文件系统的路由, 自行生成路由文件
// vite.config.js
import Pages from 'vite-plugin-pages'
export default {
plugins: [
// ...
Pages(),
],
}
// vue
import { createRouter } from 'vue-router'
import routes from '~pages'
const router = createRouter({
// ...
routes,
})
vite-plugin-html-config: 向html中注入资源, 类似于HtmlWebpackPlugin
3. 相对优势
解决大型应用构建问题:利用浏览器原生支持esm模块 和 更多的js工具使用编译语言编写特性
急速的开发服务器启动
- 使用esbuild预构建依赖,速度更快
- 以原生ESM方式提供源码,让浏览器接管打包程序的部分工作,按需加载
快速的热重载
- 基于esm模块,快速构建
- 利用浏览器的强制缓存和协商缓存快速重载页面
浏览器兼容性处理
vite:
vue-cli:
(1) 默认使用 @vue/babel-preset-app预设,它通过 @babel/preset-env 和 browserslist 配置来决定项目对于web新特性、新标准的填充;
默认情况下 @babel/preset-env根据源代码自动检测需要的polyfill;特殊情况,如需转译第三方依赖,使用如下方式处理
例如: 使用团队自行研发的组件库(使用npm包的方式管理),可以针对这部分依赖进行转译
const TEAM_UI_PATH = path.join('node_modules', 'xxx', 'xxx');
const uiRegExp = new RegExp(TEAM_UI_PATH);
module.exports = {
// ...
transpileDependencies: [uiRegExp],
}
(2) 打包为现代版本:vue-cli-service build --modern,主要面向支持ESM的浏览器
参考链接: 环境变量配置、 webpack内部实现、 HMR原理