SSF0SSF0
首页
前端
  • Node
  • Go
  • Python
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
  • 开源项目
Timeline
Github
标签
分类
首页
前端
  • Node
  • Go
  • Python
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
  • 开源项目
Timeline
Github
标签
分类
  • HTML

    • html1
    • html2
  • CSS

    • Flex 布局常见问题与解决方案
  • JavaScript

    • 数据类型及引用问题
    • 处理 Blob 类型文件下载问题总结
    • localStorage 与 sessionStorage 区别
    • JavaScript 中的 script 标签问题详解
    • JavaScript 中的 this 指向问题详解
    • SessionStorage踩坑记录
    • 动态加载 JS 脚本方法对比
    • 浏览器页面关闭场景下的数据上报
    • HTTP流式接口详解与封装实践
    • JavaScript 中 this 绑定与解构:为什么 Pinia Store 可以解构,但 Class 实例方法不行?
  • es6

    • Promise
    • es6 模块导出方式全解析
    • reduce
    • forEach 中使用 async/await 的异步陷阱
  • Vue2

    • created VS mounted 发起异步请求
    • vue2-2
  • Vue3

    • Vite + Vue3 修改 element-plus 源码
    • Vue v-if 与 v-show
    • Vue3 ref 获取组件
    • Vue3 路由传参
    • 父子组件与组件里 Hooks 加载顺序
    • 第三方组件传入参数TS提示
    • Vue3 Props 在 Hooks 中的响应性处理
    • Vue Router 的两种历史模式及部署配置详解
    • 在Vue 3项目中顺利集成Tailwind CSS的完整指南
    • Vue Scoped CSS 深度解析
    • Vue 3 Teleport 组件完全指南:从原理到实战
    • Vant List 组件中双向绑定 loading 的注意事项
    • Vue 3 + Vite 中的路径别名与静态资源处理深度解析
    • 获取图片高度
    • 深入理解 Pinia:storeToRefs vs toRefs - 避开 TypeScript 类型推断的坑
  • webSocket

    • WebSocket 鉴权入门(实战版):握手票据 / 首帧鉴权 + 连接级 cid
  • Electron

    • 快速构建 electron + vue3 项目
  • TS

    • TS 泛型
    • 记录模板使用断言的问题
    • type 与 interface
  • WebPack

    • Webpack 介绍
  • Vite

    • Vite CLI 常见命令
    • vite 与 webpack 比较
    • Vite base 配置与 public 静态资源路径问题
  • 客户端数据库

    • IndexedDB 索引陷阱:字段重命名后索引返回旧数据
    • IndexedDB 事务陷阱与最佳实践:TransactionInactiveError 完全解析
  • UniApp

    • uni-app + Monorepo + 微信小程序热更新失效问题排查与结论总结
    • Monorepo + uni-app 开发中监听 / 热更新机制差异与解决方案
    • uni-app 运行与编译原理梳理
    • 为什么 uni-app 在 Monorepo 中必须做「环境区分」,而 Web 项目却不用?
  • 项目工程

    • 前端代码风格
    • Vue3 项目规范
    • npm 镜像问题
    • 包管理工具
    • 使用 engines 限制开发环境依赖
    • 打包与shell交互指定模式
    • Monorepo示例
    • PC 项目兼容 uni-app:基于 pnpm Monorepo 的工程化重构实践
    • Vue3 + Vite + pnpm Monorepo 迁移问题指南
    • 前端工程化:深入理解 npm 依赖管理机制
    • pnpm 修改依赖源码打包报错
    • 代码片段
  • 移动端

    • 浏览器跳转外部应用时请求状态码问题
  • 记录一下小程序
  • 控制浏览器正确保存网站账号密码的技巧
  • 信息泄露
  • 使用Gulp实现前端项目哈希化压缩打包
  • 前端缓存策略与文件哈希化的关联解析
  • 浏览器刷新方式与 Vue 生命周期、缓存行为解析
  • 浏览器消息铃声实现记录

为什么 uni-app 在 Monorepo 中必须做「环境区分」,而 Web 项目却不用?

—— 从 workspace 依赖、监听机制到工程边界的一次完整拆解


一、背景:一个非常常见的工程升级场景

很多团队都会遇到类似的情况:

  • 原本有一套 PC Web 项目

  • 现在需要:

    • 兼容小程序
    • 兼容 H5
    • 兼容 App
  • 技术选型:uni-app(Vue3 + Vite + TS)

