Skip to content

Commit e5b72b7

Browse files
committed
Merge remote-tracking branch 'origin/main' into feat/vite-hmr
2 parents 6795846 + e0dab64 commit e5b72b7

4 files changed

Lines changed: 122 additions & 39 deletions

File tree

packages/angular/src/lib/nativescript-renderer.ts

Lines changed: 86 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,46 @@
1-
import { Inject, Injectable, Injector, NgZone, Optional, Renderer2, RendererFactory2, RendererStyleFlags2, RendererType2, ViewEncapsulation, inject, runInInjectionContext } from '@angular/core';
2-
import { addTaggedAdditionalCSS, Application, ContentView, Device, getViewById, Observable, profile, Utils, View } from '@nativescript/core';
3-
import { getViewClass, isKnownView } from './element-registry';
4-
import { getFirstNativeLikeView, NgView, TextNode } from './views';
5-
6-
import { NamespaceFilter, NAMESPACE_FILTERS } from './property-filter';
7-
import { APP_ROOT_VIEW, ENABLE_REUSABE_VIEWS, NATIVESCRIPT_ROOT_MODULE_ID, PREVENT_SPECIFIC_EVENTS_DURING_CD } from './tokens';
1+
import {
2+
inject,
3+
Injectable,
4+
Injector,
5+
Renderer2,
6+
RendererFactory2,
7+
RendererStyleFlags2,
8+
RendererType2,
9+
runInInjectionContext,
10+
ViewEncapsulation,
11+
} from '@angular/core';
12+
import {
13+
addTaggedAdditionalCSS,
14+
Application,
15+
ContentView,
16+
getViewById,
17+
Observable,
18+
profile,
19+
View,
20+
} from '@nativescript/core';
21+
import { isKnownView } from './element-registry';
22+
import { NAMESPACE_FILTERS } from './property-filter';
23+
import {
24+
APP_ROOT_VIEW,
25+
ENABLE_REUSABE_VIEWS,
26+
NATIVESCRIPT_ROOT_MODULE_ID,
27+
PREVENT_SPECIFIC_EVENTS_DURING_CD,
28+
WRAP_CD_IN_TRANSACTION,
29+
} from './tokens';
830
import { NativeScriptDebug } from './trace';
931
import { ViewUtil } from './view-util';
32+
import { getFirstNativeLikeView, NgView, TextNode } from './views';
1033

11-
const addStyleToCss = profile('"renderer".addStyleToCss', function addStyleToCss(style: string, tag?: string | number): void {
12-
if (tag) {
13-
addTaggedAdditionalCSS(style, tag);
14-
} else {
15-
Application.addCss(style);
16-
}
17-
});
34+
const addStyleToCss = profile(
35+
'"renderer".addStyleToCss',
36+
function addStyleToCss(style: string, tag?: string | number): void {
37+
if (tag) {
38+
addTaggedAdditionalCSS(style, tag);
39+
} else {
40+
Application.addCss(style);
41+
}
42+
},
43+
);
1844

