头一次开发Vue3项目,之前都是使用Vue2进行的开发,所以多学习多总结快速适应吧。
一、项目 Bug
1、测试环境图片展示失败
bug 背景:
本地开发,项目图片正常展示,到了测试环境上,图片展示不出来了。那就查吧:
- 问:项目里的 svg 图片 build 打包构建后在 dist / assets 下面没有怎么回事?
SVG 打包后 dist/assets 缺失常见原因 & 排查(Vite/Webpack 通用)
一、Vite 项目(最常用)
1. 引入方式错误(不被资源插件捕获)
- 字符串直接写路径(不会打包复制)
javascript// 无效,vite不解析字符串路径 icon: './assets/icon.svg'改用 import 引入 :import IconSvg from '@/assets/icon.svg'
javascriptimport IconSvg from '@/assets/icon.svg' icon: IconSvgsvg-sprite-loader / vite-plugin-svg-icons 托管 svg
插件会把 svg 编译成 sprite 内联符号 ,不会输出单独 svg 文件到 dist/assets(正常现象)
特征:页面用
<svg-icon name="xxx"/>使用,dist 找不到原 svg 文件2. 配置排除 / 静态资源过滤
- vite.config
build.rollupOptions.external把 svg 外部化- 资源目录不在 vite 解析的
public/、src/assets扫描范围3. 放在 public 文件夹
public 内资源 原路径直接输出根目录 ,不在
assets/里
public/a.svg → dist/a.svg二、Webpack/VueCli 项目
- svg 被 svg-sprite-loader 处理:编译成雪碧图,无单独 dist 文件
- file-loader / asset-module 配置
type:'asset/inline':svg 转 base64 内嵌 js,不生成文件
javascript// webpack asset配置 内嵌则无实体文件 { test:/\.svg/, type:'asset/inline' }改成
asset/resource才会打包出实体文件到 assets三、快速排查步骤
- 搜索项目是否装了
vite-plugin-svg-icons、svg-sprite-loader→ 大概率被内联- 改成**import xxx from 'xxx.svg'**重新 build,看是否生成
- 查看 svg 存放目录:public→dist 根目录;src/assets→dist/assets
- 搜索配置文件
external、exclude是否忽略 svg
- 问:在 vue setup 里面怎么写
分两种场景(Vue3 + setup)
场景 1:想要打包出单独 svg 文件到 dist/assets(找不到文件就是用了精灵图插件)
html<template> <!-- 直接用引入变量 --> <img :src="svgImg" alt="" /> </template> <script setup> // 引入src/assets里svg,打包会进dist/assets import svgImg from '@/assets/xxx.svg' </script>场景 2:项目用了 vite-plugin-svg-icons / svg-sprite(图标精灵,不会打包出单独 svg)
特点:dist/assets 不会生成原 svg 文件,是正常的
html<template> <svg-icon name="xxx" /> </template> <script setup> // 无需import,插件自动注册 </script>场景 3:svg 放 public(打包在 dist 根目录,不在 assets)
html<template> <img src="/xxx.svg" /> </template>想要打包输出独立 svg 文件解决办法
- 图标类 svg 继续用
svg-icon(不生成文件)- 需要实体文件的 svg,直接 import 引入,不要放到 svg 图标目录⭐️
- 问:项目里好像没有配置@/,控制台报错了
答:
没有配置别名 @,改用相对路径写法(setup 直接可用)
1、普通 svg 生成 dist/assets(打包出文件)
html<template> <img :src="iconSvg" /> </template> <script setup> // 从当前文件位置去找assets,../回退层级 import iconSvg from '../assets/xxx.svg' </script>目录举例:views/index.vue →
../assets/xxx.svgcomponents/xx.vue →
../../assets/xxx.svg2、public 下 svg(打包在 dist 根目录,不在 assets)
html<template> <img src="/xxx.svg" /> </template>3、svg-icon 精灵图标(不产出 dist 单独文件)
html<template> <svg-icon name="xxx"></svg-icon> </template>补充: vite 添加 @别名(一劳永逸)
vite.config.js
javascriptimport { defineConfig } from 'vite' import { resolve } from 'path' export default defineConfig({ resolve:{ alias:{ '@': resolve(__dirname,'src') } } })配完重启项目就能用
@/assets。
- "iconSvg" is declared but its value is never read.
报错:iconSvg 声明未使用(eslint 未使用变量校验)
1、原因
<script>里定义了const iconSvg = xxx,但 模板、JS 全程没用到这个变量,eslint 报错。2、三种解决
① 删掉没用的变量(最优)
javascript// 删除这行 // const iconSvg = 'xxx'② 确实后续要用,临时注释忽略单行
javascript// eslint-disable-next-line no-unused-vars const iconSvg = ''③ eslint 全局关闭(不推荐)
javascript// .eslintrc rules: { "no-unused-vars": "off" }补充:如果是模板用到了还报错
检查:变量名大小写
iconSvg / iconSVG不一致。
2、控制台报错相关
bug 背景:
本地开发,控制台报错:nodes is not iterable.
javascript/** * 递归查找指定ID的树节点 * @param id 节点ID * @returns 节点对象 / null */ function findNode(id: string): OrgTreeNode | null { function walk(nodes: OrgTreeNode[]): OrgTreeNode | null { for (const n of nodes) { if (n.id === id) return n if (n.children) { const found = walk(n.children) if (found) return found } } return null } return walk(mockOrgTree) }报错原因
nodes is not iterable= 传入的n.children不是数组(undefined /null/ 对象),不能用 for...of 遍历。树节点里部分节点没有
children字段、或children: null / {},直接传给walk循环报错。修复代码
javascript/** * 递归查找指定ID的树节点 * @param id 节点ID * @returns 节点对象 / null */ function findNode(id: string): OrgTreeNode | null { function walk(nodes: OrgTreeNode[]): OrgTreeNode | null { // 兜底:非数组直接终止遍历 if (!Array.isArray(nodes)) return null for (const n of nodes) { if (n.id === id) return n // 只有children是数组才递归 if (n.children && Array.isArray(n.children)) { const found = walk(n.children) if (found) return found } } return null } // 顶层mockOrgTree也做数组校验 return Array.isArray(mockOrgTree) ? walk(mockOrgTree) : null }关键点改动说明
walk开头增加Array.isArray(nodes)判断,非数组直接返回null,避免for...of遍历异常- 递归前校验
n.children是数组 再进入walk- 入口调用校验根数据
mockOrgTree是否为数组可选:类型层面根治(修改 OrgTreeNode)
javascriptinterface OrgTreeNode { id: string // 强制children可选、类型只能是数组 | undefined,杜绝null/其他类型 children?: OrgTreeNode[] }
if(findNode(id)?.type === 'person') continue ,
if 里面的判断条件是 true 了,continue 下一行的代码,
const parent = findPersonParentDeptId(id) ,为什么执行不到了呢?
先解答核心问题:
if(findNode(id)?.type === 'person') continue导致后续代码不执行原因
javascriptif (findNode(id)?.type === 'person') continue const parent = findPersonParentDeptId(id)逻辑释义
continue作用:跳出当前本次 for 循环,直接进入下一次循环迭代
- 当
id是人员(type='person'),if条件=true→ 执行continuecontinue会终止本轮循环剩余所有代码 ,后面const parent = ...、personSet.add(id)全都跳过,直接开启下一轮for(const id of rawIds)- 这段代码业务逻辑:
如果当前选中 ID 是 人员 ,先去查找人员所属父部门;若父部门已经被整体勾选在部门集合
deptSet里,则 不再单独把这个人存入人员列表 (部门全选自动包含下属人员,人员不用重复勾选)。所以:type=person不 continue 才走下面去判断父部门,你现在写反了条件!错误原代码
javascriptif (findNode(id)?.type === 'person') continue // 人直接跳过,逻辑反了 const parent = findPersonParentDeptId(id) if (parent && deptSet.has(parent)) continue personSet.add(id)修正代码
javascript// 只处理人员类型数据,非人员直接跳过 if (findNode(id)?.type !== 'person') continue const parent = findPersonParentDeptId(id) // 人员的父部门已被全选,则该人员不需要单独选中 if (parent && deptSet.has(parent)) continue personSet.add(id)总结
- 原代码 BUG 根源 :
if(findNode(id)?.type === 'person') continue写反条件,person直接 continue 跳过父部门判断,改为!== person continue即可;continue只作用 当前 for 循环单次迭代,触发后本循环剩余代码全部不执行,直接下一轮循环。
未完待续loading...