@rocket/js 0.2.0 → 0.3.0

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.
Files changed (69) hide show
  1. package/dist-types/exports/adapters/cloudflare.d.ts +2 -0
  2. package/dist-types/exports/adapters/cloudflare.d.ts.map +1 -0
  3. package/dist-types/exports/ssr.d.ts +1 -1
  4. package/dist-types/exports/types/rocket.d.ts +11 -0
  5. package/dist-types/exports/types/rocket.d.ts.map +1 -1
  6. package/dist-types/exports/types.d.ts +1 -1
  7. package/dist-types/exports/types.d.ts.map +1 -1
  8. package/dist-types/src/PageData.d.ts +9 -0
  9. package/dist-types/src/PageData.d.ts.map +1 -1
  10. package/dist-types/src/RocketCodeBlock.d.ts.map +1 -1
  11. package/dist-types/src/RocketJsDemo.d.ts.map +1 -1
  12. package/dist-types/src/adapters/cloudflare.d.ts +27 -0
  13. package/dist-types/src/adapters/cloudflare.d.ts.map +1 -0
  14. package/dist-types/src/adapters/netlify.d.ts.map +1 -1
  15. package/dist-types/src/adapters/redirects.d.ts +14 -0
  16. package/dist-types/src/adapters/redirects.d.ts.map +1 -0
  17. package/dist-types/src/icons.d.ts +27 -0
  18. package/dist-types/src/icons.d.ts.map +1 -1
  19. package/dist-types/src/layouts/atlas/atlasBlogLayout.d.ts.map +1 -1
  20. package/dist-types/src/layouts/atlas/atlasDocLayout.d.ts.map +1 -1
  21. package/dist-types/src/layouts/atlas/atlasHeroLayout.d.ts.map +1 -1
  22. package/dist-types/src/layouts/atlas/atlasNotFoundLayout.d.ts.map +1 -1
  23. package/dist-types/src/layouts/layout-helper.d.ts.map +1 -1
  24. package/dist-types/src/markdownHook.d.ts.map +1 -1
  25. package/dist-types/src/menus/MainMenu.d.ts.map +1 -1
  26. package/dist-types/src/menus/RocketMenu.d.ts.map +1 -1
  27. package/dist-types/src/menus/RocketToc.d.ts.map +1 -1
  28. package/dist-types/src/menus/pageNavigation.d.ts.map +1 -1
  29. package/dist-types/src/prefer-project-packages-plugin.d.ts +9 -0
  30. package/dist-types/src/prefer-project-packages-plugin.d.ts.map +1 -0
  31. package/dist-types/src/project-package-resolution.d.ts +8 -0
  32. package/dist-types/src/project-package-resolution.d.ts.map +1 -0
  33. package/dist-types/src/publicAssets.d.ts.map +1 -1
  34. package/dist-types/src/resolve.d.ts.map +1 -1
  35. package/dist-types/src/ssr.d.ts +3 -0
  36. package/dist-types/src/ssr.d.ts.map +1 -1
  37. package/dist-types/src/transform.d.ts.map +1 -1
  38. package/exports/adapters/cloudflare.js +1 -0
  39. package/exports/ssr.js +1 -1
  40. package/exports/types/rocket.ts +17 -4
  41. package/exports/types.ts +1 -0
  42. package/package.json +41 -26
  43. package/src/PageData.js +15 -0
  44. package/src/RocketCodeBlock.js +11 -9
  45. package/src/RocketJsDemo.js +8 -6
  46. package/src/adapters/cloudflare.js +522 -0
  47. package/src/adapters/netlify.js +2 -24
  48. package/src/adapters/redirects.js +31 -0
  49. package/src/cli/RocketBuild.js +5 -2
  50. package/src/config.js +1 -1
  51. package/src/icons.js +143 -1
  52. package/src/layouts/atlas/atlasBlogLayout.js +45 -31
  53. package/src/layouts/atlas/atlasDocLayout.js +22 -16
  54. package/src/layouts/atlas/atlasHeroLayout.js +39 -31
  55. package/src/layouts/atlas/atlasNotFoundLayout.js +5 -3
  56. package/src/layouts/layout-helper.js +38 -26
  57. package/src/main.js +17 -0
  58. package/src/markdownCompiler.js +5 -1
  59. package/src/menus/MainMenu.js +17 -13
  60. package/src/menus/RocketMenu.js +25 -19
  61. package/src/menus/RocketToc.js +7 -5
  62. package/src/menus/pageNavigation.js +24 -10
  63. package/src/prefer-project-packages-plugin.js +31 -0
  64. package/src/project-package-resolution.js +36 -0
  65. package/src/publicAssets.js +9 -2
  66. package/src/resolve.js +32 -2
  67. package/src/ssr.js +3 -0
  68. package/src/transform.js +15 -9
  69. package/src/wds-plugin.js +2 -1