1945
function runInRootZone<T>(fn: () => T): T {
2046
if (typeof Zone === 'undefined') {
@@ -88,7 +114,9 @@ export class NativeScriptRendererFactory implements RendererFactory2 {
88114
private reuseViews = inject(ENABLE_REUSABE_VIEWS, {
89115
optional: true,
90116
});
117+
private wrapCdInTransaction = __APPLE__ && inject(WRAP_CD_IN_TRANSACTION);
91118
private injector = inject(Injector);
119+
private cdDepth = 0;
92120
private viewUtil = new ViewUtil(this.namespaceFilters, this.reuseViews);
93121

94122
constructor() {
@@ -99,7 +127,9 @@ export class NativeScriptRendererFactory implements RendererFactory2 {
99127
}
100128
createRenderer(hostElement: any, type: RendererType2): Renderer2 {
101129
if (NativeScriptDebug.enabled) {
102-
NativeScriptDebug.rendererLog(`NativeScriptRendererFactory.createRenderer ${hostElement}. type.id: ${type.id} type.encapsulation: ${type.encapsulation}`);
130+
NativeScriptDebug.rendererLog(
131+
`NativeScriptRendererFactory.createRenderer ${hostElement}. type.id: ${type.id} type.encapsulation: ${type.encapsulation}`,
132+
);
103133
}
104134
if (!hostElement || !type) {
105135
return this.defaultRenderer;
@@ -137,12 +167,25 @@ export class NativeScriptRendererFactory implements RendererFactory2 {
137167
this.componentRenderers.set(type.id, renderer);
138168
return renderer;
139169
}
140-
// begin?(): void {
141-
// throw new Error("Method not implemented.");
142-
// }
143-
// end?(): void {
144-
// throw new Error("Method not implemented.");
145-
// }
170+
begin() {
171+
if (__APPLE__ && this.wrapCdInTransaction) {
172+
if (this.cdDepth > 0) {
173+
// previous tick threw between begin and end; flush it
174+
while (this.cdDepth > 0) {
175+
CATransaction.commit();
176+
this.cdDepth--;
177+
}
178+
}
179+
CATransaction.begin();
180+
this.cdDepth++;
181+
}
182+
}
183+
end() {
184+
if (__APPLE__ && this.wrapCdInTransaction) {
185+
CATransaction.commit();
186+
this.cdDepth--;
187+
}
188+
}
146189
whenRenderingDone(): Promise<any> {
147190
if (!this.rootView) {
148191
return Promise.resolve();
@@ -258,15 +301,19 @@ class NativeScriptRenderer implements Renderer2 {
258301
@modifiesDom()
259302
insertBefore(parent: any, newChild: any, refChild: any): void {
260303
if (NativeScriptDebug.enabled) {
261-
NativeScriptDebug.rendererLog(`NativeScriptRenderer.insertBefore child: ${newChild} ` + `parent: ${parent} refChild: ${refChild}`);
304+
NativeScriptDebug.rendererLog(
305+
`NativeScriptRenderer.insertBefore child: ${newChild} ` + `parent: ${parent} refChild: ${refChild}`,
306+
);
262307
}
263308
this.viewUtil.insertBefore(parent, newChild, refChild);
264309
}
265310
@inRootZone()
266311
@modifiesDom()
267312
removeChild(parent: any, oldChild: any, isHostElement?: boolean): void {
268313
if (NativeScriptDebug.enabled) {
269-
NativeScriptDebug.rendererLog(`NativeScriptRenderer.removeChild child: ${oldChild} parent: ${parent} oldChild.parentNode: ${oldChild?.parentNode}`);
314+
NativeScriptDebug.rendererLog(
315+
`NativeScriptRenderer.removeChild child: ${oldChild} parent: ${parent} oldChild.parentNode: ${oldChild?.parentNode}`,
316+
);
270317
}
271318
this.viewUtil.removeChild(parent ?? oldChild.parentNode, oldChild);
272319
}
@@ -319,13 +366,17 @@ class NativeScriptRenderer implements Renderer2 {
319366
@modifiesDom()
320367
setAttribute(el: any, name: string, value: string, namespace?: string): void {
321368
if (NativeScriptDebug.enabled) {
322-
NativeScriptDebug.rendererLog(`NativeScriptRenderer.setAttribute ${namespace ? namespace + ':' : ''}${el}.${name} = ${value}`);
369+
NativeScriptDebug.rendererLog(
370+
`NativeScriptRenderer.setAttribute ${namespace ? namespace + ':' : ''}${el}.${name} = ${value}`,
371+
);
323372
}
324373
this.viewUtil.setProperty(el, name, value, namespace);
325374
}
326375
removeAttribute(el: any, name: string, namespace?: string): void {
327376
if (NativeScriptDebug.enabled) {
328-
NativeScriptDebug.rendererLog(`NativeScriptRenderer.removeAttribute ${namespace ? namespace + ':' : ''}${el}.${name}`);
377+
NativeScriptDebug.rendererLog(
378+
`NativeScriptRenderer.removeAttribute ${namespace ? namespace + ':' : ''}${el}.${name}`,
379+
);
329380
}
330381
}
331382
@inRootZone()
@@ -418,13 +469,16 @@ const replaceNgAttribute = function (input: string, componentId: string): string
418469
return input.replace(COMPONENT_REGEX, componentId);
419470
};
420471

421-
const addScopedStyleToCss = profile(`"renderer".addScopedStyleToCss`, function addScopedStyleToCss(style: string, tag?: number | string): void {
422-
if (tag) {
423-
addTaggedAdditionalCSS(style, tag);
424-
} else {
425-
Application.addCss(style);
426-
}
427-
});
472+
const addScopedStyleToCss = profile(
473+
`"renderer".addScopedStyleToCss`,
474+
function addScopedStyleToCss(style: string, tag?: number | string): void {
475+
if (tag) {
476+
addTaggedAdditionalCSS(style, tag);
477+
} else {
478+
Application.addCss(style);
479+
}
480+
},
481+
);
428482

429483
@Injectable()
430484
export class EmulatedRenderer extends NativeScriptRenderer {

packages/angular/src/lib/platform-nativescript.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { DOCUMENT, LocationChangeListener, LocationStrategy, PlatformLocation }
1919
import { NativeScriptPlatformRefProxy } from './platform-ref';
2020
import { AppHostView } from './app-host-view';
2121
import { Color, GridLayout } from '@nativescript/core';
22-
import { defaultPageFactory, PAGE_FACTORY } from './tokens';
22+
import { defaultPageFactory, ENABLE_REUSABE_VIEWS, PAGE_FACTORY, WRAP_CD_IN_TRANSACTION } from './tokens';
2323
import { AppLaunchView } from './application';
2424
import { NATIVESCRIPT_MODULE_PROVIDERS, NATIVESCRIPT_MODULE_STATIC_PROVIDERS } from './nativescript';
2525
import { registerNativeScriptViewComponents } from './element-registry';
@@ -144,19 +144,38 @@ export interface BootstrapContext {
144144
platformRef?: PlatformRef;
145145
}
146146

147-
function createProvidersConfig(options?: ApplicationConfig, context?: BootstrapContext) {
147+
export interface NativeScriptApplicationConfig extends ApplicationConfig {
148+
reusableViews?: boolean;
149+
ios?: {
150+
wrapChangeDetectionInTransaction?: boolean;
151+
};
152+
}
153+
154+
function createProvidersConfig(options?: NativeScriptApplicationConfig, context?: BootstrapContext) {
155+
const nsProviders: StaticProvider[] = [];
156+
if (options?.reusableViews) {
157+
nsProviders.push({ provide: ENABLE_REUSABE_VIEWS, useValue: true });
158+
}
159+
if (options?.ios?.wrapChangeDetectionInTransaction) {
160+
nsProviders.push({ provide: WRAP_CD_IN_TRANSACTION, useValue: true });
161+
}
148162
return {
149163
platformRef: context?.platformRef,
150164
appProviders: [
151165
...NATIVESCRIPT_MODULE_STATIC_PROVIDERS,
152166
...NATIVESCRIPT_MODULE_PROVIDERS,
167+
...nsProviders,
153168
...(options?.providers ?? []),
154169
],
155170
platformProviders: context?.platformRef ? [] : COMMON_PROVIDERS,
156171
};
157172
}
158173

159-
export function bootstrapApplication(rootComponent: Type<any>, options?: ApplicationConfig) {
174+
export function bootstrapApplication(
175+
rootComponent: Type<any>,
176+
options?: NativeScriptApplicationConfig,
177+
context?: BootstrapContext,
178+
) {
160179
// Ensure NativeScript view components are registered in this module instance's
161180
// element registry. During Vite HMR, the vendor bundle and HTTP-loaded modules
162181
// may have separate module instances of @nativescript/angular, each with their
@@ -165,11 +184,11 @@ export function bootstrapApplication(rootComponent: Type<any>, options?: Applica
165184
registerNativeScriptViewComponents();
166185
return ɵinternalCreateApplication({
167186
rootComponent: rootComponent,
168-
...createProvidersConfig(options),
187+
...createProvidersConfig(options, context),
169188
});
170189
}
171190

172-
export function createApplication(options?: ApplicationConfig, context?: BootstrapContext) {
191+
export function createApplication(options?: NativeScriptApplicationConfig, context?: BootstrapContext) {
173192
registerNativeScriptViewComponents();
174193
return ɵinternalCreateApplication(createProvidersConfig(options, context));
175194
}

packages/angular/src/lib/public_api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export {
88
BootstrapContext,
99
COMMON_PROVIDERS,
1010
HmrOptions,
11+
NativeScriptApplicationConfig,
1112
NativeScriptDocument,
1213
NativeScriptSanitizer,
1314
defaultPageFactoryProvider,

packages/angular/src/lib/tokens.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@ export const APP_ROOT_VIEW = new InjectionToken<View>('NativeScriptAppRootView')
55
export const NATIVESCRIPT_ROOT_MODULE_ID = new InjectionToken<string | number>('NativeScriptRootModuleId');
66

77
export const START_PATH = new InjectionToken<Promise<string> | string>('NativeScriptStartPath');
8-
export const ENABLE_REUSABE_VIEWS = new InjectionToken<boolean>('NativeScriptEnableReusableViews');
8+
export const ENABLE_REUSABE_VIEWS = new InjectionToken<boolean>('NativeScriptEnableReusableViews', {
9+
providedIn: 'root',
10+
factory: () => false,
11+
});
12+
export const WRAP_CD_IN_TRANSACTION = new InjectionToken<boolean>('NativeScriptWrapChangeDetectionInTransaction', {
13+
providedIn: 'root',
14+
factory: () => false,
15+
});
916

1017
export type PageFactory = (options: PageFactoryOptions) => Page;
1118
export interface PageFactoryOptions {
@@ -24,4 +31,6 @@ export const defaultPageFactory: PageFactory = function (_opts: PageFactoryOptio
2431
};
2532

2633
export const PREVENT_CHANGE_EVENTS_DURING_CD = new InjectionToken<boolean>('NativeScriptPreventChangeEventsDuringCd');
27-
export const PREVENT_SPECIFIC_EVENTS_DURING_CD = new InjectionToken<string[]>('NativeScriptPreventSpecificEventsDuringCd');
34+
export const PREVENT_SPECIFIC_EVENTS_DURING_CD = new InjectionToken<string[]>(
35+
'NativeScriptPreventSpecificEventsDuringCd',
36+
);

0 commit comments

Comments
 (0)