Vue 项目中的 data-v-xxx 是怎么生成的

最近在研究微前端的样式隔离方案,看到了这样一个评论:

来自:微前端方案 qiankun 的样式隔离能不用就别用吧,比较坑 - 掘金

大意是说 Vue scoped 的 data-v-xxx 是根据文件相对路径计算的,如果微前端的两个 Vue 子项目采用相同的路径结构,那么算出来的 data-v-xxx 是一样的,可能会导致样式冲突。

听起来有点离谱,但事实是这样的么? 直接看源码:

  • webpack + vue-loader 对 vue2 的处理
js 复制代码
  // vue-loader/src/index.ts
  
  const shortFilePath = path
    .relative(rootContext || process.cwd(), filename)
    .replace(/^(..[/\])+/, '').replace(/\/g, '/')
  
  const id = hash(
    isProduction
      ? shortFilePath + '\n' + source.replace(/\r\n/g, '\n')
      : shortFilePath
  )

github.com/vuejs/vue-l...

  • vite + @vitejs/plugin-vue 对 vue3 的处理
js 复制代码
// vite-plugin-vue/src/util/descriptorCache.ts
  
import path from "node:path";
import { createHash } from "node:crypto";
import slash from "slash";

function getHash(text) {
  return createHash("sha256").update(text).digest("hex").substring(0, 8);
}

// 获取文件相对路径
const normalizedPath = slash(path.normalize(path.relative(root, filename)));
// 计算 ID
descriptor.id = getHash(normalizedPath + (isProduction ? source : ""));

github.com/vitejs/vite...

可以发现,不管是 vue-loader 还是 @vitejs/plugin-vue ,data 属性 ID 的生成机制都是一样的,即:

  • 开发环境下会根据文件相对路径 生成唯一 ID,比如 vite 中 src/App.vue 固定生成 7a7a37b1
  • 生产环境下会根据文件相对路径+文件内容共同生成唯一 ID

因此,我们可以回答文章一开始的问题:

相同路径结构的 Vue 子应用的组件,在开发环境下会产生样式冲突,但在生产环境下大概率不会,除非文件内容完全一样。

那如果遇到了冲突问题,除了手动修改文件路径或文件名,还有什么办法可以完全避免?

给 Vue 提 PR 一个更好的 ID 计算方式是加上项目名(或者 package.json 的 name),并支持手动指定,这样就可以彻底避免冲突问题了。

js 复制代码
import path from "node:path";
import { createHash } from "node:crypto";
import slash from "slash";

function getHash(text) {
  return createHash("sha256").update(text).digest("hex").substring(0, 8);
}

// 获取项目名
const projectName = config.projectName || path.basename(root)
// 获取文件相对路径(含项目名)
const normalizedPath = slash(path.normalize(path.join(projectName, path.relative(root, filename))));
// 计算 ID
descriptor.id = getHash(normalizedPath + (isProduction ? source : ""));

有遇到冲突的小伙伴,给 Vue 提 PR 的机会来了~

进一步思考:为什么开发环境和生产环境的 ID 计算方式不一样?

首先,开发环境下最好不要加入文件内容进行 hash 计算。

这很好理解,一来 hash 计算是耗时的,内容越多耗时越长;二来还会频繁变动节点样式,徒增成本。

那生产环境为什么还要加入文件内容计算 hash ?

如果 ID 与文件内容无关,就可以实现稳定的 data 属性。对于 E2E 测试用例,就可以直接使用 data 属性进行元素寻址。

我能想到的原因同本文主题相关,为了缓解多个 Vue 应用的样式冲突问题,但确实不算是一个非常好的解决措施。如果还有其他原因,欢迎在评论区分享 ~

总结

本文简单分析了 Vue 中 data-v-xxx 的计算规则 。

在开发环境中,会采用文件相对路径进行 hash 计算,而在生产环境中,还会加入文件内容共同计算。

在微前端逐步流行的情况下,这套生成策略在某些情况下会导致样式冲突。或许更好的计算方式是加入应用名,取消文件代码。


最后,笔者水平有限,欢迎评论探讨。如果本文对你有帮助的话,也欢迎一键三连(点赞、收藏、分享)~

相关推荐
码事漫谈2 小时前
比尔·盖茨这次谈的不是模型,是账单
前端·后端
星栈2 小时前
AI 生成页面全是紫粉渐变?我用 ui-ux-pro-max-skill 重构了整个产品页
前端·weui
avi91113 小时前
【】js不同颜色(Vue 框架)今时今日2026年学编程入门(10月1日)
前端·vue.js·vue·vue框架·前端入门·vue入门·html上传
Fluxart.ai3 小时前
商品多角度图怎么做?Flux Art 从白底图到规格图、包装图的 10 步教程
开发语言·前端·javascript
前端繁华如梦3 小时前
React + Three.js 造了一个"乙烯基娃娃"3D 角色编辑器:配方驱动、程序化生成、还能跳舞
前端
繁华若梦7593 小时前
全项目 Skills 适配:把「会写代码的 Agent」变成「会按你们规范干活的同事」
前端
江华森4 小时前
云原生从0到1:Kubernetes 工作负载实战——Deployment/Service/滚动更新/弹性伸缩
前端·后端
江华森4 小时前
《云原生从0到1:4台华为云ECS搭建Kubernetes 1.28集群实录(上)——环境与踩坑全记录》
前端·后端
codeY4 小时前
Vite 前端发布后「点击菜单没反应」?旧版本资源 404 的完整排查与修复实录
前端·前端工程化