package/src/icons.js CHANGED
@@ -5,6 +5,7 @@ import { readFileSync } from 'node:fs';
5
5
  import path from 'node:path';
6
6
  import { createRequire } from 'node:module';
7
7
  import * as parse5 from 'parse5';
8
+ import { resolve } from './resolve.js';
8
9
 
9
10
  const require = createRequire(import.meta.url);
10
11
 
@@ -13,6 +14,8 @@ const ICON_REFERENCE_CONFIG_FIELDS = new Set(['library', 'name']);
13
14
  const ROCKET_ICON_ASSET_PREFIX = '/_rocket/icons/';
14
15
  const ROCKET_ICON_DEFINE_MODULE_PATH = '/_rocket/rocket-icon.js';
15
16
  const ROCKET_ICON_CLASS_MODULE_PATH = '/_rocket/RocketIcon.js';
17
+ const WEB_AWESOME_ICON_ASSET_PREFIX = '/_rocket/wa-icons/';
18
+ const WEB_AWESOME_ICON_LIBRARY_MODULE = '@awesome.me/webawesome/dist/components/icon/library.js';
16
19
  const SHADOW_ICON_STYLE =
17
20
  ':host{display:inline-block;width:1em;height:1em;vertical-align:-0.125em;line-height:1}' +
18
21
  ':host([hidden]){display:none}' +
@@ -66,6 +69,52 @@ export class IconAssetStore {
66
69
  /** @type {Map<string, { url: string; svg: string; library: string; name: string }>} */
67
70
  this.assets = new Map();
68
71
  this.needsRuntime = false;
72
+ /** @type {Map<string, { library: string; config: import('@rocket/js/types.js').NormalizedIconLibraryConfig }>} */
73
+ this.webAwesomeIconLibraries = new Map();
74
+ }
75
+
76
+ /**
77
+ * Publishes every icon of an Icon Library at `/_rocket/wa-icons/{library}/{name}.svg`, because
78
+ * browser code may ask `wa-icon` for any name.
79
+ *
80
+ * @param {string} library
81
+ * @param {import('@rocket/js/types.js').NormalizedIconLibraryConfig} config
82
+ */
83
+ addWebAwesomeIconLibrary(library, config) {
84
+ this.webAwesomeIconLibraries.set(sanitizePathSegment(library), { library, config });
85
+ }
86
+
87
+ /**
88
+ * @param {string} url
89
+ * @returns {Promise<{ url: string; svg: string } | undefined>}
90
+ */
91
+ async getWebAwesomeIcon(url) {
92
+ const match = /^\/_rocket\/wa-icons\/([^/]+)\/([^/]+)\.svg$/.exec(url);
93
+ const entry = match && this.webAwesomeIconLibraries.get(match[1]);
94
+ if (!match || !entry) {
95
+ return undefined;
96
+ }
97
+ let name;
98
+ try {
99
+ name = decodeURIComponent(match[2]);
100
+ } catch {
101
+ return undefined;
102
+ }
103
+ const svg = (await indexIconLibrary(entry.library, entry.config)).get(name);
104
+ return svg === undefined ? undefined : { url, svg };
105
+ }
106
+
107
+ async webAwesomeIconOutputs() {
108
+ const outputs = [];
109
+ for (const [segment, { library, config }] of this.webAwesomeIconLibraries) {
110
+ for (const [name, svg] of await indexIconLibrary(library, config)) {
111
+ outputs.push({
112
+ url: `${WEB_AWESOME_ICON_ASSET_PREFIX}${segment}/${name}.svg`,
113
+ svg,
114
+ });
115
+ }
116
+ }
117
+ return outputs;
69
118
  }
70
119
 
