最近在迁移开源项目 vue-admin 到最新技术上的时候,遇到了一些技术隐形的问题,毕竟是最新的技术点,不免有些疑难杂症,因此分享给有须要的朋友javascript
预览效果css
node.js 文件系统html
浏览器环境文件操做api
使用,webpack
对应Vite
vue
// webpack
require.context
// 对应 vite 二选一,详细使用说明看文档 https://vitejs.dev/guide/features.html#glob-import
import.meta.globEager
import.meta.glob
复制代码
举个例子,当前项目须要读取src/icons/svg/
目录下的全部svg
名称,那么就要这样写:java
<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
的文件系统模块,这里跟webpack
环境基本一致。一样是当前项目的svg
组件,这里要单独写一个svg
的加载插件(vite插件),那么要像这样:node
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
文件中使用:webpack
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 报错git
这个问题比较诡异,npm run dev
连警告都没有,npm run build
打包竟然报错了,后面摸索了一下,原来在tsconfig.json
中,须要在include
的全部路径前面加个/
,webpack
环境表示没有出现过这类问题。像这样:github
{
...more,
// 这里全部的路径前面都要加上 / 猜想应该是 vite 在处理文件的时候,路径校验规则不太同样
"include": ["/src/**/*.ts", "/src/**/*.d.ts", "/src/**/*.tsx", "/src/**/*.vue"]
}
复制代码
可是呢,在全部路径前面加上/
以后又致使在开发中没法正常配置ts
的一些类型检测,因此又得把前面的/
给手动删掉,等npm run build
的时候再加上去,不知道这是否是vite
的一个bug
。web
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
做为删除惟一键值的,因此咱们在定义路由的时候最好写上,且惟一,删除路由操做能够看代码片断:
由于改用了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
}
}
})
复制代码
不肯定其余库的hooks
使用方式是否也是须要把声明写在顶层,但vue-router
是须要的。
以前webpack
环境中导出的方式依然不变,稍做变更的是文件命名,例如variables.scss
要做为js/ts
中导入使用,只须要在名字后面加个.module
便可,像这样:variables.module.scss
$--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 variables from "../styles/variables.module.scss";
console.log(variables) // 输出 { theme: "#1890FF" }
复制代码
注意事项
在main.ts
中引入带有module.scss
后缀的文件做为样式引入使用,默认是不会加载到<style>
去的,因此须要在没有module.scss
后缀的文件中@import ./xxx.module.scss
,而后再在main.ts
引入该文件
npm run build 报错
目前还不肯定是什么缘由,npm run dev
的时候正常使用,可是npm run build
就报错,出现:
[vite:css-post] value.replace is not a function
复制代码
因此我在项目中放弃xxx.module.scss
这种命名导入使用方式,而是采用直接暴力的解决方案:正常导入xxx.scss
以后,写一个提取导出变量的工具函数,这样就实现相同的功能了。
处理导出工具函数:
/** * 格式化`.scss`文件中导出的变量 * @param val */
function formatStyleModule(val: string) {
val = val.replace(/:export {/, ":export{").replace(/(\n|\t|\s)*/g, "");
const matchInfo = val.match(/:export{(\S*)}/);
if (matchInfo && matchInfo[1]) {
let match = matchInfo[1];
if (match[match.length - 1] == ";") {
match = match.slice(0, match.length - 1);
}
val = match.replace(/;/g, `","`).replace(/:/g, `":"`);
}
// console.log(`{"${val}"}`);
return JSON.parse(`{"${val}"}`);
}
复制代码
使用示例:
import style from "../styles/variables.scss";
const variables = formatStyleModule(style);
console.log(variables);
复制代码
第三方插件库
像一些比较老的插件,是不支持ES模块的,也就是不支持import
,只能使用require
的这类插件,目前是不支持在vite
中使用的,由于它只支持ES模块,或者本身手动去修改源码导出方式。
生产环境
最后须要注意的是,咱们在开发环境使用的原生ES模块
并不会由于打包后转成以往的兼容模式,意思就是打包后仍是ES模块
,而且只能用服务端形式来打开index.html
,一些低版本的浏览器是不支持或者存在兼容性的,仔细看下构建后的index.html
引用的js
标签就明白了;若是追求兼容、稳定,建议仍是用vue 2.x
+vue-cli
...