@nativescript/vite: extensionless shared-workspace module requests return 404
维护者通常 3 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 57/100
- Issue 类型
- 缺陷
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- javascript, node.js, typescript, vite
调研方向
Start at resolveNsMTransformedModule and resolveFsAnchoredSpec in the NativeScript Vite package’s hmr/server/websocket-ns.js route. Trace how extension and platform candidates are resolved under project and workspace roots, including Vite filesystem access checks. Reproduce with the supplied workspace-fetch.mjs; done means the extensionless shared module request returns 200 and relevant regression checks pass.
由索引模型根据 Issue 内容生成。
描述
@nativescript/vite 8.0.20 serves a workspace-shared TSX module when its device URL includes .tsx, but returns 404 for the extensionless URL. The HMR client uses extensionless script URLs for reimports, so a successful static import does not establish that the same shared module can be hot-reimported.
Verified with the unpatched production NativeScript HTTP route, Vite 8.3.0 and Node 26.12.0. No Coreframe or Octane plugins, device runtime, or images are involved. This is separate from the graph-identity collision in #11569.
Expected and observed
With a native project at <workspace>/native and a module at <workspace>/shared/src/screen.tsx:
| Request | Actual |
|---|---|
/ns/m/shared/src/screen.tsx |
200 |
/ns/m/shared/src/screen |
404 |
Both should serve the same module. server.fs.allow explicitly includes the workspace. The project and temporary directory use real paths to avoid a symlink/filesystem-allow artifact.
Reproduction
Create these files in an empty directory, run pnpm install, then node workspace-fetch.mjs. The assertion intentionally fails after printing the status pair and writing workspace-fetch-result.json.
package.json:
{
"name": "nativescript-hmr-identity-repro",
"version": "0.0.0",
"private": true,
"type": "module",
"packageManager": "[email protected]",
"scripts": {
"check": "node repro.mjs"
},
"devDependencies": {
"@nativescript/vite": "8.0.20",
"vite": "8.3.0"
}
}
pnpm-workspace.yaml:
packages:
- .
allowBuilds:
esbuild: true
"@parcel/watcher": true
minimumReleaseAgeExclude:
- "@nativescript/[email protected]"
workspace-fetch.mjs:
import assert from 'node:assert/strict'
import { mkdtempSync, realpathSync, mkdirSync, writeFileSync, rmSync } from 'node:fs'
import { createRequire } from 'node:module'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { pathToFileURL } from 'node:url'
import { createServer } from 'vite'
const ns = pathToFileURL(createRequire(import.meta.url).resolve('@nativescript/vite'))
const { registerNsModuleServerRoute } = await import(new URL('./hmr/server/websocket-ns-m.js', ns))
const { setProjectFlavor } = await import(new URL('./helpers/flavor.js', ns))
setProjectFlavor('javascript')
const workspace = realpathSync(mkdtempSync(join(tmpdir(), 'ns-workspace-fetch-')))
const root = join(workspace, 'native')
mkdirSync(join(root, 'src'), { recursive: true })
mkdirSync(join(workspace, 'shared/src'), { recursive: true })
writeFileSync(join(root, 'package.json'), '{"type":"module"}')
writeFileSync(join(workspace, 'pnpm-workspace.yaml'), 'packages:\n - native\n')
writeFileSync(join(workspace, 'shared/src/screen.tsx'), 'export default "baseline";')
const server = await createServer({
root, configFile: false, logLevel: 'silent', optimizeDeps: { noDiscovery: true },
server: { host: '127.0.0.1', port: 0, watch: null, fs: { allow: [workspace] } },
plugins: [{ name: 'native-route-repro', configureServer(server) {
registerNsModuleServerRoute(server, {
verbose: false, appVirtualWithSlash: '/src/', sfcFileMap: new Map(), depFileMap: new Map(),
getGraphVersion: () => 1, getStrategy: () => ({ flavor: 'javascript' }), depsBundle: null,
sharedTransformRequest: (id) => server.transformRequest(id),
ensureInitialGraphPopulationStarted() {}, upsertGraphModule() {},
})
} }],
})
try {
await server.listen()
const origin = `http://127.0.0.1:${server.httpServer.address().port}`
const results = []
for (const url of ['/ns/m/shared/src/screen.tsx', '/ns/m/shared/src/screen']) {
const response = await fetch(origin + url)
results.push({ url, status: response.status })
await response.text()
}
console.log(JSON.stringify(results))
writeFileSync(new URL('./workspace-fetch-result.json', import.meta.url), JSON.stringify(results, null, 2) + '\n')
assert.ok(results.every(({ status }) => status === 200), 'HMR extensionless fetch must serve the same shared module as its static URL')
} finally {
await server.close()
rmSync(workspace, { recursive: true, force: true })
}
Source finding and requested fix
resolveNsMTransformedModule first tries extension/platform candidates as Vite app URLs. Those URLs do not address shared files outside the Vite root. Its later filesystem-root fallback calls resolveFsAnchoredSpec only with the original, extensionless spec; it does not probe the expanded candidates under the workspace root.
Please resolve the same extension/platform candidates under the project/workspace filesystem roots and preserve Vite filesystem access checks. A local exact-version patch doing that passes a real HTTP regression for native-host, shared-workspace and external-source modules, together with graph/hot-context identity checks. This report does not claim device HMR qualification or an upstream-main runtime test.
- 主要语言
- TypeScript
- 星标
- 25.7k
- 派生
- 1.7k
- 平均合并
- 4 天 14 小时
- 30 天内合并 PR
- 53
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
NativeScript/NativeScript 的其他 Issue
-
bug css
难度 2/5 1-3 小时 新手友好度 70/100
NativeScript/NativeScript#11525 ·
维护者通常 3 天内回复
-
bug
难度 3/5 1-2 天 新手友好度 69/100
NativeScript/NativeScript#11591 ·
维护者通常 3 天内回复
-
[iOS 26] Inset Frame cannot start native content Back with default navigation可能已有人在做 @rafaelaugustos 于 6 天前认领。 未关闭bug-pending-triage
难度 4/5 3-5 天 新手友好度 15/100
NativeScript/NativeScript#11589 ·
维护者通常 3 天内回复
-
iOS: prebuilt Frame tree with inherited CSS direction triggers UIKit targetNode assertion可能已有人在做 @rafaelaugustos 于 7 天前认领。 未关闭
难度 5/5 一周以上 新手友好度 15/100
NativeScript/NativeScript#11586 ·
维护者通常 3 天内回复
-
[Android] After exiting with Back, reopening the app in the same process never fires launch again (9.1 regression, Angular apps stay dead and unstyled)可能已有人在做 @anjak03 于 9 天前认领。 未关闭bug os: android
难度 4/5 1-2 天 新手友好度 56/100
NativeScript/NativeScript#11572 ·
维护者通常 3 天内回复
查看 NativeScript/NativeScript 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 66/100
Equal-Vote/bettervoting#1754 ·
维护者通常 2 天内回复
-
难度 1/5 1 小时以内 新手友好度 82/100
Doist/todoist-sdk-typescript#740 ·
维护者通常 1 天内回复
-
难度 1/5 1 小时以内 新手友好度 62/100
privatenumber/cleye#47 ·
-
clawsweeper:fix-shape-clear clawsweeper:queueable-fix clawsweeper:source-repro impact:auth-provider issue-rating: 🦞 diamond lobster no-stale P1
难度 2/5 1-3 小时 新手友好度 70/100
steipete/oracle#614 · 1 条评论 · 1 个 reaction ·
维护者通常 1 天内回复
-
enhancement
难度 2/5 1-3 小时 新手友好度 72/100
MoonshotAI/kimi-code#4591 ·
维护者通常 1 天内回复