Skip to content

Commit 9068d29

Browse files
committed
Move fastboot specific config to a meta tag; keep manifest in
package.json for broccoli-asset-rev support This commit builds fastboot specific config (available via FastBoot.config()) to meta tag, which will be extracted by fastboot when served. The fastboot config meta has the name ending with "config/fastboot-environement" to distinguish from regular "config/environement" meta tags. If the new meta tags are not found, which happens in embroider builds, we fallback to find regular meta tags.
1 parent c4d2dbc commit 9068d29

File tree

18 files changed

+223
-84251
lines changed

18 files changed

+223
-84251
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ jobs:
6666
- name: Yarn Install
6767
run: yarn install --ignore-engines --frozen-lockfile
6868
- name: Integration Tests
69-
run: yarn workspace integration-tests test
69+
run: yarn workspace integration-tests test
7070

7171
test-packages:
7272
name: Test Packages

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
"test:fastboot": "yarn workspace fastboot test",
1616
"test:fastboot-express-middleware": "yarn workspace fastboot-express-middleware test",
1717
"test:fastboot-app-server": "yarn workspace fastboot-app-server test:mocha",
18-
"test:integration": "yarn workspace integration-tests test"
18+
"test:integration": "yarn workspace integration-tests test",
19+
"test:extra": "yarn workspace basic-app test:mocha && yarn workspace custom-fastboot-app test:mocha"
1920
},
2021
"devDependencies": {
2122
"npm-run-all": "^4.1.5",

packages/ember-cli-fastboot/lib/broccoli/fastboot-config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,9 @@ module.exports = class FastBootConfig extends Plugin {
182182
moduleWhitelist: this.moduleWhitelist,
183183
schemaVersion: LATEST_SCHEMA_VERSION,
184184
hostWhitelist: this.normalizeHostWhitelist(),
185-
config: this.fastbootConfig,
185+
// We can't drop manifest until broccoli-asset-rev also supports v5 HTML based manifest
186+
// https://github.com/ember-cli/broccoli-asset-rev/blob/78f6047c15acb3bd348611f658b03bdd1041911f/lib/fastboot-manifest-rewrite.js
187+
manifest: this.manifest,
186188
htmlEntrypoint: this.manifest.htmlFile
187189
}
188190
},

