@analogjs/astro-angular 2.8.0-beta.4 → 2.8.0-beta.6
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 +76 -1
- package/package.json +2 -2
- package/src/client-ngh.d.ts +1 -1
- package/src/client-ngh.d.ts.map +1 -1
- package/src/client-ngh.js +13 -9
- package/src/client-ngh.js.map +1 -1
- package/src/client.d.ts +1 -1
- package/src/client.d.ts.map +1 -1
- package/src/client.js +10 -4
- package/src/client.js.map +1 -1
- package/src/create-component.d.ts +8 -1
- package/src/create-component.d.ts.map +1 -1
- package/src/create-component.js +15 -1
- package/src/create-component.js.map +1 -1
- package/src/projection.d.ts +29 -0
- package/src/projection.d.ts.map +1 -0
- package/src/projection.js +124 -0
- package/src/projection.js.map +1 -0
- package/src/selector.d.ts +17 -0
- package/src/selector.d.ts.map +1 -0
- package/src/selector.js +78 -0
- package/src/selector.js.map +1 -0
- package/src/server-ngh.d.ts +1 -1
- package/src/server-ngh.d.ts.map +1 -1
- package/src/server-ngh.js +35 -21
- package/src/server-ngh.js.map +1 -1
- package/src/server.d.ts +1 -1
- package/src/server.d.ts.map +1 -1
- package/src/server.js +32 -48
- package/src/server.js.map +1 -1
- package/src/server-providers.d.ts +0 -9
- package/src/server-providers.d.ts.map +0 -1
- package/src/server-providers.js +0 -25
- package/src/server-providers.js.map +0 -1
package/README.md
CHANGED
|
@@ -428,7 +428,82 @@ import { HelloComponent } from "../../components/hello.component.ts";
|
|
|
428
428
|
|
|
429
429
|
> Important: In `.mdx` files the component import must end with the `.ts` suffix. Otherwise the dynamic import of the component will fail and the component won't be hydrated.
|
|
430
430
|
|
|
431
|
+
## Content Projection
|
|
432
|
+
|
|
433
|
+
Children passed to an Angular component in an Astro file are projected into the component's `ng-content` slots. Angular's own `select` semantics apply, so existing components work unchanged.
|
|
434
|
+
|
|
435
|
+
```ts
|
|
436
|
+
import { Component } from '@angular/core';
|
|
437
|
+
|
|
438
|
+
@Component({
|
|
439
|
+
selector: 'app-card',
|
|
440
|
+
template: `
|
|
441
|
+
<div class="card">
|
|
442
|
+
<div class="card__header">
|
|
443
|
+
<ng-content select="[question]"></ng-content>
|
|
444
|
+
</div>
|
|
445
|
+
<div class="card__body">
|
|
446
|
+
<ng-content></ng-content>
|
|
447
|
+
</div>
|
|
448
|
+
</div>
|
|
449
|
+
`,
|
|
450
|
+
})
|
|
451
|
+
export class CardComponent {}
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
```html
|
|
455
|
+
---
|
|
456
|
+
import { CardComponent } from '../components/card.component';
|
|
457
|
+
---
|
|
458
|
+
|
|
459
|
+
<CardComponent client:visible>
|
|
460
|
+
<p question>Is content projection cool?</p>
|
|
461
|
+
<p>Let's learn about content projection!</p>
|
|
462
|
+
</CardComponent>
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
Content that does not match any `select` is projected into the default `<ng-content>`. Without a default slot it is dropped, as in Angular. `ngProjectAs` is honored as well.
|
|
466
|
+
|
|
467
|
+
Astro's `slot` attribute is not needed to target a slot. Astro removes the attribute before rendering, so use Angular selectors such as attributes, classes, or element names instead.
|
|
468
|
+
|
|
469
|
+
> Note: for hydrated islands, Astro also emits the projected content in an inert `<template data-astro-template>` so it is available on the client. The slot markup therefore appears twice in the HTML response of hydrated components.
|
|
470
|
+
|
|
471
|
+
### Components in Projected Content
|
|
472
|
+
|
|
473
|
+
Angular components used inside the slot are rendered and hydrated as islands of their own, the same way nested React, Vue or Svelte components behave in Astro. The parent component only receives their markup, so `@ContentChild`, `@ContentChildren`, input and output bindings, and dependency injection do not cross the island boundary.
|
|
474
|
+
|
|
475
|
+
```html
|
|
476
|
+
---
|
|
477
|
+
import { CardComponent } from '../components/card.component';
|
|
478
|
+
import { BadgeComponent } from '../components/badge.component';
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
<!-- Two separate islands: the card cannot query or bind to the badge -->
|
|
482
|
+
<CardComponent client:visible>
|
|
483
|
+
<BadgeComponent client:visible label="New" />
|
|
484
|
+
</CardComponent>
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
For a real parent and child relationship, compose the components in an Angular template and use that component as the island.
|
|
488
|
+
|
|
489
|
+
```ts
|
|
490
|
+
import { Component } from '@angular/core';
|
|
491
|
+
import { CardComponent } from './card.component';
|
|
492
|
+
import { BadgeComponent } from './badge.component';
|
|
493
|
+
|
|
494
|
+
@Component({
|
|
495
|
+
selector: 'app-card-with-badge',
|
|
496
|
+
imports: [CardComponent, BadgeComponent],
|
|
497
|
+
template: `
|
|
498
|
+
<app-card>
|
|
499
|
+
<app-badge label="New" />
|
|
500
|
+
</app-card>
|
|
501
|
+
`,
|
|
502
|
+
})
|
|
503
|
+
export class CardWithBadgeComponent {}
|
|
504
|
+
```
|
|
505
|
+
|
|
431
506
|
## Current Limitations
|
|
432
507
|
|
|
433
508
|
- Only standalone Angular components in version v14.2+ are supported
|
|
434
|
-
- Content
|
|
509
|
+
- Angular components inside projected content are separate islands. Content queries, bindings and dependency injection from the parent component do not reach them, see [Components in Projected Content](#components-in-projected-content)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@analogjs/astro-angular",
|
|
3
|
-
"version": "2.8.0-beta.
|
|
3
|
+
"version": "2.8.0-beta.6",
|
|
4
4
|
"description": "Use Angular components within Astro",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Brandon Roberts <robertsbt@gmail.com>",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"url": "https://github.com/sponsors/brandonroberts"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@analogjs/vite-plugin-angular": "^2.8.0-beta.
|
|
37
|
+
"@analogjs/vite-plugin-angular": "^2.8.0-beta.6",
|
|
38
38
|
"rehype": "^13.0.2"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
package/src/client-ngh.d.ts
CHANGED
|
@@ -3,6 +3,6 @@ import { type HydrationFeature, type HydrationFeatureKind } from '@angular/platf
|
|
|
3
3
|
declare const _default: (element: HTMLElement) => (Component: Type<unknown> & {
|
|
4
4
|
clientProviders?: (Provider | EnvironmentProviders)[];
|
|
5
5
|
hydrationFeatures?: () => HydrationFeature<HydrationFeatureKind>[];
|
|
6
|
-
}, props?: Record<string, unknown
|
|
6
|
+
}, props?: Record<string, unknown>, slots?: unknown) => Promise<void | import("@angular/core").ApplicationRef> | undefined;
|
|
7
7
|
export default _default;
|
|
8
8
|
//# sourceMappingURL=client-ngh.d.ts.map
|
package/src/client-ngh.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-ngh.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client-ngh.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,QAAQ,EAGb,IAAI,
|
|
1
|
+
{"version":3,"file":"client-ngh.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client-ngh.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,QAAQ,EAGb,IAAI,EAGL,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAE1B,MAAM,2BAA2B,CAAC;yBAUnB,SAAS,WAAW,MAEhC,WAAW,IAAI,CAAC,OAAO,CAAC,GAAG;IACzB,eAAe,CAAC,EAAE,CAAC,QAAQ,GAAG,oBAAoB,CAAC,EAAE,CAAC;IACtD,iBAAiB,CAAC,EAAE,MAAM,gBAAgB,CAAC,oBAAoB,CAAC,EAAE,CAAC;CACpE,EACD,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,OAAO;AAPnB,wBAkEE"}
|
package/src/client-ngh.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { reflectComponentType, provideZonelessChangeDetection, APP_ID, createComponent,
|
|
1
|
+
import { reflectComponentType, provideZonelessChangeDetection, APP_ID, createComponent, } from '@angular/core';
|
|
2
2
|
import { createApplication, provideClientHydration, } from '@angular/platform-browser';
|
|
3
|
-
import { createComponentBindings, getComponentElementTag, } from "./create-component.js";
|
|
3
|
+
import { createComponentBindings, getComponentElementTag, registerRootComponent, } from "./create-component.js";
|
|
4
4
|
import { ID_PROP_NAME } from "./id.js";
|
|
5
5
|
import { ensureSsrIntegrityMarker } from "./ssr-integrity.js";
|
|
6
|
+
import { buildProjectableNodes, collectProjectedNodes } from "./projection.js";
|
|
6
7
|
export default (element) => {
|
|
7
|
-
return (Component, props) => {
|
|
8
|
+
return (Component, props, slots) => {
|
|
8
9
|
const mirror = reflectComponentType(Component);
|
|
9
10
|
if (!mirror) {
|
|
10
11
|
// Not an Angular component
|
|
@@ -20,7 +21,12 @@ export default (element) => {
|
|
|
20
21
|
reuseDom = false;
|
|
21
22
|
}
|
|
22
23
|
const ngAppId = hostElement?.getAttribute(ID_PROP_NAME);
|
|
23
|
-
|
|
24
|
+
// Hydration reuses the server-rendered DOM, so hand Angular the projected
|
|
25
|
+
// nodes it already rendered instead of freshly parsed copies.
|
|
26
|
+
const projectableNodes = (reuseDom && ngAppId
|
|
27
|
+
? collectProjectedNodes(hostElement, mirror, ngAppId)
|
|
28
|
+
: undefined) ?? buildProjectableNodes(mirror, slots, document);
|
|
29
|
+
return createApplication({
|
|
24
30
|
providers: [
|
|
25
31
|
provideZonelessChangeDetection(),
|
|
26
32
|
reuseDom
|
|
@@ -37,13 +43,11 @@ export default (element) => {
|
|
|
37
43
|
const componentRef = createComponent(Component, {
|
|
38
44
|
environmentInjector: appRef.injector,
|
|
39
45
|
hostElement,
|
|
46
|
+
projectableNodes,
|
|
40
47
|
bindings: createComponentBindings(mirror, props, hostElement),
|
|
41
48
|
});
|
|
42
|
-
appRef
|
|
43
|
-
appRef
|
|
44
|
-
appRef.injector
|
|
45
|
-
.get(APP_BOOTSTRAP_LISTENER, [])
|
|
46
|
-
.forEach((cb) => cb(componentRef));
|
|
49
|
+
registerRootComponent(appRef, componentRef);
|
|
50
|
+
return appRef;
|
|
47
51
|
})
|
|
48
52
|
.catch((error) => {
|
|
49
53
|
console.error('Failed to hydrate Angular component:', error);
|
package/src/client-ngh.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-ngh.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client-ngh.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,oBAAoB,EACpB,8BAA8B,EAE9B,MAAM,EACN,eAAe,
|
|
1
|
+
{"version":3,"file":"client-ngh.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client-ngh.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,oBAAoB,EACpB,8BAA8B,EAE9B,MAAM,EACN,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EAGjB,sBAAsB,GACvB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE/E,eAAe,CAAC,OAAoB,EAAE,EAAE;IACtC,OAAO,CACL,SAGC,EACD,KAA+B,EAC/B,KAAe,EACf,EAAE;QACF,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;QAE/C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,2BAA2B;YAC3B,OAAO;QACT,CAAC;QAED,wBAAwB,EAAE,CAAC;QAE3B,IAAI,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzD,IAAI,QAAQ,GAAG,IAAI,CAAC;QAEpB,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,kCAAkC;YAClC,WAAW,GAAG,QAAQ,CAAC,aAAa,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC;YACrE,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;YACjC,QAAQ,GAAG,KAAK,CAAC;QACnB,CAAC;QAED,MAAM,OAAO,GAAG,WAAW,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;QAExD,0EAA0E;QAC1E,8DAA8D;QAC9D,MAAM,gBAAgB,GACpB,CAAC,QAAQ,IAAI,OAAO;YAClB,CAAC,CAAC,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC;YACrD,CAAC,CAAC,SAAS,CAAC,IAAI,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;QAEnE,OAAO,iBAAiB,CAAC;YACvB,SAAS,EAAE;gBACT,8BAA8B,EAAE;gBAChC,QAAQ;oBACN,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,SAAS,CAAC,iBAAiB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;oBACpE,CAAC,CAAC,EAAE;gBACN;oBACE,OAAO,EAAE,MAAM;oBACf,QAAQ,EAAE,OAAO,IAAI,IAAI;iBAC1B;gBACD,GAAG,CAAC,SAAS,CAAC,eAAe,IAAI,EAAE,CAAC;aACrC;SACF,CAAC;aACC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,MAAM,YAAY,GAAG,eAAe,CAAC,SAAS,EAAE;gBAC9C,mBAAmB,EAAE,MAAM,CAAC,QAAQ;gBACpC,WAAW;gBACX,gBAAgB;gBAChB,QAAQ,EAAE,uBAAuB,CAAC,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC;aAC9D,CAAC,CAAC;YAEH,qBAAqB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YAE5C,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,KAAK,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {\n type EnvironmentProviders,\n type Provider,\n reflectComponentType,\n provideZonelessChangeDetection,\n Type,\n APP_ID,\n createComponent,\n} from '@angular/core';\nimport {\n createApplication,\n type HydrationFeature,\n type HydrationFeatureKind,\n provideClientHydration,\n} from '@angular/platform-browser';\nimport {\n createComponentBindings,\n getComponentElementTag,\n registerRootComponent,\n} from './create-component.ts';\nimport { ID_PROP_NAME } from './id.ts';\nimport { ensureSsrIntegrityMarker } from './ssr-integrity.ts';\nimport { buildProjectableNodes, collectProjectedNodes } from './projection.ts';\n\nexport default (element: HTMLElement) => {\n return (\n Component: Type<unknown> & {\n clientProviders?: (Provider | EnvironmentProviders)[];\n hydrationFeatures?: () => HydrationFeature<HydrationFeatureKind>[];\n },\n props?: Record<string, unknown>,\n slots?: unknown,\n ) => {\n const mirror = reflectComponentType(Component);\n\n if (!mirror) {\n // Not an Angular component\n return;\n }\n\n ensureSsrIntegrityMarker();\n\n let hostElement = element.querySelector(mirror.selector);\n let reuseDom = true;\n\n if (!hostElement) {\n // This is a client-only component\n hostElement = document.createElement(getComponentElementTag(mirror));\n element.appendChild(hostElement);\n reuseDom = false;\n }\n\n const ngAppId = hostElement?.getAttribute(ID_PROP_NAME);\n\n // Hydration reuses the server-rendered DOM, so hand Angular the projected\n // nodes it already rendered instead of freshly parsed copies.\n const projectableNodes =\n (reuseDom && ngAppId\n ? collectProjectedNodes(hostElement, mirror, ngAppId)\n : undefined) ?? buildProjectableNodes(mirror, slots, document);\n\n return createApplication({\n providers: [\n provideZonelessChangeDetection(),\n reuseDom\n ? provideClientHydration(...(Component.hydrationFeatures?.() || []))\n : [],\n {\n provide: APP_ID,\n useValue: ngAppId || 'ng',\n },\n ...(Component.clientProviders || []),\n ],\n })\n .then((appRef) => {\n const componentRef = createComponent(Component, {\n environmentInjector: appRef.injector,\n hostElement,\n projectableNodes,\n bindings: createComponentBindings(mirror, props, hostElement),\n });\n\n registerRootComponent(appRef, componentRef);\n\n return appRef;\n })\n .catch((error) => {\n console.error('Failed to hydrate Angular component:', error);\n });\n };\n};\n"]}
|
package/src/client.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EnvironmentProviders, Provider, ɵComponentType as ComponentType } from '@angular/core';
|
|
2
2
|
declare const _default: (element: HTMLElement) => (Component: ComponentType<unknown> & {
|
|
3
3
|
clientProviders?: (Provider | EnvironmentProviders)[];
|
|
4
|
-
}, props?: Record<string, unknown>,
|
|
4
|
+
}, props?: Record<string, unknown>, slots?: unknown) => void;
|
|
5
5
|
export default _default;
|
|
6
6
|
//# sourceMappingURL=client.d.ts.map
|
package/src/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,QAAQ,EAER,cAAc,IAAI,aAAa,EAEhC,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,QAAQ,EAER,cAAc,IAAI,aAAa,EAEhC,MAAM,eAAe,CAAC;yBAMP,SAAS,WAAW,MAEhC,WAAW,aAAa,CAAC,OAAO,CAAC,GAAG;IAClC,eAAe,CAAC,EAAE,CAAC,QAAQ,GAAG,oBAAoB,CAAC,EAAE,CAAC;CACvD,EACD,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,OAAO;AANnB,wBA2EE"}
|
package/src/client.js
CHANGED
|
@@ -2,8 +2,14 @@ import { reflectComponentType, provideZonelessChangeDetection, } from '@angular/
|
|
|
2
2
|
import { createComponent } from '@angular/core';
|
|
3
3
|
import { createApplication } from '@angular/platform-browser';
|
|
4
4
|
import { Subject, takeUntil } from 'rxjs';
|
|
5
|
+
import { buildProjectableNodes } from "./projection.js";
|
|
5
6
|
export default (element) => {
|
|
6
|
-
return (Component, props,
|
|
7
|
+
return (Component, props, slots) => {
|
|
8
|
+
const mirror = reflectComponentType(Component);
|
|
9
|
+
if (!mirror) {
|
|
10
|
+
// Not an Angular component
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
7
13
|
createApplication({
|
|
8
14
|
providers: [
|
|
9
15
|
provideZonelessChangeDetection(),
|
|
@@ -13,16 +19,16 @@ export default (element) => {
|
|
|
13
19
|
const componentRef = createComponent(Component, {
|
|
14
20
|
environmentInjector: appRef.injector,
|
|
15
21
|
hostElement: element,
|
|
22
|
+
projectableNodes: buildProjectableNodes(mirror, slots, document),
|
|
16
23
|
});
|
|
17
|
-
|
|
18
|
-
if (props && mirror) {
|
|
24
|
+
if (props) {
|
|
19
25
|
for (const [key, value] of Object.entries(props)) {
|
|
20
26
|
if (mirror.inputs.some(({ templateName, propName }) => templateName === key || propName === key)) {
|
|
21
27
|
componentRef.setInput(key, value);
|
|
22
28
|
}
|
|
23
29
|
}
|
|
24
30
|
}
|
|
25
|
-
if (mirror
|
|
31
|
+
if (mirror.outputs.length && props?.['data-analog-id']) {
|
|
26
32
|
const destroySubject = new Subject();
|
|
27
33
|
element.setAttribute('data-analog-id', props['data-analog-id']);
|
|
28
34
|
mirror.outputs.forEach(({ templateName, propName }) => {
|
package/src/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,oBAAoB,EAEpB,8BAA8B,GAC/B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAkB,eAAe,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAc,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,oBAAoB,EAEpB,8BAA8B,GAC/B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAkB,eAAe,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAc,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAExD,eAAe,CAAC,OAAoB,EAAE,EAAE;IACtC,OAAO,CACL,SAEC,EACD,KAA+B,EAC/B,KAAe,EACf,EAAE;QACF,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;QAE/C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,2BAA2B;YAC3B,OAAO;QACT,CAAC;QAED,iBAAiB,CAAC;YAChB,SAAS,EAAE;gBACT,8BAA8B,EAAE;gBAChC,GAAG,CAAC,SAAS,CAAC,eAAe,IAAI,EAAE,CAAC;aACrC;SACF,CAAC,CAAC,IAAI,CAAC,CAAC,MAAsB,EAAE,EAAE;YACjC,MAAM,YAAY,GAAG,eAAe,CAAC,SAAS,EAAE;gBAC9C,mBAAmB,EAAE,MAAM,CAAC,QAAQ;gBACpC,WAAW,EAAE,OAAO;gBACpB,gBAAgB,EAAE,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC;aACjE,CAAC,CAAC;YAEH,IAAI,KAAK,EAAE,CAAC;gBACV,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;oBACjD,IACE,MAAM,CAAC,MAAM,CAAC,IAAI,CAChB,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE,CAC7B,YAAY,KAAK,GAAG,IAAI,QAAQ,KAAK,GAAG,CAC3C,EACD,CAAC;wBACD,YAAY,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;oBACpC,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBACvD,MAAM,cAAc,GAAG,IAAI,OAAO,EAAQ,CAAC;gBAC3C,OAAO,CAAC,YAAY,CAClB,gBAAgB,EAChB,KAAK,CAAC,gBAAgB,CAAW,CAClC,CAAC;gBAEF,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE;oBACpD,MAAM,UAAU,GAAG,YAAY,IAAI,QAAQ,CAAC;oBAC5C,MAAM,SAAS,GAAG,YAAY,CAAC,QAG9B,CAAC;oBACF,SAAS,CAAC,UAAU,CAAC;yBAClB,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;yBAC/B,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE;wBACpB,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,UAAU,EAAE;4BACxC,OAAO,EAAE,IAAI;4BACb,UAAU,EAAE,IAAI;4BAChB,QAAQ,EAAE,IAAI;4BACd,MAAM;yBACP,CAAC,CAAC;wBACH,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;oBAC/B,CAAC,CAAC,CAAC;gBACP,CAAC,CAAC,CAAC;gBAEH,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE;oBACpB,cAAc,CAAC,IAAI,EAAE,CAAC;oBACtB,cAAc,CAAC,QAAQ,EAAE,CAAC;gBAC5B,CAAC,CAAC,CAAC;YACL,CAAC;YAED,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {\n EnvironmentProviders,\n Provider,\n reflectComponentType,\n ɵComponentType as ComponentType,\n provideZonelessChangeDetection,\n} from '@angular/core';\nimport { ApplicationRef, createComponent } from '@angular/core';\nimport { createApplication } from '@angular/platform-browser';\nimport { Observable, Subject, takeUntil } from 'rxjs';\nimport { buildProjectableNodes } from './projection.ts';\n\nexport default (element: HTMLElement) => {\n return (\n Component: ComponentType<unknown> & {\n clientProviders?: (Provider | EnvironmentProviders)[];\n },\n props?: Record<string, unknown>,\n slots?: unknown,\n ) => {\n const mirror = reflectComponentType(Component);\n\n if (!mirror) {\n // Not an Angular component\n return;\n }\n\n createApplication({\n providers: [\n provideZonelessChangeDetection(),\n ...(Component.clientProviders || []),\n ],\n }).then((appRef: ApplicationRef) => {\n const componentRef = createComponent(Component, {\n environmentInjector: appRef.injector,\n hostElement: element,\n projectableNodes: buildProjectableNodes(mirror, slots, document),\n });\n\n if (props) {\n for (const [key, value] of Object.entries(props)) {\n if (\n mirror.inputs.some(\n ({ templateName, propName }) =>\n templateName === key || propName === key,\n )\n ) {\n componentRef.setInput(key, value);\n }\n }\n }\n\n if (mirror.outputs.length && props?.['data-analog-id']) {\n const destroySubject = new Subject<void>();\n element.setAttribute(\n 'data-analog-id',\n props['data-analog-id'] as string,\n );\n\n mirror.outputs.forEach(({ templateName, propName }) => {\n const outputName = templateName || propName;\n const component = componentRef.instance as Record<\n string,\n Observable<unknown>\n >;\n component[outputName]\n .pipe(takeUntil(destroySubject))\n .subscribe((detail) => {\n const event = new CustomEvent(outputName, {\n bubbles: true,\n cancelable: true,\n composed: true,\n detail,\n });\n element.dispatchEvent(event);\n });\n });\n\n appRef.onDestroy(() => {\n destroySubject.next();\n destroySubject.complete();\n });\n }\n\n appRef.attachView(componentRef.hostView);\n });\n };\n};\n"]}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import { type Binding, type ComponentMirror } from '@angular/core';
|
|
1
|
+
import { type ApplicationRef, type Binding, type ComponentMirror, type ComponentRef } from '@angular/core';
|
|
2
2
|
export declare function getComponentElementTag(mirror: ComponentMirror<unknown>): string;
|
|
3
3
|
export declare function createInputBindings(mirror: ComponentMirror<unknown>, props?: Record<string, unknown>): Binding[];
|
|
4
4
|
export declare function createOutputBindings(hostElement: Element, mirror: ComponentMirror<unknown>): Binding[];
|
|
5
5
|
export declare function createComponentBindings(mirror: ComponentMirror<unknown>, props?: Record<string, unknown>, hostElement?: Element): Binding[];
|
|
6
|
+
/**
|
|
7
|
+
* Registers a component created with `createComponent` as a root component,
|
|
8
|
+
* the way `bootstrapApplication` does: attach the view, track it on the
|
|
9
|
+
* application, run the initial change detection and notify
|
|
10
|
+
* `APP_BOOTSTRAP_LISTENER`s such as the router's.
|
|
11
|
+
*/
|
|
12
|
+
export declare function registerRootComponent(appRef: ApplicationRef, componentRef: ComponentRef<unknown>): void;
|
|
6
13
|
//# sourceMappingURL=create-component.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-component.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/create-component.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"create-component.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/create-component.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,OAAO,EACZ,KAAK,eAAe,EACpB,KAAK,YAAY,EAGlB,MAAM,eAAe,CAAC;AAGvB,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,GAC/B,MAAM,CAER;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,EAAE,CAYX;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,OAAO,EACpB,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,GAC/B,OAAO,EAAE,CAcX;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,WAAW,CAAC,EAAE,OAAO,GACpB,OAAO,EAAE,CAUX;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,cAAc,EACtB,YAAY,EAAE,YAAY,CAAC,OAAO,CAAC,GAClC,IAAI,CAON"}
|
package/src/create-component.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { inputBinding, outputBinding, } from '@angular/core';
|
|
1
|
+
import { APP_BOOTSTRAP_LISTENER, inputBinding, outputBinding, } from '@angular/core';
|
|
2
2
|
import { ID_PROP_NAME } from "./id.js";
|
|
3
3
|
export function getComponentElementTag(mirror) {
|
|
4
4
|
return mirror.selector.split(',')[0] || 'ng-component';
|
|
@@ -32,4 +32,18 @@ export function createComponentBindings(mirror, props, hostElement) {
|
|
|
32
32
|
const outputBindings = createOutputBindings(hostElement, mirror);
|
|
33
33
|
return [...inputBindings, ...outputBindings];
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Registers a component created with `createComponent` as a root component,
|
|
37
|
+
* the way `bootstrapApplication` does: attach the view, track it on the
|
|
38
|
+
* application, run the initial change detection and notify
|
|
39
|
+
* `APP_BOOTSTRAP_LISTENER`s such as the router's.
|
|
40
|
+
*/
|
|
41
|
+
export function registerRootComponent(appRef, componentRef) {
|
|
42
|
+
appRef.attachView(componentRef.hostView);
|
|
43
|
+
appRef.tick();
|
|
44
|
+
appRef.components.push(componentRef);
|
|
45
|
+
appRef.injector
|
|
46
|
+
.get(APP_BOOTSTRAP_LISTENER, [])
|
|
47
|
+
.forEach((listener) => listener(componentRef));
|
|
48
|
+
}
|
|
35
49
|
//# sourceMappingURL=create-component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-component.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/create-component.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"create-component.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/create-component.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EAKtB,YAAY,EACZ,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,UAAU,sBAAsB,CACpC,MAAgC;IAEhC,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,MAAgC,EAChC,KAA+B;IAE/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;SACxC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAChB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,YAAY,KAAK,GAAG,CAAC,CAC/D;SACA,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEzD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,WAAoB,EACpB,MAAgC;IAEhC,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAC7D,aAAa,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,YAAY,EAAE;YAC1C,OAAO,EAAE,IAAI;YACb,UAAU,EAAE,IAAI;YAChB,QAAQ,EAAE,IAAI;YACd,MAAM;SACP,CAAC,CAAC;QACH,WAAW,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,MAAgC,EAChC,KAA+B,EAC/B,WAAqB;IAErB,MAAM,aAAa,GAAG,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAEzD,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACrE,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,MAAM,cAAc,GAAG,oBAAoB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAEjE,OAAO,CAAC,GAAG,aAAa,EAAE,GAAG,cAAc,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAsB,EACtB,YAAmC;IAEnC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,CAAC,IAAI,EAAE,CAAC;IACd,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACrC,MAAM,CAAC,QAAQ;SACZ,GAAG,CAAC,sBAAsB,EAAE,EAAE,CAAC;SAC/B,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;AACnD,CAAC","sourcesContent":["import {\n APP_BOOTSTRAP_LISTENER,\n type ApplicationRef,\n type Binding,\n type ComponentMirror,\n type ComponentRef,\n inputBinding,\n outputBinding,\n} from '@angular/core';\nimport { ID_PROP_NAME } from './id.ts';\n\nexport function getComponentElementTag(\n mirror: ComponentMirror<unknown>,\n): string {\n return mirror.selector.split(',')[0] || 'ng-component';\n}\n\nexport function createInputBindings(\n mirror: ComponentMirror<unknown>,\n props?: Record<string, unknown>,\n): Binding[] {\n if (!props) {\n return [];\n }\n\n const inputBindings = Object.entries(props)\n .filter(([key]) =>\n mirror.inputs.some(({ templateName }) => templateName === key),\n )\n .map(([key, value]) => inputBinding(key, () => value));\n\n return inputBindings;\n}\n\nexport function createOutputBindings(\n hostElement: Element,\n mirror: ComponentMirror<unknown>,\n): Binding[] {\n const outputBindings = mirror.outputs.map(({ templateName }) =>\n outputBinding(templateName, (detail) => {\n const event = new CustomEvent(templateName, {\n bubbles: true,\n cancelable: true,\n composed: true,\n detail,\n });\n hostElement.dispatchEvent(event);\n }),\n );\n\n return outputBindings;\n}\n\nexport function createComponentBindings(\n mirror: ComponentMirror<unknown>,\n props?: Record<string, unknown>,\n hostElement?: Element,\n): Binding[] {\n const inputBindings = createInputBindings(mirror, props);\n\n if (!mirror.outputs.length || !props?.[ID_PROP_NAME] || !hostElement) {\n return inputBindings;\n }\n\n const outputBindings = createOutputBindings(hostElement, mirror);\n\n return [...inputBindings, ...outputBindings];\n}\n\n/**\n * Registers a component created with `createComponent` as a root component,\n * the way `bootstrapApplication` does: attach the view, track it on the\n * application, run the initial change detection and notify\n * `APP_BOOTSTRAP_LISTENER`s such as the router's.\n */\nexport function registerRootComponent(\n appRef: ApplicationRef,\n componentRef: ComponentRef<unknown>,\n): void {\n appRef.attachView(componentRef.hostView);\n appRef.tick();\n appRef.components.push(componentRef);\n appRef.injector\n .get(APP_BOOTSTRAP_LISTENER, [])\n .forEach((listener) => listener(componentRef));\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ComponentMirror } from '@angular/core';
|
|
2
|
+
/**
|
|
3
|
+
* Distributes the HTML Astro rendered for the component's slots across the
|
|
4
|
+
* component's `<ng-content>` slots, using Angular's own selector semantics.
|
|
5
|
+
*
|
|
6
|
+
* The result is indexed to match `mirror.ngContentSelectors`. Angular does not
|
|
7
|
+
* apply `select` matching to `projectableNodes`, so the matching happens here.
|
|
8
|
+
* @param mirror The component mirror, to read the `ng-content` selectors
|
|
9
|
+
* @param slots The slot HTML passed by Astro, keyed by slot name
|
|
10
|
+
* @param document The document the component is rendered into
|
|
11
|
+
* @returns The nodes to project, or `undefined` when the component has no `ng-content`
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildProjectableNodes(mirror: ComponentMirror<unknown>, slots: unknown, document: Document): Node[][] | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Wraps each non-empty slot in comment markers, so the client can find the
|
|
16
|
+
* server-rendered nodes again when hydrating. Angular reuses the DOM during
|
|
17
|
+
* hydration, so it must be handed those nodes rather than freshly parsed ones.
|
|
18
|
+
* @param projectableNodes The distributed nodes, see `buildProjectableNodes`
|
|
19
|
+
* @param appId The island's APP_ID, to keep markers apart from nested islands
|
|
20
|
+
* @param document The document the component is rendered into
|
|
21
|
+
*/
|
|
22
|
+
export declare function markProjectableNodes(projectableNodes: Node[][], appId: string, document: Document): Node[][];
|
|
23
|
+
/**
|
|
24
|
+
* Collects the server-rendered projected nodes from the host element using the
|
|
25
|
+
* markers added by `markProjectableNodes`.
|
|
26
|
+
* @returns The nodes per slot, or `undefined` when the host carries no markers
|
|
27
|
+
*/
|
|
28
|
+
export declare function collectProjectedNodes(hostElement: Element, mirror: ComponentMirror<unknown>, appId: string): Node[][] | undefined;
|
|
29
|
+
//# sourceMappingURL=projection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projection.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/projection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAUrD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,QAAQ,GACjB,IAAI,EAAE,EAAE,GAAG,SAAS,CA6BtB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,gBAAgB,EAAE,IAAI,EAAE,EAAE,EAC1B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,GACjB,IAAI,EAAE,EAAE,CAUV;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,OAAO,EACpB,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,EAAE,MAAM,GACZ,IAAI,EAAE,EAAE,GAAG,SAAS,CA4CtB"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { isSameSelector, parseSelectorList } from "./selector.js";
|
|
2
|
+
const ELEMENT_NODE = 1;
|
|
3
|
+
const TEXT_NODE = 3;
|
|
4
|
+
const COMMENT_NODE = 8;
|
|
5
|
+
const SHOW_COMMENT = 128;
|
|
6
|
+
const MARKER_PREFIX = 'analog-slot:';
|
|
7
|
+
/**
|
|
8
|
+
* Distributes the HTML Astro rendered for the component's slots across the
|
|
9
|
+
* component's `<ng-content>` slots, using Angular's own selector semantics.
|
|
10
|
+
*
|
|
11
|
+
* The result is indexed to match `mirror.ngContentSelectors`. Angular does not
|
|
12
|
+
* apply `select` matching to `projectableNodes`, so the matching happens here.
|
|
13
|
+
* @param mirror The component mirror, to read the `ng-content` selectors
|
|
14
|
+
* @param slots The slot HTML passed by Astro, keyed by slot name
|
|
15
|
+
* @param document The document the component is rendered into
|
|
16
|
+
* @returns The nodes to project, or `undefined` when the component has no `ng-content`
|
|
17
|
+
*/
|
|
18
|
+
export function buildProjectableNodes(mirror, slots, document) {
|
|
19
|
+
const selectors = mirror.ngContentSelectors;
|
|
20
|
+
if (!selectors.length) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
const projectableNodes = selectors.map(() => []);
|
|
24
|
+
// As in Angular, unmatched content goes to the last default slot.
|
|
25
|
+
const wildcardIndex = selectors.lastIndexOf('*');
|
|
26
|
+
for (const node of parseSlots(slots, document)) {
|
|
27
|
+
// Angular drops whitespace-only text nodes between elements at compile
|
|
28
|
+
// time, so projecting them would only suppress `ng-content` fallbacks.
|
|
29
|
+
if (node.nodeType === TEXT_NODE && !node.textContent?.trim()) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const matched = selectors.findIndex((selector) => selector !== '*' && matches(node, selector));
|
|
33
|
+
const target = matched > -1 ? matched : wildcardIndex;
|
|
34
|
+
if (target > -1) {
|
|
35
|
+
projectableNodes[target].push(node);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return projectableNodes;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Wraps each non-empty slot in comment markers, so the client can find the
|
|
42
|
+
* server-rendered nodes again when hydrating. Angular reuses the DOM during
|
|
43
|
+
* hydration, so it must be handed those nodes rather than freshly parsed ones.
|
|
44
|
+
* @param projectableNodes The distributed nodes, see `buildProjectableNodes`
|
|
45
|
+
* @param appId The island's APP_ID, to keep markers apart from nested islands
|
|
46
|
+
* @param document The document the component is rendered into
|
|
47
|
+
*/
|
|
48
|
+
export function markProjectableNodes(projectableNodes, appId, document) {
|
|
49
|
+
return projectableNodes.map((nodes, index) => nodes.length
|
|
50
|
+
? [
|
|
51
|
+
document.createComment(`${MARKER_PREFIX}${appId}:${index}`),
|
|
52
|
+
...nodes,
|
|
53
|
+
document.createComment(`/${MARKER_PREFIX}${appId}:${index}`),
|
|
54
|
+
]
|
|
55
|
+
: nodes);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Collects the server-rendered projected nodes from the host element using the
|
|
59
|
+
* markers added by `markProjectableNodes`.
|
|
60
|
+
* @returns The nodes per slot, or `undefined` when the host carries no markers
|
|
61
|
+
*/
|
|
62
|
+
export function collectProjectedNodes(hostElement, mirror, appId) {
|
|
63
|
+
const selectors = mirror.ngContentSelectors;
|
|
64
|
+
if (!selectors.length) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
const projectableNodes = selectors.map(() => []);
|
|
68
|
+
const walker = hostElement.ownerDocument.createTreeWalker(hostElement, SHOW_COMMENT);
|
|
69
|
+
let found = false;
|
|
70
|
+
for (let start = walker.nextNode(); start; start = walker.nextNode()) {
|
|
71
|
+
const match = start.textContent?.startsWith(`${MARKER_PREFIX}${appId}:`)
|
|
72
|
+
? Number(start.textContent.slice(`${MARKER_PREFIX}${appId}:`.length))
|
|
73
|
+
: NaN;
|
|
74
|
+
if (Number.isNaN(match) || match >= selectors.length) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const end = `/${MARKER_PREFIX}${appId}:${match}`;
|
|
78
|
+
const nodes = [start];
|
|
79
|
+
let node = start.nextSibling;
|
|
80
|
+
while (node &&
|
|
81
|
+
!(node.nodeType === COMMENT_NODE && node.textContent === end)) {
|
|
82
|
+
nodes.push(node);
|
|
83
|
+
node = node.nextSibling;
|
|
84
|
+
}
|
|
85
|
+
if (node) {
|
|
86
|
+
nodes.push(node);
|
|
87
|
+
}
|
|
88
|
+
projectableNodes[match] = nodes;
|
|
89
|
+
found = true;
|
|
90
|
+
}
|
|
91
|
+
return found ? projectableNodes : undefined;
|
|
92
|
+
}
|
|
93
|
+
function parseSlots(slots, document) {
|
|
94
|
+
const html = slots && typeof slots === 'object'
|
|
95
|
+
? Object.values(slots).join('')
|
|
96
|
+
: String(slots ?? '');
|
|
97
|
+
if (!html) {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
const template = document.createElement('template');
|
|
101
|
+
template.innerHTML = html;
|
|
102
|
+
return Array.from(template.content.childNodes);
|
|
103
|
+
}
|
|
104
|
+
function matches(node, selector) {
|
|
105
|
+
if (node.nodeType !== ELEMENT_NODE) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
const element = node;
|
|
109
|
+
const projectAs = element.getAttribute('ngProjectAs');
|
|
110
|
+
// As in Angular, `ngProjectAs` replaces the element's own selector and is
|
|
111
|
+
// compared structurally against the `select` list.
|
|
112
|
+
if (projectAs !== null) {
|
|
113
|
+
const [alias] = parseSelectorList(projectAs);
|
|
114
|
+
return parseSelectorList(selector).some((candidate) => isSameSelector(alias, candidate));
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
return element.matches(selector);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// `ngContentSelectors` may contain selectors that `matches()` rejects.
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=projection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projection.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/projection.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ComponentMirror } from '@angular/core';\nimport { isSameSelector, parseSelectorList } from './selector.ts';\n\nconst ELEMENT_NODE = 1;\nconst TEXT_NODE = 3;\nconst COMMENT_NODE = 8;\nconst SHOW_COMMENT = 128;\n\nconst MARKER_PREFIX = 'analog-slot:';\n\n/**\n * Distributes the HTML Astro rendered for the component's slots across the\n * component's `<ng-content>` slots, using Angular's own selector semantics.\n *\n * The result is indexed to match `mirror.ngContentSelectors`. Angular does not\n * apply `select` matching to `projectableNodes`, so the matching happens here.\n * @param mirror The component mirror, to read the `ng-content` selectors\n * @param slots The slot HTML passed by Astro, keyed by slot name\n * @param document The document the component is rendered into\n * @returns The nodes to project, or `undefined` when the component has no `ng-content`\n */\nexport function buildProjectableNodes(\n mirror: ComponentMirror<unknown>,\n slots: unknown,\n document: Document,\n): Node[][] | undefined {\n const selectors = mirror.ngContentSelectors;\n\n if (!selectors.length) {\n return undefined;\n }\n\n const projectableNodes: Node[][] = selectors.map(() => []);\n // As in Angular, unmatched content goes to the last default slot.\n const wildcardIndex = selectors.lastIndexOf('*');\n\n for (const node of parseSlots(slots, document)) {\n // Angular drops whitespace-only text nodes between elements at compile\n // time, so projecting them would only suppress `ng-content` fallbacks.\n if (node.nodeType === TEXT_NODE && !node.textContent?.trim()) {\n continue;\n }\n\n const matched = selectors.findIndex(\n (selector) => selector !== '*' && matches(node, selector),\n );\n const target = matched > -1 ? matched : wildcardIndex;\n\n if (target > -1) {\n projectableNodes[target].push(node);\n }\n }\n\n return projectableNodes;\n}\n\n/**\n * Wraps each non-empty slot in comment markers, so the client can find the\n * server-rendered nodes again when hydrating. Angular reuses the DOM during\n * hydration, so it must be handed those nodes rather than freshly parsed ones.\n * @param projectableNodes The distributed nodes, see `buildProjectableNodes`\n * @param appId The island's APP_ID, to keep markers apart from nested islands\n * @param document The document the component is rendered into\n */\nexport function markProjectableNodes(\n projectableNodes: Node[][],\n appId: string,\n document: Document,\n): Node[][] {\n return projectableNodes.map((nodes, index) =>\n nodes.length\n ? [\n document.createComment(`${MARKER_PREFIX}${appId}:${index}`),\n ...nodes,\n document.createComment(`/${MARKER_PREFIX}${appId}:${index}`),\n ]\n : nodes,\n );\n}\n\n/**\n * Collects the server-rendered projected nodes from the host element using the\n * markers added by `markProjectableNodes`.\n * @returns The nodes per slot, or `undefined` when the host carries no markers\n */\nexport function collectProjectedNodes(\n hostElement: Element,\n mirror: ComponentMirror<unknown>,\n appId: string,\n): Node[][] | undefined {\n const selectors = mirror.ngContentSelectors;\n\n if (!selectors.length) {\n return undefined;\n }\n\n const projectableNodes: Node[][] = selectors.map(() => []);\n const walker = hostElement.ownerDocument.createTreeWalker(\n hostElement,\n SHOW_COMMENT,\n );\n let found = false;\n\n for (let start = walker.nextNode(); start; start = walker.nextNode()) {\n const match = start.textContent?.startsWith(`${MARKER_PREFIX}${appId}:`)\n ? Number(start.textContent.slice(`${MARKER_PREFIX}${appId}:`.length))\n : NaN;\n\n if (Number.isNaN(match) || match >= selectors.length) {\n continue;\n }\n\n const end = `/${MARKER_PREFIX}${appId}:${match}`;\n const nodes: Node[] = [start];\n let node = start.nextSibling;\n\n while (\n node &&\n !(node.nodeType === COMMENT_NODE && node.textContent === end)\n ) {\n nodes.push(node);\n node = node.nextSibling;\n }\n\n if (node) {\n nodes.push(node);\n }\n\n projectableNodes[match] = nodes;\n found = true;\n }\n\n return found ? projectableNodes : undefined;\n}\n\nfunction parseSlots(slots: unknown, document: Document): Node[] {\n const html =\n slots && typeof slots === 'object'\n ? Object.values(slots).join('')\n : String(slots ?? '');\n\n if (!html) {\n return [];\n }\n\n const template = document.createElement('template');\n template.innerHTML = html;\n\n return Array.from(template.content.childNodes);\n}\n\nfunction matches(node: Node, selector: string): boolean {\n if (node.nodeType !== ELEMENT_NODE) {\n return false;\n }\n\n const element = node as Element;\n const projectAs = element.getAttribute('ngProjectAs');\n\n // As in Angular, `ngProjectAs` replaces the element's own selector and is\n // compared structurally against the `select` list.\n if (projectAs !== null) {\n const [alias] = parseSelectorList(projectAs);\n return parseSelectorList(selector).some((candidate) =>\n isSameSelector(alias, candidate),\n );\n }\n\n try {\n return element.matches(selector);\n } catch {\n // `ngContentSelectors` may contain selectors that `matches()` rejects.\n return false;\n }\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A CSS selector in the shape Angular's compiler uses for `ng-content` and
|
|
3
|
+
* `ngProjectAs` matching. Ported from `CssSelector` in `@angular/compiler`.
|
|
4
|
+
*/
|
|
5
|
+
export interface ParsedSelector {
|
|
6
|
+
element: string;
|
|
7
|
+
attrs: [string, string][];
|
|
8
|
+
classNames: string[];
|
|
9
|
+
notSelectors: ParsedSelector[];
|
|
10
|
+
}
|
|
11
|
+
export declare function parseSelectorList(selector: string): ParsedSelector[];
|
|
12
|
+
/**
|
|
13
|
+
* Structural equality, matching how Angular compares an `ngProjectAs` selector
|
|
14
|
+
* against the selectors of an `ng-content`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function isSameSelector(a: ParsedSelector, b: ParsedSelector): boolean;
|
|
17
|
+
//# sourceMappingURL=selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/selector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IAC1B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,EAAE,cAAc,EAAE,CAAC;CAChC;AAuBD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,CA+CpE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAa5E"}
|
package/src/selector.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const SELECTOR_REGEXP = new RegExp('(\\:not\\()|' + // 1: ":not("
|
|
2
|
+
'(([\\.\\#]?)[-\\w]+)|' + // 2: "tag"; 3: "."/"#"
|
|
3
|
+
'(?:\\[([-.\\w*\\\\$]+)(?:=(["\']?)([^\\]"\']*)\\5)?\\])|' + // 4: attribute; 5: quote; 6: value
|
|
4
|
+
'(\\))|' + // 7: ")"
|
|
5
|
+
'(\\s*,\\s*)', // 8: ","
|
|
6
|
+
'g');
|
|
7
|
+
const NOT = 1;
|
|
8
|
+
const TAG = 2;
|
|
9
|
+
const PREFIX = 3;
|
|
10
|
+
const ATTRIBUTE = 4;
|
|
11
|
+
const ATTRIBUTE_VALUE = 6;
|
|
12
|
+
const NOT_END = 7;
|
|
13
|
+
const SEPARATOR = 8;
|
|
14
|
+
function createSelector() {
|
|
15
|
+
return { element: '', attrs: [], classNames: [], notSelectors: [] };
|
|
16
|
+
}
|
|
17
|
+
export function parseSelectorList(selector) {
|
|
18
|
+
const results = [];
|
|
19
|
+
let cssSelector = createSelector();
|
|
20
|
+
let current = cssSelector;
|
|
21
|
+
let inNot = false;
|
|
22
|
+
let match;
|
|
23
|
+
const regexp = new RegExp(SELECTOR_REGEXP.source, 'g');
|
|
24
|
+
while ((match = regexp.exec(selector))) {
|
|
25
|
+
if (match[NOT]) {
|
|
26
|
+
inNot = true;
|
|
27
|
+
current = createSelector();
|
|
28
|
+
cssSelector.notSelectors.push(current);
|
|
29
|
+
}
|
|
30
|
+
const tag = match[TAG];
|
|
31
|
+
if (tag) {
|
|
32
|
+
const prefix = match[PREFIX];
|
|
33
|
+
if (prefix === '#') {
|
|
34
|
+
current.attrs.push(['id', tag.slice(1)]);
|
|
35
|
+
}
|
|
36
|
+
else if (prefix === '.') {
|
|
37
|
+
current.classNames.push(tag.slice(1).toLowerCase());
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
current.element = tag;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const attribute = match[ATTRIBUTE];
|
|
44
|
+
if (attribute) {
|
|
45
|
+
current.attrs.push([attribute, match[ATTRIBUTE_VALUE] ?? '']);
|
|
46
|
+
}
|
|
47
|
+
if (match[NOT_END]) {
|
|
48
|
+
inNot = false;
|
|
49
|
+
current = cssSelector;
|
|
50
|
+
}
|
|
51
|
+
if (match[SEPARATOR]) {
|
|
52
|
+
results.push(cssSelector);
|
|
53
|
+
cssSelector = current = createSelector();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
results.push(cssSelector);
|
|
57
|
+
return results;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Structural equality, matching how Angular compares an `ngProjectAs` selector
|
|
61
|
+
* against the selectors of an `ng-content`.
|
|
62
|
+
*/
|
|
63
|
+
export function isSameSelector(a, b) {
|
|
64
|
+
return (normalizeElement(a.element) === normalizeElement(b.element) &&
|
|
65
|
+
a.attrs.length === b.attrs.length &&
|
|
66
|
+
a.attrs.every(([name, value], i) => {
|
|
67
|
+
const [otherName, otherValue] = b.attrs[i];
|
|
68
|
+
return name === otherName && value === otherValue;
|
|
69
|
+
}) &&
|
|
70
|
+
a.classNames.length === b.classNames.length &&
|
|
71
|
+
a.classNames.every((name, i) => name === b.classNames[i]) &&
|
|
72
|
+
a.notSelectors.length === b.notSelectors.length &&
|
|
73
|
+
a.notSelectors.every((not, i) => isSameSelector(not, b.notSelectors[i])));
|
|
74
|
+
}
|
|
75
|
+
function normalizeElement(element) {
|
|
76
|
+
return element === '*' ? '' : element;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/selector.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A CSS selector in the shape Angular's compiler uses for `ng-content` and\n * `ngProjectAs` matching. Ported from `CssSelector` in `@angular/compiler`.\n */\nexport interface ParsedSelector {\n element: string;\n attrs: [string, string][];\n classNames: string[];\n notSelectors: ParsedSelector[];\n}\n\nconst SELECTOR_REGEXP = new RegExp(\n '(\\\\:not\\\\()|' + // 1: \":not(\"\n '(([\\\\.\\\\#]?)[-\\\\w]+)|' + // 2: \"tag\"; 3: \".\"/\"#\"\n '(?:\\\\[([-.\\\\w*\\\\\\\\$]+)(?:=([\"\\']?)([^\\\\]\"\\']*)\\\\5)?\\\\])|' + // 4: attribute; 5: quote; 6: value\n '(\\\\))|' + // 7: \")\"\n '(\\\\s*,\\\\s*)', // 8: \",\"\n 'g',\n);\n\nconst NOT = 1;\nconst TAG = 2;\nconst PREFIX = 3;\nconst ATTRIBUTE = 4;\nconst ATTRIBUTE_VALUE = 6;\nconst NOT_END = 7;\nconst SEPARATOR = 8;\n\nfunction createSelector(): ParsedSelector {\n return { element: '', attrs: [], classNames: [], notSelectors: [] };\n}\n\nexport function parseSelectorList(selector: string): ParsedSelector[] {\n const results: ParsedSelector[] = [];\n let cssSelector = createSelector();\n let current = cssSelector;\n let inNot = false;\n let match: RegExpExecArray | null;\n\n const regexp = new RegExp(SELECTOR_REGEXP.source, 'g');\n\n while ((match = regexp.exec(selector))) {\n if (match[NOT]) {\n inNot = true;\n current = createSelector();\n cssSelector.notSelectors.push(current);\n }\n\n const tag = match[TAG];\n if (tag) {\n const prefix = match[PREFIX];\n if (prefix === '#') {\n current.attrs.push(['id', tag.slice(1)]);\n } else if (prefix === '.') {\n current.classNames.push(tag.slice(1).toLowerCase());\n } else {\n current.element = tag;\n }\n }\n\n const attribute = match[ATTRIBUTE];\n if (attribute) {\n current.attrs.push([attribute, match[ATTRIBUTE_VALUE] ?? '']);\n }\n\n if (match[NOT_END]) {\n inNot = false;\n current = cssSelector;\n }\n\n if (match[SEPARATOR]) {\n results.push(cssSelector);\n cssSelector = current = createSelector();\n }\n }\n\n results.push(cssSelector);\n\n return results;\n}\n\n/**\n * Structural equality, matching how Angular compares an `ngProjectAs` selector\n * against the selectors of an `ng-content`.\n */\nexport function isSameSelector(a: ParsedSelector, b: ParsedSelector): boolean {\n return (\n normalizeElement(a.element) === normalizeElement(b.element) &&\n a.attrs.length === b.attrs.length &&\n a.attrs.every(([name, value], i) => {\n const [otherName, otherValue] = b.attrs[i];\n return name === otherName && value === otherValue;\n }) &&\n a.classNames.length === b.classNames.length &&\n a.classNames.every((name, i) => name === b.classNames[i]) &&\n a.notSelectors.length === b.notSelectors.length &&\n a.notSelectors.every((not, i) => isSameSelector(not, b.notSelectors[i]))\n );\n}\n\nfunction normalizeElement(element: string): string {\n return element === '*' ? '' : element;\n}\n"]}
|
package/src/server-ngh.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ declare function check(Component: Type<unknown>): Promise<boolean>;
|
|
|
6
6
|
declare function renderToStaticMarkup(this: RendererContext, Component: Type<unknown> & {
|
|
7
7
|
renderProviders?: (Provider | EnvironmentProviders)[];
|
|
8
8
|
hydrationFeatures?: () => HydrationFeature<HydrationFeatureKind>[];
|
|
9
|
-
}, props: Record<string, unknown>,
|
|
9
|
+
}, props: Record<string, unknown>, children: unknown, metadata?: AstroComponentMetadata): Promise<{
|
|
10
10
|
html: string;
|
|
11
11
|
}>;
|
|
12
12
|
declare const _default: {
|
package/src/server-ngh.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-ngh.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server-ngh.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"server-ngh.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server-ngh.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAc1E,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAG1B,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,sBAAsB,EAA0B,MAAM,OAAO,CAAC;AAC5E,OAAO,EAA2B,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAyB7E,iBAAe,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,oBAE5C;AAED,iBAAe,oBAAoB,CACjC,IAAI,EAAE,eAAe,EACrB,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG;IACzB,eAAe,CAAC,EAAE,CAAC,QAAQ,GAAG,oBAAoB,CAAC,EAAE,CAAC;IACtD,iBAAiB,CAAC,EAAE,MAAM,gBAAgB,CAAC,oBAAoB,CAAC,EAAE,CAAC;CACpE,EACD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,QAAQ,EAAE,OAAO,EACjB,QAAQ,CAAC,EAAE,sBAAsB;;GAyFlC;;;;;;AAED,wBAImC"}
|
package/src/server-ngh.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { reflectComponentType, provideZonelessChangeDetection, DOCUMENT, APP_ID, } from '@angular/core';
|
|
3
|
+
import { createComponent, reflectComponentType, provideZonelessChangeDetection, DOCUMENT, APP_ID, } from '@angular/core';
|
|
4
4
|
import { provideServerRendering, renderApplication, ɵSERVER_CONTEXT, platformServer, } from '@angular/platform-server';
|
|
5
|
-
import {
|
|
5
|
+
import { createApplication, provideClientHydration, } from '@angular/platform-browser';
|
|
6
6
|
import { getContext, incrementId } from "./context.js";
|
|
7
|
-
import { provideBootstrapListener } from "./server-providers.js";
|
|
8
7
|
import { ID_PROP_NAME } from "./id.js";
|
|
9
|
-
import { getComponentElementTag } from "./create-component.js";
|
|
8
|
+
import { createInputBindings, getComponentElementTag, registerRootComponent, } from "./create-component.js";
|
|
9
|
+
import { buildProjectableNodes, markProjectableNodes } from "./projection.js";
|
|
10
10
|
const require = createRequire(import.meta.url);
|
|
11
11
|
let jsActionContractScript = undefined;
|
|
12
12
|
const HYDRATION_SCRIPT_ID = 'ng-event-dispatch-contract';
|
|
@@ -20,7 +20,7 @@ function getHydrationScript() {
|
|
|
20
20
|
async function check(Component) {
|
|
21
21
|
return !!reflectComponentType(Component);
|
|
22
22
|
}
|
|
23
|
-
async function renderToStaticMarkup(Component, props,
|
|
23
|
+
async function renderToStaticMarkup(Component, props, children, metadata) {
|
|
24
24
|
const mirror = reflectComponentType(Component);
|
|
25
25
|
if (!mirror) {
|
|
26
26
|
// This should be unreachable: the `check` function verifies that Component is an Angular component.
|
|
@@ -36,22 +36,36 @@ async function renderToStaticMarkup(Component, props, _children, metadata) {
|
|
|
36
36
|
const document = platformRef.injector.get(DOCUMENT);
|
|
37
37
|
// Incremental hydration requires the event dispatch script to be present.
|
|
38
38
|
document.body.innerHTML = `${getHydrationScript()}<${elementTag} ${ID_PROP_NAME}="${ngAppId}"></${elementTag}>`;
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
39
|
+
const hostElement = document.querySelector(elementTag);
|
|
40
|
+
let projectableNodes = buildProjectableNodes(mirror, children, document);
|
|
41
|
+
if (metadata?.hydrate && projectableNodes) {
|
|
42
|
+
projectableNodes = markProjectableNodes(projectableNodes, String(ngAppId), document);
|
|
43
|
+
}
|
|
44
|
+
const bootstrap = async (context) => {
|
|
45
|
+
const appRef = await createApplication({
|
|
46
|
+
providers: [
|
|
47
|
+
provideServerRendering(),
|
|
48
|
+
{ provide: ɵSERVER_CONTEXT, useValue: 'analog' },
|
|
49
|
+
provideZonelessChangeDetection(),
|
|
50
|
+
metadata?.hydrate
|
|
51
|
+
? provideClientHydration(...(Component.hydrationFeatures?.() || []))
|
|
52
|
+
: [],
|
|
53
|
+
{
|
|
54
|
+
provide: APP_ID,
|
|
55
|
+
useValue: ngAppId,
|
|
56
|
+
},
|
|
57
|
+
...(Component.renderProviders || []),
|
|
58
|
+
],
|
|
59
|
+
}, context);
|
|
60
|
+
const componentRef = createComponent(Component, {
|
|
61
|
+
environmentInjector: appRef.injector,
|
|
62
|
+
hostElement,
|
|
63
|
+
projectableNodes,
|
|
64
|
+
bindings: createInputBindings(mirror, props),
|
|
65
|
+
});
|
|
66
|
+
registerRootComponent(appRef, componentRef);
|
|
67
|
+
return appRef;
|
|
68
|
+
};
|
|
55
69
|
const html = await renderApplication(bootstrap, {
|
|
56
70
|
document,
|
|
57
71
|
});
|
package/src/server-ngh.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-ngh.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server-ngh.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,EACL,oBAAoB,EACpB,8BAA8B,EAC9B,QAAQ,EACR,MAAM,GACP,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,eAAe,EACf,cAAc,GACf,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"server-ngh.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server-ngh.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,8BAA8B,EAC9B,QAAQ,EACR,MAAM,GACP,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,eAAe,EACf,cAAc,GACf,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,iBAAiB,EAGjB,sBAAsB,GAEvB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAwB,MAAM,cAAc,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAE9E,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,IAAI,sBAAsB,GAAuB,SAAS,CAAC;AAE3D,MAAM,mBAAmB,GAAG,4BAA4B,CAAC;AAEzD,SAAS,kBAAkB;IACzB,sBAAsB;QACpB,sCAAsC,mBAAmB,IAAI;YAC7D,YAAY,CACV,OAAO,CAAC,OAAO,CAAC,8CAA8C,CAAC,EAC/D,OAAO,CACR;YACD,WAAW,CAAC;IACd,OAAO,sBAAsB,CAAC;AAChC,CAAC;AAED,KAAK,UAAU,KAAK,CAAC,SAAwB;IAC3C,OAAO,CAAC,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC;AAC3C,CAAC;AAED,KAAK,UAAU,oBAAoB,CAEjC,SAGC,EACD,KAA8B,EAC9B,QAAiB,EACjB,QAAiC;IAEjC,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAE/C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,oGAAoG;QACpG,MAAM,IAAI,KAAK,CACb,CAAC,QAAQ,EAAE,WAAW,IAAI,qBAAqB,CAAC;YAC9C,8BAA8B,CACjC,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAE9E,sHAAsH;IACtH,4IAA4I;IAC5I,UAAU,CAAC,YAAY,GAAG,IAAI,CAAC;IAE/B,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAEpD,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,GAAG,kBAAkB,EAAE,IAAI,UAAU,IAAI,YAAY,KAAK,OAAO,OAAO,UAAU,GAAG,CAAC;IAEhH,MAAM,WAAW,GAAG,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAY,CAAC;IAClE,IAAI,gBAAgB,GAAG,qBAAqB,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEzE,IAAI,QAAQ,EAAE,OAAO,IAAI,gBAAgB,EAAE,CAAC;QAC1C,gBAAgB,GAAG,oBAAoB,CACrC,gBAAgB,EAChB,MAAM,CAAC,OAAO,CAAC,EACf,QAAQ,CACT,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,KAAK,EAAE,OAA0B,EAAE,EAAE;QACrD,MAAM,MAAM,GAAG,MAAM,iBAAiB,CACpC;YACE,SAAS,EAAE;gBACT,sBAAsB,EAAE;gBACxB,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE;gBAChD,8BAA8B,EAAE;gBAChC,QAAQ,EAAE,OAAO;oBACf,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,SAAS,CAAC,iBAAiB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;oBACpE,CAAC,CAAC,EAAE;gBACN;oBACE,OAAO,EAAE,MAAM;oBACf,QAAQ,EAAE,OAAO;iBAClB;gBACD,GAAG,CAAC,SAAS,CAAC,eAAe,IAAI,EAAE,CAAC;aACrC;SACF,EACD,OAAO,CACR,CAAC;QAEF,MAAM,YAAY,GAAG,eAAe,CAAC,SAAS,EAAE;YAC9C,mBAAmB,EAAE,MAAM,CAAC,QAAQ;YACpC,WAAW;YACX,gBAAgB;YAChB,QAAQ,EAAE,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC;SAC7C,CAAC,CAAC;QAEH,qBAAqB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAE5C,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,SAAS,EAAE;QAC9C,QAAQ;KACT,CAAC,CAAC;IAEH,QAAQ,CAAC,eAAe,CAAC,SAAS,GAAG,IAAI,CAAC;IAC1C,IAAI,SAAS,GAAG,EAAE,CAAC;IAEnB,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACxC,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YAC9B,SAAS,IAAK,IAAoB,CAAC,SAAS,CAAC;QAC/C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,mEAAmE;IACnE,QAAQ,CAAC,cAAc,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAEvD,MAAM,aAAa,GAAG,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC;IAE1D,WAAW,CAAC,OAAO,EAAE,CAAC;IAEtB,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;AACjC,CAAC;AAED,eAAe;IACb,KAAK;IACL,oBAAoB;IACpB,qBAAqB,EAAE,GAAG,EAAE,CAAC,kBAAkB,EAAE;CACjB,CAAC","sourcesContent":["import { readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\n\nimport type { EnvironmentProviders, Provider, Type } from '@angular/core';\nimport {\n createComponent,\n reflectComponentType,\n provideZonelessChangeDetection,\n DOCUMENT,\n APP_ID,\n} from '@angular/core';\nimport {\n provideServerRendering,\n renderApplication,\n ɵSERVER_CONTEXT,\n platformServer,\n} from '@angular/platform-server';\nimport {\n createApplication,\n type HydrationFeature,\n type HydrationFeatureKind,\n provideClientHydration,\n type BootstrapContext,\n} from '@angular/platform-browser';\nimport type { AstroComponentMetadata, SSRLoadedRendererValue } from 'astro';\nimport { getContext, incrementId, type RendererContext } from './context.ts';\nimport { ID_PROP_NAME } from './id.ts';\nimport {\n createInputBindings,\n getComponentElementTag,\n registerRootComponent,\n} from './create-component.ts';\nimport { buildProjectableNodes, markProjectableNodes } from './projection.ts';\n\nconst require = createRequire(import.meta.url);\nlet jsActionContractScript: string | undefined = undefined;\n\nconst HYDRATION_SCRIPT_ID = 'ng-event-dispatch-contract';\n\nfunction getHydrationScript(): string {\n jsActionContractScript ??=\n `<script type=\"text/javascript\" id=\"${HYDRATION_SCRIPT_ID}\">` +\n readFileSync(\n require.resolve('@angular/core/event-dispatch-contract.min.js'),\n 'utf-8',\n ) +\n '</script>';\n return jsActionContractScript;\n}\n\nasync function check(Component: Type<unknown>) {\n return !!reflectComponentType(Component);\n}\n\nasync function renderToStaticMarkup(\n this: RendererContext,\n Component: Type<unknown> & {\n renderProviders?: (Provider | EnvironmentProviders)[];\n hydrationFeatures?: () => HydrationFeature<HydrationFeatureKind>[];\n },\n props: Record<string, unknown>,\n children: unknown,\n metadata?: AstroComponentMetadata,\n) {\n const mirror = reflectComponentType(Component);\n\n if (!mirror) {\n // This should be unreachable: the `check` function verifies that Component is an Angular component.\n throw new Error(\n (metadata?.displayName || '<unknown component>') +\n ' is not an Angular component',\n );\n }\n\n const elementTag = getComponentElementTag(mirror);\n const ngAppId = props?.[ID_PROP_NAME] || incrementId(getContext(this.result));\n\n // When the platform ref is destroyed, it will reset ngServerMode back to `undefined` if it was not defined when it is\n // created. See https://github.com/angular/angular/blob/2ce0e98f79a02ddc550d00580e8e232cfed3bfb2/packages/platform-server/src/server.ts#L138\n globalThis.ngServerMode = true;\n\n const platformRef = platformServer();\n const document = platformRef.injector.get(DOCUMENT);\n\n // Incremental hydration requires the event dispatch script to be present.\n document.body.innerHTML = `${getHydrationScript()}<${elementTag} ${ID_PROP_NAME}=\"${ngAppId}\"></${elementTag}>`;\n\n const hostElement = document.querySelector(elementTag) as Element;\n let projectableNodes = buildProjectableNodes(mirror, children, document);\n\n if (metadata?.hydrate && projectableNodes) {\n projectableNodes = markProjectableNodes(\n projectableNodes,\n String(ngAppId),\n document,\n );\n }\n\n const bootstrap = async (context?: BootstrapContext) => {\n const appRef = await createApplication(\n {\n providers: [\n provideServerRendering(),\n { provide: ɵSERVER_CONTEXT, useValue: 'analog' },\n provideZonelessChangeDetection(),\n metadata?.hydrate\n ? provideClientHydration(...(Component.hydrationFeatures?.() || []))\n : [],\n {\n provide: APP_ID,\n useValue: ngAppId,\n },\n ...(Component.renderProviders || []),\n ],\n },\n context,\n );\n\n const componentRef = createComponent(Component, {\n environmentInjector: appRef.injector,\n hostElement,\n projectableNodes,\n bindings: createInputBindings(mirror, props),\n });\n\n registerRootComponent(appRef, componentRef);\n\n return appRef;\n };\n\n const html = await renderApplication(bootstrap, {\n document,\n });\n\n document.documentElement.innerHTML = html;\n let styleTags = '';\n\n document.head.childNodes.forEach((node) => {\n if (node.nodeName === 'STYLE') {\n styleTags += (node as HTMLElement).outerHTML;\n }\n });\n\n // Remove the hydration script, so only one is present on the page.\n document.getElementById(HYDRATION_SCRIPT_ID)?.remove();\n\n const correctedHtml = styleTags + document.body.innerHTML;\n\n platformRef.destroy();\n\n return { html: correctedHtml };\n}\n\nexport default {\n check,\n renderToStaticMarkup,\n renderHydrationScript: () => getHydrationScript(),\n} satisfies SSRLoadedRendererValue;\n"]}
|
package/src/server.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { EnvironmentProviders, Provider, ɵComponentType as ComponentType }
|
|
|
2
2
|
declare function check(Component: ComponentType<unknown>, _props: Record<string, unknown>, _children: unknown): boolean;
|
|
3
3
|
declare function renderToStaticMarkup(Component: ComponentType<unknown> & {
|
|
4
4
|
renderProviders: (Provider | EnvironmentProviders)[];
|
|
5
|
-
}, props: Record<string, unknown>,
|
|
5
|
+
}, props: Record<string, unknown>, children: unknown): Promise<{
|
|
6
6
|
html: string;
|
|
7
7
|
}>;
|
|
8
8
|
declare const _default: {
|
package/src/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,QAAQ,EACR,cAAc,IAAI,aAAa,EAChC,MAAM,eAAe,CAAC;AAwBvB,iBAAS,KAAK,CACZ,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,EACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,SAAS,EAAE,OAAO,WAGnB;AAED,iBAAe,oBAAoB,CACjC,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG;IAClC,eAAe,EAAE,CAAC,QAAQ,GAAG,oBAAoB,CAAC,EAAE,CAAC;CACtD,EACD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,QAAQ,EAAE,OAAO;;GA6DlB;;;;;AAED,wBAGE"}
|
package/src/server.js
CHANGED
|
@@ -1,57 +1,41 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return { props: {}, mirror: {} };
|
|
7
|
-
},
|
|
8
|
-
});
|
|
1
|
+
import { createComponent, reflectComponentType, provideZonelessChangeDetection, DOCUMENT, } from '@angular/core';
|
|
2
|
+
import { provideServerRendering, renderApplication, ɵSERVER_CONTEXT, platformServer, } from '@angular/platform-server';
|
|
3
|
+
import { createApplication, } from '@angular/platform-browser';
|
|
4
|
+
import { createInputBindings, getComponentElementTag, registerRootComponent, } from "./create-component.js";
|
|
5
|
+
import { buildProjectableNodes } from "./projection.js";
|
|
9
6
|
function check(Component, _props, _children) {
|
|
10
7
|
return !!reflectComponentType(Component);
|
|
11
8
|
}
|
|
12
|
-
|
|
13
|
-
// before the platform renders to string
|
|
14
|
-
const STATIC_PROPS_HOOK_PROVIDER = {
|
|
15
|
-
provide: BEFORE_APP_SERIALIZED,
|
|
16
|
-
useFactory: (appRef, { props, mirror, }) => {
|
|
17
|
-
return () => {
|
|
18
|
-
const compRef = appRef.components[0];
|
|
19
|
-
if (compRef && props && mirror) {
|
|
20
|
-
for (const [key, value] of Object.entries(props)) {
|
|
21
|
-
if (
|
|
22
|
-
// we double-check inputs on ComponentMirror
|
|
23
|
-
// because Astro might add additional props
|
|
24
|
-
// that aren't actually Input defined on the Component
|
|
25
|
-
mirror.inputs.some(({ templateName, propName }) => templateName === key || propName === key)) {
|
|
26
|
-
compRef.setInput(key, value);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
compRef.changeDetectorRef.detectChanges();
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
},
|
|
33
|
-
deps: [ApplicationRef, ANALOG_ASTRO_STATIC_PROPS],
|
|
34
|
-
multi: true,
|
|
35
|
-
};
|
|
36
|
-
async function renderToStaticMarkup(Component, props, _children) {
|
|
9
|
+
async function renderToStaticMarkup(Component, props, children) {
|
|
37
10
|
const mirror = reflectComponentType(Component);
|
|
38
|
-
|
|
11
|
+
if (!mirror) {
|
|
12
|
+
// This should be unreachable: the `check` function verifies that Component is an Angular component.
|
|
13
|
+
throw new Error(Component.name + ' is not an Angular component');
|
|
14
|
+
}
|
|
15
|
+
const elementTag = getComponentElementTag(mirror);
|
|
39
16
|
const platformRef = platformServer();
|
|
40
17
|
const document = platformRef.injector.get(DOCUMENT);
|
|
41
|
-
document.body.innerHTML = `<${
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
18
|
+
document.body.innerHTML = `<${elementTag}></${elementTag}>`;
|
|
19
|
+
const hostElement = document.querySelector(elementTag);
|
|
20
|
+
const projectableNodes = buildProjectableNodes(mirror, children, document);
|
|
21
|
+
const bootstrap = async (context) => {
|
|
22
|
+
const appRef = await createApplication({
|
|
23
|
+
providers: [
|
|
24
|
+
provideServerRendering(),
|
|
25
|
+
{ provide: ɵSERVER_CONTEXT, useValue: 'analog' },
|
|
26
|
+
provideZonelessChangeDetection(),
|
|
27
|
+
...(Component.renderProviders || []),
|
|
28
|
+
],
|
|
29
|
+
}, context);
|
|
30
|
+
const componentRef = createComponent(Component, {
|
|
31
|
+
environmentInjector: appRef.injector,
|
|
32
|
+
hostElement,
|
|
33
|
+
projectableNodes,
|
|
34
|
+
bindings: createInputBindings(mirror, props),
|
|
35
|
+
});
|
|
36
|
+
registerRootComponent(appRef, componentRef);
|
|
37
|
+
return appRef;
|
|
38
|
+
};
|
|
55
39
|
const html = await renderApplication(bootstrap, {
|
|
56
40
|
document,
|
|
57
41
|
});
|
package/src/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n EnvironmentProviders,\n Provider,\n ɵComponentType as ComponentType,\n} from '@angular/core';\nimport {\n createComponent,\n reflectComponentType,\n provideZonelessChangeDetection,\n DOCUMENT,\n} from '@angular/core';\nimport {\n provideServerRendering,\n renderApplication,\n ɵSERVER_CONTEXT,\n platformServer,\n} from '@angular/platform-server';\nimport {\n createApplication,\n type BootstrapContext,\n} from '@angular/platform-browser';\nimport {\n createInputBindings,\n getComponentElementTag,\n registerRootComponent,\n} from './create-component.ts';\nimport { buildProjectableNodes } from './projection.ts';\n\nfunction check(\n Component: ComponentType<unknown>,\n _props: Record<string, unknown>,\n _children: unknown,\n) {\n return !!reflectComponentType(Component);\n}\n\nasync function renderToStaticMarkup(\n Component: ComponentType<unknown> & {\n renderProviders: (Provider | EnvironmentProviders)[];\n },\n props: Record<string, unknown>,\n children: unknown,\n) {\n const mirror = reflectComponentType(Component);\n\n if (!mirror) {\n // This should be unreachable: the `check` function verifies that Component is an Angular component.\n throw new Error(Component.name + ' is not an Angular component');\n }\n\n const elementTag = getComponentElementTag(mirror);\n\n const platformRef = platformServer();\n const document = platformRef.injector.get(DOCUMENT);\n document.body.innerHTML = `<${elementTag}></${elementTag}>`;\n\n const hostElement = document.querySelector(elementTag) as Element;\n const projectableNodes = buildProjectableNodes(mirror, children, document);\n\n const bootstrap = async (context?: BootstrapContext) => {\n const appRef = await createApplication(\n {\n providers: [\n provideServerRendering(),\n { provide: ɵSERVER_CONTEXT, useValue: 'analog' },\n provideZonelessChangeDetection(),\n ...(Component.renderProviders || []),\n ],\n },\n context,\n );\n\n const componentRef = createComponent(Component, {\n environmentInjector: appRef.injector,\n hostElement,\n projectableNodes,\n bindings: createInputBindings(mirror, props),\n });\n\n registerRootComponent(appRef, componentRef);\n\n return appRef;\n };\n\n const html = await renderApplication(bootstrap, {\n document,\n });\n\n document.documentElement.innerHTML = html;\n let styleTags = '';\n\n document.head.childNodes.forEach((node) => {\n if (node.nodeName === 'STYLE') {\n styleTags += (node as HTMLElement).outerHTML;\n }\n });\n\n const correctedHtml = styleTags + document.body.innerHTML;\n\n platformRef.destroy();\n\n return { html: correctedHtml };\n}\n\nexport default {\n check,\n renderToStaticMarkup,\n};\n"]}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type ComponentMirror, type Provider } from '@angular/core';
|
|
2
|
-
/**
|
|
3
|
-
* Provide bootstrap listeners to ensure the rendered state matches the settled component state after applying component inputs.
|
|
4
|
-
* @param mirror The component mirror, to detect component inputs
|
|
5
|
-
* @param props Properties applied to the component in the Astro file
|
|
6
|
-
* @returns A providers array for the server renderer
|
|
7
|
-
*/
|
|
8
|
-
export declare function provideBootstrapListener(mirror: ComponentMirror<unknown>, props: Record<string, unknown>): Provider[];
|
|
9
|
-
//# sourceMappingURL=server-providers.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"server-providers.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server-providers.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,eAAe,EAEpB,KAAK,QAAQ,EACd,MAAM,eAAe,CAAC;AAEvB;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,QAAQ,EAAE,CAkBZ"}
|
package/src/server-providers.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { APP_BOOTSTRAP_LISTENER, } from '@angular/core';
|
|
2
|
-
/**
|
|
3
|
-
* Provide bootstrap listeners to ensure the rendered state matches the settled component state after applying component inputs.
|
|
4
|
-
* @param mirror The component mirror, to detect component inputs
|
|
5
|
-
* @param props Properties applied to the component in the Astro file
|
|
6
|
-
* @returns A providers array for the server renderer
|
|
7
|
-
*/
|
|
8
|
-
export function provideBootstrapListener(mirror, props) {
|
|
9
|
-
return [
|
|
10
|
-
{
|
|
11
|
-
provide: APP_BOOTSTRAP_LISTENER,
|
|
12
|
-
useValue: (compRef) => {
|
|
13
|
-
if (props) {
|
|
14
|
-
for (const [key, value] of Object.entries(props)) {
|
|
15
|
-
if (mirror.inputs.some(({ templateName }) => templateName === key)) {
|
|
16
|
-
compRef.setInput(key, value);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
multi: true,
|
|
22
|
-
},
|
|
23
|
-
];
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=server-providers.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"server-providers.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server-providers.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,GAIvB,MAAM,eAAe,CAAC;AAEvB;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,MAAgC,EAChC,KAA8B;IAE9B,OAAO;QACL;YACE,OAAO,EAAE,sBAAsB;YAC/B,QAAQ,EAAE,CAAC,OAA8B,EAAE,EAAE;gBAC3C,IAAI,KAAK,EAAE,CAAC;oBACV,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;wBACjD,IACE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,YAAY,KAAK,GAAG,CAAC,EAC9D,CAAC;4BACD,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;wBAC/B,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YACD,KAAK,EAAE,IAAI;SACZ;KACF,CAAC;AACJ,CAAC","sourcesContent":["import {\n APP_BOOTSTRAP_LISTENER,\n type ComponentMirror,\n type ComponentRef,\n type Provider,\n} from '@angular/core';\n\n/**\n * Provide bootstrap listeners to ensure the rendered state matches the settled component state after applying component inputs.\n * @param mirror The component mirror, to detect component inputs\n * @param props Properties applied to the component in the Astro file\n * @returns A providers array for the server renderer\n */\nexport function provideBootstrapListener(\n mirror: ComponentMirror<unknown>,\n props: Record<string, unknown>,\n): Provider[] {\n return [\n {\n provide: APP_BOOTSTRAP_LISTENER,\n useValue: (compRef: ComponentRef<unknown>) => {\n if (props) {\n for (const [key, value] of Object.entries(props)) {\n if (\n mirror.inputs.some(({ templateName }) => templateName === key)\n ) {\n compRef.setInput(key, value);\n }\n }\n }\n },\n multi: true,\n },\n ];\n}\n"]}
|