为了避免逻辑重复,自然会想到:

抽离业务逻辑为共享包, 用 Monorepo 统一管理

于是工程结构演进为:

.
├─ apps/
│  ├─ web/        # 原 PC Web 项目
│  └─ uni/        # uni-app 项目
├─ packages/
│  └─ core/       # 共享业务逻辑
├─ pnpm-workspace.yaml
└─ package.json

二、Web 项目:为什么「什么都不配」也能正常开发 + 打包?

1. pnpm workspace 已经把依赖“连好了”

在 Web 子项目中:

import { xxx } from "@zkzq/core";

pnpm 会在:

apps/web/node_modules/@zkzq/core

创建一个 软链接,指向:

packages/core

2. Vite 对 workspace 包“非常友好”

在 开发模式(dev) 下,Vite 有一个重要特性:

如果依赖是 workspace 本地包, 且是 ESM 源码 → 当作源码处理

结果是:

  • 修改 packages/core/src
  • Web 项目立即重新编译
  • 不需要 alias
  • 不需要额外配置

👉 这就是 Web 项目“看起来什么都不用做”的根本原因


3. Web 项目为什么 build 阶段也总是“最新的”?

因为:

  • build 读取的是软链接指向的真实文件
  • 永远是磁盘当前状态
  • 不存在“缓存旧包”的情况

所以: Web:dev 省心,build 也省心


三、uni-app:问题从哪里开始?

1. uni 的 Vite ≠ 原生 Vite

虽然 uni 使用的是 vite-plugin-uni,但它:

  • 接管了模块解析
  • 接管了依赖分析
  • 接管了监听范围
  • 接管了多端编译流程

uni 在开发期有一个非常关键的判断:

这个文件是不是 uni 项目的“源码”?


2. workspace 包在 uni 看来是什么?

在 uni 的视角中:

  • apps/uni/src/** → 源码 ✅
  • packages/core/** → 依赖 ❌

结果是:

  • 文件确实发生了变化
  • 但 不进入 uni 的依赖图
  • 不触发重新编译
  • 页面自然不会更新

3. 不同端的监听差异(非常关键)

运行端uni 的监听策略
H5会监听部分入口文件(如 index.html),但不会重编译 workspace 包
小程序只监听 src/,workspace 包完全被忽略

这也是为什么:

同一套 Monorepo Web 正常 uni H5 半正常 uni 小程序完全无效


四、为什么给 uni 配 alias 就“好了”?

resolve: {
  alias: {
    "@zkzq/core": "../../packages/core/src"
  }
}

这一步的本质是:

强制把共享包“伪装成” uni 项目的源码

结果:

  • 进入 uni 的依赖图
  • 被纳入监听范围
  • 修改即重新编译
  • 开发体验恢复正常

五、那为什么 build 阶段不推荐继续 alias 到 src?

这是工程边界问题,而不是“能不能跑”的问题。

1. alias src 在 build 阶段会破坏什么?

  • 绕过 package.json
  • 绕过 exports / main
  • 绕过依赖版本边界
  • apps 不再“依赖一个包”,而是“引用一堆路径”

👉 Monorepo 名存实亡


2. uni build 是否会打包到最新代码?

会的,而且一定会。

原因:

  • workspace 依赖是软链接
  • build 读取的是实时文件系统
  • 不区分 root / 子项目执行

所以正确结论是:

alias src 不是为了解决 build 正确性, 而是为了 dev 期监听能力


六、正确且推荐的工程模式

✅ 开发期(Dev)

const isDev = process.env.NODE_ENV === "development";

resolve: {
  alias: isDev ? { "@zkzq/core": "../../packages/core/src" } : {};
}

目标:开发体验最大化


✅ 构建期(Build)

import { xxx } from "@zkzq/core";

目标:依赖边界清晰、产物稳定、可迁移


七、为什么说「uni 必须做环境分析,而 Web 不需要」?

本质原因只有一句话:

Web 的构建工具帮你承担了 Monorepo 的复杂度, uni 没有,也不能。

所以:

  • Web:工具“聪明”
  • uni:工程师必须“清醒”

八、最终总结(一句话带走)

uni-app 在 Monorepo 中需要环境区分, 不是因为它麻烦, 而是因为它对工程边界更敏感。

最后更新时间:
贡献者: 何风顺
上一页
uni-app 运行与编译原理梳理