71
120
  /**
@@ -177,6 +226,7 @@ export function validateIconLibrariesConfig(iconLibraries) {
177
226
  * _iconLibraries?: Map<string, import('@rocket/js/types.js').NormalizedIconLibraryConfig>;
178
227
  * _defaultIconLibrary?: string;
179
228
  * _iconReferences?: import('@rocket/js/types.js').IconReferenceConfig[];
229
+ * _webAwesomeIconLibrary?: string;
180
230
  * _hydrationScript?: string;
181
231
  * _hasBrowserLoadedComponents?: boolean;
182
232
  * };
@@ -185,6 +235,15 @@ export function validateIconLibrariesConfig(iconLibraries) {
185
235
  * @returns {Promise<string>}
186
236
  */
187
237
  export async function finalizeRocketIcons(html, options = {}) {
238
+ const output = await finalizeRocketIconHostsAndManifest(html, options);
239
+ return finalizeWebAwesomeIcons(output, options);
240
+ }
241
+
242
+ /**
243
+ * @param {string} html
244
+ * @param {Parameters<typeof finalizeRocketIcons>[1] & {}} options
245
+ */
246
+ async function finalizeRocketIconHostsAndManifest(html, options) {
188
247
  const lowerHtml = html.toLowerCase();
189
248
  const hasIconHosts = lowerHtml.includes('<rocket-icon');
190
249
  const hasIconLoadingPolicy =
@@ -261,6 +320,85 @@ export async function finalizeRocketIcons(html, options = {}) {
261
320
  });
262
321
  }
263
322
 
