Skip to content
This repository was archived by the owner on Mar 20, 2024. It is now read-only.

Commit 8e7d5cc

Browse files
authored
feat(module): only add the inline script if not in the DOM (#77)
* Add the inline script only if the script is not already in the DOM Fixes #76
1 parent 9d1030b commit 8e7d5cc

File tree

3 files changed

+87
-73
lines changed

3 files changed

+87
-73
lines changed

src/lib/api/inline.preboot.code.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import {EventSelector, PrebootOptions} from '../common/preboot.interfaces';
8+
import {PrebootOptions} from '../common/preboot.interfaces';
99
import {getNodeKeyForPreboot} from '../common/get-node-key';
1010

1111
import {

src/lib/module.ts

Lines changed: 6 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -5,86 +5,20 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import {
9-
Inject,
10-
ModuleWithProviders,
11-
NgModule,
12-
Optional,
13-
PLATFORM_ID,
14-
InjectionToken,
15-
APP_BOOTSTRAP_LISTENER,
16-
ApplicationRef,
17-
} from '@angular/core';
18-
import {DOCUMENT, isPlatformBrowser, isPlatformServer} from '@angular/common';
19-
import {filter} from 'rxjs/operators/filter';
20-
import {take} from 'rxjs/operators/take';
8+
import {ModuleWithProviders, NgModule} from '@angular/core';
219

2210
import {EventReplayer} from './api/event.replayer';
23-
import {getInlinePrebootCode} from './api/inline.preboot.code';
2411
import {PrebootOptions} from './common/preboot.interfaces';
25-
import {PREBOOT_NONCE} from './common/tokens';
12+
import {PREBOOT_OPTIONS, PREBOOT_PROVIDER} from './provider';
2613

27-
28-
export const PREBOOT_OPTIONS = new InjectionToken<PrebootOptions>('PrebootOptions');
29-
30-
export function prebootHook(doc: Document,
31-
prebootOpts: PrebootOptions,
32-
nonce: string|null,
33-
platformId: Object,
34-
appRef: ApplicationRef,
35-
eventReplayer: EventReplayer) {
36-
// necessary because of angular/angular/issues/14485
37-
const res = () => {
38-
39-
if (isPlatformServer(platformId)) {
40-
const inlineCode = getInlinePrebootCode(prebootOpts);
41-
const script = doc.createElement('script');
42-
if (nonce) {
43-
(<any>script)['nonce'] = nonce;
44-
}
45-
script.textContent = inlineCode;
46-
doc.head.appendChild(script);
47-
}
48-
if (isPlatformBrowser(platformId)) {
49-
const replay = prebootOpts.replay != null ? prebootOpts.replay : true;
50-
if (replay) {
51-
appRef.isStable
52-
.pipe(
53-
filter(stable => stable),
54-
take(1)
55-
).subscribe(() => {
56-
eventReplayer.replayAll();
57-
});
58-
}
59-
}
60-
};
61-
62-
return res;
63-
64-
}
65-
66-
@NgModule()
14+
@NgModule({
15+
providers: [EventReplayer, PREBOOT_PROVIDER]
16+
})
6717
export class PrebootModule {
6818
static withConfig(opts: PrebootOptions): ModuleWithProviders {
6919
return {
7020
ngModule: PrebootModule,
71-
providers: [
72-
EventReplayer,
73-
{ provide: PREBOOT_OPTIONS, useValue: opts },
74-
{
75-
provide: APP_BOOTSTRAP_LISTENER,
76-
useFactory: prebootHook,
77-
deps: [
78-
DOCUMENT,
79-
PREBOOT_OPTIONS,
80-
[new Optional(), new Inject(PREBOOT_NONCE)],
81-
PLATFORM_ID,
82-
ApplicationRef,
83-
EventReplayer,
84-
],
85-
multi: true
86-
}
87-
]
21+
providers: [{provide: PREBOOT_OPTIONS, useValue: opts}]
8822
};
8923
}
9024
}

src/lib/provider.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
import {
9+
APP_BOOTSTRAP_LISTENER,
10+
ApplicationRef,
11+
Inject,
12+
InjectionToken,
13+
Optional,
14+
PLATFORM_ID
15+
} from '@angular/core';
16+
import {DOCUMENT, isPlatformBrowser, isPlatformServer} from '@angular/common';
17+
import {take} from 'rxjs/operators/take';
18+
import {filter} from 'rxjs/operators/filter';
19+
20+
import {EventReplayer} from './api/event.replayer';
21+
import {PREBOOT_NONCE} from './common/tokens';
22+
import {getInlinePrebootCode} from './api/inline.preboot.code';
23+
import {PrebootOptions} from './common/preboot.interfaces';
24+
25+
const PREBOOT_SCRIPT_ID = 'preboot-inline-script';
26+
export const PREBOOT_OPTIONS = new InjectionToken<PrebootOptions>('PrebootOptions');
27+
28+
export function PREBOOT_FACTORY(doc: Document,
29+
prebootOpts: PrebootOptions,
30+
nonce: string|null,
31+
platformId: Object,
32+
appRef: ApplicationRef,
33+
eventReplayer: EventReplayer) {
34+
return () => {
35+
if (isPlatformServer(platformId)) {
36+
const inlineCode = getInlinePrebootCode(prebootOpts);
37+
const script = doc.createElement('script');
38+
if (nonce) {
39+
(<any>script)['nonce'] = nonce;
40+
}
41+
script.id = PREBOOT_SCRIPT_ID;
42+
script.textContent = inlineCode;
43+
const existingScripts = doc.querySelectorAll(`#${PREBOOT_SCRIPT_ID}`);
44+
45+
// Check to see if a preboot script is already inlined before adding
46+
// it to the DOM. If it is, update the nonce to be current
47+
if (existingScripts.length === 0) {
48+
doc.head.appendChild(script);
49+
} else if (existingScripts.length > 0 && nonce) {
50+
(<any>existingScripts[0])['nonce'] = nonce;
51+
}
52+
}
53+
if (isPlatformBrowser(platformId)) {
54+
const replay = prebootOpts.replay != null ? prebootOpts.replay : true;
55+
if (replay) {
56+
appRef.isStable
57+
.pipe(
58+
filter(stable => stable),
59+
take(1)
60+
).subscribe(() => {
61+
eventReplayer.replayAll();
62+
});
63+
}
64+
}
65+
};
66+
}
67+
68+
export const PREBOOT_PROVIDER = {
69+
provide: <InjectionToken<() => void>>APP_BOOTSTRAP_LISTENER,
70+
useFactory: PREBOOT_FACTORY,
71+
deps: [
72+
DOCUMENT,
73+
PREBOOT_OPTIONS,
74+
[new Optional(), new Inject(PREBOOT_NONCE)],
75+
PLATFORM_ID,
76+
ApplicationRef,
77+
EventReplayer,
78+
],
79+
multi: true
80+
};

0 commit comments

Comments
 (0)