🚀 从 create-react-app 迁移到 vite ⚡️
要不要迁移❓
一、star 对比
create-react-app 底层用的是 webpack,让我们来对比下 webpack 和 vite 的历史 star 数趋势:
webpack 从 2012 开始,11 年间到达 63k star,而 vite 从 2020 年,只用了 3 年就达到 56k star,曲线更陡峭,上升更快。
二、时间对比
以我维护的项目(技术栈:webpack5+Ant4+React18+mobx+axios)进行体验
create-react-app vs vite4:
启动开发服务器(dev server) | 模块热替换(HMR) | 构建产物(build) | |
---|---|---|---|
create-react-app | 15.45s | 4.09s | 1min08s |
vite | 0.49s~0.63s | <=1s | 19.57s~23.81s |
节省时间 | 14.86s | 3.09s | 44.19s |
节省时间占比 | 96.8% | 77% | 65% |
其中,启动开发服务器在 0.49s ~ 0.63s,真是比秒开还快了!
说明:create-react-app 是手动计时取中间值,vite dev server时间是观察命令行控制台,多次记录取最大值和最小值,HMR 刷新是红轴机械键盘按键一按到底,页面就已经刷新,从控制台上看到的每次的时间差值,都是 1s,那实际应该小于等于 1s。
三、vite 两大特点
正如官网介绍的,它大大提升了本地开发体验:
-
更快地启动(对应 create-react-app 的
npm run start
命令)关键在于依赖模块的处理,由于 底层使用编译型语言 Go 预构建依赖,比以 JavaScript 编写的打包器(create-react-app 就是基于JavaScript)预构建依赖 快 10-100 倍;
-
更快热更新(对应 create-react-app 的 动态模块热替换 HMR)
在源码处理上,Vite 以 ESM 方式返回浏览器源码。 只需在浏览器请求源码时进行转换并按需提供,这样某个文件改变时,可以精确定位,无需打包就返回给浏览器。
下面官方中文文档的对比图,可以帮助更好理解。
图一 是基于 JS bundle 的开发服务器(如 webpcak)
图二 是基于 ESM 方式的开发服务器
一起迁移吧 💪
零、尝试迁移工具
先尝试下 wp2vite,按操作发现 vite 版本还是 2,npm run start
也没有跑起来,从代码记录上已经两年多没更新了。
package.json
的 vite 版本:
npm run start
报错了:
代码记录:
而 webpack-to-vite 是在 awesome-vite 列表上出现的。从文档上看,目前支持 vue,还未支持 create-react-app。
坚强的 React 开发者,只能一起手动迁移了!💪
一、常规步骤
新建一个 Vite React 模板代码库:
对照 vite 项目和旧的 create-react-app 项目,需要更改如下:
-
更新 package.json
// package.json { "version": "x.y.z", "private": true, "scripts": { "dev": "vite", "build": "tsc && vite build", "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview" }, "devDependencies": { "vite": "^4.3.9", "@vitejs/plugin-react": "^4.0.0", } }
-
在要迁移的create-react-app项目新建
vite.config.ts
文件// vite.config.ts import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], })
-
把
index.html
从public
文件夹下移到根目录 -
index.html
需要去掉%PUBLIC_URL%
; 同时新增 script<script type="module" src="/src/index.jsx"></script>
; 记得把/src/index.js
更改为/src/index.jsx
<-- index.html --> <script type="module" src="/src/index.jsx"></script>
-
把带有 JSX 的
js/ts
文件名,更新为jsx/tsx
不然会报错:
二、路径别名
如果在 config/webpack.config.js
或其他位置配置了路径别名,则需要到 vite/config.ts
也配置
比如我配置的是 '@' 路径别名
// config/webpack.config.js
module.exports = function (webpackEnv) {
return {
resolve: {
alias: {
// ...
'@': path.resolve(__dirname, '../src')
}
}
}
}
需要在 vite/config.ts
对应配置如下:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from "path";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
alias: [{
find: "@", replacement: path.resolve(__dirname, "src")
}]
},
})
三、CSS 预处理器
vite 自动提示了缺少的预处理器,如 sass
安装 sass: npm i sass --save-dev
如果使用的是 less、stylus,安装下对应的处理器即可,更多可查阅 Vite 官方中文文档 - CSS 预处理器
四、require is not define
运行 npm run dev
时,浏览器报错 require is not define
通过添加 @originjs/vite-plugin-commonjs 插件解决了
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { viteCommonjs, esbuildCommonjs } from '@originjs/vite-plugin-commonjs'
import path from "path";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
viteCommonjs(),
],
// ...
optimizeDeps: {
esbuildOptions: {
plugins:[
// 我用到了 react-resizable,添加了 viteCommonjs 仍报错,单独在这里配置解决了
esbuildCommonjs(['react-resizable'])
]
}
}
})
参考链接: github.com/vitejs/vite…
五、代理开发服务器请求
在 webpack 中如果对开发服务器的 localhost api 路径代理到自己的后端服务器
// src/setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
changeOrigin: true,
target: 'https://dev.mysite.com',
})
)
};
则对应到 vite 的配置如下:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { viteCommonjs, esbuildCommonjs } from '@originjs/vite-plugin-commonjs'
import path from "path";
// https://vitejs.dev/config/
export default defineConfig({
// ...
server: {
// create-react-app 默认端口是 3000,可以在这改
port: 3000,
proxy: { // 开发服务器代理规则
'/api': { // 使用 proxy 实例
target: 'https://dev.mysite.com',
changeOrigin: true,
},
},
},
})
更多配置可以查看 Vite 官方中文文档 - server.proxy
六、Antd 样式问题与按需导入
Antd 样式 less 报错:
通过配置 preprocessorOptions.less.javascriptEnabled = true 解决
// https://vitejs.dev/config/
export default defineConfig({
css: {
preprocessorOptions: {
less: { javascriptEnabled: true },
},
},
})
支持 antd 样式按需导入
npm i vite-plugin-imp --save-dev
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { viteCommonjs } from '@originjs/vite-plugin-commonjs'
import vitePluginImp from 'vite-plugin-imp'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
viteCommonjs(),
// antd 样式按需导入
vitePluginImp({
optimize: true,
libList: [
{
libName: 'antd',
libDirectory: 'es',
style: (name) => `antd/es/${name}/style`
}
]
})
],
})
七、svg 图片转换为 svg 元素
引入 svg 图片给 img src 是 vite 默认就支持的。这样 svg 会作为一张图片传给浏览器。使用如下:
import logo from "./icons/logo.svg";
<img src={logo} alt={"logo"}
如果 webpack 配置了将 svg 图片作为组件使用,最后转换为 svg 元素传给浏览器,可能会用到了 webpack svg loader react-svg-loader 或 @svgr/webpack。
对应到 vite,需要安装依赖 npm i vite-plugin-svgr --save-dev
vite 新增配置如下:
import svgr from 'vite-plugin-svgr'
export default defineConfig({
// ...
plugins: [
react(),
svgr(),
// ...
],
})
在代码上使用:
import logo, { ReactComponent as Logo } from "./icons/logo.svg";
<img src={logo} alt={"logo"}/>
<Logo />
浏览器效果:
八、生产版本 require is not defined
运行 npm run build
, 再运行 npm run preview
时浏览器报错:
-> err bound ReferenceError: require is not defined
定位报错位置:
在 vite 使用行内 require 图片会报错,可以修改如下:
{
titleIcon: new URL('../icons/info-icon.png', import.meta.url).href
}
上面这种方式更适合动态 URL
我们也可以直接改为 import 引入图片即可
import infoIcon from '../icons/info-icon.png';
{
titleIcon: infoIcon
}
更多资料可查询 Vite中文网 - 静态资源处理
另一个 require is not defined
报错是 uuid
引入方式问题,需要把 require 改为 import
修改如下:
九、产物太大,如何优化
一起看下 npm run build
后得到文件:
只有一个 JS 文件 和 CSS 文件,其他都是图片等资源。
也就是全部 JS 源码都打包到一起了,有 2004kB,即使 gzip 了也有 639kB,算是挺大了。
回想下以前 webpack 一般如何进行打包优化的,分为几个部分:
- 对于单页面,拆分JS,减小体积(代码分割)
- 对于多页面之间,提取公共资源,减少加载次数(代码合并)
- 几乎不变动的第三方库也提取出来(node_modules/* 打包后叫 vendor.js) 比如 Antd、lodash、react 这些第三方库,升级版本了,才会更新
- manifest.js,记录了 JS 文件映射表
Vite 4 里有什么可选的打包优化方案呢?
参考资料
到这里本文就结束了,您的点赞、关注与收藏,是我持续学习和写作的动力!
本文未涉及的或写得不清楚的,热烈欢迎您的评论和留言! Thanks♪(・ω・)ノ
转载自:https://juejin.cn/post/7240487843223142458