GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — @nativescript/vite: extensionless shared-workspace module requests return 404 · Issue #11570 · NativeScript/NativeScript

@nativescript/vite: extensionless shared-workspace module requests return 404 #11570

New issue
Copy link
New issue
Copy link
Open
Open
@nativescript/vite: extensionless shared-workspace module requests return 404#11570
Copy link
Labels
bug

Description

@aleclarson
aleclarson
opened on Oct 22, 2026
Issue body actions

@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.

Activity

  1. NathanWalker
    added
    bug
    on Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.