vite + Vue3 遇到的一些问题汇总
啰嗦一下,
vite
和vue3
已经出来很长一段时间了,一直没生产实践过,之前一直都是使用 vue2,通过这次实践,个人感觉还是喜欢使用那经典且深入人心的 vue2,或许这是众多顽固派不愿跟随技术更新的最后的倔强吧。不过 vue3 的<script setup>
语法糖挺好使的,可以减少许多代码,不用在 return 出去。
1. 项目开始的准备
熟悉下vue3 文档 和 vite 文档
vsoce 编辑器安装
Vue Language Features (Volar)
拓展
2. 关于 vite 遇到的一些问题
vite 的最大感觉就是“快”,本地开发比 webpack 快很多,因为不用打包所有看模块再启动,浏览器原生支持 ES 模块,文件修改后即生效,即使修改
vite.config.js
配置文件,也可以监听到,自动重启生效。
2.1 关于打包成 ES5 代码
通过build.target
配置项指定构建目标,传统浏览器可以通过插件@vitejs/plugin-legacy
来支持,最低仅支持到es2015
,即es6
,不能打包成es5
的代码。打包出来的代码<script type=module></script>
有type=module
属性,可以直接在里面使用模块化调用。有知道怎么处理成 es5 的,可以分享出来给大家。
// vite.config.js import { defineConfig } from "vite"; // https://github.com/vitejs/vite/tree/main/packages/plugin-legacy import legacy from "@vitejs/plugin-legacy"; export default defineConfig({ plugins: [ legacy({ targets: ["ie >= 11"], additionalLegacyPolyfills: ["regenerator-runtime/runtime"], }), ], build: { target: "es2015", // 默认 "modules" }, }); 复制代码
2.2 vite 中使用css
预处理器等
vite 中使用 less/scss/sass/stylus 等 css 预处理器
vitejs.cn/guide/featu… 直接进行安装,不用像 webpack 那样安装 loader 和配置
npm install -D less 复制代码
<style> /* use less */ </style> 复制代码
vite 中使用 postcss
vitejs.cn/config/#css… vite 中已集成了 postcss,无需再单独安装
vite 中使用 autoprefixer
import autoprefixer from "autoprefixer"; export default defineConfig({ css: { postcss: { plugins: [autoprefixer], }, }, }); 复制代码
2.3 vite 打包将 js 和 css 文件夹分离
默认打包后,js 和 css 是全部混在一起的,对强迫症很难受
github.com/vitejs/vite…
export default defineConfig({ build: { rollupOptions: { output: { chunkFileNames: "static/js/[name]-[hash].js", entryFileNames: "static/js/[name]-[hash].js", assetFileNames: "static/[ext]/[name]-[hash].[ext]", }, }, }, }); 复制代码
2.4 vite 根目录vite.config.js
配置文件异步配置
官方默认是支持的
cn.vitejs.dev/config/#asy…
export default defineConfig(async ({ command, mode }) => { const data = await asyncFunction(); return { // 构建模式所需的特有配置 }; }); 复制代码
2.5 vite 根目录vite.config.js
配置文件读取env
变量
在配置文件中直接使用import.meta.env.xxx
这样读取是报错的,不过有了上面的异步配置,读取env
变量就方便了,我们可以直接使用fs
直接获取
.env
文件
# PROXY_URL VITE_PROXY_URL=http://xxxxxx/ # DBPATH_ENV DBPATH_ENV=XXXX 复制代码
vite.config.js
文件
const fs = require("fs"); const path = require("path"); const { promisify } = require("util"); const fsState = promisify(fs.stat); const readFile = promisify(fs.readFile); // 定义一个函数,读取.env文件中的内容 async function getEnvConfig(vite_env_key) { const envFilePath = path.resolve(__dirname, "./.env"); const [notExistEnvFile, existEnvFile] = await fsState(envFilePath) .then((data) => [null, data]) .catch((e) => [e, null]); if (notExistEnvFile || existEnvFile.size <= 0) return; const envContent = await readFile(envFilePath, "utf8"); if (!envContent) return; const envContentArr = envContent .split("\n") .filter((str) => !str.startsWith("#")) // 过滤掉注释行 .filter(Boolean); const resultKey = envContentArr.find((item) => item.includes(vite_env_key)); return resultKey ? resultKey.split("=")[1] : null; } const resolveConf = async () => { // 读取 .env 文件中的VITE_PROXY_URL的值 const PROXY_URL = await getEnvConfig("VITE_PROXY_URL"); return { server: { host: "0.0.0.0", port: 3000, open: true, proxy: { "/api": { target: PROXY_URL, changeOrigin: true, // rewrite: (path) => path.replace(/^\/api/, ""), }, }, }, }; }; export default defineConfig(resolveConf()); 复制代码
2.6 vite 项目index.html
中使用env
环境变量
如何像webpack
项目的html-webpack-plugin
那样使用<%= htmlWebpackPlugin.options.title %>
,这种方式动态注入变量,vite 中可以使用vite-plugin-html
来完成。
安装
npm i vite-plugin-html -D 复制代码
使用(比如不同环境下动态注入高德地图的
key
)
vite.config.js
配置文件
import { minifyHtml, injectHtml } from "vite-plugin-html"; const AMAP_KEY = "xxx"; export default defineConfig({ plugins: [ injectHtml({ data: { title: "hello", // 高德地图 injectAMapScript: `<script src="https://webapi.amap.com/maps?v=1.4.15&key=${AMAP_KEY}"></script>`, }, }), ], }); 复制代码
index.html
中使用 ejs 模板引擎动态注入
<!DOCTYPE html> <html lang="en"> <head> <title><%- title %></title> </head> <body> <div id="app"></div> <script type="module" src="/src/main.js"></script> <%- injectAMapScript %> </body> </html> 复制代码
2.7 引用静态资源和 public 目录
cn.vitejs.dev/config/#pub…
引用静态资源
在 vue 文件中template
和style
中以相对路径和绝对路径两种方式引用静态资源
<template> <!-- 相对路径 --> <img src="./assets/img/test.png" /> <!-- 绝对路径 --> <img src="/src/assets/img/test.png" /> </template> <style scoped> #app { background-image: url("./assets/img/test.png"); } </style> 复制代码
public 目录
cn.vitejs.dev/guide/asset…
放在
public
目录下的文件应使用绝对路径引用,例如public/icon.png
应该使用/icon.png
public
中的资源不应该被JavaScript
文件引用
<img src="/logo.png" /> 复制代码
2.8 打包生产环境移除 console 和 debugger
export default defineConfig({ build: { // 生产环境移除console terserOptions: { compress: { drop_console: true, drop_debugger: true, }, }, }, }); 复制代码
2.9 异步 import 如何像 webpack webpackChunkName 那样支持自定义 chunkname
github.com/vitejs/vite…
// 这里如何像webpack那样支持自定义自定义chunkname,打包后文件名是自定义的名字 const Login = () => import("@/views/Login"); 复制代码
未解决,知道的,麻烦分享一下
3. 关于 vue3 遇到的一些问题
3.1 深度选择器
v3.cn.vuejs.org/api/sfc-sty…
之前的 '>>>' 已经被废弃,现在使用:deep()
伪类
<style scoped> .a :deep(.b) { /* ... */ } </style> 复制代码
3.2 vue-router4.x
路由 404 匹配
捕获所有路由或 404 Not found 路由
import { createRouter, createWebHistory } from "vue-router"; const Result = () => import("@/views/Result"); const router = createRouter({ history: createWebHistory(), routes: [ { // 注意这里,404页面匹配规则和以前不相同,要采用这种配置方式才行 path: "/:pathMatch(.*)*", component: Result, name: "Result", }, ], }); export default router; 复制代码
3.3 <script setup>
特性中使用vant3.x
组件
vant-contrib.gitee.io/vant/v3/#/z…
在<script setup>
中可以直接使用 Vant 组件,不需要进行组件注册
<template> <Button /> </template> <script setup> import { Button } from "vant"; </script> 复制代码
3.4 vite 启动后关于defineEmits
的警告
defineEmits
is a compiler macro and no longer needs to be importe
删掉defineEmits
的引用即可
- import { reactive, defineEmits } from 'vue'; + import { reactive } from 'vue'; // 直接使用defineEmits const emit = defineEmits(['test1', 'test2']); emit('test1', 'hello1'); 复制代码
3.5 vue3 和echarts5
动态更新数据报错
barPolar.js:63 Uncaught TypeError: Cannot read properties of undefined (reading 'type')
造成报错的原因是 vue3 中使用 proxy 的方式监听响应式,charts 实例会被在 vue 内部转换成响应式对象
在初始化的时候可以使用
markRaw
指定为非响应式即可
<template> <div ref="lineChartDomRef"></div> </template> <script setup> import { markRaw, ref, onMounted } from "vue"; import * as echarts from "echarts"; const lineChartInsRef = ref(); const lineChartDomRef = ref(); onMounted(() => { // 初始化时使用markRaw,后面使用lineChartInsRef.value实例更新时,就不会报错了 const option = { // ... }; lineChartInsRef.value = markRaw(echarts.init(lineChartDomRef.value)); lineChartInsRef.value.setOption(option); window.addEventListener("resize", () => { lineChartInsRef.value.resize(); }); }); </script> 复制代码
3.6 Vue3.x 使用<script setup>
如何设置组件name
名称
forum.vuejs.org/t/vue3-2-sc…
其实可以写两个 script 标签,下面两个可以并存
<script> import { defineComponent } from "vue"; export default defineComponent({ name: "Test", }); </script> <script setup> // ... </script> 复制代码
3.7 vue3 中的 vue-router4.x 下的 keep-alive 写法
[Vue Router Warn]: <router-view> can no longer be used directly inside <transition> or <keep-alive>
router-view 的 v-slot
在动态组件上使用 keep-alive
之前这样写,会报警告
<keep-alive> <RouterView /> </keep-alive> 复制代码
根据提示,得这样写:
<template> <router-view v-slot="{ Component }"> <!-- 缓存name名称为aaa和bbb的组件 --> <keep-alive :include="['aaa', 'bbb']"> <component :is="Component" /> </keep-alive> </router-view> </template> 复制代码
3.8 vue-router4 监听路由变化 onBeforeRouteUpdate
import { onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue-router'; onBeforeRouteUpdate((to, from, next) => { if (from.name === 'MachineList') { ... } next(); }); 复制代码
3.9 nginx 线上部署,刷新后页面 404
修改 nginx 配置
location / { root /usr/share/nginx/dist; # 服务默认启动目录 index index.html index.htm; # 默认访问文件 + try_files $uri /index.html; # 防止浏览器刷新后,页面404 client_max_body_size 100m; }
作者:sRect
链接:https://juejin.cn/post/7028137821269393438