323
+ /**
324
+ * Points Web Awesome's `default` icon library at the Page's Web Awesome Icon Library, so
325
+ * `wa-icon` elements created by browser code load self-hosted SVGs instead of a CDN.
326
+ *
327
+ * @param {string} html
328
+ * @param {Parameters<typeof finalizeRocketIcons>[1] & {}} options
329
+ */
330
+ async function finalizeWebAwesomeIcons(html, options) {
331
+ const library = options.pageData?._webAwesomeIconLibrary;
332
+ if (!library) {
333
+ return html;
334
+ }
335
+ const resolver = createIconResolver({
336
+ layoutIconLibraries: options.layoutIconLibraries || options.pageData?._iconLibraries,
337
+ layoutDefaultIconLibrary:
338
+ options.layoutDefaultIconLibrary || options.pageData?._defaultIconLibrary,
339
+ projectIconLibraries: options.iconLibraries,
340
+ projectDefaultIconLibrary: options.defaultIconLibrary,
341
+ });
342
+ const config = resolver.libraries.get(library);
343
+ if (!config) {
344
+ throw new Error(`Web Awesome Icon Library "${library}" is not configured.`);
345
+ }
346
+ options.iconAssetStore?.addWebAwesomeIconLibrary(library, config);
347
+
348
+ const iconBaseUrl = `${WEB_AWESOME_ICON_ASSET_PREFIX}${sanitizePathSegment(library)}/`;
349
+ const registrationHtml =
350
+ '<script type="module" data-rocket-wa-icon-library>' +
351
+ `import { registerIconLibrary } from '${resolve(WEB_AWESOME_ICON_LIBRARY_MODULE, import.meta)}';` +
352
+ `registerIconLibrary('default', { resolver: name => '${iconBaseUrl}' + encodeURIComponent(name) + '.svg' });` +
353
+ '</script>';
354
+ return insertWebAwesomeIconRegistration(html, registrationHtml);
355
+ }
356
+
357
+ /**
358
+ * Places the registration after every import map, because browsers ignore or restrict an import
359
+ * map that follows a module script. Otherwise it goes before the Page's first head script: module
360
+ * scripts run in document order, so it runs before component code. Scripts inside HTML comments
361
+ * are ignored.
362
+ *
363
+ * @param {string} html
364
+ * @param {string} insertion
365
+ */
366
+ function insertWebAwesomeIconRegistration(html, insertion) {
367
+ const scanHtml = html
368
+ .replace(/<!--[\s\S]*?(?:-->|$)/g, comment => ' '.repeat(comment.length))
369
+ .toLowerCase();
370
+ const headClose = scanHtml.indexOf('</head>');
371
+ /** @type {number[]} */
372
+ const scriptStarts = [];
373
+ let afterImportMaps = 0;
374
+ const scriptOpen = /<script(?=[\s>/])[^>]*>/g;
375
+ let match;
376
+ while ((match = scriptOpen.exec(scanHtml))) {
377
+ const close = scanHtml.indexOf('</script', scriptOpen.lastIndex);
378
+ const closeEnd = close === -1 ? -1 : scanHtml.indexOf('>', close);
379
+ const end = closeEnd === -1 ? scanHtml.length : closeEnd + 1;
380
+ if (/\btype\s*=\s*["']?importmap["'\s/>]/.test(match[0])) {
381
+ afterImportMaps = end;
382
+ } else {
383
+ scriptStarts.push(match.index);
384
+ }
385
+ scriptOpen.lastIndex = end;
386
+ }
387
+
388
+ const firstHeadScript = scriptStarts.find(
389
+ start => start >= afterImportMaps && (headClose === -1 || start < headClose),
390
+ );
391
+ let index;
392
+ if (firstHeadScript !== undefined) {
393
+ index = firstHeadScript;
394
+ } else if (headClose !== -1 && headClose >= afterImportMaps) {
395
+ index = headClose;
396
+ } else {
397
+ index = afterImportMaps;
398
+ }
399
+ return html.slice(0, index) + insertion + html.slice(index);
400
+ }
401
+
264
402
  /**
265
403
  * @param {unknown} iconLibraries
266
404
  * @param {string} owner
@@ -723,7 +861,11 @@ async function iconSourceFiles(source) {
723
861
  */
724
862
  function packageRoot(packageName) {
725
863
  try {
726
- return path.dirname(require.resolve(`${packageName}/package.json`, { paths: [process.cwd()] }));
864
+ return path.dirname(
865
+ require.resolve(`${packageName}/package.json`, {
866
+ paths: [process.cwd(), import.meta.dirname],
867
+ }),
868
+ );
727
869
  } catch (error) {
728
870
  throw new Error(`Could not resolve Icon package ${JSON.stringify(packageName)}.`, {
729
871
  cause: error,
@@ -53,9 +53,11 @@ export function renderBlogTags(tags, data) {
53
53
  ${tags.map(
54
54
  tag => html`
55
55
  <li>
56
- ${data.tagPathPrefix
57
- ? html`<a href=${blogTagPath(data.tagPathPrefix, tag)} rel="tag">${tag}</a>`
58
- : html`<span>${tag}</span>`}
56
+ ${
57
+ data.tagPathPrefix
58
+ ? html`<a href=${blogTagPath(data.tagPathPrefix, tag)} rel="tag">${tag}</a>`
59
+ : html`<span>${tag}</span>`
60
+ }
59
61
  </li>
60
62
  `,
61
63
  )}
@@ -84,9 +86,11 @@ export function renderBlogByline(metadata, data, language) {
84
86
  }
85
87
  return html`
86
88
  <div class="atlas-blog-byline">
87
- ${metadata.date
88
- ? html`<time datetime=${metadata.date}>${formatBlogDate(metadata.date, language)}</time>`
89
- : ''}
89
+ ${
90
+ metadata.date
91
+ ? html`<time datetime=${metadata.date}>${formatBlogDate(metadata.date, language)}</time>`
92
+ : ''
93
+ }
90
94
  ${authors.length ? html`<span class="atlas-blog-authors">${authors.join(', ')}</span>` : ''}
91
95
  ${renderBlogTags(metadata.tags, data)}
92
96
  </div>
@@ -108,11 +112,13 @@ export function renderBlogPostList(items, data, language) {
108
112
  item => html`
109
113
  <li class="atlas-blog-post-card">
110
114
  <h2><a href=${item.url}>${item.metadata.title}</a></h2>
111
- ${item.metadata.date
112
- ? html`<time datetime=${item.metadata.date}
113
- >${formatBlogDate(item.metadata.date, language)}</time
114
- >`
115
- : ''}
115
+ ${
116
+ item.metadata.date
117
+ ? html`<time datetime=${item.metadata.date}
118
+ >${formatBlogDate(item.metadata.date, language)}</time
119
+ >`
120
+ : ''
121
+ }
116
122
  ${item.metadata.description ? html`<p>${item.metadata.description}</p>` : ''}
117
123
  ${renderBlogTags(item.metadata.tags, data)}
118
124
  </li>
@@ -131,13 +137,17 @@ export function renderBlogPagination(pagination) {
131
137
  }
132
138
  return html`
133
139
  <nav class="atlas-blog-pagination" aria-label="Blog pages">
134
- ${pagination.previousPath
135
- ? html`<a href=${pagination.previousPath} rel="prev">Newer posts</a>`
136
- : html`<span></span>`}
140
+ ${
141
+ pagination.previousPath
142
+ ? html`<a href=${pagination.previousPath} rel="prev">Newer posts</a>`
143
+ : html`<span></span>`
144
+ }
137
145
  <span>Page ${pagination.currentPage} of ${pagination.totalPages}</span>
138
- ${pagination.nextPath
139
- ? html`<a href=${pagination.nextPath} rel="next">Older posts</a>`
140
- : html`<span></span>`}
146
+ ${
147
+ pagination.nextPath
148
+ ? html`<a href=${pagination.nextPath} rel="next">Older posts</a>`
149
+ : html`<span></span>`
150
+ }
141
151
  </nav>
142
152
  `;
143
153
  }
@@ -181,14 +191,16 @@ function atlasBlogDocument(pageData, data, mainContent) {
181
191
  />
182
192
  <link rel="stylesheet" href="${resolve('@rocket/js/layouts/atlasDoc.css', import.meta)}" />
183
193
  <link rel="stylesheet" href="${resolve('@rocket/js/layouts/atlasBlog.css', import.meta)}" />
184
- ${data.feedPath
185
- ? html`<link
186
- rel="alternate"
187
- type="application/atom+xml"
188
- href=${data.feedPath}
189
- title=${siteName}
190
- />`
191
- : ''}
194
+ ${
195
+ data.feedPath
196
+ ? html`<link
197
+ rel="alternate"
198
+ type="application/atom+xml"
199
+ href=${data.feedPath}
200
+ title=${siteName}
201
+ />`
202
+ : ''
203
+ }
192
204
  ${renderStylesheets(data.stylesheets)} ${headContent}
193
205
  `,
194
206
  },
@@ -220,12 +232,14 @@ export const atlasBlogIndexLayout = (pageData, data) => {
220
232
  <section class="atlas-blog-index">
221
233
  <div class="atlas-blog-intro">
222
234
  ${pageData.content}
223
- ${data.feedPath
224
- ? html`<a class="atlas-blog-feed-link" href=${data.feedPath}>
225
- <rocket-icon library="bootstrap" name="rss" aria-hidden="true"></rocket-icon>
226
- Feed
227
- </a>`
228
- : ''}
235
+ ${
236
+ data.feedPath
237
+ ? html`<a class="atlas-blog-feed-link" href=${data.feedPath}>
238
+ <rocket-icon library="bootstrap" name="rss" aria-hidden="true"></rocket-icon>
239
+ Feed
240
+ </a>`
241
+ : ''
242
+ }
229
243
  </div>
230
244
  ${renderBlogPostList(items, data, language)} ${renderBlogPagination(pageData.pagination)}
231
245
  </section>
@@ -245,22 +245,28 @@ export const atlasDocLayout = (pageData, data) => {
245
245
 
246
246
  <main id="content" class="atlas-content">${pageData.content}</main>
247
247
 
248
- ${pageNavigation.previous || pageNavigation.next
249
- ? html`<nav id="prev-next" slot="main-footer" class="atlas-prev-next" aria-label="Page">
250
- ${pageNavigation.previous
251
- ? html`<rocket-previous-page
252
- .pageTree=${pageData.pageTree}
253
- .currentPath=${pageData.url}
254
- ></rocket-previous-page>`
255
- : ''}
256
- ${pageNavigation.next
257
- ? html`<rocket-next-page
258
- .pageTree=${pageData.pageTree}
259
- .currentPath=${pageData.url}
260
- ></rocket-next-page>`
261
- : ''}
262
- </nav>`
263
- : ''}
248
+ ${
249
+ pageNavigation.previous || pageNavigation.next
250
+ ? html`<nav id="prev-next" slot="main-footer" class="atlas-prev-next" aria-label="Page">
251
+ ${
252
+ pageNavigation.previous
253
+ ? html`<rocket-previous-page
254
+ .pageTree=${pageData.pageTree}
255
+ .currentPath=${pageData.url}
256
+ ></rocket-previous-page>`
257
+ : ''
258
+ }
259
+ ${
260
+ pageNavigation.next
261
+ ? html`<rocket-next-page
262
+ .pageTree=${pageData.pageTree}
263
+ .currentPath=${pageData.url}
264
+ ></rocket-next-page>`
265
+ : ''
266
+ }
267
+ </nav>`
268
+ : ''
269
+ }
264
270
 
265
271
  <aside slot="aside" class="atlas-toc">
266
272
  <rocket-toc toc=${serializedToc}></rocket-toc>
@@ -69,16 +69,18 @@ function renderTrustBadges(badges) {
69
69
 
70
70
  return html`
71
71
  <li>
72
- ${href && icon
73
- ? html`
74
- <rocket-social-link
75
- url=${href}
76
- name=${icon}
77
- label=${text}
78
- aria-label=${text}
79
- ></rocket-social-link>
80
- `
81
- : html`<span class="trust-badge-text">${text}</span>`}
72
+ ${
73
+ href && icon
74
+ ? html`
75
+ <rocket-social-link
76
+ url=${href}
77
+ name=${icon}
78
+ label=${text}
79
+ aria-label=${text}
80
+ ></rocket-social-link>
81
+ `
82
+ : html`<span class="trust-badge-text">${text}</span>`
83
+ }
82
84
  </li>
83
85
  `;
84
86
  })}
@@ -142,13 +144,15 @@ function renderWhyCard(card) {
142
144
  <h3>${card.title}</h3>
143
145
  <p>${card.description}</p>
144
146
  </div>
145
- ${card.tags?.length
146
- ? html`
147
- <ul class="tag-list" aria-label="${card.title} tags">
148
- ${card.tags.map(tag => html`<li>${tag}</li>`)}
149
- </ul>
150
- `
151
- : html``}
147
+ ${
148
+ card.tags?.length
149
+ ? html`
150
+ <ul class="tag-list" aria-label="${card.title} tags">
151
+ ${card.tags.map(tag => html`<li>${tag}</li>`)}
152
+ </ul>
153
+ `
154
+ : html``
155
+ }
152
156
  </article>
153
157
  `;
154
158
  }
@@ -303,25 +307,29 @@ export const atlasHeroLayout = (pageData, data) => {
303
307
  ${renderInstallPill(hero)} ${renderTrustBadges(hero.badges ?? [])}
304
308
  </div>
305
309
 
306
- ${hero.logoNoText
307
- ? html`
308
- <div class="hero-art" aria-hidden="true">
309
- <div class="rocket-visual">
310
- <span class="spark spark-one"></span>
311
- <span class="spark spark-two"></span>
312
- <span class="spark spark-three"></span>
313
- <img src=${hero.logoNoText} alt="" width="370" />
310
+ ${
311
+ hero.logoNoText
312
+ ? html`
313
+ <div class="hero-art" aria-hidden="true">
314
+ <div class="rocket-visual">
315
+ <span class="spark spark-one"></span>
316
+ <span class="spark spark-two"></span>
317
+ <span class="spark spark-three"></span>
318
+ <img src=${hero.logoNoText} alt="" width="370" />
319
+ </div>
314
320
  </div>
315
- </div>
316
- `
317
- : html``}
321
+ `
322
+ : html``
323
+ }
318
324
  </section>
319
325
  <div class="home-content">${pageData.content}</div>
320
326
  ${renderWhyRocket(data.whyRocketData)}
321
327
  ${renderHomeColumns(data.quickStartData, data.workflowData)}
322
- ${data.featuresData?.length
323
- ? html`<rocket-feature-list .features=${data.featuresData}></rocket-feature-list>`
324
- : html``}
328
+ ${
329
+ data.featuresData?.length
330
+ ? html`<rocket-feature-list .features=${data.featuresData}></rocket-feature-list>`
331
+ : html``
332
+ }
325
333
  </main>
326
334
  <rocket-footer .data=${data.footerData}></rocket-footer>
327
335
  `,
@@ -40,9 +40,11 @@ export const atlasNotFoundLayout = (pageData, data) => {
40
40
  <div class="atlas-not-found-stars"></div>
41
41
  <div class="atlas-not-found-orbit"></div>
42
42
  <p class="atlas-not-found-code">404</p>
43
- ${rocketLogo
44
- ? html`<img class="atlas-not-found-rocket" src=${rocketLogo} alt="" />`
45
- : html``}
43
+ ${
44
+ rocketLogo
45
+ ? html`<img class="atlas-not-found-rocket" src=${rocketLogo} alt="" />`
46
+ : html``
47
+ }
46
48
  </div>
47
49
  </main>
48
50
  </div>
@@ -30,23 +30,27 @@ export function document(
30
30
  <meta name="viewport" content="width=device-width, initial-scale=1" />
31
31
  <title>${title}</title>
32
32
  ${siteHeadMetadataTemplate(siteHeadMetadata)}
33
- ${menu
34
- ? html`<style>
35
- body {
36
- display: flex;
37
- }
38
- #menu {
39
- margin-right: 1em;
40
- }
41
- </style>`
42
- : ''}
33
+ ${
34
+ menu
35
+ ? html`<style>
36
+ body {
37
+ display: flex;
38
+ }
39
+ #menu {
40
+ margin-right: 1em;
41
+ }
42
+ </style>`
43
+ : ''
44
+ }
43
45
  ${data.clientCode} ${headContent}
44
46
  </head>
45
47
  <body>
46
- ${menu
47
- ? html`<nav id="menu" aria-label="Site">${defaultHtmlMenu(data.pageTree)}</nav>
48
- <main id="content">${content}</main>`
49
- : content}
48
+ ${
49
+ menu
50
+ ? html`<nav id="menu" aria-label="Site">${defaultHtmlMenu(data.pageTree)}</nav>
51
+ <main id="content">${content}</main>`
52
+ : content
53
+ }
50
54
  </body>
51
55
  </html>`;
52
56
  }
@@ -63,21 +67,27 @@ function siteHeadMetadataTemplate(metadata) {
63
67
  ${metadata.indexing === 'noindex' ? html`<meta name="robots" content="noindex" />` : ''}
64
68
  <link rel="canonical" href=${metadata.canonicalUrl} />
65
69
  ${metadata.icons?.ico ? html`<link rel="icon" href=${metadata.icons.ico} sizes="any" />` : ''}
66
- ${metadata.icons?.svg
67
- ? html`<link rel="icon" href=${metadata.icons.svg} type="image/svg+xml" />`
68
- : ''}
69
- ${metadata.icons?.appleTouchIcon
70
- ? html`<link rel="apple-touch-icon" href=${metadata.icons.appleTouchIcon} />`
71
- : ''}
70
+ ${
71
+ metadata.icons?.svg
72
+ ? html`<link rel="icon" href=${metadata.icons.svg} type="image/svg+xml" />`
73
+ : ''
74
+ }
75
+ ${
76
+ metadata.icons?.appleTouchIcon
77
+ ? html`<link rel="apple-touch-icon" href=${metadata.icons.appleTouchIcon} />`
78
+ : ''
79
+ }
72
80
  ${metadata.themeColor ? html`<meta name="theme-color" content=${metadata.themeColor} />` : ''}
73
81
  <meta property="og:site_name" content=${metadata.siteName} />
74
82
  <meta property="og:title" content=${metadata.title} />
75
83
  <meta property="og:description" content=${metadata.description} />
76
84
  <meta property="og:url" content=${metadata.canonicalUrl} />
77
85
  <meta property="og:type" content="website" />
78
- ${metadata.socialPreview?.image
79
- ? html`<meta property="og:image" content=${metadata.socialPreview.image} />`
80
- : ''}
86
+ ${
87
+ metadata.socialPreview?.image
88
+ ? html`<meta property="og:image" content=${metadata.socialPreview.image} />`
89
+ : ''
90
+ }
81
91
  <meta
82
92
  name="twitter:card"
83
93
  content=${metadata.socialPreview?.image ? 'summary_large_image' : 'summary'}
@@ -85,8 +95,10 @@ function siteHeadMetadataTemplate(metadata) {
85
95
  <meta name="twitter:title" content=${metadata.title} />
86
96
  <meta name="twitter:description" content=${metadata.description} />
87
97
  <meta name="twitter:url" content=${metadata.canonicalUrl} />
88
- ${metadata.socialPreview?.image
89
- ? html`<meta name="twitter:image" content=${metadata.socialPreview.image} />`
90
- : ''}
98
+ ${
99
+ metadata.socialPreview?.image
100
+ ? html`<meta name="twitter:image" content=${metadata.socialPreview.image} />`
101
+ : ''
102
+ }
91
103
  `;
92
104
  }
package/src/main.js CHANGED
@@ -5,6 +5,8 @@ import customRocketPlugin from './wds-plugin.js';
5
5
  import { MessageChannel } from 'node:worker_threads';
6
6
  import { customElements } from '@lit-labs/ssr-dom-shim';
7
7
  import { readConfig } from './config.js';
8
+ import { preferProjectPackagesPlugin } from './prefer-project-packages-plugin.js';
9
+ import { getPages } from './pages.js';
8
10
 
9
11
  const configFilePath = process.argv[2] || undefined;
10
12
  const startOptions = readStartOptions(process.argv[3]);
@@ -40,6 +42,7 @@ let devServerConfig = {
40
42
  defaultIconLibrary: config.defaultIconLibrary,
41
43
  watch: startOptions.watch,
42
44
  }),
45
+ preferProjectPackagesPlugin(),
43
46
  ],
44
47
  open: startOptions.open ?? true,
45
48
  nodeResolve: { exportConditions: ['browser'] },
@@ -47,6 +50,20 @@ let devServerConfig = {
47
50
  port: startOptions.port ?? 8888,
48
51
  };
49
52
 
53
+ if (config.adapter?.adjustDevServerConfig) {
54
+ try {
55
+ devServerConfig = await config.adapter.adjustDevServerConfig(devServerConfig, {
56
+ pages: await getPages(process.cwd(), config.includeGlobs, config.excludeRegex),
57
+ projectRoot: process.cwd(),
58
+ config,
59
+ });
60
+ } catch (error) {
61
+ // Adapter startup checks are author-facing, so show the message like the CLI does.
62
+ // eslint-disable-next-line no-console
63
+ console.error(error instanceof Error && !process.env.ROCKET_DEBUG ? error.message : error);
64
+ process.exit(1);
65
+ }
66
+ }
50
67
  devServerConfig = config.adjustDevServerConfig(devServerConfig);
51
68
 
52
69
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -237,7 +237,11 @@ function extractDemoNames() {
237
237
  const node = /** @type {import('mdast').Code} */ (_node);
238
238
  if (isDemoCodeNode(node) && typeof node.value === 'string') {
239
239
  for (const exported of parseExports(node.value)[1]) {
240
- demoNames.push(exported.ln || exported.n);
240
+ if (exported.type === 'direct') {
241
+ demoNames.push(exported.localName || exported.name);
242
+ } else if (exported.type === 'reexport') {
243
+ demoNames.push(exported.name);
244
+ }
241
245
  }
242
246
  }
243
247
  };
@@ -39,19 +39,23 @@ export class MainMenu extends LitElement {
39
39
  classes[level] = true;
40
40
  return html`
41
41
  <li>
42
- ${page.menuNoLink
43
- ? html`<span class=${classMap(classes)}>${title}</span>`
44
- : html`<a
45
- href=${ifDefined(page.url)}
46
- class=${classMap(classes)}
47
- aria-current=${ifDefined(isCurrent ? 'page' : undefined)}
48
- >${title}</a
49
- >`}
50
- ${page.children.length > 0
51
- ? html`<ul>
52
- ${page.children.map(child => this.list(child, depth + 1))}
53
- </ul>`
54
- : ''}
42
+ ${
43
+ page.menuNoLink
44
+ ? html`<span class=${classMap(classes)}>${title}</span>`
45
+ : html`<a
46
+ href=${ifDefined(page.url)}
47
+ class=${classMap(classes)}
48
+ aria-current=${ifDefined(isCurrent ? 'page' : undefined)}
49
+ >${title}</a
50
+ >`
51
+ }
52
+ ${
53
+ page.children.length > 0
54
+ ? html`<ul>
55
+ ${page.children.map(child => this.list(child, depth + 1))}
56
+ </ul>`
57
+ : ''
58
+ }
55
59
  </li>
56
60
  `;
57
61
  }