packages/ember-cli-fastboot/lib/broccoli/html-writer.js

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module.exports = class BasePageWriter extends Filter {
1212
});
1313
this._manifest = manifest;
1414
this._rootURL = getRootURL(fastbootConfig, appName);
15+
this._fastbootConfig = fastbootConfig;
1516
this._appJsPath = outputPaths.app.js;
1617
this._expectedFiles = expectedFiles(outputPaths);
1718
}
@@ -24,15 +25,46 @@ module.exports = class BasePageWriter extends Filter {
2425

2526
processString(content) {
2627
let dom = new JSDOM(content);
28+
this._handleConfig(dom);
29+
this._handleScripts(dom);
30+
return dom.serialize();
31+
}
32+
33+
_handleConfig(dom) {
34+
function findFistConfigMeta(dom) {
35+
let metaTags = dom.window.document.querySelectorAll('meta');
36+
for (let element of metaTags) {
37+
let name = element.getAttribute('name');
38+
if (name && name.endsWith('/config/environment')) {
39+
return element;
40+
}
41+
}
42+
}
43+
let firstConfigMeta;
44+
if (firstConfigMeta) {
45+
firstConfigMeta = findFistConfigMeta(dom);
46+
} else {
47+
firstConfigMeta = dom.window.document.createTextNode('\n');
48+
dom.window.document.head.appendChild(firstConfigMeta);
49+
}
50+
let nodeRange = new NodeRange(firstConfigMeta);
51+
for (let [name, options] of Object.entries(this._fastbootConfig)) {
52+
nodeRange.insertJsonAsMetaTag(`${name}/config/fastboot-environment`, options);
53+
}
54+
}
55+
56+
_handleScripts(dom) {
2757
let scriptTags = dom.window.document.querySelectorAll('script');
2858

2959
this._ignoreUnexpectedScripts(scriptTags);
3060

3161
let fastbootScripts = this._findFastbootScriptToInsert(scriptTags);
3262
let appJsTag = findAppJsTag(scriptTags, this._appJsPath, this._rootURL);
33-
insertFastbootScriptsBeforeAppJsTags(fastbootScripts, appJsTag);
63+
if (!appJsTag) {
64+
throw new Error('ember-cli-fastboot cannot find own app script tag');
65+
}
3466

35-
return dom.serialize();
67+
insertFastbootScriptsBeforeAppJsTags(fastbootScripts, appJsTag);
3668
}
3769

3870
_findFastbootScriptToInsert(scriptTags) {
@@ -79,6 +111,10 @@ function getRootURL(appName, config) {
79111
}
80112

81113
function urlWithin(candidate, root) {
114+
// this is a null or relative path
115+
if (!candidate || !candidate.startsWith('/')) {
116+
return candidate;
117+
}
82118
let candidateURL = new URL(candidate, 'http://_the_current_origin_');
83119
let rootURL = new URL(root, 'http://_the_current_origin_');
84120
if (candidateURL.href.startsWith(rootURL.href)) {
@@ -114,6 +150,18 @@ class NodeRange {
114150
let newTag = this.end.ownerDocument.createElement('fastboot-script');
115151
newTag.setAttribute('src', src);
116152
this.insertNode(newTag);
153+
this.insertNewLine();
154+
}
155+
156+
insertJsonAsMetaTag(name, content) {
157+
let newTag = this.end.ownerDocument.createElement('meta');
158+
newTag.setAttribute('name', name);
159+
newTag.setAttribute('content', encodeURIComponent(JSON.stringify(content)));
160+
this.insertNode(newTag);
161+
this.insertNewLine();
162+
}
163+
164+
insertNewLine() {
117165
this.insertNode(this.end.ownerDocument.createTextNode('\n'));
118166
}
119167

packages/fastboot/src/fastboot-schema.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@ function loadConfig(distPath) {
7979
({ appName, config, html, scripts } = loadManifest(distPath, pkg.fastboot, schemaVersion));
8080
} else {
8181
appName = pkg.name;
82-
config = pkg.fastboot.config;
83-
({ html, scripts } = htmlEntrypoint(appName, distPath, pkg.fastboot.htmlEntrypoint, config));
82+
({ config, html, scripts } = htmlEntrypoint(appName, distPath, pkg.fastboot.htmlEntrypoint));
8483
}
8584

8685
let sandboxRequire = buildWhitelistedRequire(

packages/fastboot/src/html-entrypoint.js

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,35 @@ const { JSDOM } = require('jsdom');
44
const fs = require('fs');
55
const path = require('path');
66

7-
function htmlEntrypoint(appName, distPath, htmlPath, config = {}) {
7+
function htmlEntrypoint(appName, distPath, htmlPath) {
88
let html = fs.readFileSync(path.join(distPath, htmlPath), 'utf8');
99
let dom = new JSDOM(html);
10-
let scripts = [];
1110

11+
function mergeContent(metaElement, config, configName) {
12+
let name = metaElement.getAttribute('name');
13+
if (name && name.endsWith(configName)) {
14+
let content = JSON.parse(decodeURIComponent(metaElement.getAttribute('content')));
15+
content.APP = Object.assign({ autoboot: false }, content.APP);
16+
config[name.slice(0, -1 * configName.length)] = content;
17+
return true;
18+
}
19+
return false;
20+
}
21+
let fastbootConfig = {};
22+
let config = {};
23+
for (let element of dom.window.document.querySelectorAll('meta')) {
24+
mergeContent(element, config, '/config/environment');
25+
let fastbootMerged = mergeContent(element, fastbootConfig, '/config/fastboot-environment');
26+
if (fastbootMerged) {
27+
element.remove();
28+
}
29+
}
30+
let isFastbootConfigBuilt = Object.keys(fastbootConfig).length > 0;
31+
if (isFastbootConfigBuilt) {
32+
config = fastbootConfig;
33+
}
34+
35+
let scripts = [];
1236
let rootURL = getRootURL(appName, config);
1337

1438
for (let element of dom.window.document.querySelectorAll('script,fastboot-script')) {
@@ -24,7 +48,7 @@ function htmlEntrypoint(appName, distPath, htmlPath, config = {}) {
2448
}
2549
}
2650

27-
return { html: dom.serialize(), scripts };
51+
return { config, html: dom.serialize(), scripts };
2852
}
2953

3054
function extractSrc(element) {

packages/fastboot/test/fastboot-test.js

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -455,18 +455,4 @@ describe('FastBoot', function() {
455455
usedPrebuiltSandbox: true,
456456
});
457457
});
458-
459-
it('htmlEntrypoint works', function() {
460-
var fastboot = new FastBoot({
461-
distPath: fixture('html-entrypoint'),
462-
});
463-
464-
return fastboot
465-
.visit('/')
466-
.then(r => r.html())
467-
.then(html => {
468-
expect(html).to.match(/Welcome to Ember/);
469-
expect(html).to.not.match(/fastboot-script/);
470-
});
471-
});
472458
});

0 commit comments

Comments
 (0)