最近在迁移开源项目 vue-admin 到最新技术上的时候,遇到了一些技术隐形的问题,毕竟是最新的技术点,难免有些疑难杂症,所以分享给有需要的朋友
预览效果
Vite 与 webpack 使用注意点
node.js 文件系统
以往在webpack环境中,是可以在任意地方使用import path from "path"或者import fs from "fs"来做一些文件处理的。现在Vite环境有些特殊的区分,就是在浏览器运行的文件,包括任何.js、.vue或者.ts,是不能正常使用import path from "path"或者import fs from "fs"等一些node.js模块的,必需要改用Vite环境特有的import.meta.globEager和import.meta.glob作为文件处理api使用。举个例子,当前项目需要读取src/icons/svg/目录下的所有svg名称,那么就要这样写:
<template>
<div v-for="item of svgIcons" :key="item">
<svg-icon :name="item" />
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
const svgFileReg = /(?<=(svg\/)).*?(?=(.svg))/;
/** 获取所有`svg`名称 */
function getSvgNames() {
const svgInfo = import.meta.globEager("../../icons/svg/*.svg");
const svgs = Object.keys(svgInfo);
const names = svgs.map(value => {
const res = value.match(svgFileReg)![0];
return res;
});
return names;
}
export default defineComponent({
name: "Icons",
setup() {
return {
svgIcons: getSvgNames()
}
}
})
</script>
说完浏览器运行文件,还有一个就是在vite.config.ts文件中,import.meta.globEager和import.meta.glob这个两个api就用不了了,只能用node.js的文件系统模块,也就是上说的那些import fs from fs。同样是当前项目的svg组件,这里要单独写一个svg的加载插件(vite插件),那么要像这样:
import { readFileSync, readdirSync } from "fs";
// svg-sprite-loader 这个貌似在 vite 中用不了
// 该文件只能作为`vite.config.ts`导入使用
// 其他地方导入会报错,因为浏览器环境不支持`fs`模块
/** `id`前缀 */
let idPerfix = "";
const svgTitle = /<svg([^>+].*?)>/;
const clearHeightWidth = /(width|height)="([^>+].*?)"/g;
const hasViewBox = /(viewBox="[^>+].*?")/g;
const clearReturn = /(\r)|(\n)/g;
/**
* 查找`svg`文件
* @param dir 文件目录
*/
function findSvgFile(dir: string): Array<string> {
const svgRes = []
const dirents = readdirSync(dir, {
withFileTypes: true
})
for (const dirent of dirents) {
if (dirent.isDirectory()) {
svgRes.push(...findSvgFile(dir + dirent.name + "/"));
} else {
const svg = readFileSync(dir + dirent.name).toString().replace(clearReturn, "").replace(svgTitle, (value, group) => {
// console.log(++i)
// console.log(dirent.name)
let width = 0;
let height = 0;
let content = group.replace(clearHeightWidth, (val1: string, val2: string, val3: number) => {
if (val2 === "width") {
width = val3;
} else if (val2 === "height") {
height = val3;
}
return "";
}
)
if (!hasViewBox.test(group)) {
content += `viewBox="0 0 ${width} ${height}"`;
}
return `<symbol id="${idPerfix}-${dirent.name.replace(".svg", "")}" ${content}>`;
}).replace("</svg>", "</symbol>");
svgRes.push(svg);
}
}
return svgRes;
}
/**
* `svg`打包器
* @param path 资源路径
* @param perfix 后缀名(标签`id`前缀)
*/
export function svgBuilder(path: string, perfix = "icon") {
if (path.trim() === "") return;
idPerfix = perfix;
const res = findSvgFile(path);
// console.log(res.length)
return {
name: "svg-transform",
transformIndexHtml(html: string) {
return html.replace("<body>",
`<body>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0">
${res.join("")}
</svg>`)
}
}
}
最后在vite.config.ts文件中使用:
import { defineConfig } from "vite"
import vue from "@vitejs/plugin-vue"
import vueJsx from "@vitejs/plugin-vue-jsx";
import { svgBuilder } from "./src/icons/loader"; // 这里是上面写的`svg`加载插件
export default defineConfig({
plugins: [vue(), vueJsx(), svgBuilder("./src/icons/svg/")],
})
npm run build 报错
这个问题比较诡异,npm run dev连警告都没有,npm run build打包居然报错了,后面摸索了一下,原来在tsconfig.json中,需要在include的所有路径前面加个/,我佛,webpack环境表示没有出现过这类问题。像这样:
{
...more,
// 这里所有的路径前面都要加上 / 猜测应该是 vite 在处理文件的时候,用的是严格路径校验
"include": ["/src/**/*.ts", "/src/**/*.d.ts", "/src/**/*.tsx", "/src/**/*.vue"]
}
但是呢,在所有路径前面加上/之后又导致在开发中无法正常配置ts的一些类型检测,所以又得把前面的/给手动删掉,等npm run build的时候再加上去,不知道这是不是vite的一个bug,已经向作者提问了...
vue-router
vue-router 4.x之后剔除了路由路径匹配,什么意思呢?看个代码片段
import { createRouter, createWebHashHistory } from "vue-router";
const base = [
{
path: "https://github.com/Hansen-hjs/vue-admin",
name: "baidu",
component: () => import("../views/404.vue"), // 这里一定要给个组件(虽然不会显示),不然会卡死
meta: {
icon: "star",
title: "跳转外部链接"
}
}
]
const router = createRouter({
history: createWebHashHistory(),
routes: base
})
这个时候会警告并卡死,因为现在不能匹配path为非/开头的路径了,这时候需要在外链前面加个/即可,然后对应的获取路由的时候做对应的的处理即可,像这样:
const base = [
{
path: "/https://github.com/Hansen-hjs/vue-admin",
...more
}
]
同时vue-router 4.x加入以往没有的新api:removeRoute现在可以轻松的做退出登陆删除之前动态拼接的路由了,不过这个api是以路由定义中name作为删除唯一键值的,所以我们在定义路由的时候最好写上,且唯一,删除路由操作可以看代码片段
removeRoutes 方法
因为改用了Composition API,所以路由的使用方式变了,不过需要注意的是:useRoute和useRouter这两个hooks函数必选要写在顶层,如果是写在代码运行之后的函数中,是获取不到的,看下面代码:
import { useRouter, useRoute } from "vue-router";
import { defineComponent } from "vue";
export default defineComponent({
setup() {
const route = useRoute();
const router = useRouter();
function getRouterInfo() {
// const route = useRoute(); // 如果写在这里,是获取不到对象的
// const router = useRouter(); // 如果写在这里,是获取不到对象的
console.log(route, router);
}
return {
getRouterInfo
}
}
})
scss 变量无法在 js 或 ts 中使用
之前在webpack中,.scss文件中导出的变量,是可以在对应的文件中作为js模块导入使用,现在换成vite之后就不行了,即使装了sass-loader,来看下之前能正确使用的代码片段:
$--color-primary: #1890FF;
// The :export directive is the magic sauce for webpack
// https://mattferderer.com/use-sass-variables-in-typescript-and-javascript
:export {
theme: $--color-primary;
}
其他非.scss文件导入使用
import elementVariables from "../styles/element-variables.scss";
console.log(elementVariables) // 输出 { theme: "#1890FF" }
详细翻了 vite文档 也是没有找到相关的配置,所以暂时用不了该功能。
打包后依然是使用最新的ES模块
最后需要注意的是,我们在开发环境使用的原生ES模块并不会因为打包后转成以往的兼容模式,意思就是只能用服务器形式来打开,并且不支持IE(好像是废话),仔细看下构建后的index.html引用的js标签就明白了,如果追求兼容、稳定,建议还是用vue 2.x+vue-cli...
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!