最近在迁移开源项目 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介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!