[Vite, Vue, HMR] per-module-served plugin subpath that imports `nativescript-vue` bare evaluates the real package root and double-runs `init()` (Element for AbsoluteLayout already registered)
还没有人认领这个 Issue。
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 45/100
- Issue 类型
- 缺陷
- 描述清晰度
- 基本清楚
- 活跃度
- 活跃
- 技术栈
- ios, typescript, vite
- 领域
- mobile-dev, tooling
调研方向
首先使用 HMR 重现 collectionview 导入,然后阅读 hmr/shared/vendor/manifest-collect.ts 和 hmr/server/deps-bundle.ts,尤其关注 issue 中提到的 Solid 处理和 shim 逻辑。当按模块提供的 Vue 插件导入能够复用已打包的 nativescript-vue 实例、避免重复注册,并且无需 NS_VENDOR_INCLUDE 即可保留 HMR 时,即视为完成。
由索引模型根据 Issue 内容生成。
描述
Issue Description
Runtime error (dev server / HMR only). @nativescript/vite 8.0.5 (same on 8.0.4) · nativescript-vue 3.0.3 · @nativescript/core 9.1.1 · vite 8.2.2 · @nativescript/ios 9.1.0 · iOS simulator (iPhone 17 Pro Max).
Scope: iOS simulator only; not tested on Android or a physical device.
A blank Vue app boots fine under HMR. It stops booting the moment I import one plugin subpath whose file is served per-module (not shimmed into the deps bundle) and contains a bare import ... from 'nativescript-vue'. I only tested that one plugin, but the routing below suggests any file with that shape would do the same.
Bare nativescript-vue is mapped in the device import map to the real package root (/ns/m/node_modules/nativescript-vue), unlike @nativescript/core, which is mapped to the /ns/core bridge. (Every other package root maps the way nativescript-vue does — @nativescript/core is the special case.) The real root cannot be shimmed (its export * from '@vue/runtime-core' is a bare star), so importing it evaluates it — and its module-scope init() runs a second time, on top of the copy the deps bundle already evaluated:
Error: Element for AbsoluteLayout already registered.
If this is intentional set 'overwriteExisting: true' in 'meta'
at registerElement (/ns/deps-bundle.mjs)
at registerCoreElements (/ns/deps-bundle.mjs)
at init (/ns/deps-bundle.mjs)
at (/ns/m/node_modules/nativescript-vue:41:1)
Concrete trigger: @nativescript-community/ui-collectionview/vue3. There is a config-only workaround (NS_VENDOR_INCLUDE, below), so this is not a blocker — but there may be a similar case to cover for Vue to what manifest-collect already does for Solid.
Expected behavior: importing a plugin's Vue entry should share the one nativescript-vue instance the deps bundle already evaluated, the way app-code imports (rewritten to /ns/rt) do.
A second, separate bridge problem surfaces once this one is worked around: #11422 ($navigateTo "app navigator missing" race).
Line numbers below refer to the published @nativescript/vite 8.0.5 package (compiled .js in node_modules) unless marked .ts, which refers to packages/vite on main.
Reproduction
Minimal repro (blank app, two steps):
ns createa blank Vue TS app (template-blank-vue 9.1.0 — it ships webpack), thennpx nativescript-vite init(adds@valor/nativescript-websocketsplus the two config keys). Boots under HMR, and live HMR works — aHome.vueedit applies on device.npm i @nativescript-community/ui-collectionview@6.0.25, and inapp/app.ts:
import { createApp } from 'nativescript-vue';
import CollectionView from '@nativescript-community/ui-collectionview/vue3';
import Home from './components/Home.vue';
const app = createApp(Home);
app.use(CollectionView);
app.start();
ns debug ios→ crashes with the error above.
Controls, same tree:
| Variant | Result |
|---|---|
| plugin installed but not imported | boots |
pinia installed and app.use(createPinia()) |
boots |
| plugin imported (as above) | crashes |
ns debug ios --no-hmr |
boots |
So the trigger is exactly that one import.
Mechanism — steps 1-3 from my run's manifest, the served file and the import map; steps 4-5 from reading the shipped code
-
The
vue3/subpath isn't in the bundle. In my run's deps-bundle manifest (node_modules/.ns-vite/deps-bundle-ios-*.json), the only keys under@nativescript-community/ui-collectionviewwereindex.ios.jsandindex-common.js— its root entry closure.vue3/index.jsandvue3/component.jsare not bundle keys, so no shim is emitted and they are served as real per-module ESM. -
Their
nativescript-vueimport is not rewritten. Servedvue3/component.jsline 2 is a bareimport { NSVRoot, defineComponent, getCurrentInstance, h, ref, render, toRaw, watch } from "nativescript-vue";— while line 1 of the same served file was rewritten toimport __ns_core_ns1 from ".../ns/core". App-code imports ofnativescript-vueare rewritten to/ns/rt; this node_modules file's are not. -
The import map sends it to the real root.
/ns/import-map.json→importMap.imports(1987 entries) maps"nativescript-vue"→http://<host>:5173/ns/m/node_modules/nativescript-vue, but"@nativescript/core"→http://<host>:5173/ns/core. That asymmetry is what routes the bare import at the real package root. -
The real root can't be shimmed.
nativescript-vue/dist/index.js:16isexport * from '@vue/runtime-core'— a bare star.collectDepsModuleExportInforeturnsnames: nullfor a non-relativeexport *(hmr/server/deps-bundle.js:781-785;.ts~:798-813), and the shim site (hmr/server/deps-bundle.js:920-938) emits a shim only whennames !== nulloropaqueCjsis set. Neither holds → per-module serving → the URL evaluates the file, anddist/index.js:10init()runs. -
The bundle already ran
init(). Every vendor file gets a static namespace import in the synthetic entry (hmr/server/deps-bundle.js:310-322), tree-shaking is off (hmr/server/deps-bundle.js:631-633;.ts:658, comment: "dep packages rely on registration side effects"), and the deps bundle is evaluated as part of the dev-client graph, imported before the app entry (hmr/shared/runtime/session-bootstrap.js:276vs:304).init()→registerCoreElements()(nativescript-vue/dist/nativescript/index.js:3-4) →registerElement('AbsoluteLayout')(dist/nativescript/elements.js:6) into a module-localelementMap(dist/registry/index.js:4) that throws on a repeat (dist/registry/index.js:39-45).
The served root's init() resolves registerCoreElements through dist/nativescript/index.js, which is served as a shim into the bundle — so the second call writes into the already-populated map and throws.
What it is not (all tested)
- Not
dependenciesvsdevDependencies—nativescript-vueis independencies, and the blank-template layout matches the failing app. - Not whether
vueis in the vendor set — a variant withvueinvendorSpecToKeyand 17@vue/*keys boots. - Not
pinia— installed and used, boots. - Not duplicate Vue copies —
@vue/*resolves to a single hoisted copy, no nested duplicates. - Not Vite's dep optimizer —
optimizeDeps.noDiscovery/excludechanged nothing. - Not stale caches —
ns clean+ reinstall reproduces identically.
Workaround (config only)
NS_VENDOR_INCLUDE=@nativescript-community/ui-collectionview/vue3 ns debug ios
Exactly that bare subpath. addCandidate accepts subpaths (hmr/shared/vendor/manifest-collect.js:465-471 — adds to vendor, and skips only the dependency traversal for non-root specifiers; the env hook is at :629, .ts:616). resolveSpecToFile (hmr/server/deps-bundle.js:184-200) falls through to the /index<ext> candidate fan-out (:109-114) and lands on vue3/index.js; esbuild pulls component.js into the closure. What I observed directly: with that one env var the manifest gains vue3/index.js and vue3/component.js as keys, the served component.js becomes a __NS_DEPS_MODULES__ shim, and the app boots.
Verified: the repro boots, live HMR works, and on a real app (larger, same stack) the already registered error is gone.
Suggested direction (there's precedent in the plugin's own code)
hmr/shared/vendor/manifest-collect.js:614-628 (.ts:601-611) vendors @tanstack/solid-router, @tanstack/router-core and @tanstack/history when @nativescript/tanstack-router is a dependency, for three reasons — the third of which is this class of problem: "Import solid-js internally — loading via HTTP creates a separate solid-js instance". The Vue flavor has no equivalent, and given the import map above, any per-module-served node_modules file that imports nativescript-vue bare would resolve to the real root the same way (only the collectionview subpath was actually exercised).
Options, in rough order of how targeted they seem:
- Route bare
nativescript-vuein the import map to the bridge/bundle, the way@nativescript/core→/ns/corealready is. - Auto-vendor node_modules files whose source imports
nativescript-vue. - Make the root shim-able despite the bare
export *(resolve the star target instead of returningnames: null).
Happy to test a patch on the repro.
Relevant log output (if applicable)
Error: Element for AbsoluteLayout already registered.
If this is intentional set 'overwriteExisting: true' in 'meta'
at registerElement (/ns/deps-bundle.mjs)
at registerCoreElements (/ns/deps-bundle.mjs)
at init (/ns/deps-bundle.mjs)
at (/ns/m/node_modules/nativescript-vue:41:1)
Environment
OS: macOS 26.6.2
CPU: (16) arm64 Apple M3 Max
Shell: /bin/zsh
node: 24.21.0
npm: 11.19.0
nativescript: 9.1.0 (project-local)
# ios
xcode: 26.6/17F113
cocoapods: 1.14.2
platforms:
- iOS 26.5
"dependencies": {
"@nativescript/core": "~9.1.0",
"nativescript-vue": "~3.0.3",
"@valor/nativescript-websockets": "^2.0.2",
"@nativescript-community/ui-collectionview": "6.0.25"
},
"devDependencies": {
"@nativescript/ios": "~9.1.0",
"@nativescript/tailwind": "^4.0.0",
"@nativescript/types": "~9.1.0",
"@nativescript/vite": "~8.0.4",
"@types/node": "^20.0.0",
"@vitejs/plugin-vue": "^6.0.8",
"@vitejs/plugin-vue-jsx": "^5.1.6",
"nativescript": "~9.1.0",
"tailwindcss": "^4.0.0",
"typescript": "~6.0.0",
"vite": "^8.2.2",
"vue-tsc": "^3.3.9"
}
Please accept these terms
- I have searched the existing issues as well as StackOverflow and this has not been posted before
- This is a bug report
- I agree to follow this project's Code of Conduct
- 主要语言
- TypeScript
- 星标
- 25.7k
- 派生
- 1.7k
- 平均合并
- 1 天 5 小时
- 30 天内合并 PR
- 35
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
NativeScript/NativeScript 的其他 Issue
-
难度 2/5 1-3 小时 新手友好度 65/100
NativeScript/NativeScript#11068 ·
-
bug-pending-triage
难度 3/5 1-2 天 新手友好度 66/100
NativeScript/NativeScript#11436 ·
-
bug-pending-triage
难度 3/5 1-2 天 新手友好度 52/100
NativeScript/NativeScript#11415 ·
-
bug-pending-triage
难度 3/5 1-2 天 新手友好度 48/100
NativeScript/NativeScript#11374 ·
-
bug-pending-triage
难度 4/5 3-5 天 新手友好度 42/100
NativeScript/NativeScript#11265 · 1 条评论 ·
查看 NativeScript/NativeScript 的全部 Issue
相似的 Issue
-
Type/Bug
难度 2/5 1-3 小时 新手友好度 78/100
OpenNSW/nsw-srilanka#497 ·
-
难度 2/5 1-3 小时 新手友好度 72/100
0xMiden/bridge-portal#132 ·
-
react-doctor severity:warning tech-debt
难度 1/5 1 小时以内 新手友好度 88/100
digidem/comapeo-cloud-app#403 ·
-
难度 2/5 1-3 小时 新手友好度 72/100
-
难度 2/5 1-3 小时 新手友好度 78/100