这是我参与「第四届青训营 」笔记创作活动的第11天。
前端工程痛点
-
模块化
- 提供模块加载方案
- 兼容不同模块的规范
-
资源编译
浏览器的速度赶不上我们前端一些语言一些特性的速度,所以就需要进行编译
- 对于高级语法转译:
less/scss/typescript等 - 资源加载等:图片,字体等
- 对于高级语法转译:
-
产物质量
- 关于一些dead code的删除等,语法降级等
-
开发效率
热更新
Vite概览
新一代的前端构建工具
大部分的浏览器都支持ESM
浏览器原生ESM支持
<!DOCTYPE html>
<html>
<head>
<title>tset</title>
</head>
<body>
<script type="mode">
import {foo} from './foo.js'
console.log(foo)
</script>
</body>
</html>
export const foo = "foo"
两大要素
script标签添加type="module"- 使用
ESM模块导入导出语法
优势
- 无需打包项目源代码
- 天然的就支持按需加载
- 可以利用文件级的浏览器缓存
sequenceDiagram
浏览器->>Vite Dev Server: 请求/src/main.tsx
Vite Dev Server->>浏览器: 编译文件内容,将数据返回给浏览器
内置的web构建功能
Vite开箱即用的功能等价于
webpackcss-loaderstyle-loaderless-loaderHTMLWebpackPlugin- ....
Vite使用
//安装pnpm
npm i pnpm
//执行初始化命令
pnpm create vite
//安装依赖
pnpm install
//启动项目
npm run dev
使用Sass/Scss& CSS Modules
npm i scss
.header{
color:red;
}
import styles from './index.module.scss'
//使用CSS modules 模块化方案,防止className命名冲突
export function Header(){
return <p className={styles.header}> this is message</p>
}
使用静态资源
import {Header} from './components/Header'
import logUrl from './logo.svg'
function App(){
return (
<div>
<Header></Header>
<img src={logUrl} alt=""/>
</div>
)
}
参考链接:功能 | Vite 官方中文文档 (vitejs.dev)
使用HMR
无需配置,自动开启即可
生成环境Tree Shaking(树摇)
Tree shaking 在vite里面无需配置,默认开启
优化原理:
- 基于
ESM的import/export语句依赖关系,与运行时状态无关 - 在构建阶段将未使用的代码进行删除
Vite整体架构
为什么要进行预打包
- 避免
node-modules过多文件请求 - 将
CommonJs格式转换为ESM格式
实现原理
- 服务启动前扫描代码中用到的依赖
- 用
Esbuild对依赖代码进行预打包 - 改写
import指定依赖为与构建产物路径
//改写前
import React from 'react'
//改写后
import React from '/node_modules/.vite/react.js'
单文件编译
用
Esbuild编译TS/JS
优势:
- 编译速度大大提升
劣势
- 不支持类型检查
- 不支持
ES5,可能有些兼容性不好的浏览器不兼容
代码压缩
使用minify
build: {
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
minify: "terser",
}
参考链接:构建选项 | Vite 官方中文文档 (vitejs.dev)
插件机制
- 开发阶段 -> 模拟
Rollup插件机制 - 生产环境 -> 直接使用
Rollup
Vite进阶路线
深入双引擎
ESbuildRollup.js
插件机制
示例
const fileRegex = /\.(my-file-ext)$/
export default function myPlugin(){
return {
name:'transform-file',
transform(src,id){
if(fileRegex.test(id)){
return {
code:compileFileToJS(src),
map:null
}
}
}
}
}
使用插件
在vite.config.js里面声明插件
import plugin from './myPlugin'
export default defineConfig({
plugins:[plugin()]
})
代码分割
出现原因:
- 无法进行并发请求
- 缓存复用率低
我们将一个入口文件差分为几个,当我们需要改变A组件的时候,那么只有A组件对应的文件进行更改
Babel
出现的原因
Javascript的语法标准繁多,浏览器支持的程度不一- 开发者需要用到高级的语法
语法安全降级
- 上层解决方案:@vite/plugin-legacy
- 底层原理
- 借助Babel进行语法自动降级
- 提前注入
Polyfill,如core.js