On this page
preserveSymlinks:启用此选项会使 Vite 通过原始文件路径(即不跟随符号链接的路径)而不是真正的文件路径(即跟随符号链接后的路径)确定文件身份
什么是符号连接路径
# 符号链接(Symlink)位置
/my-project/node_modules/my-library -> /real/path/my-library
即:
- preserveSymlinks 为 true 用/my-project/node_modules/my-library
- preserveSymlinks 为 false 用/real/path/my-library
技术原理(Node.js 模块解析)
Node.js 在解析模块时,会根据 require() 调用方的文件路径 向上查找 node_modules。符号链接的位置决定了这个“调用方路径”的起点:
// 文件:/my-project/src/index.js
// 若 my-library 是符号链接
const lib = require('my-library');
- preserveSymlinks: true:查找路径基于 /my-project/node_modules/my-library
- preserveSymlinks: false:查找路径基于 /real/path/my-library
可能的现象与影响
启用 可能会导致:
- 模块重复(相同的模块可能被加载多次,因为它们通过不同的路径被引用)
- 影响热更新和缓存行
停用:
- 避免模块重复:当不保留符号链接时,相同的模块通过不同路径引用会被识别为同一个模块(视为源码)
- 保持依赖关系:在某些情况下,保留符号链接结构对于正确解析依赖关系很重要
示例
仓库:https://github.com/sunven/preserve-symlinks-in-vite-demo
查看 vite resolve 日志
pnpm dev -d resolve --force
依赖关系
- app [email protected]
- utils [email protected]
4.13.1 > 4.14.0
- Added _.conformsTo & _.defaultTo
- 即 4.14.0 中新增了 _.conformsTo 和 _.defaultTo,而 4.13.1 中没有
preserveSymlinks 为 false
vite dev 日志
vite:resolve 0.53ms /src/main.ts -> C:/Users/Administrator/Desktop/preserve-symlinks-demo/packages/app/src/main.ts +0ms
vite:resolve 3.14ms lodash-es -> C:/Users/Administrator/Desktop/preserve-symlinks-demo/node_modules/.pnpm/[email protected]/node_modules/lodash-es/lodash.js +7ms
vite:resolve 2.16ms utils -> C:/Users/Administrator/Desktop/preserve-symlinks-demo/packages/utils/index.ts +3ms
页面请求顺序
localhost http://localhost:5173/
main.ts http://localhost:5173/src/main.ts
lodash-es.js?v=876c6261 http://localhost:5173/node_modules/.vite/deps/lodash-es.js?v=876c6261
index.ts http://localhost:5173/@fs/C:/Users/Administrator/Desktop/preserve-symlinks-demo/packages/utils/index.ts
页面控制台报错
Uncaught SyntaxError: The requested module '/node_modules/.vite/deps/lodash-es.js?v=876c6261' does not provide an export named 'defaultTo' (at index.ts:1:10)
packages/app/src/main.ts 中:
import { util1 } from 'utils'
变为
// 用的真实路径
import {util1} from "/@fs/C:/Users/Administrator/Desktop/preserve-symlinks-demo/packages/utils/index.ts";
packages/utils/index.ts 中
import { defaultTo } from 'lodash-es'
变为
import {defaultTo} from "/node_modules/.vite/deps/lodash-es.js?v=8b0d0e60";
说明了什么?
- 连接依赖会被当做源码处理,所以 utils 依赖的 lodash-es 会从 app 中找
- app 中 [email protected], 没有 defaultTo 方法,所以报错
额外的:
- app src 中模拟一个 lodash-es ,可以被引用,证明包的查找方法
- utils 的 node_modules 删除不影响,证明:utils 依赖的 lodash-es 会从 app 中找
preserveSymlinks 为 true
vite dev 日志
vite:resolve 0.36ms /src/main.ts -> C:/Users/Administrator/Desktop/preserve-symlinks-demo/packages/app/src/main.ts +0ms
vite:resolve 1.43ms lodash-es -> C:/Users/Administrator/Desktop/preserve-symlinks-demo/packages/app/node_modules/lodash-es/lodash.js +4ms
vite:resolve 0.72ms utils -> C:/Users/Administrator/Desktop/preserve-symlinks-demo/packages/app/node_modules/utils/index.ts +1ms
vite:resolve 1.33ms lodash-es -> C:/Users/Administrator/Desktop/preserve-symlinks-demo/packages/app/node_modules/utils/node_modules/lodash-es/lodash.js +37ms
页面请求顺序
localhost http://localhost:5173/
main.ts http://localhost:5173/src/main.ts
lodash-es.js?v=122d68ec http://localhost:5173/node_modules/.vite/deps/lodash-es.js?v=122d68ec
utils.js?v=a932a310 http://localhost:5173/node_modules/.vite/deps/utils.js?v=a932a310
页面控制台正常输出
可以看到 utils -> C:/Users/Administrator/Desktop/preserve-symlinks-demo/packages/app/node_modules/utils/index.ts
路径中存在 node_modules,会被优化,不会当源码,app,utils 用各自的 node_modules,也就不会报错
问题
符号链接循环
reference
node 中 require 加载模块
- https://nodejs.org/api/modules.html#all-together
- https://nodejs.org/api/modules.html#loading-from-node_modules-folders
为什么使用硬链接? 为什么不直接创建到全局存储的符号链接?