Skip to content

Commit 31584ad

Browse files
Add fastboot/prember (#1691)
* Add fastboot/prember * Fix lint * pnpm update * Update pnpm-lock.yaml * Update package.json * Revert "Update package.json" This reverts commit 53d5e4d. * Revert "Update pnpm-lock.yaml" This reverts commit 7db0cf3. * Revert "pnpm update" This reverts commit bbaa25e. * Update addon/services/docs-store.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update tests-node/unit/prember-urls-test.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Strip index from routes * Update docs-store.js * Update tests/dummy/config/environment.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Various fixes * Update addon/services/docs-store.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix lint * Update docs-store.js * Update package.json * Load from dist instead of using http --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 544490e commit 31584ad

21 files changed

Lines changed: 1557 additions & 70 deletions

File tree

addon/components/docs-header/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ export default class DocsHeader extends Component {
8787
@action
8888
didVisitPage() {
8989
this.query = null;
90-
let search = document.querySelector('[data-search-box-input]');
91-
search.blur();
90+
if (typeof document !== 'undefined') {
91+
let search = document.querySelector('[data-search-box-input]');
92+
search?.blur();
93+
}
9294
}
9395
}

addon/components/docs-header/search-box/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ export default class DocsHeaderSearchBox extends Component {
2222

2323
@action
2424
focusSearch() {
25+
if (typeof document === 'undefined') return;
26+
2527
if (!formElementHasFocus()) {
2628
this.element.querySelector('input').focus();
2729
}

addon/components/docs-modal-dialog.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ export default class DocsModalDialog extends ModalDialog {
77
super.init(...arguments);
88

99
const config = getOwner(this).resolveRegistration('config:environment');
10-
this.set('renderInPlace', config.environment === 'test');
10+
let fastboot = getOwner(this).lookup('service:fastboot');
11+
this.set(
12+
'renderInPlace',
13+
config.environment === 'test' || fastboot?.isFastBoot,
14+
);
1115
}
1216
}

addon/components/docs-viewer/x-main/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export default class XMain extends Component {
2121

2222
@action
2323
setupElement(element) {
24+
if (typeof MutationObserver === 'undefined') return;
25+
2426
let target = element.querySelector('[data-current-page-index-target]');
2527

2628
this._mutationObserver = new MutationObserver(

addon/keyboard-config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ const TAGNAMES_THAT_WHEN_FOCUSED_PREVENT_KEYBOARD_SHORTCUTS = [
99
@hide
1010
*/
1111
export function formElementHasFocus() {
12+
if (typeof document === 'undefined') return false;
13+
1214
return TAGNAMES_THAT_WHEN_FOCUSED_PREVENT_KEYBOARD_SHORTCUTS.includes(
1315
document.activeElement.tagName,
1416
);

addon/services/docs-search.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Service from '@ember/service';
2+
import { getOwner } from '@ember/application';
23
import lunr from 'lunr';
34
import { task } from 'ember-concurrency';
45
import {
@@ -12,6 +13,7 @@ export default class DocsSearch extends Service {
1213
async search(phrase) {
1314
const { searchTokenSeparator } = getAddonDocsConfig(this);
1415
let { index, documents } = await this.loadSearchIndex();
16+
if (!index) return [];
1517
let words = phrase.toLowerCase().split(new RegExp(searchTokenSeparator));
1618
let results = index.query((query) => {
1719
// In the future we could boost results based on the field they come from
@@ -91,6 +93,12 @@ export default class DocsSearch extends Service {
9193

9294
_loadSearchIndex = task({ enqueue: true }, async () => {
9395
if (!this._searchIndex) {
96+
let fastboot = getOwner(this).lookup('service:fastboot');
97+
if (fastboot?.isFastBoot) {
98+
this._searchIndex = { index: null, documents: {} };
99+
return this._searchIndex;
100+
}
101+
94102
let response = await fetch(this._indexURL);
95103
let json = await response.json();
96104

addon/services/docs-store.js

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
/* global FastBoot */
12
import Service from '@ember/service';
3+
import { getOwner } from '@ember/application';
24
import { tracked } from '@glimmer/tracking';
35
import { getRootURL } from 'ember-cli-addon-docs/-private/config';
46

@@ -52,11 +54,35 @@ export default class DocsStoreService extends Service {
5254
}
5355

5456
async _fetchProject(id) {
55-
let namespace = `${getRootURL(this).replace(/\/$/, '')}/docs`;
56-
let url = `${namespace}/${id}.json`;
57-
58-
let response = await fetch(url);
59-
let payload = await response.json();
57+
let payload;
58+
59+
let fastboot = getOwner(this).lookup('service:fastboot');
60+
if (fastboot?.isFastBoot) {
61+
// In FastBoot, read the docs JSON directly from the dist directory
62+
// using FastBoot.distPath. This works during both prember builds and
63+
// ember serve with fastboot, without needing an HTTP request.
64+
let fs = FastBoot.require('fs');
65+
let path = FastBoot.require('path');
66+
let filePath = path.join(FastBoot.distPath, 'docs', `${id}.json`);
67+
payload = JSON.parse(fs.readFileSync(filePath, 'utf8'));
68+
} else {
69+
let namespace = `${getRootURL(this).replace(/\/$/, '')}/docs`;
70+
let url = `${namespace}/${id}.json`;
71+
let response;
72+
try {
73+
response = await fetch(url);
74+
} catch (e) {
75+
throw new Error(
76+
`Network error while fetching ${url}: ${e && e.message}`,
77+
);
78+
}
79+
if (!response.ok) {
80+
throw new Error(
81+
`Request to ${url} failed with status ${response.status}`,
82+
);
83+
}
84+
payload = await response.json();
85+
}
6086

6187
this._loadPayload(payload);
6288

@@ -67,7 +93,11 @@ export default class DocsStoreService extends Service {
6793
let allRecords = [];
6894

6995
// Collect data (can be single or array)
70-
let dataItems = Array.isArray(payload.data) ? payload.data : [payload.data];
96+
let dataItems = Array.isArray(payload.data)
97+
? payload.data
98+
: payload.data
99+
? [payload.data]
100+
: [];
71101
allRecords.push(...dataItems);
72102

73103
// Collect included

addon/services/project-version.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Service from '@ember/service';
2+
import { getOwner } from '@ember/application';
23
import { task } from 'ember-concurrency';
34
import { tracked } from '@glimmer/tracking';
45
import {
@@ -12,6 +13,18 @@ export default class ProjectVersionService extends Service {
1213
@addonDocsConfig config;
1314

1415
_loadAvailableVersions = task(async () => {
16+
let fastboot = getOwner(this).lookup('service:fastboot');
17+
if (fastboot?.isFastBoot) {
18+
this.versions = [
19+
{
20+
...this.currentVersion,
21+
truncatedSha: this.currentVersion.sha?.substr(0, 5) || '',
22+
key: this.config.latestVersionName,
23+
},
24+
];
25+
return;
26+
}
27+
1528
let response = await fetch(`${this.root}versions.json`);
1629
let json;
1730
if (response.ok) {
@@ -32,6 +45,7 @@ export default class ProjectVersionService extends Service {
3245
});
3346

3447
redirectTo(version) {
48+
if (typeof window === 'undefined') return;
3549
window.location.href = `${this.root}${version.path}`;
3650
}
3751

blueprints/ember-cli-addon-docs/index.js

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,34 +19,13 @@ module.exports = {
1919
'ember-cli-deploy-build',
2020
'ember-cli-deploy-git',
2121
'ember-cli-deploy-git-ci',
22+
'ember-cli-fastboot',
23+
'prember',
2224
],
2325
});
2426
},
2527

26-
afterInstall(options) {
27-
let configPath = require.resolve(this.project.configPath());
28-
let configContents = fs.readFileSync(configPath, 'utf-8');
29-
30-
if (configContents.indexOf('ADDON_DOCS_ROOT_URL') === -1) {
31-
configContents = configContents.replace(
32-
/([ \t]+)if \(environment === 'production'\) {/,
33-
[
34-
'$&',
35-
'$1 // Allow ember-cli-addon-docs to update the rootURL in compiled assets',
36-
"$1 ENV.rootURL = '/ADDON_DOCS_ROOT_URL/';",
37-
].join('\n'),
38-
);
39-
40-
if (configContents.indexOf('ADDON_DOCS_ROOT_URL') === -1) {
41-
this.ui.writeWarnLine(
42-
`Unable to update rootURL configuration. You should update ${configPath} so that your rootURL is ` +
43-
`the string '/ADDON_DOCS_ROOT_URL/' in production.`,
44-
);
45-
}
46-
}
47-
48-
fs.writeFileSync(configPath, configContents, 'utf-8');
49-
28+
afterInstall() {
5029
if (fs.existsSync('.npmignore')) {
5130
this.insertIntoFile('.npmignore', '/config/addon-docs.js');
5231
}

index.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,13 @@ module.exports = {
130130
}
131131
}
132132

133+
// Set up prember for static site generation if not already configured
134+
if (!includer.options.prember) {
135+
includer.options.prember = {
136+
urls: require('./lib/prember-urls'),
137+
};
138+
}
139+
133140
includer.options.includeFileExtensionInSnippetNames =
134141
includer.options.includeFileExtensionInSnippetNames || false;
135142
if (!includer.options.snippetSearchPaths) {

0 commit comments

Comments
 (0)