Vue-cli 迁移 Vite (Vue3 + TSX + Antd-Vue)Vue-cli创建的项目迁移到Vite,项
背景
上个月入职新东家当天便被拉着开了一个紧急项目启动会,于是下午和晚上便开始了项目的技术选型和基础搭建。最终选择了使用vue-cli
作为脚手架,并使用以Vue3
+TypeScript
+Antd-Vue
为核心的技术栈来完成该项目。
随着项目代码的增多,之前vue-cli
中使用webpack
进行打包构建的方式变得越来越慢,于是在新一阶段的开发任务推进前,决定将vue-cli
迁移到vite
。
本来以为在网上这么多资料的情况下一两个小时就能搞定的事情,结果却花了半天🤭,所以这里把迁移的过程进行记录。
迁移过程
将整个迁移过程详细拆分后,可包含以下多个步骤:
- 引入
vite
; - 迁移
index.html
; - 迁移
alias
; - 迁移
Antd
; - 迁移
DevServer
- 支持
jsx
; - 支持
TypeScript
; babel
配置- 无用文件清理
其中在迁移
alias
、Antd
以及babel配置
过程中遇到了一些坑,可重点关注。
引入vite
使用 npm 安装vite
到当前项目中,如下所示:
npm install vite -D
安装完成后修改package.json
中的命令,使用vite
进行开发、打包和预览,如下:
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
}
迁移index.html
现在执行npm run dev
命令,命令行中不会报错,因为vite
并没有找到项目的入口,只是启动了一个空的server,通过浏览器访问我们的开发地址也会出现404
的报错。
vite
是根据index.html
来确定项目的入口文件的,且该index.html
文件的位置默认是需要在项目的根目录下的,具体原因这里不多介绍,可以查看官方文档的说明index.html与项目根目录。
于是我们将/public/index.html
和/public/favicon.ico
文件移动到项目的根目录,并修改index.html
文件的内容如下:
<!DOCTYPE html>
<html lang="">
<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" />
<link rel="icon" href="/favicon.ico" />
<title><%- title %></title>
</head>
<body>
<noscript>
<strong
>We're sorry but <%- title %> doesn't work properly without
JavaScript enabled. Please enable it to continue.</strong
>
</noscript>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
这里主要有以下两个改动点:
- 在文件底部加入了
<script type="module" src="/src/main.ts"></script>
用来引入项目js主文件; - 将之前
webpack-html-plugin
的一些变量引用改成了vite-plugin-html
插件的引用方式。
vite-plugin-html
需要在vite.config.js
中进行配置,我们在项目的根目录创建vite.config.js
文件,并通过插件去配置index.html
中需要的变量,如下所示:
import { defineConfig } from "vite";
import { minifyHtml, injectHtml } from "vite-plugin-html";
export default defineConfig({
plugins: [
minifyHtml(),
injectHtml({
data: {
title: "IDG Data Platform",
},
}),
]
});
完成上述必备工作后启动项目就能够看到具体的报错信息了,开发者便可以根据相应的报错信息去依次解决。后面的步骤便是我在项目迁移过程中解决的数个问题。
迁移alias
在将vue.config.js
中的alias
配置直接复制到新的配置文件中后,启动项目产生错误如下:
在官方的issue列表中我们找到了该问题的解决方案less import no support webpack alias '~',由于vite
默认无法识别出~
,因此我们需要手动设置该alias
,使用以下配置即可:
export default defineConfig({
...
resolve: {
// 别名配置
alias: [
{ find: /^~/, replacement: "" },
{
find: /^@\//,
replacement: resolve("./src/"),
},
],
},
...
});
迁移Antd
Antd
的迁移主要包含两部分,一是自定义主题中less
变量的迁移,第二个则是按需加载的迁移。
在原vue.config.js
中,我们使用如下配置来定义less
变量:
module.exports = {
...
css: {
extract: true,
loaderOptions: {
less: {
lessOptions: {
modifyVars: {
"theme-color": "#2b384f",
"layout-header-background": "#2b384f",
"layout-sider-background": "#354053",
"menu-item-color": "#fff",
"menu-highlight-color": "#fff",
"menu-bg": "#354053",
"menu-item-active-bg": "#2b384f",
"font-size-base": "12px"
},
javascriptEnabled: true
}
}
}
}
...
}
将该配置复制到vite.config.js
中,发现会出现如下错误,相当于配置未生效,导致无法找到对应的样式变量。
同样的,我们可以在官方issue找到类似的问题cssPreprocessOptions less modifyVars Invalid modification,在vite 2.x
中 CSS 预处理器的配置方式与之前不同,因此我们需要将配置修改为以下即可。
export default defineConfig({
...
css: {
extract: true,
preprocessorOptions: {
less: {
javascriptEnabled: true,
modifyVars: {
"theme-color": "#2b384f",
"layout-header-background": "#2b384f",
"layout-sider-background": "#354053",
"menu-item-color": "#fff",
"menu-highlight-color": "#fff",
"menu-bg": "#354053",
"menu-item-active-bg": "#2b384f",
"font-size-base": "12px",
},
},
},
},
...
});
按需加载的迁移比较简单,只需要将原先babel
配置中按需加载的插件配置进行迁移即可,该功能依赖babel-plugin-import
插件,此插件为babel插件,配置如下。
export default defineConfig({
...
plugins: [
...
babel({
...
plugins: [
...
[
"import",
{
libraryName: "ant-design-vue",
libraryDirectory: "es",
style: true,
},
],
],
}),
],
...
});
迁移DevServer
DevServer
的迁移相对比较简单,只需要将之前的代理配置复制过来即可。
export default defineConfig({
...
server: {
proxy: {
"/api": {
target: "http://192.168.xxx.xx:8080",
},
},
before(app) {
app.get("/mock/*", (req, res) => {
const url =
req.url.indexOf("?") > -1 ? req.url.split("?")[0] : req.url;
const func = require(resolve(`./src/${url}`));
res.json(func(req, res));
});
},
},
...
});
支持jsx
由于整个项目是采用了TSX的写法,因此在vite
中需要配置支持jsx
,否则便会出现Uncaught ReferenceError: React is not defined
的报错。
vite
官方已经提供了对应的插件,我们只需要安装并引用@vitejs/plugin-vue-jsx
插件即可,配置如下:
import vueJsx from "@vitejs/plugin-vue-jsx";
export default defineConfig({
...
plugins: [
...
vueJsx(),
...
],
...
});
支持TypeScript
Vite 天然支持引入
.ts
文件。
这是官方文档中关于TypeScript
部分的开头语,在vite
项目中使用TS语法,修改tsconfig.json
配置中compilerOptions.types
值为["vite/client"]
便可以支持TS开发。
babel
配置
并不是每一个项目的迁移都需要进行额外的babel
配置,此项目中使用了decorators
以及Optional Chaining
的语法,同时使用了Antd
按需加载的插件,所以需要进行一些基础的babel
配置。
vite
的内部使用rollup
进行打包,所以支持通过@rollup/plugin-babel
插件来配置babel
。
其他依赖及插件可通过以下两个命令分别安装:
npm i @babel/runtime core-js -S
npm i @babel/plugin-proposal-optional-chaining @babel/plugin-transform-runtime @babel/preset-env @rollup/plugin-babel babel-plugin-import -D
这里的配置都比较常用,就不一一展开,整体配置如下所示:
import babel from "@rollup/plugin-babel";
export default defineConfig({
...
plugins: [
...
babel({
babelHelpers: "runtime",
presets: [
[
"@babel/preset-env",
{
modules: false,
},
],
],
extensions: [".ts", ".tsx", ".js"],
exclude: "node_modules/**",
plugins: [
"@babel/plugin-transform-runtime",
[
"import",
{
libraryName: "ant-design-vue",
libraryDirectory: "es",
style: true,
},
],
["@babel/plugin-proposal-optional-chaining"],
],
}),
...
],
...
});
无用文件清理
在上述配置均完成之后,我们已经可以正常启动并构建我们的项目啦,为了保持工作区干净,删除掉无用的.babelrc
和vue.config.js
,整个项目的迁移过程便完成了🎉🎉🎉!
附录
整个项目迁移完成之后的目录结构和配置文件如下。
目录结构
├── .editorconfig
├── .env.dev
├── .eslintignore
├── .git
├── .gitignore
├── .gitlab-ci.yml
├── .prettierrc
├── README.md
├── favicon.ico
├── index.html
├── node_modules/
├── package-lock.json
├── package.json
├── public/
├── scripts/
├── src/
├── tsconfig.json
└── vite.config.js
vite.config.js
import { defineConfig } from "vite";
import { minifyHtml, injectHtml } from "vite-plugin-html";
import babel from "@rollup/plugin-babel";
import vueJsx from "@vitejs/plugin-vue-jsx";
const path = require("path");
function resolve(dir) {
return path.join(__dirname, dir);
}
export default defineConfig({
css: {
extract: true,
preprocessorOptions: {
less: {
javascriptEnabled: true,
modifyVars: {
"theme-color": "#2b384f",
"layout-header-background": "#2b384f",
"layout-sider-background": "#354053",
"menu-item-color": "#fff",
"menu-highlight-color": "#fff",
"menu-bg": "#354053",
"menu-item-active-bg": "#2b384f",
"font-size-base": "12px",
},
},
},
},
resolve: {
// 别名配置
alias: [
{ find: /^~/, replacement: "" },
{
find: /^@\//,
replacement: resolve("./src/"),
},
],
},
server: {
proxy: {
"/api": {
target: "http://192.168.xxx.xx:8080",
},
},
before(app) {
app.get("/mock/*", (req, res) => {
const url =
req.url.indexOf("?") > -1 ? req.url.split("?")[0] : req.url;
const func = require(resolve(`./src/${url}`));
res.json(func(req, res));
});
},
},
plugins: [
minifyHtml(),
injectHtml({
data: {
title: "Platform",
},
}),
vueJsx(),
babel({
babelHelpers: "runtime",
presets: [
[
"@babel/preset-env",
{
modules: false,
},
],
],
extensions: [".ts", ".tsx", ".js"],
exclude: "node_modules/**",
plugins: [
"@babel/plugin-transform-runtime",
[
"import",
{
libraryName: "ant-design-vue",
libraryDirectory: "es",
style: true,
},
],
["@babel/plugin-proposal-optional-chaining"],
],
}),
],
});
转载自:https://juejin.cn/post/7002561636380704798