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 — feat(webpack,vite): keep ns: builtin module imports for the runtime by edusperoni · Pull Request #11626 · NativeScript/NativeScript

Conversation

@edusperoni

@edusperoni edusperoni commented Nov 9, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

PR Checklist

  • The PR title follows our guidelines: https://github.com/NativeScript/NativeScript/blob/master/tools/notes/CONTRIBUTING.md#commit-messages.
  • There is an issue for the bug/feature this PR is for. To avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it.
  • You have signed the CLA.
  • All existing tests are passing: https://github.com/NativeScript/NativeScript/blob/master/tools/notes/DevelopmentWorkflow.md#unit-testing.
  • Tests for the changes are included - https://github.com/NativeScript/NativeScript/blob/master/tools/notes/WritingUnitTests.md.

What is the current behavior?

The iOS and Android runtimes resolve ns:<name> builtin modules (ns:util, ns:module, ns:runtime, ns:url, ns:worker_threads, …) and a few node:<name> compatibility shims themselves, before any file or npm resolution. Neither bundler lets these imports through:

  • webpack treats ns:util as a URL scheme, which skips resolve.alias, and fails with UnhandledSchemeError. node:* fails the same way, because externalsPresets.node is off.
  • Vite fails with Rolldown failed to resolve import "ns:util", and silently replaces node:url / node:util / node:worker_threads with an empty browser stub. Under HMR, several dev-server passes also rewrite or stub these specifiers: /@id/ wrapping, routing to /ns/m/node_modules/ns:util, the esbuild dependency bundles, the dev import map, and the CommonJS require shim.

What is the new behavior?

Every ns: import is left verbatim in the output. Specifiers are matched by the ns: prefix, so modules added in future runtime versions work without changes here. ESM output keeps import … from "ns:util"; CommonJS output keeps require("ns:util").

Customization uses each bundler's own mechanisms:

webpack: the base config registers NativeScriptBuiltinModulesPlugin (default include: [/^ns:/]).

  • Change its include list with webpack-chain: config.plugin('NativeScriptBuiltinModulesPlugin').tap(...).
  • The plugin matches on the request after beforeResolve, so a stock NormalModuleReplacementPlugin can:
    • redirect a builtin to a polyfill (/^ns:url$/ → a file);
    • forward a bare name to a runtime shim (/^worker_threads$/ → node:worker_threads).

Vite: the base config adds nativescriptBuiltinModules().

  • Add another instance with { include: ['node:worker_threads'] } to opt in more specifiers.
  • resolve.alias handles polyfills and forwarding, since aliases resolve before the plugin.

node: stays opt-in rather than hardcoding the current shim list, because the set grows with each runtime version. Both READMEs show how to forward to the runtime's shims, using worker_threads as the example.

Vite coverage:

  • vite build: the plugin runs first in the main build, worker builds and the dependency optimizer.
  • HMR:
    • an esbuild counterpart runs first in the deps, vendor and core bundles;
    • /@id/<builtin> is unwrapped before the device rewriting passes;
    • guards in core rewriteSpec, worker-realm module bindings and the plugin-specifier check keep these imports untouched;
    • opted-in node: names are left out of the dev import map;
    • the CommonJS require shim tries the runtime's require first for ns: / node: ids.

Tests:

  • packages/webpack5/__tests__/plugins/NativeScriptBuiltinModulesPlugin.spec.ts: real webpack compiles checking ESM and CommonJS output, polyfill and forwarding through NormalModuleReplacementPlugin, and the build failure without the plugin.
  • packages/vite/helpers/builtin-modules.spec.ts: in-process vite build (ESM, import(), require() in a CommonJS dependency, alias forwarding and polyfill, and the failure without the plugin), plus the esbuild plugin.
  • packages/vite/hmr/server/builtin-modules-hmr.spec.ts: each HMR touch point. All four tests fail without the HMR changes.

Notes for reviewers:

  • The webpack config snapshots already fail on main: they contain absolute paths from another machine and a FixSourceMapUrlPlugin that no longer exists. I added only the new plugin entry to them rather than regenerating. The set of failing tests is identical to main. The mdn-data alias re-wrap in base.ts comes from the prettier pre-commit hook.
  • packages/vite/typescript-optional.spec.ts also fails on main (5 tests) and is unchanged by this PR.
  • Under HMR, the esbuild dependency bundles don't see Vite's resolve.alias. A ns: polyfill or bare-name forward set up with an alias applies to vite build and the Vite module graph, but not to dependencies bundled by esbuild during a dev session.
  • No on-device run yet. Manual check: import ns:util from app code, a CommonJS dependency and a worker. Opt in node:worker_threads and check that it reaches the runtime, under both ns run (HMR) and a release build.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@edusperoni
feat(webpack,vite): keep ns: builtin module imports for the runtime
4faf46b
The iOS and Android runtimes resolve `ns:<name>` builtin modules (and a
few `node:<name>` compatibility shims) themselves. Webpack failed on these
imports with an unhandled-scheme error, and Vite failed to resolve `ns:`
specifiers and replaced `node:` ones with an empty browser stub.

Every `ns:` specifier is now left verbatim in the output, matched by
prefix so modules added in future runtime versions work without changes.
Both packages expose the same helpers:

- addBuiltinModule(matcher, target?) opts more specifiers in, e.g. the
  `node:` shims a runtime version ships, optionally forwarding a bare
  specifier such as `worker_threads` to `node:worker_threads`.
- polyfillBuiltinModule(specifier, path) bundles a replacement instead,
  for runtimes that don't provide a builtin.

In Vite this covers `vite build`, workers, dep optimization and the HMR
dev server (esbuild dependency bundles, `/@id/` unwrapping, worker realm
routing, core rewriting, the dev import map and the CommonJS require
shim).
@nx-cloud

nx-cloud Bot commented Nov 9, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 8635dd3

Command Status Duration Result
nx test apps-automated -c=ios ✅ Succeeded 3m 15s View ↗
nx run-many --target=test --configuration=ci --... ✅ Succeeded 1s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-11-09 18:10:50 UTC

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@pkg-pr-new

pkg-pr-new Bot commented Nov 9, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@nativescript/core@11626
npm i https://pkg.pr.new/@nativescript/vite@11626
npm i https://pkg.pr.new/@nativescript/webpack@11626

commit: 8635dd3

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@edusperoni
refactor(webpack,vite): configure builtin modules through bundler-nat…
8635dd3
…ive hooks

Replace the addBuiltinModule/polyfillBuiltinModule helpers with a single
plugin per bundler, customized the way each bundler is normally
customized:

- webpack: NativeScriptBuiltinModulesPlugin, registered by name so
  webpack-chain can `.tap()` its `include` list. It externalizes on the
  request after `beforeResolve`, so a NormalModuleReplacementPlugin can
  redirect a builtin to a polyfill or forward a bare specifier to one.
- vite: nativescriptBuiltinModules({ include }). Extra instances add
  specifiers; resolve.alias handles polyfills and forwarding, since
  aliases resolve before the plugin.
NathanWalker
NathanWalker approved these changes Nov 9, 2026
View reviewed changes
@NathanWalker
NathanWalker merged commit e532d62 into main Nov 9, 2026
10 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@NathanWalker
NathanWalker deleted the feat/ns-builtin-module-externals branch November 9, 2026 22:21
@edusperoni edusperoni mentioned this pull request Nov 10, 2026
fix(webpack): find ExternalModuleFactoryPlugin where webpack 5.112 moved it #11633
Merged
5 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@NathanWalker NathanWalker NathanWalker approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@edusperoni @NathanWalker
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.