Vite 与 webpack 使用注意点
node.js 文件系统
浏览器环境文件操做api使用,webpack对应Vitevue
// webpack
require.context
// 对应 vite 二选一,详细使用说明看文档 https://vitejs.dev/guide/features.html#glob-import
import.meta.globEager
import.meta.glob
举个例子,当前项目须要读取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的文件系统模块,这里跟webpack环境基本一致。一样是当前项目的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
}
}
})
不肯定其余库的hooks使用方式是否也是须要把声明写在顶层,但vue-router是须要的。
scss变量在js或ts中使用
以前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模块
第三方插件库
像一些比较老的插件,是不支持ES模块的,也就是不支持import,只能使用require的这类插件,目前是不支持在vite中使用的,由于它只支持ES模块,或者本身手动去修改源码导出方式。
生产环境
最后须要注意的是,咱们在开发环境使用的原生ES模块并不会由于打包后转成以往的兼容模式,意思就是打包后仍是ES模块,而且只能用服务端形式来打开index.html,一些低版本的浏览器是不支持或者存在兼容性的,仔细看下构建后的index.html引用的js标签就明白了;若是追求兼容、稳定,建议仍是用vue 2.x+vue-cli…
© 著作权归作者所有
发表评论