@nativescript/vite 8.0.0-alpha.3 → 8.0.0-alpha.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -11
- package/configuration/angular.d.ts +34 -1
- package/configuration/angular.js +369 -159
- package/configuration/angular.js.map +1 -1
- package/configuration/base.js +184 -14
- package/configuration/base.js.map +1 -1
- package/configuration/javascript.js +5 -72
- package/configuration/javascript.js.map +1 -1
- package/configuration/solid.js +27 -1
- package/configuration/solid.js.map +1 -1
- package/configuration/typescript.js +5 -75
- package/configuration/typescript.js.map +1 -1
- package/helpers/angular/angular-linker.d.ts +5 -6
- package/helpers/angular/angular-linker.js +36 -121
- package/helpers/angular/angular-linker.js.map +1 -1
- package/helpers/angular/inject-component-hmr-registration.d.ts +112 -0
- package/helpers/angular/inject-component-hmr-registration.js +291 -0
- package/helpers/angular/inject-component-hmr-registration.js.map +1 -0
- package/helpers/angular/inject-hmr-vite-ignore.d.ts +75 -0
- package/helpers/angular/inject-hmr-vite-ignore.js +221 -0
- package/helpers/angular/inject-hmr-vite-ignore.js.map +1 -0
- package/helpers/angular/inline-decorator-component-templates.js +1 -170
- package/helpers/angular/inline-decorator-component-templates.js.map +1 -1
- package/helpers/angular/js-lexer.d.ts +4 -0
- package/helpers/angular/js-lexer.js +182 -0
- package/helpers/angular/js-lexer.js.map +1 -0
- package/helpers/angular/shared-linker.d.ts +31 -3
- package/helpers/angular/shared-linker.js +67 -14
- package/helpers/angular/shared-linker.js.map +1 -1
- package/helpers/angular/synthesize-decorator-ctor-parameters.js +2 -170
- package/helpers/angular/synthesize-decorator-ctor-parameters.js.map +1 -1
- package/helpers/angular/synthesize-injectable-factories.js +1 -174
- package/helpers/angular/synthesize-injectable-factories.js.map +1 -1
- package/helpers/angular/util.d.ts +1 -0
- package/helpers/angular/util.js +88 -0
- package/helpers/angular/util.js.map +1 -1
- package/helpers/app-components.d.ts +2 -1
- package/helpers/app-components.js.map +1 -1
- package/helpers/app-css-state.d.ts +8 -0
- package/helpers/app-css-state.js +8 -0
- package/helpers/app-css-state.js.map +1 -0
- package/helpers/bundler-context.d.ts +11 -0
- package/helpers/bundler-context.js +71 -0
- package/helpers/bundler-context.js.map +1 -0
- package/helpers/config-as-json.js +10 -0
- package/helpers/config-as-json.js.map +1 -1
- package/helpers/dev-host.d.ts +341 -0
- package/helpers/dev-host.js +617 -0
- package/helpers/dev-host.js.map +1 -0
- package/helpers/esbuild-platform-resolver.js +4 -1
- package/helpers/esbuild-platform-resolver.js.map +1 -1
- package/helpers/global-defines.d.ts +51 -0
- package/helpers/global-defines.js +77 -0
- package/helpers/global-defines.js.map +1 -1
- package/helpers/hmr-scope.d.ts +26 -0
- package/helpers/hmr-scope.js +67 -0
- package/helpers/hmr-scope.js.map +1 -0
- package/helpers/init.js +0 -18
- package/helpers/init.js.map +1 -1
- package/helpers/logging.d.ts +1 -0
- package/helpers/logging.js +63 -3
- package/helpers/logging.js.map +1 -1
- package/helpers/main-entry.d.ts +2 -1
- package/helpers/main-entry.js +430 -47
- package/helpers/main-entry.js.map +1 -1
- package/helpers/nativeclass-esbuild-plugin.d.ts +2 -1
- package/helpers/nativeclass-esbuild-plugin.js.map +1 -1
- package/helpers/nativeclass-transform.js.map +1 -1
- package/helpers/nativeclass-transformer-plugin.d.ts +9 -2
- package/helpers/nativeclass-transformer-plugin.js +157 -14
- package/helpers/nativeclass-transformer-plugin.js.map +1 -1
- package/helpers/nativescript-package-resolver.js +8 -3
- package/helpers/nativescript-package-resolver.js.map +1 -1
- package/helpers/normalize-id.d.ts +42 -0
- package/helpers/normalize-id.js +60 -0
- package/helpers/normalize-id.js.map +1 -0
- package/helpers/ns-core-url.d.ts +88 -0
- package/helpers/ns-core-url.js +191 -0
- package/helpers/ns-core-url.js.map +1 -0
- package/helpers/package-platform-aliases.js +4 -3
- package/helpers/package-platform-aliases.js.map +1 -1
- package/helpers/platform-types.d.ts +2 -0
- package/helpers/platform-types.js +2 -0
- package/helpers/platform-types.js.map +1 -0
- package/helpers/prelink-angular.js +12 -33
- package/helpers/prelink-angular.js.map +1 -1
- package/helpers/project.d.ts +35 -0
- package/helpers/project.js +120 -2
- package/helpers/project.js.map +1 -1
- package/helpers/resolver.js +17 -2
- package/helpers/resolver.js.map +1 -1
- package/helpers/solid-jsx-deps.d.ts +15 -0
- package/helpers/solid-jsx-deps.js +178 -0
- package/helpers/solid-jsx-deps.js.map +1 -0
- package/helpers/ts-config-paths.d.ts +14 -0
- package/helpers/ts-config-paths.js +89 -8
- package/helpers/ts-config-paths.js.map +1 -1
- package/helpers/typescript-check.d.ts +2 -1
- package/helpers/typescript-check.js.map +1 -1
- package/helpers/workers.d.ts +20 -19
- package/helpers/workers.js +624 -4
- package/helpers/workers.js.map +1 -1
- package/hmr/client/css-handler.d.ts +1 -0
- package/hmr/client/css-handler.js +33 -20
- package/hmr/client/css-handler.js.map +1 -1
- package/hmr/client/css-update-overlay.d.ts +18 -0
- package/hmr/client/css-update-overlay.js +27 -0
- package/hmr/client/css-update-overlay.js.map +1 -0
- package/hmr/client/hmr-pending-overlay.d.ts +27 -0
- package/hmr/client/hmr-pending-overlay.js +50 -0
- package/hmr/client/hmr-pending-overlay.js.map +1 -0
- package/hmr/client/index.js +419 -15
- package/hmr/client/index.js.map +1 -1
- package/hmr/client/utils.d.ts +6 -1
- package/hmr/client/utils.js +184 -8
- package/hmr/client/utils.js.map +1 -1
- package/hmr/client/vue-sfc-update-overlay.d.ts +82 -0
- package/hmr/client/vue-sfc-update-overlay.js +133 -0
- package/hmr/client/vue-sfc-update-overlay.js.map +1 -0
- package/hmr/entry-runtime.d.ts +2 -1
- package/hmr/entry-runtime.js +252 -65
- package/hmr/entry-runtime.js.map +1 -1
- package/hmr/frameworks/angular/client/index.d.ts +1 -0
- package/hmr/frameworks/angular/client/index.js +778 -20
- package/hmr/frameworks/angular/client/index.js.map +1 -1
- package/hmr/frameworks/angular/server/linker.js +1 -4
- package/hmr/frameworks/angular/server/linker.js.map +1 -1
- package/hmr/frameworks/angular/server/strategy.js +13 -15
- package/hmr/frameworks/angular/server/strategy.js.map +1 -1
- package/hmr/frameworks/solid/server/strategy.js +3 -18
- package/hmr/frameworks/solid/server/strategy.js.map +1 -1
- package/hmr/frameworks/typescript/server/strategy.js +2 -15
- package/hmr/frameworks/typescript/server/strategy.js.map +1 -1
- package/hmr/frameworks/vue/client/index.js +30 -199
- package/hmr/frameworks/vue/client/index.js.map +1 -1
- package/hmr/helpers/ast-normalizer.js +52 -5
- package/hmr/helpers/ast-normalizer.js.map +1 -1
- package/hmr/helpers/cjs-named-exports.d.ts +23 -0
- package/hmr/helpers/cjs-named-exports.js +152 -0
- package/hmr/helpers/cjs-named-exports.js.map +1 -0
- package/hmr/helpers/package-exports.d.ts +16 -0
- package/hmr/helpers/package-exports.js +396 -0
- package/hmr/helpers/package-exports.js.map +1 -0
- package/hmr/server/angular-root-component.d.ts +79 -0
- package/hmr/server/angular-root-component.js +149 -0
- package/hmr/server/angular-root-component.js.map +1 -0
- package/hmr/server/constants.js +13 -4
- package/hmr/server/constants.js.map +1 -1
- package/hmr/server/core-sanitize.d.ts +90 -7
- package/hmr/server/core-sanitize.js +211 -56
- package/hmr/server/core-sanitize.js.map +1 -1
- package/hmr/server/framework-strategy.d.ts +9 -19
- package/hmr/server/hmr-module-graph.d.ts +37 -0
- package/hmr/server/hmr-module-graph.js +214 -0
- package/hmr/server/hmr-module-graph.js.map +1 -0
- package/hmr/server/import-map.js +60 -8
- package/hmr/server/import-map.js.map +1 -1
- package/hmr/server/index.js +1 -0
- package/hmr/server/index.js.map +1 -1
- package/hmr/server/ns-core-cjs-shape.d.ts +204 -0
- package/hmr/server/ns-core-cjs-shape.js +271 -0
- package/hmr/server/ns-core-cjs-shape.js.map +1 -0
- package/hmr/server/ns-rt-bridge.d.ts +51 -0
- package/hmr/server/ns-rt-bridge.js +131 -0
- package/hmr/server/ns-rt-bridge.js.map +1 -0
- package/hmr/server/ns-rt-route.d.ts +5 -0
- package/hmr/server/ns-rt-route.js +35 -0
- package/hmr/server/ns-rt-route.js.map +1 -0
- package/hmr/server/perf-instrumentation.d.ts +114 -0
- package/hmr/server/perf-instrumentation.js +195 -0
- package/hmr/server/perf-instrumentation.js.map +1 -0
- package/hmr/server/require-guard.d.ts +1 -0
- package/hmr/server/require-guard.js +12 -0
- package/hmr/server/require-guard.js.map +1 -0
- package/hmr/server/route-helpers.d.ts +7 -0
- package/hmr/server/route-helpers.js +13 -0
- package/hmr/server/route-helpers.js.map +1 -0
- package/hmr/server/server-origin.d.ts +12 -0
- package/hmr/server/server-origin.js +66 -0
- package/hmr/server/server-origin.js.map +1 -0
- package/hmr/server/shared-transform-request.js +12 -5
- package/hmr/server/shared-transform-request.js.map +1 -1
- package/hmr/server/vendor-bare-module-shims.d.ts +4 -0
- package/hmr/server/vendor-bare-module-shims.js +80 -0
- package/hmr/server/vendor-bare-module-shims.js.map +1 -0
- package/hmr/server/vite-plugin.js +60 -42
- package/hmr/server/vite-plugin.js.map +1 -1
- package/hmr/server/websocket-angular-entry.js +1 -1
- package/hmr/server/websocket-angular-entry.js.map +1 -1
- package/hmr/server/websocket-angular-hot-update.d.ts +17 -0
- package/hmr/server/websocket-angular-hot-update.js +176 -2
- package/hmr/server/websocket-angular-hot-update.js.map +1 -1
- package/hmr/server/websocket-core-bridge.d.ts +41 -6
- package/hmr/server/websocket-core-bridge.js +72 -75
- package/hmr/server/websocket-core-bridge.js.map +1 -1
- package/hmr/server/websocket-css-hot-update.d.ts +33 -0
- package/hmr/server/websocket-css-hot-update.js +65 -0
- package/hmr/server/websocket-css-hot-update.js.map +1 -0
- package/hmr/server/websocket-device-transform.d.ts +21 -0
- package/hmr/server/websocket-device-transform.js +1570 -0
- package/hmr/server/websocket-device-transform.js.map +1 -0
- package/hmr/server/websocket-graph-upsert.d.ts +15 -0
- package/hmr/server/websocket-graph-upsert.js +20 -0
- package/hmr/server/websocket-graph-upsert.js.map +1 -1
- package/hmr/server/websocket-hmr-pending.d.ts +43 -0
- package/hmr/server/websocket-hmr-pending.js +55 -0
- package/hmr/server/websocket-hmr-pending.js.map +1 -0
- package/hmr/server/websocket-hot-update.d.ts +51 -0
- package/hmr/server/websocket-hot-update.js +1160 -0
- package/hmr/server/websocket-hot-update.js.map +1 -0
- package/hmr/server/websocket-import-map-route.d.ts +15 -0
- package/hmr/server/websocket-import-map-route.js +44 -0
- package/hmr/server/websocket-import-map-route.js.map +1 -0
- package/hmr/server/websocket-module-bindings.js +3 -3
- package/hmr/server/websocket-module-bindings.js.map +1 -1
- package/hmr/server/websocket-module-specifiers.d.ts +66 -2
- package/hmr/server/websocket-module-specifiers.js +202 -19
- package/hmr/server/websocket-module-specifiers.js.map +1 -1
- package/hmr/server/websocket-ns-core.d.ts +21 -0
- package/hmr/server/websocket-ns-core.js +305 -0
- package/hmr/server/websocket-ns-core.js.map +1 -0
- package/hmr/server/websocket-ns-entry.d.ts +22 -0
- package/hmr/server/websocket-ns-entry.js +150 -0
- package/hmr/server/websocket-ns-entry.js.map +1 -0
- package/hmr/server/websocket-ns-m-paths.d.ts +3 -0
- package/hmr/server/websocket-ns-m-paths.js +92 -0
- package/hmr/server/websocket-ns-m-paths.js.map +1 -0
- package/hmr/server/websocket-ns-m-request.d.ts +45 -0
- package/hmr/server/websocket-ns-m-request.js +196 -0
- package/hmr/server/websocket-ns-m-request.js.map +1 -0
- package/hmr/server/websocket-ns-m.d.ts +34 -0
- package/hmr/server/websocket-ns-m.js +853 -0
- package/hmr/server/websocket-ns-m.js.map +1 -0
- package/hmr/server/websocket-served-module-helpers.d.ts +39 -0
- package/hmr/server/websocket-served-module-helpers.js +654 -0
- package/hmr/server/websocket-served-module-helpers.js.map +1 -0
- package/hmr/server/websocket-sfc.d.ts +24 -0
- package/hmr/server/websocket-sfc.js +1223 -0
- package/hmr/server/websocket-sfc.js.map +1 -0
- package/hmr/server/websocket-txn.d.ts +6 -0
- package/hmr/server/websocket-txn.js +39 -0
- package/hmr/server/websocket-txn.js.map +1 -0
- package/hmr/server/websocket-vendor-unifier.d.ts +10 -0
- package/hmr/server/websocket-vendor-unifier.js +45 -0
- package/hmr/server/websocket-vendor-unifier.js.map +1 -0
- package/hmr/server/websocket.d.ts +0 -30
- package/hmr/server/websocket.js +599 -6038
- package/hmr/server/websocket.js.map +1 -1
- package/hmr/shared/runtime/boot-placeholder-ui.d.ts +69 -0
- package/hmr/shared/runtime/boot-placeholder-ui.js +101 -0
- package/hmr/shared/runtime/boot-placeholder-ui.js.map +1 -0
- package/hmr/shared/runtime/boot-progress.d.ts +40 -0
- package/hmr/shared/runtime/boot-progress.js +128 -0
- package/hmr/shared/runtime/boot-progress.js.map +1 -0
- package/hmr/shared/runtime/boot-timeline.d.ts +18 -0
- package/hmr/shared/runtime/boot-timeline.js +52 -0
- package/hmr/shared/runtime/boot-timeline.js.map +1 -0
- package/hmr/shared/runtime/dev-overlay-snapshots.d.ts +31 -0
- package/hmr/shared/runtime/dev-overlay-snapshots.js +324 -0
- package/hmr/shared/runtime/dev-overlay-snapshots.js.map +1 -0
- package/hmr/shared/runtime/dev-overlay.d.ts +75 -26
- package/hmr/shared/runtime/dev-overlay.js +990 -260
- package/hmr/shared/runtime/dev-overlay.js.map +1 -1
- package/hmr/shared/runtime/module-provenance.js +1 -4
- package/hmr/shared/runtime/module-provenance.js.map +1 -1
- package/hmr/shared/runtime/root-placeholder-view.d.ts +19 -0
- package/hmr/shared/runtime/root-placeholder-view.js +310 -0
- package/hmr/shared/runtime/root-placeholder-view.js.map +1 -0
- package/hmr/shared/runtime/root-placeholder.js +352 -194
- package/hmr/shared/runtime/root-placeholder.js.map +1 -1
- package/hmr/shared/runtime/session-bootstrap.js +164 -1
- package/hmr/shared/runtime/session-bootstrap.js.map +1 -1
- package/hmr/shared/runtime/vendor-bootstrap.js +1 -9
- package/hmr/shared/runtime/vendor-bootstrap.js.map +1 -1
- package/hmr/shared/vendor/manifest-collect.d.ts +32 -0
- package/hmr/shared/vendor/manifest-collect.js +512 -0
- package/hmr/shared/vendor/manifest-collect.js.map +1 -0
- package/hmr/shared/vendor/manifest-loader.d.ts +2 -1
- package/hmr/shared/vendor/manifest-loader.js +3 -2
- package/hmr/shared/vendor/manifest-loader.js.map +1 -1
- package/hmr/shared/vendor/manifest.d.ts +1 -5
- package/hmr/shared/vendor/manifest.js +102 -739
- package/hmr/shared/vendor/manifest.js.map +1 -1
- package/hmr/shared/vendor/vendor-device-shim.d.ts +1 -0
- package/hmr/shared/vendor/vendor-device-shim.js +208 -0
- package/hmr/shared/vendor/vendor-device-shim.js.map +1 -0
- package/hmr/shared/vendor/vendor-esbuild-plugins.d.ts +16 -0
- package/hmr/shared/vendor/vendor-esbuild-plugins.js +203 -0
- package/hmr/shared/vendor/vendor-esbuild-plugins.js.map +1 -0
- package/index.d.ts +1 -0
- package/index.js +5 -0
- package/index.js.map +1 -1
- package/package.json +55 -11
- package/runtime/core-aliases-early.js +17 -41
- package/runtime/core-aliases-early.js.map +1 -1
package/configuration/angular.js
CHANGED
|
@@ -1,143 +1,67 @@
|
|
|
1
1
|
import { mergeConfig } from 'vite';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import fs from 'node:fs';
|
|
4
|
-
import { createRequire } from 'node:module';
|
|
5
4
|
import angular from '@analogjs/vite-plugin-angular';
|
|
6
5
|
import { angularLinkerVitePlugin, angularLinkerVitePluginPost } from '../helpers/angular/angular-linker.js';
|
|
7
6
|
import { synthesizeMissingInjectableFactories } from '../helpers/angular/synthesize-injectable-factories.js';
|
|
8
|
-
import {
|
|
7
|
+
import { getAngularLinkerFactory, runAngularLinker } from '../helpers/angular/shared-linker.js';
|
|
9
8
|
import { inlineDecoratorComponentTemplates } from '../helpers/angular/inline-decorator-component-templates.js';
|
|
9
|
+
import { appendComponentHmrRegistration, findComponentClassNames, INJECTION_MARKER as HMR_REGISTER_MARKER } from '../helpers/angular/inject-component-hmr-registration.js';
|
|
10
|
+
import { injectAngularHmrViteIgnore } from '../helpers/angular/inject-hmr-vite-ignore.js';
|
|
10
11
|
import { synthesizeDecoratorCtorParameters } from '../helpers/angular/synthesize-decorator-ctor-parameters.js';
|
|
11
|
-
import { containsRealNgDeclare } from '../helpers/angular/util.js';
|
|
12
|
+
import { containsRealNgDeclare, stripJsComments } from '../helpers/angular/util.js';
|
|
12
13
|
import { baseConfig } from './base.js';
|
|
13
14
|
import { getCliFlags } from '../helpers/cli-flags.js';
|
|
14
15
|
import { resolveRelativeToImportMeta } from '../helpers/import-meta-path.js';
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
async function importLinkerFactory() {
|
|
19
|
-
if (_cachedLinkerFactory)
|
|
20
|
-
return _cachedLinkerFactory;
|
|
21
|
-
const req = createRequire(process.cwd() + '/package.json');
|
|
22
|
-
try {
|
|
23
|
-
const linkerPath = req.resolve('@angular/compiler-cli/linker/babel');
|
|
24
|
-
const linkerMod = await import(linkerPath);
|
|
25
|
-
_cachedLinkerFactory = linkerMod.createLinkerPlugin || linkerMod.createEs2015LinkerPlugin || null;
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
try {
|
|
29
|
-
const linkerMod = await import('@angular/compiler-cli/linker/babel');
|
|
30
|
-
_cachedLinkerFactory = linkerMod.createLinkerPlugin || linkerMod.createEs2015LinkerPlugin || null;
|
|
31
|
-
}
|
|
32
|
-
catch { }
|
|
33
|
-
}
|
|
34
|
-
return _cachedLinkerFactory;
|
|
16
|
+
import { resolveVerboseFlag } from '../helpers/logging.js';
|
|
17
|
+
function hasNgDeclarePartial(code) {
|
|
18
|
+
return code.indexOf('\u0275\u0275ngDeclare') !== -1 || code.indexOf('ɵɵngDeclare') !== -1 || code.indexOf('ngDeclare') !== -1;
|
|
35
19
|
}
|
|
36
20
|
// Rollup-level linker to guarantee Angular libraries are linked when included in the bundle graph.
|
|
37
21
|
function angularRollupLinker(projectRoot) {
|
|
38
|
-
let babel = null;
|
|
39
|
-
let createLinker = null;
|
|
40
|
-
let angularFileSystem = null;
|
|
41
22
|
const FILTER = /node_modules\/(?:@angular|@nativescript\/angular)\/.*\.[mc]?js$/;
|
|
42
|
-
|
|
43
|
-
if (babel && createLinker)
|
|
44
|
-
return;
|
|
45
|
-
try {
|
|
46
|
-
const req = createRequire((projectRoot ? projectRoot + '/package.json' : import.meta.url));
|
|
47
|
-
const babelPath = req.resolve('@babel/core');
|
|
48
|
-
const linkerPath = req.resolve('@angular/compiler-cli/linker/babel');
|
|
49
|
-
babel = await import(babelPath);
|
|
50
|
-
const linkerMod = await import(linkerPath);
|
|
51
|
-
createLinker = linkerMod.createLinkerPlugin || linkerMod.createEs2015LinkerPlugin;
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
try {
|
|
55
|
-
babel = await import('@babel/core');
|
|
56
|
-
}
|
|
57
|
-
catch { }
|
|
58
|
-
try {
|
|
59
|
-
const linkerMod = await import('@angular/compiler-cli/linker/babel');
|
|
60
|
-
createLinker = linkerMod.createLinkerPlugin || linkerMod.createEs2015LinkerPlugin;
|
|
61
|
-
}
|
|
62
|
-
catch { }
|
|
63
|
-
}
|
|
64
|
-
if (!angularFileSystem) {
|
|
65
|
-
angularFileSystem = await resolveAngularFileSystem(projectRoot);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
23
|
+
const debug = process.env.VITE_DEBUG_LOGS === 'true' || process.env.VITE_DEBUG_LOGS === '1';
|
|
68
24
|
return {
|
|
69
25
|
name: 'ns-angular-linker-rollup',
|
|
70
26
|
enforce: 'pre',
|
|
71
27
|
apply: 'build',
|
|
72
28
|
async load(id) {
|
|
73
|
-
const
|
|
74
|
-
const cleanId = id.split('?', 1)[0];
|
|
29
|
+
const cleanId = normalizeAngularWatchPath(id);
|
|
75
30
|
if (!FILTER.test(cleanId))
|
|
76
31
|
return null;
|
|
77
32
|
try {
|
|
78
|
-
await ensureDeps();
|
|
79
|
-
if (!babel || !createLinker)
|
|
80
|
-
return null;
|
|
81
33
|
const fs = await import('node:fs/promises');
|
|
82
34
|
const code = await fs.readFile(cleanId, 'utf8');
|
|
83
35
|
const forceLink = cleanId.includes('/node_modules/@nativescript/angular/') && cleanId.includes('polyfills');
|
|
84
36
|
if (!code)
|
|
85
37
|
return null;
|
|
86
|
-
if (!forceLink &&
|
|
38
|
+
if (!forceLink && !hasNgDeclarePartial(code))
|
|
87
39
|
return null;
|
|
88
|
-
const
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
console.log('[ns-angular-linker][rollup-load]
|
|
92
|
-
}
|
|
93
|
-
catch { }
|
|
94
|
-
}
|
|
95
|
-
const result = await babel.transformAsync(code, {
|
|
96
|
-
filename: cleanId,
|
|
97
|
-
configFile: false,
|
|
98
|
-
babelrc: false,
|
|
99
|
-
sourceMaps: false,
|
|
100
|
-
compact: false,
|
|
101
|
-
plugins: [plugin],
|
|
102
|
-
});
|
|
103
|
-
if (result?.code && result.code !== code) {
|
|
104
|
-
return { code: result.code, map: null };
|
|
40
|
+
const linked = await runAngularLinker(code, { filename: cleanId, projectRoot, freshPlugin: true });
|
|
41
|
+
if (linked) {
|
|
42
|
+
if (debug)
|
|
43
|
+
console.log('[ns-angular-linker][rollup-load] linked', cleanId);
|
|
44
|
+
return { code: linked, map: null };
|
|
105
45
|
}
|
|
106
46
|
}
|
|
107
47
|
catch { }
|
|
108
48
|
return null;
|
|
109
49
|
},
|
|
110
50
|
async transform(code, id) {
|
|
111
|
-
const
|
|
112
|
-
const cleanId = id.split('?', 1)[0];
|
|
51
|
+
const cleanId = normalizeAngularWatchPath(id);
|
|
113
52
|
if (!FILTER.test(cleanId))
|
|
114
53
|
return null;
|
|
115
54
|
const forceLink = cleanId.includes('/node_modules/@nativescript/angular/') && cleanId.includes('polyfills');
|
|
116
55
|
if (!code)
|
|
117
56
|
return null;
|
|
118
|
-
if (!forceLink &&
|
|
119
|
-
return null;
|
|
120
|
-
await ensureDeps();
|
|
121
|
-
if (!babel || !createLinker)
|
|
57
|
+
if (!forceLink && !hasNgDeclarePartial(code))
|
|
122
58
|
return null;
|
|
123
59
|
try {
|
|
124
|
-
const
|
|
125
|
-
if (
|
|
126
|
-
|
|
127
|
-
console.log('[ns-angular-linker][rollup]
|
|
128
|
-
}
|
|
129
|
-
catch { }
|
|
130
|
-
}
|
|
131
|
-
const result = await babel.transformAsync(code, {
|
|
132
|
-
filename: cleanId,
|
|
133
|
-
configFile: false,
|
|
134
|
-
babelrc: false,
|
|
135
|
-
sourceMaps: false,
|
|
136
|
-
compact: false,
|
|
137
|
-
plugins: [plugin],
|
|
138
|
-
});
|
|
139
|
-
if (result?.code && result.code !== code) {
|
|
140
|
-
return { code: result.code, map: null };
|
|
60
|
+
const linked = await runAngularLinker(code, { filename: cleanId, projectRoot, freshPlugin: true });
|
|
61
|
+
if (linked) {
|
|
62
|
+
if (debug)
|
|
63
|
+
console.log('[ns-angular-linker][rollup] linked', cleanId);
|
|
64
|
+
return { code: linked, map: null };
|
|
141
65
|
}
|
|
142
66
|
}
|
|
143
67
|
catch { }
|
|
@@ -148,6 +72,37 @@ function angularRollupLinker(projectRoot) {
|
|
|
148
72
|
const cliFlags = getCliFlags();
|
|
149
73
|
const isDevEnv = process.env.NODE_ENV !== 'production';
|
|
150
74
|
const hmrActive = isDevEnv && !!cliFlags.hmr;
|
|
75
|
+
/**
|
|
76
|
+
* Web-style template HMR opt-out.
|
|
77
|
+
*
|
|
78
|
+
* When `hmrActive` is true we default to the in-place template-replacement
|
|
79
|
+
* pipeline (`liveReload: true` on Analog → `_enableHmr: true` on the Angular
|
|
80
|
+
* TS compiler → `angular:component-update` events served via the
|
|
81
|
+
* `/@ng/component` middleware → `ɵɵreplaceMetadata` on the live class).
|
|
82
|
+
* Setting `_enableHmr: true` also forces Analog to set
|
|
83
|
+
* `externalRuntimeStyles: true`, changing how component styles are emitted
|
|
84
|
+
* (URLs fetched lazily instead of inlined). On the web that's fine; for
|
|
85
|
+
* NativeScript it's a new code path that touches the SCSS / Tailwind
|
|
86
|
+
* pipeline and the iOS runtime's HTTP module loader.
|
|
87
|
+
*
|
|
88
|
+
* If a project hits a regression on day one (broken styling, unresolved
|
|
89
|
+
* `?ngcomp=` imports, etc.) the user can roll back to the legacy reboot
|
|
90
|
+
* pipeline without an upstream patch by setting the env flag. We honour
|
|
91
|
+
* `0`, `false`, `off`, and `no` (case-insensitive) as "off" — anything
|
|
92
|
+
* else (including unset) keeps the new path on.
|
|
93
|
+
*
|
|
94
|
+
* The flag is read once at module load, mirroring how `hmrActive` is
|
|
95
|
+
* computed, so a project can flip it via `cross-env` in their dev script
|
|
96
|
+
* and never look back.
|
|
97
|
+
*/
|
|
98
|
+
const angularLiveReloadDisabledByEnv = (() => {
|
|
99
|
+
const raw = process.env.NS_VITE_ANGULAR_LIVE_RELOAD;
|
|
100
|
+
if (typeof raw !== 'string')
|
|
101
|
+
return false;
|
|
102
|
+
const v = raw.trim().toLowerCase();
|
|
103
|
+
return v === '0' || v === 'false' || v === 'off' || v === 'no';
|
|
104
|
+
})();
|
|
105
|
+
const hmrAngularLiveReload = hmrActive && !angularLiveReloadDisabledByEnv;
|
|
151
106
|
const projectRoot = process.cwd();
|
|
152
107
|
const tsConfigAppPath = path.resolve(projectRoot, 'tsconfig.app.json');
|
|
153
108
|
const tsConfigPath = path.resolve(projectRoot, 'tsconfig.json');
|
|
@@ -193,15 +148,24 @@ function extractComponentAssetPaths(code, componentId) {
|
|
|
193
148
|
const componentPath = normalizeAngularWatchPath(componentId);
|
|
194
149
|
const assetPaths = new Set();
|
|
195
150
|
const resolveAssetPath = (assetPath) => normalizeAngularWatchPath(path.resolve(path.dirname(componentPath), assetPath));
|
|
196
|
-
|
|
151
|
+
// Blank out `//` and `/* */` comments before scanning. The regexes below
|
|
152
|
+
// are intentionally simple (no JS parser) so they would otherwise match
|
|
153
|
+
// commented-out `templateUrl` / `styleUrls` declarations and register
|
|
154
|
+
// phantom asset deps via `addWatchFile`. In current Rolldown-Vite that
|
|
155
|
+
// also enrolls them as `_addedImports`, which `vite:import-analysis`
|
|
156
|
+
// then tries to resolve — surfacing as a misleading
|
|
157
|
+
// `Failed to resolve import "<file>" from "<importer>". Does the file
|
|
158
|
+
// exist?` pre-transform error if the file (predictably) doesn't exist.
|
|
159
|
+
const scanCode = stripJsComments(code);
|
|
160
|
+
const templateUrlMatch = scanCode.match(/templateUrl\s*:\s*['"](.+?\.(?:html|htm))['"]/);
|
|
197
161
|
if (templateUrlMatch) {
|
|
198
162
|
assetPaths.add(resolveAssetPath(templateUrlMatch[1]));
|
|
199
163
|
}
|
|
200
|
-
const styleUrlMatch =
|
|
164
|
+
const styleUrlMatch = scanCode.match(/styleUrl\s*:\s*['"](.+?\.(?:css|less|sass|scss))['"]/);
|
|
201
165
|
if (styleUrlMatch) {
|
|
202
166
|
assetPaths.add(resolveAssetPath(styleUrlMatch[1]));
|
|
203
167
|
}
|
|
204
|
-
const styleUrlsMatch =
|
|
168
|
+
const styleUrlsMatch = scanCode.match(/styleUrls\s*:\s*\[([\s\S]*?)\]/m);
|
|
205
169
|
if (styleUrlsMatch) {
|
|
206
170
|
for (const match of styleUrlsMatch[1].matchAll(/['"](.+?\.(?:css|less|sass|scss))['"]/g)) {
|
|
207
171
|
assetPaths.add(resolveAssetPath(match[1]));
|
|
@@ -210,9 +174,18 @@ function extractComponentAssetPaths(code, componentId) {
|
|
|
210
174
|
return Array.from(assetPaths);
|
|
211
175
|
}
|
|
212
176
|
function createAngularPlugins(opts) {
|
|
177
|
+
const verbose = resolveVerboseFlag();
|
|
213
178
|
const assetToComponents = new Map();
|
|
214
179
|
const componentToAssets = new Map();
|
|
215
180
|
const pendingComponentInvalidations = new Set();
|
|
181
|
+
// Shared state between the `enforce: 'pre'` discovery plugin and the
|
|
182
|
+
// `enforce: 'post'` injection plugin. Maps a clean (no-querystring)
|
|
183
|
+
// .ts file id to the list of `@Component`-decorated class names found
|
|
184
|
+
// in its RAW TypeScript source. The pre plugin populates this map;
|
|
185
|
+
// the post plugin reads it to know which class names to register
|
|
186
|
+
// against the compiled output. Cleared on each pre-plugin invocation
|
|
187
|
+
// so renames or `@Component` removals don't leave stale entries.
|
|
188
|
+
const componentsByCleanId = new Map();
|
|
216
189
|
const untrackComponentAssets = (componentPath) => {
|
|
217
190
|
const previousAssets = componentToAssets.get(componentPath);
|
|
218
191
|
if (!previousAssets)
|
|
@@ -240,7 +213,121 @@ function createAngularPlugins(opts) {
|
|
|
240
213
|
assetToComponents.set(assetPath, components);
|
|
241
214
|
}
|
|
242
215
|
};
|
|
216
|
+
const isCandidateComponentTs = (cleanId) => {
|
|
217
|
+
if (!cleanId.endsWith('.ts'))
|
|
218
|
+
return false;
|
|
219
|
+
if (cleanId.includes('/node_modules/'))
|
|
220
|
+
return false;
|
|
221
|
+
if (cleanId.endsWith('.d.ts'))
|
|
222
|
+
return false;
|
|
223
|
+
if (cleanId.endsWith('.spec.ts') || cleanId.endsWith('.test.ts'))
|
|
224
|
+
return false;
|
|
225
|
+
return true;
|
|
226
|
+
};
|
|
243
227
|
return [
|
|
228
|
+
// HMR self-registration runs in two phases:
|
|
229
|
+
//
|
|
230
|
+
// 1. (this plugin, `enforce: 'pre'`) Walk the raw TypeScript
|
|
231
|
+
// source for each user `.ts` file and record the names of
|
|
232
|
+
// any `@Component`-decorated classes into the shared
|
|
233
|
+
// `componentsByCleanId` map. Discovery has to happen on the
|
|
234
|
+
// raw source because the Analog Angular plugin rewrites
|
|
235
|
+
// `@Component(...)` into static metadata calls and removes
|
|
236
|
+
// the textual decorator pattern.
|
|
237
|
+
//
|
|
238
|
+
// 2. (`ns-component-hmr-register-post`, `enforce: 'post'`)
|
|
239
|
+
// After the Analog Angular plugin has compiled the file,
|
|
240
|
+
// append the global `__NS_HMR_REGISTER_COMPONENT__`
|
|
241
|
+
// registration calls keyed by the names recorded in step 1.
|
|
242
|
+
//
|
|
243
|
+
// Why the two-phase split: the Analog Angular plugin's `transform`
|
|
244
|
+
// returns its OWN regenerated compiled output (from its internal
|
|
245
|
+
// `outputFiles` cache populated at `buildStart`), discarding any
|
|
246
|
+
// code modifications applied earlier in the pipeline. We
|
|
247
|
+
// previously appended the registration snippet here, in the pre
|
|
248
|
+
// plugin, and the snippet was silently dropped — leaving the
|
|
249
|
+
// HMR class registry empty and `getFreshComponentClass` returning
|
|
250
|
+
// `found=false reason=no-registry` after every reboot.
|
|
251
|
+
//
|
|
252
|
+
// Placement notes that still apply:
|
|
253
|
+
// - `apply: 'serve'`: the registry runtime hook is dev-only;
|
|
254
|
+
// production builds never need self-registration.
|
|
255
|
+
// - Intentionally NOT gated on `hmrActive`. The injected
|
|
256
|
+
// snippet self-guards with
|
|
257
|
+
// `typeof globalThis.__NS_HMR_REGISTER_COMPONENT__ === 'function'`,
|
|
258
|
+
// so it's a no-op when the runtime hook isn't installed
|
|
259
|
+
// (e.g. `--no-hmr` users still serving modules through
|
|
260
|
+
// Vite). Gating the transform itself on `hmrActive` produced
|
|
261
|
+
// a silent failure mode where `--no-hmr` users got HMR
|
|
262
|
+
// machinery up but never got the registration calls
|
|
263
|
+
// injected, leaving the registry empty.
|
|
264
|
+
{
|
|
265
|
+
name: 'ns-component-hmr-register',
|
|
266
|
+
enforce: 'pre',
|
|
267
|
+
apply: 'serve',
|
|
268
|
+
transform(code, id) {
|
|
269
|
+
const cleanId = normalizeAngularWatchPath(id);
|
|
270
|
+
if (!isCandidateComponentTs(cleanId))
|
|
271
|
+
return null;
|
|
272
|
+
const componentNames = findComponentClassNames(code);
|
|
273
|
+
if (componentNames.length === 0) {
|
|
274
|
+
// Drop any stale entry from a previous transform
|
|
275
|
+
// pass; the file may have lost its `@Component`
|
|
276
|
+
// decorator across a rename/refactor.
|
|
277
|
+
componentsByCleanId.delete(cleanId);
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
componentsByCleanId.set(cleanId, componentNames);
|
|
281
|
+
if (verbose) {
|
|
282
|
+
console.info(`[ns-hmr][ns-component-hmr-register] discovered ${componentNames.length} component(s) in ${cleanId} (${componentNames.join(', ')})`);
|
|
283
|
+
}
|
|
284
|
+
// Discovery only — never modify the raw TS source. Any
|
|
285
|
+
// modification here is discarded by the Analog Angular
|
|
286
|
+
// plugin downstream; the actual snippet append happens
|
|
287
|
+
// in `ns-component-hmr-register-post`.
|
|
288
|
+
return null;
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
// Phase 2: append the HMR registration snippet to the compiled
|
|
292
|
+
// JS output produced by `@analogjs/vite-plugin-angular`. Runs
|
|
293
|
+
// `enforce: 'post'` so we see the post-Angular code (where the
|
|
294
|
+
// pre plugin's work would otherwise be discarded). Reads the
|
|
295
|
+
// component names recorded by the pre plugin via
|
|
296
|
+
// `componentsByCleanId`.
|
|
297
|
+
{
|
|
298
|
+
name: 'ns-component-hmr-register-post',
|
|
299
|
+
enforce: 'post',
|
|
300
|
+
apply: 'serve',
|
|
301
|
+
transform(code, id) {
|
|
302
|
+
const cleanId = normalizeAngularWatchPath(id);
|
|
303
|
+
if (!isCandidateComponentTs(cleanId))
|
|
304
|
+
return null;
|
|
305
|
+
const componentNames = componentsByCleanId.get(cleanId);
|
|
306
|
+
if (!componentNames || componentNames.length === 0)
|
|
307
|
+
return null;
|
|
308
|
+
// Idempotency: the Vite cache may replay the transform
|
|
309
|
+
// pipeline on cached modules. The marker comment is
|
|
310
|
+
// inserted by `appendComponentHmrRegistration` and
|
|
311
|
+
// guards against double-injection. We also defensively
|
|
312
|
+
// short-circuit here so we don't have to allocate the
|
|
313
|
+
// suffix string on every cached re-run.
|
|
314
|
+
if (code.includes(HMR_REGISTER_MARKER))
|
|
315
|
+
return null;
|
|
316
|
+
const result = appendComponentHmrRegistration(code, componentNames);
|
|
317
|
+
if (!result.code)
|
|
318
|
+
return null;
|
|
319
|
+
if (verbose) {
|
|
320
|
+
console.info(`[ns-hmr][ns-component-hmr-register-post] appended registrations for ${result.componentNames.length} component(s) in ${cleanId} (${result.componentNames.join(', ')})`);
|
|
321
|
+
}
|
|
322
|
+
// Returning `null` for the source map is acceptable for
|
|
323
|
+
// dev: lines 1..N (the original compiled body) keep
|
|
324
|
+
// the upstream Angular source map; the appended snippet
|
|
325
|
+
// is invisible to debuggers but harmless. For
|
|
326
|
+
// production-grade source maps a MagicString-based
|
|
327
|
+
// pass-through could be used; not required for HMR.
|
|
328
|
+
return { code: result.code, map: null };
|
|
329
|
+
},
|
|
330
|
+
},
|
|
244
331
|
// Allow external html template changes to trigger hot reload: Make .ts files depend on their .html templates
|
|
245
332
|
{
|
|
246
333
|
name: 'angular-template-deps',
|
|
@@ -255,6 +342,15 @@ function createAngularPlugins(opts) {
|
|
|
255
342
|
for (const assetPath of assetPaths) {
|
|
256
343
|
this.addWatchFile(assetPath);
|
|
257
344
|
}
|
|
345
|
+
// Diagnostic: surface which .ts files we've registered
|
|
346
|
+
// asset (template/styleUrls) dependencies for. This is
|
|
347
|
+
// the first fence the HTML→TS invalidation pipeline must
|
|
348
|
+
// pass — if we never see a [tracking] log for the
|
|
349
|
+
// component we're editing, the watcher will never fire
|
|
350
|
+
// and `pendingComponentInvalidations` stays empty.
|
|
351
|
+
if (verbose) {
|
|
352
|
+
console.info(`[ns-hmr][angular-template-deps] [tracking] componentKey=${componentKey} assets=${assetPaths.length} (${assetPaths.slice(0, 4).join(', ')})`);
|
|
353
|
+
}
|
|
258
354
|
return null;
|
|
259
355
|
},
|
|
260
356
|
watchChange(id) {
|
|
@@ -269,12 +365,27 @@ function createAngularPlugins(opts) {
|
|
|
269
365
|
for (const componentPath of components) {
|
|
270
366
|
pendingComponentInvalidations.add(componentPath);
|
|
271
367
|
}
|
|
368
|
+
if (verbose) {
|
|
369
|
+
console.info(`[ns-hmr][angular-template-deps] watchChange [via assetToComponents] changed=${changedPath} → invalidating ${components.size} component(s):`, Array.from(components));
|
|
370
|
+
}
|
|
272
371
|
return;
|
|
273
372
|
}
|
|
274
373
|
if (/\.(html|htm)$/i.test(changedPath)) {
|
|
275
374
|
const componentPath = changedPath.replace(/\.(html|htm)$/i, '.ts');
|
|
276
|
-
|
|
277
|
-
|
|
375
|
+
const exists = fs.existsSync(resolveAngularWatchFilePath(componentPath));
|
|
376
|
+
if (exists) {
|
|
377
|
+
const componentKey = normalizeAngularWatchKey(componentPath);
|
|
378
|
+
pendingComponentInvalidations.add(componentKey);
|
|
379
|
+
if (verbose) {
|
|
380
|
+
console.info(`[ns-hmr][angular-template-deps] watchChange [via fallback .html→.ts] changed=${changedPath} componentKey=${componentKey}`);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
// Truly anomalous: a watched template/style asset has no companion
|
|
385
|
+
// `.ts` file, so we cannot route the edit through the Angular
|
|
386
|
+
// HMR pipeline. Always-on warning so it surfaces in non-verbose
|
|
387
|
+
// runs — silent fallback would hide a real wiring break.
|
|
388
|
+
console.warn(`[ns-hmr][angular-template-deps] watchChange [no companion .ts found] changed=${changedPath} expectedTs=${componentPath}`);
|
|
278
389
|
}
|
|
279
390
|
}
|
|
280
391
|
},
|
|
@@ -283,6 +394,9 @@ function createAngularPlugins(opts) {
|
|
|
283
394
|
if (!pendingComponentInvalidations.has(componentPath))
|
|
284
395
|
return null;
|
|
285
396
|
pendingComponentInvalidations.delete(componentPath);
|
|
397
|
+
if (verbose) {
|
|
398
|
+
console.info(`[ns-hmr][angular-template-deps] shouldTransformCachedModule → re-transform componentKey=${componentPath}`);
|
|
399
|
+
}
|
|
286
400
|
return true;
|
|
287
401
|
},
|
|
288
402
|
},
|
|
@@ -295,11 +409,140 @@ function createAngularPlugins(opts) {
|
|
|
295
409
|
experimental: {
|
|
296
410
|
useAngularCompilationAPI: opts.useAngularCompilationAPI,
|
|
297
411
|
},
|
|
298
|
-
liveReload
|
|
412
|
+
// `liveReload` is Analog's flag for Angular's web-style template HMR
|
|
413
|
+
// pipeline. When ON, Analog:
|
|
414
|
+
// 1. Sets `_enableHmr = true` on the TS compiler so each compiled
|
|
415
|
+
// component `.mjs` emits `<ClassName>_HmrLoad` plus an
|
|
416
|
+
// `import.meta.hot.on('angular:component-update', ...)` listener.
|
|
417
|
+
// 2. Registers a `/@ng/component?c=<id>` middleware that serves the
|
|
418
|
+
// recompiled template's `_UpdateMetadata` source on demand.
|
|
419
|
+
// 3. In `handleHotUpdate` for `.html` / `.css` / `.scss` edits, sends
|
|
420
|
+
// `server.ws.send('angular:component-update', { id, timestamp })`
|
|
421
|
+
// so the runtime can call `ɵɵreplaceMetadata` on the live class —
|
|
422
|
+
// swapping the template definition AND walking live LViews to
|
|
423
|
+
// recreate matching views in-place. NO Angular reboot, NO route
|
|
424
|
+
// navigation.
|
|
425
|
+
//
|
|
426
|
+
// Previously this was `false` because the NativeScript HMR pipeline
|
|
427
|
+
// rebuilt every save through `__reboot_ng_modules__`. That works but
|
|
428
|
+
// has two big downsides on mobile: every save triggers a full app
|
|
429
|
+
// reboot AND the captured route-history replay (see
|
|
430
|
+
// `@nativescript/angular`'s `hmr-route-replay.ts`), which produces 2-3
|
|
431
|
+
// re-navigations per save and re-instantiates the page component
|
|
432
|
+
// multiple times. For pure template/style edits — the common case —
|
|
433
|
+
// the web-style component-replacement path keeps the page mounted and
|
|
434
|
+
// only swaps the changed bits.
|
|
435
|
+
//
|
|
436
|
+
// We only enable this when HMR itself is active (`hmrActive` already
|
|
437
|
+
// gates on `--hmr` and `NODE_ENV !== 'production'`). With HMR off the
|
|
438
|
+
// behaviour is unchanged: production builds and `--no-hmr` dev still
|
|
439
|
+
// see `liveReload: false`, the compiler skips the HMR initializers,
|
|
440
|
+
// and the middleware is not registered.
|
|
441
|
+
//
|
|
442
|
+
// Important interactions to be aware of:
|
|
443
|
+
// - When `_enableHmr` is true, Analog also sets
|
|
444
|
+
// `externalRuntimeStyles = true`, changing how component styles
|
|
445
|
+
// are emitted (URLs fetched at runtime instead of inlined). For
|
|
446
|
+
// NativeScript, the existing CSS pipeline expects inlined styles;
|
|
447
|
+
// `ns-component-hmr-style-overrides` (below) restores the
|
|
448
|
+
// pre-HMR style-emission strategy so Tailwind/global SCSS
|
|
449
|
+
// packaging keeps working.
|
|
450
|
+
// - The runtime dynamic-import resolves the metadata URL relative
|
|
451
|
+
// to `import.meta.url`, e.g. `http://host:port/ns/m/<componentDir>/@ng/component?c=...`.
|
|
452
|
+
// Analog's middleware uses `req.url.includes('/@ng/component')`
|
|
453
|
+
// (substring match), so the request still matches even with the
|
|
454
|
+
// `/ns/m/` prefix in the path.
|
|
455
|
+
// - The NS HMR client (`packages/vite/hmr/client/index.ts`)
|
|
456
|
+
// forwards Vite's standard `{ type: 'custom', event, data }`
|
|
457
|
+
// payloads to `import.meta.hot.on` listeners via
|
|
458
|
+
// `__NS_DISPATCH_HOT_EVENT__`, and short-circuits before the
|
|
459
|
+
// reboot path for `angular:component-update`.
|
|
460
|
+
// - The NS server-side hot-update handler in
|
|
461
|
+
// `packages/vite/hmr/server/websocket.ts` skips its own
|
|
462
|
+
// `ns:angular-update` broadcast for `.html` / component-style
|
|
463
|
+
// edits so we don't double-fire (the reboot path stays for `.ts`
|
|
464
|
+
// edits).
|
|
465
|
+
// - To roll back to the legacy reboot-only pipeline (e.g. while
|
|
466
|
+
// debugging an `externalRuntimeStyles` regression), set
|
|
467
|
+
// `NS_VITE_ANGULAR_LIVE_RELOAD=0` in the dev environment.
|
|
468
|
+
// `hmrAngularLiveReload` collapses both gates above.
|
|
469
|
+
liveReload: hmrAngularLiveReload,
|
|
470
|
+
// NativeScript can't consume Angular's `externalRuntimeStyles`
|
|
471
|
+
// mode — that emits component styles as runtime-loaded
|
|
472
|
+
// `<hash>.css` URL references which only a browser CSSOM/`<link>`
|
|
473
|
+
// pipeline can resolve. We tell our patched Analog plugin (see
|
|
474
|
+
// `patches/@analogjs+vite-plugin-angular+2.3.1.patch` in
|
|
475
|
+
// downstream apps; upstream PR pending) to keep the legacy
|
|
476
|
+
// behavior of inlining preprocessed CSS strings into the
|
|
477
|
+
// component metadata's `styles: [...]` array, which the NS
|
|
478
|
+
// renderer's CSS-bundle pipeline already knows how to apply.
|
|
479
|
+
// The option is independent from `liveReload` (`_enableHmr`
|
|
480
|
+
// still wires up `ɵɵreplaceMetadata` for in-place template
|
|
481
|
+
// HMR) — we keep HMR ON, just opt out of the URL-style
|
|
482
|
+
// emission. Note the option lands as a no-op on stock
|
|
483
|
+
// Analog releases that haven't merged the patch; once
|
|
484
|
+
// merged, this will switch the compiler off external styles
|
|
485
|
+
// for NativeScript without affecting web builds.
|
|
486
|
+
//
|
|
487
|
+
// `@ts-expect-error` because the option is not yet in
|
|
488
|
+
// `@analogjs/vite-plugin-angular`'s published `PluginOptions`
|
|
489
|
+
// type. When the upstream PR (https://github.com/analogjs/analog)
|
|
490
|
+
// adds it, this `@ts-expect-error` will itself become an
|
|
491
|
+
// "unused suppression" error — that's the signal to remove
|
|
492
|
+
// this comment AND the surrounding explanation, and bump
|
|
493
|
+
// the Analog peer dep to the version that ships the type.
|
|
494
|
+
// @ts-expect-error -- pending upstream Analog type publish
|
|
495
|
+
externalRuntimeStyles: false,
|
|
299
496
|
tsconfig: tsConfig,
|
|
497
|
+
// Forward Angular-style file replacements (e.g. `environment.ts`
|
|
498
|
+
// → `environment.stg.ts`) directly into the Analog plugin so the
|
|
499
|
+
// Angular TypeScript host (which reads source files via its own
|
|
500
|
+
// CompilerHost, bypassing Vite's load chain) sees the swap. This
|
|
501
|
+
// is the same hook Angular CLI uses for `fileReplacements` in
|
|
502
|
+
// `angular.json` build configurations.
|
|
503
|
+
fileReplacements: opts.fileReplacements ?? [],
|
|
504
|
+
workspaceRoot: opts.workspaceRoot ?? process.cwd(),
|
|
300
505
|
}),
|
|
301
506
|
// Post-phase linker to catch any declarations introduced after other transforms (including project code)
|
|
302
507
|
angularLinkerVitePluginPost(process.cwd()),
|
|
508
|
+
// Re-inject the `/* @vite-ignore */` annotation onto Angular's HMR
|
|
509
|
+
// initializer dynamic imports.
|
|
510
|
+
//
|
|
511
|
+
// Angular's compiler emits each component's HMR loader as
|
|
512
|
+
// `import(/* @vite-ignore */ i0.ɵɵgetReplaceMetadataURL(...))` so
|
|
513
|
+
// Vite leaves the runtime-computed URL alone. The annotation goes
|
|
514
|
+
// missing somewhere in the post-Angular pipeline (empirically the
|
|
515
|
+
// linker's `compact: false` Babel pass loses it on some files),
|
|
516
|
+
// causing Vite's static analyzer to flag the import and rewrite
|
|
517
|
+
// the call site through its runtime resolver — which then throws
|
|
518
|
+
// `TypeError at ɵɵgetReplaceMetadataURL` on the iOS device because
|
|
519
|
+
// the resolver expects a statically known specifier.
|
|
520
|
+
//
|
|
521
|
+
// Running `enforce: 'post'` and `apply: 'serve'` here ensures we
|
|
522
|
+
// see the file AFTER every other transform has had its chance to
|
|
523
|
+
// strip comments, AND only in dev (the HMR initializer is gated
|
|
524
|
+
// behind `ngDevMode` and never runs in a production build, so the
|
|
525
|
+
// fix would be wasted work outside `serve`). The helper is
|
|
526
|
+
// idempotent: if the annotation is already present, the file is
|
|
527
|
+
// returned unchanged.
|
|
528
|
+
{
|
|
529
|
+
name: 'ns-angular-hmr-vite-ignore',
|
|
530
|
+
enforce: 'post',
|
|
531
|
+
apply: 'serve',
|
|
532
|
+
transform(code, id) {
|
|
533
|
+
if (!hmrAngularLiveReload)
|
|
534
|
+
return null;
|
|
535
|
+
const cleanId = normalizeAngularWatchPath(id);
|
|
536
|
+
if (!cleanId.endsWith('.ts') && !cleanId.endsWith('.mjs') && !cleanId.endsWith('.js'))
|
|
537
|
+
return null;
|
|
538
|
+
if (cleanId.includes('/node_modules/'))
|
|
539
|
+
return null;
|
|
540
|
+
const next = injectAngularHmrViteIgnore(code);
|
|
541
|
+
if (next === code)
|
|
542
|
+
return null;
|
|
543
|
+
return { code: next, map: null };
|
|
544
|
+
},
|
|
545
|
+
},
|
|
303
546
|
// Enforce: fully disable dependency optimization during serve to avoid rxjs esm5 crawling and OOM
|
|
304
547
|
{
|
|
305
548
|
name: 'ns-disable-optimize-deps',
|
|
@@ -338,7 +581,7 @@ function createAngularPlugins(opts) {
|
|
|
338
581
|
},
|
|
339
582
|
];
|
|
340
583
|
}
|
|
341
|
-
export const angularConfig = ({ mode }) => {
|
|
584
|
+
export const angularConfig = ({ mode, fileReplacements, workspaceRoot, }) => {
|
|
342
585
|
const useSingleBundleDevOutput = mode === 'development' && !hmrActive;
|
|
343
586
|
const plugins = createAngularPlugins({
|
|
344
587
|
// Vite build --watch with the legacy Analog compilation path can regress
|
|
@@ -346,6 +589,8 @@ export const angularConfig = ({ mode }) => {
|
|
|
346
589
|
// Restrict the newer compilation API to NativeScript's development no-HMR
|
|
347
590
|
// flow, which is where the unstable rebuilds occur today.
|
|
348
591
|
useAngularCompilationAPI: useSingleBundleDevOutput,
|
|
592
|
+
fileReplacements,
|
|
593
|
+
workspaceRoot,
|
|
349
594
|
});
|
|
350
595
|
const disableAnimations = true;
|
|
351
596
|
//process.env.NS_DISABLE_NG_ANIMATIONS === "1" ||
|
|
@@ -366,17 +611,16 @@ export const angularConfig = ({ mode }) => {
|
|
|
366
611
|
apply: 'build',
|
|
367
612
|
enforce: 'post',
|
|
368
613
|
async generateBundle(_options, bundle) {
|
|
614
|
+
function isNsAngularPolyfillsModule(id) {
|
|
615
|
+
return normalizeAngularWatchPath(id).includes('node_modules/@nativescript/angular/fesm2022/nativescript-angular-polyfills.mjs');
|
|
616
|
+
}
|
|
369
617
|
function isNsAngularPolyfillsChunk(chunk) {
|
|
370
618
|
if (!chunk || !chunk.modules)
|
|
371
619
|
return false;
|
|
372
|
-
return Object.keys(chunk.modules).some(
|
|
620
|
+
return Object.keys(chunk.modules).some(isNsAngularPolyfillsModule);
|
|
373
621
|
}
|
|
374
|
-
const { babel } = await
|
|
375
|
-
if (!babel)
|
|
376
|
-
return;
|
|
377
|
-
const fileSystem = await resolveAngularFileSystem(process.cwd());
|
|
378
|
-
const linkerFactory = await importLinkerFactory();
|
|
379
|
-
if (!linkerFactory)
|
|
622
|
+
const { babel, createLinker } = await getAngularLinkerFactory(process.cwd());
|
|
623
|
+
if (!babel || !createLinker)
|
|
380
624
|
return;
|
|
381
625
|
const strict = process.env.NS_STRICT_NG_LINK === '1' || process.env.NS_STRICT_NG_LINK === 'true';
|
|
382
626
|
const enforceStrict = process.env.NS_STRICT_NG_LINK_ENFORCE === '1' || process.env.NS_STRICT_NG_LINK_ENFORCE === 'true';
|
|
@@ -396,26 +640,13 @@ export const angularConfig = ({ mode }) => {
|
|
|
396
640
|
continue;
|
|
397
641
|
const isNsPolyfills = isNsAngularPolyfillsChunk(chunk);
|
|
398
642
|
try {
|
|
399
|
-
//
|
|
400
|
-
|
|
401
|
-
const
|
|
402
|
-
const res = await babel.transformAsync(code, {
|
|
403
|
-
filename: fileName,
|
|
404
|
-
configFile: false,
|
|
405
|
-
babelrc: false,
|
|
406
|
-
sourceMaps: false,
|
|
407
|
-
compact: false,
|
|
408
|
-
plugins: [freshPlugin],
|
|
409
|
-
});
|
|
410
|
-
const linkedCode = res?.code && res.code !== code ? res.code : code;
|
|
411
|
-
const finalCode = applyAngularChunkPostProcessing(linkedCode, { vendorInjectExport });
|
|
643
|
+
// Fresh plugin per chunk — avoids stale linker state across watch-mode rebuilds.
|
|
644
|
+
const linked = await runAngularLinker(code, { filename: fileName, projectRoot: process.cwd(), freshPlugin: true });
|
|
645
|
+
const finalCode = applyAngularChunkPostProcessing(linked ?? code, { vendorInjectExport });
|
|
412
646
|
if (finalCode !== code) {
|
|
413
647
|
chunk.code = finalCode;
|
|
414
648
|
if (debug) {
|
|
415
|
-
|
|
416
|
-
console.log('[ns-angular-linker][post] linked', fileName, isNsPolyfills ? '(polyfills)' : '');
|
|
417
|
-
}
|
|
418
|
-
catch { }
|
|
649
|
+
console.log('[ns-angular-linker][post] linked', fileName, isNsPolyfills ? '(polyfills)' : '');
|
|
419
650
|
}
|
|
420
651
|
}
|
|
421
652
|
if (strict && !isNsPolyfills && containsRealNgDeclare(finalCode)) {
|
|
@@ -435,10 +666,10 @@ export const angularConfig = ({ mode }) => {
|
|
|
435
666
|
const chunk = bundle[fname];
|
|
436
667
|
const modIds = chunk?.modules
|
|
437
668
|
? Object.keys(chunk.modules)
|
|
438
|
-
.filter((m) => /node_modules\/(?:@angular|@nativescript\/angular)\//.test(m))
|
|
669
|
+
.filter((m) => /node_modules\/(?:@angular|@nativescript\/angular)\//.test(normalizeAngularWatchPath(m)))
|
|
439
670
|
.slice(0, 8)
|
|
440
671
|
: [];
|
|
441
|
-
const isOnlyPolyfills = modIds.length > 0 && modIds.every(
|
|
672
|
+
const isOnlyPolyfills = modIds.length > 0 && modIds.every(isNsAngularPolyfillsModule);
|
|
442
673
|
if (isOnlyPolyfills)
|
|
443
674
|
continue;
|
|
444
675
|
let snippet = '';
|
|
@@ -461,10 +692,7 @@ export const angularConfig = ({ mode }) => {
|
|
|
461
692
|
throw new Error(message);
|
|
462
693
|
}
|
|
463
694
|
else {
|
|
464
|
-
|
|
465
|
-
console.warn(`[ns-angular-linker-post] ${message}`);
|
|
466
|
-
}
|
|
467
|
-
catch { }
|
|
695
|
+
console.warn(`[ns-angular-linker-post] ${message}`);
|
|
468
696
|
}
|
|
469
697
|
}
|
|
470
698
|
},
|
|
@@ -484,37 +712,19 @@ export const angularConfig = ({ mode }) => {
|
|
|
484
712
|
try {
|
|
485
713
|
let transformed = code;
|
|
486
714
|
if (containsRealNgDeclare(code)) {
|
|
487
|
-
const { babel } = await
|
|
488
|
-
if (!babel)
|
|
715
|
+
const { babel, createLinker } = await getAngularLinkerFactory(process.cwd());
|
|
716
|
+
if (!babel || !createLinker)
|
|
489
717
|
return null;
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
const freshPlugin = (await importLinkerFactory())?.({ sourceMapping: false, fileSystem });
|
|
493
|
-
if (!freshPlugin)
|
|
494
|
-
return null;
|
|
495
|
-
const runLink = async (input) => {
|
|
496
|
-
const result = await babel.transformAsync(input, {
|
|
497
|
-
filename,
|
|
498
|
-
configFile: false,
|
|
499
|
-
babelrc: false,
|
|
500
|
-
sourceMaps: false,
|
|
501
|
-
compact: false,
|
|
502
|
-
plugins: [freshPlugin],
|
|
503
|
-
});
|
|
504
|
-
return result?.code ?? input;
|
|
505
|
-
};
|
|
506
|
-
transformed = await runLink(code);
|
|
718
|
+
// Fresh plugin per pass — avoids stale linker state across watch-mode rebuilds.
|
|
719
|
+
transformed = (await runAngularLinker(code, { filename, projectRoot: process.cwd(), freshPlugin: true })) ?? code;
|
|
507
720
|
if (containsRealNgDeclare(transformed)) {
|
|
508
|
-
transformed = await
|
|
721
|
+
transformed = (await runAngularLinker(transformed, { filename, projectRoot: process.cwd(), freshPlugin: true })) ?? transformed;
|
|
509
722
|
}
|
|
510
723
|
}
|
|
511
724
|
transformed = applyAngularChunkPostProcessing(transformed);
|
|
512
725
|
if (transformed !== code) {
|
|
513
726
|
if (debug) {
|
|
514
|
-
|
|
515
|
-
console.log('[ns-angular-linker][render] linked', filename);
|
|
516
|
-
}
|
|
517
|
-
catch { }
|
|
727
|
+
console.log('[ns-angular-linker][render] linked', filename);
|
|
518
728
|
}
|
|
519
729
|
return { code: transformed, map: null };
|
|
520
730
|
}
|