@rocket/js 0.1.1 → 0.2.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 (107) hide show
  1. package/README.md +14 -23
  2. package/dist-types/exports/layouts/atlasBlog.d.ts +2 -0
  3. package/dist-types/exports/layouts/atlasBlog.d.ts.map +1 -0
  4. package/dist-types/exports/types/rocket.d.ts +68 -2
  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 +3 -1
  9. package/dist-types/src/PageData.d.ts.map +1 -1
  10. package/dist-types/src/RocketJsDemo.d.ts.map +1 -1
  11. package/dist-types/src/SocialPreviewPlayground.d.ts +1 -0
  12. package/dist-types/src/SocialPreviewPlayground.d.ts.map +1 -1
  13. package/dist-types/src/asyncMessage.d.ts +5 -0
  14. package/dist-types/src/asyncMessage.d.ts.map +1 -1
  15. package/dist-types/src/cli/RocketBuild.d.ts.map +1 -1
  16. package/dist-types/src/cli/RocketCli.d.ts.map +1 -1
  17. package/dist-types/src/cli/RocketInit.d.ts +5 -1
  18. package/dist-types/src/cli/RocketInit.d.ts.map +1 -1
  19. package/dist-types/src/cli/RocketStart.d.ts +6 -1
  20. package/dist-types/src/cli/RocketStart.d.ts.map +1 -1
  21. package/dist-types/src/component-hydration.d.ts.map +1 -1
  22. package/dist-types/src/components/RocketDrawer.d.ts +8 -0
  23. package/dist-types/src/components/RocketDrawer.d.ts.map +1 -1
  24. package/dist-types/src/components/RocketSocialLink.d.ts.map +1 -1
  25. package/dist-types/src/config.d.ts.map +1 -1
  26. package/dist-types/src/feeds.d.ts +38 -0
  27. package/dist-types/src/feeds.d.ts.map +1 -0
  28. package/dist-types/src/hydration/hydrationLoader.d.ts +13 -4
  29. package/dist-types/src/hydration/hydrationLoader.d.ts.map +1 -1
  30. package/dist-types/src/icons.d.ts.map +1 -1
  31. package/dist-types/src/layouts/atlas/atlasBlogLayout.d.ts +42 -0
  32. package/dist-types/src/layouts/atlas/atlasBlogLayout.d.ts.map +1 -0
  33. package/dist-types/src/layouts/atlas/atlasDocLayout.d.ts +4 -0
  34. package/dist-types/src/layouts/atlas/atlasDocLayout.d.ts.map +1 -1
  35. package/dist-types/src/layouts/atlas/atlasHeroLayout.d.ts.map +1 -1
  36. package/dist-types/src/layouts/atlas/atlasNotFoundLayout.d.ts.map +1 -1
  37. package/dist-types/src/layouts/layout-helper.d.ts +3 -3
  38. package/dist-types/src/layouts/layout-helper.d.ts.map +1 -1
  39. package/dist-types/src/markdownHook.d.ts.map +1 -1
  40. package/dist-types/src/menu.d.ts +8 -3
  41. package/dist-types/src/menu.d.ts.map +1 -1
  42. package/dist-types/src/menus/MainMenu.d.ts.map +1 -1
  43. package/dist-types/src/{development-page-module-loader.d.ts → page-module-loader.d.ts} +7 -2
  44. package/dist-types/src/page-module-loader.d.ts.map +1 -0
  45. package/dist-types/src/page-runtime.d.ts +11 -0
  46. package/dist-types/src/page-runtime.d.ts.map +1 -1
  47. package/dist-types/src/pages.d.ts.map +1 -1
  48. package/dist-types/src/route-pattern.d.ts +10 -0
  49. package/dist-types/src/route-pattern.d.ts.map +1 -0
  50. package/dist-types/src/siteDiscoverability.d.ts +4 -0
  51. package/dist-types/src/siteDiscoverability.d.ts.map +1 -1
  52. package/dist-types/src/socialPreviewImages.d.ts +2 -1
  53. package/dist-types/src/socialPreviewImages.d.ts.map +1 -1
  54. package/dist-types/src/static-params.d.ts +33 -0
  55. package/dist-types/src/static-params.d.ts.map +1 -0
  56. package/dist-types/src/transform.d.ts +4 -0
  57. package/dist-types/src/transform.d.ts.map +1 -1
  58. package/dist-types/src/wds-plugin.d.ts.map +1 -1
  59. package/exports/layouts/atlasBlog.js +11 -0
  60. package/exports/types/rocket.test.ts +26 -0
  61. package/exports/types/rocket.ts +78 -2
  62. package/exports/types.ts +7 -0
  63. package/package.json +16 -32
  64. package/src/PageData.js +12 -2
  65. package/src/RocketJsDemo.js +1 -0
  66. package/src/SocialPreviewPlayground.js +26 -20
  67. package/src/asyncMessage.js +8 -2
  68. package/src/cli/RocketBuild.js +110 -13
  69. package/src/cli/RocketCli.js +11 -1
  70. package/src/cli/RocketInit.js +64 -12
  71. package/src/cli/RocketStart.js +60 -16
  72. package/src/cli/cli.js +10 -1
  73. package/src/component-hydration.js +23 -3
  74. package/src/components/RocketDrawer.js +44 -10
  75. package/src/components/RocketSocialLink.js +26 -2
  76. package/src/config.js +33 -4
  77. package/src/feeds.js +212 -0
  78. package/src/hydration/hydrationLoader.js +80 -48
  79. package/src/icons.js +5 -0
  80. package/src/layouts/atlas/atlasBlog.css +143 -0
  81. package/src/layouts/atlas/atlasBlogLayout.js +234 -0
  82. package/src/layouts/atlas/atlasDocLayout.js +10 -1
  83. package/src/layouts/atlas/atlasHeroLayout.js +10 -6
  84. package/src/layouts/atlas/atlasNotFoundLayout.js +12 -22
  85. package/src/layouts/layout-helper.js +5 -5
  86. package/src/layouts/layout.js +2 -2
  87. package/src/loaded-page-module.js +3 -1
  88. package/src/markdownCompiler.js +2 -2
  89. package/src/markdownHook.js +7 -2
  90. package/src/menu.js +25 -19
  91. package/src/menus/MainMenu.js +10 -4
  92. package/src/{static-page-module-loader.js → page-module-loader.js} +6 -1
  93. package/src/page-pagination.js +2 -2
  94. package/src/page-runtime.js +48 -3
  95. package/src/pages.js +47 -56
  96. package/src/publicAssets.js +2 -2
  97. package/src/route-pattern.js +21 -0
  98. package/src/siteDiscoverability.js +14 -1
  99. package/src/socialPreviewImages.js +80 -14
  100. package/src/standalone-demo-url.js +2 -2
  101. package/src/static-params.js +114 -0
  102. package/src/transform.js +89 -22
  103. package/src/wds-plugin.js +16 -3
  104. package/dist-types/src/development-page-module-loader.d.ts.map +0 -1
  105. package/dist-types/src/static-page-module-loader.d.ts +0 -15
  106. package/dist-types/src/static-page-module-loader.d.ts.map +0 -1
  107. package/src/development-page-module-loader.js +0 -29
@@ -0,0 +1,114 @@
1
+ import { PageData } from './PageData.js';
2
+
3
+ /** @typedef {import('@rocket/js/types.js').Page} Page */
4
+ /** @typedef {import('@rocket/js/types.js').PageRegistry} PageRegistry */
5
+ /** @typedef {import('@rocket/js/types.js').PageStaticParams} PageStaticParams */
6
+ /** @typedef {import('@rocket/js/types.js').PageStaticParamsDeclaration} PageStaticParamsDeclaration */
7
+
8
+ /**
9
+ * @param {Page} page
10
+ */
11
+ export function hasStaticParams(page) {
12
+ return page.file.endsWith('.js') && page.module.staticParams !== undefined;
13
+ }
14
+
15
+ /**
16
+ * @param {string} pagePath
17
+ */
18
+ export function hasPathParameter(pagePath) {
19
+ return /(^|\/):[^/]+/.test(pagePath);
20
+ }
21
+
22
+ /**
23
+ * Enumerates the concrete output paths of a parameterized static JavaScript
24
+ * Page from its `staticParams` export.
25
+ *
26
+ * @param {{
27
+ * pages: PageRegistry;
28
+ * page: Page;
29
+ * pagePath: string;
30
+ * }} options
31
+ * @returns {string[]}
32
+ */
33
+ export function staticParamsPagePaths({ pages, page, pagePath }) {
34
+ if (!hasPathParameter(pagePath)) {
35
+ throw new Error(
36
+ `Static params for ${page.file} require a parameterized Page path, ` +
37
+ `but its path ${pagePath} has no route params.`,
38
+ );
39
+ }
40
+ const declaration = /** @type {PageStaticParamsDeclaration} */ (page.module.staticParams);
41
+ const paramsList =
42
+ typeof declaration === 'function'
43
+ ? declaration(new PageData(pages, page.metadata, pagePath))
44
+ : declaration;
45
+ if (!Array.isArray(paramsList)) {
46
+ throw new Error(`Static params for ${page.file} must be an array of route param objects.`);
47
+ }
48
+ const paths = [];
49
+ const seen = new Set();
50
+ for (const params of paramsList) {
51
+ const concretePath = substituteRouteParams(pagePath, params, page);
52
+ if (seen.has(concretePath)) {
53
+ throw new Error(
54
+ `Static params for ${page.file} produce the duplicate output path ${concretePath}.`,
55
+ );
56
+ }
57
+ seen.add(concretePath);
58
+ paths.push(concretePath);
59
+ }
60
+ return paths;
61
+ }
62
+
63
+ /**
64
+ * @param {string} pagePath
65
+ * @param {unknown} params
66
+ * @param {Page} page
67
+ * @returns {string}
68
+ */
69
+ function substituteRouteParams(pagePath, params, page) {
70
+ if (typeof params !== 'object' || params === null || Array.isArray(params)) {
71
+ throw new Error(`Static params for ${page.file} must be objects with string values.`);
72
+ }
73
+ const paramValues = /** @type {Record<string, unknown>} */ (params);
74
+ const usedNames = new Set();
75
+ const segments = pagePath.split('/').map(segment => {
76
+ if (!segment.startsWith(':')) {
77
+ return segment;
78
+ }
79
+ const name = segment.slice(1);
80
+ usedNames.add(name);
81
+ return routeParamValue(name, paramValues[name], page);
82
+ });
83
+ for (const name of Object.keys(paramValues)) {
84
+ if (!usedNames.has(name)) {
85
+ throw new Error(
86
+ `Static params for ${page.file} set unknown route param "${name}" ` +
87
+ `for the Page path ${pagePath}.`,
88
+ );
89
+ }
90
+ }
91
+ return segments.join('/');
92
+ }
93
+
94
+ /**
95
+ * @param {string} name
96
+ * @param {unknown} value
97
+ * @param {Page} page
98
+ * @returns {string}
99
+ */
100
+ function routeParamValue(name, value, page) {
101
+ if (typeof value !== 'string' || value === '') {
102
+ throw new Error(
103
+ `Static params for ${page.file} must provide a non-empty string ` +
104
+ `for route param "${name}".`,
105
+ );
106
+ }
107
+ if (encodeURIComponent(value) !== value) {
108
+ throw new Error(
109
+ `Static params for ${page.file} route param "${name}" value ${JSON.stringify(value)} ` +
110
+ `is not a URL-safe path segment. Slugify param values before returning them.`,
111
+ );
112
+ }
113
+ return value;
114
+ }
package/src/transform.js CHANGED
@@ -90,10 +90,7 @@ export async function mdToJsSingleDemo(md, demo) {
90
90
 
91
91
  const code = /** @type {{client: string; server: string}} */ (result.data.code);
92
92
 
93
- let litImport = "import { html } from 'lit'";
94
- if (/import\s*?{(?:\n|.)*?html(\n|.)*}.*/m.test(code.server)) {
95
- litImport = '';
96
- }
93
+ const litImport = hasTopLevelHtmlBinding(code.server) ? '' : "import { html } from 'lit'";
97
94
  const moduleCode = `
98
95
  import {render} from '@lit-labs/ssr';
99
96
  ${litImport}
@@ -119,11 +116,10 @@ export function contentFn(data, layout) {
119
116
  * @returns {Promise<string>}
120
117
  */
121
118
  async function makeJsFile(serverCode, clientCode, markdown, headlines) {
122
- let litImport = "import { html } from 'lit'";
123
119
  const normalizedServerCode = normalizeLayoutExportBindings(serverCode);
124
- if (/import\s*?{(?:\n|.)*?html(\n|.)*}.*/m.test(normalizedServerCode)) {
125
- litImport = '';
126
- }
120
+ const litImport = hasTopLevelHtmlBinding(normalizedServerCode)
121
+ ? ''
122
+ : "import { html } from 'lit'";
127
123
  return `
128
124
  import {render} from '@lit-labs/ssr';
129
125
  ${litImport}
@@ -145,6 +141,56 @@ export function contentFn(data, defaultLayout) {
145
141
  }`;
146
142
  }
147
143
 
144
+ /**
145
+ * The generated Markdown module wraps the page content in a lit `html` template, so it must inject
146
+ * `import { html } from 'lit'` unless the Page's server code already provides a top-level `html`
147
+ * binding (an import binding or a top-level declaration).
148
+ *
149
+ * @param {string} code
150
+ * @returns {boolean}
151
+ */
152
+ function hasTopLevelHtmlBinding(code) {
153
+ if (typeof code !== 'string' || code === '') {
154
+ return false;
155
+ }
156
+ const sourceFile = ts.createSourceFile(
157
+ 'page-server.js',
158
+ code,
159
+ ts.ScriptTarget.Latest,
160
+ true,
161
+ ts.ScriptKind.JS,
162
+ );
163
+ for (const statement of sourceFile.statements) {
164
+ if (ts.isImportDeclaration(statement) && statement.importClause) {
165
+ const { name, namedBindings } = statement.importClause;
166
+ if (name?.text === 'html') {
167
+ return true;
168
+ }
169
+ if (namedBindings) {
170
+ if (ts.isNamespaceImport(namedBindings)) {
171
+ if (namedBindings.name.text === 'html') {
172
+ return true;
173
+ }
174
+ } else if (namedBindings.elements.some(element => element.name.text === 'html')) {
175
+ return true;
176
+ }
177
+ }
178
+ } else if (ts.isVariableStatement(statement)) {
179
+ for (const declaration of statement.declarationList.declarations) {
180
+ if (ts.isIdentifier(declaration.name) && declaration.name.text === 'html') {
181
+ return true;
182
+ }
183
+ }
184
+ } else if (
185
+ (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) &&
186
+ statement.name?.text === 'html'
187
+ ) {
188
+ return true;
189
+ }
190
+ }
191
+ return false;
192
+ }
193
+
148
194
  /**
149
195
  * Direct ESM re-exports do not create local bindings, but the generated Markdown module calls the
150
196
  * selected layout from inside contentFn. Rewriting only direct `layout` re-exports keeps the public
@@ -242,8 +288,7 @@ function parseDemos() {
242
288
  codePreview.visited = true;
243
289
  codePreview.meta = demoCodeBlockMeta(node.meta);
244
290
  const code = node.value;
245
- const parsed = parseExports(code);
246
- const name = parsed[1][0].ln || parsed[1][0].n;
291
+ const name = demoExportName(code);
247
292
  // we transform a code node into a root node, so cast
248
293
  const rootNode = /** @type {import('mdast').Root} */ (/** @type {unknown} */ (node));
249
294
  rootNode.type = 'root';
@@ -357,10 +402,26 @@ function isRequestDemoCodeNode(node) {
357
402
  /**
358
403
  * @param {import('mdast').Code} node
359
404
  */
360
- function isDemoCodeNode(node) {
405
+ export function isDemoCodeNode(node) {
361
406
  return node.lang === 'js' && /(?:^|\s)demo(?:\s|$)/.test(node.meta || '');
362
407
  }
363
408
 
409
+ /**
410
+ * @param {string} code
411
+ * @returns {string}
412
+ */
413
+ function demoExportName(code) {
414
+ const [, moduleExports] = parseExports(code);
415
+ const name = moduleExports[0] && (moduleExports[0].ln || moduleExports[0].n);
416
+ if (!name) {
417
+ throw new Error(
418
+ 'A ```js demo code block must export the demo function, ' +
419
+ 'e.g. "export const myDemo = () => html`...`".',
420
+ );
421
+ }
422
+ return name;
423
+ }
424
+
364
425
  /**
365
426
  * @param {string | null | undefined} meta
366
427
  */
@@ -400,8 +461,7 @@ function extractSingleDemo(demoName) {
400
461
  codePreview.visited = true;
401
462
  codePreview.meta = demoCodeBlockMeta(node.meta);
402
463
  const code = node.value;
403
- const parsed = parseExports(code);
404
- const name = parsed[1][0].ln || parsed[1][0].n;
464
+ const name = demoExportName(code);
405
465
  if (name !== demoName) {
406
466
  return;
407
467
  }
@@ -596,17 +656,24 @@ function readStringProperty(value) {
596
656
  */
597
657
  function escapeOutsideTemplates(string) {
598
658
  let result = '';
599
- let templateLevels = 0;
659
+ let braceDepth = 0;
600
660
  for (let i = 0; i < string.length; i++) {
601
- if (string[i] === '$' && string[i + 1] === '{' && string[i - 1] !== '\\') {
602
- templateLevels++;
603
- } else if (templateLevels && string[i] === '}') {
604
- templateLevels--;
605
- }
606
- if (templateLevels) {
607
- result += string[i];
608
- } else {
661
+ if (braceDepth === 0) {
662
+ if (string[i] === '$' && string[i + 1] === '{' && string[i - 1] !== '\\') {
663
+ braceDepth = 1;
664
+ result += '${';
665
+ i++;
666
+ continue;
667
+ }
609
668
  result += string[i].replace('\\', '\\\\').replace('`', '\\`');
669
+ } else {
670
+ // Track nested braces so expressions like `${ fn({ a: 1 }) }` stay intact.
671
+ if (string[i] === '{') {
672
+ braceDepth++;
673
+ } else if (string[i] === '}') {
674
+ braceDepth--;
675
+ }
676
+ result += string[i];
610
677
  }
611
678
  }
612
679
 
package/src/wds-plugin.js CHANGED
@@ -6,7 +6,8 @@ import fs from 'node:fs';
6
6
  import { debounce } from './debounce.js';
7
7
  import path from 'node:path';
8
8
  import { createIconAssetStore, rocketIconRuntimeOutputs } from './icons.js';
9
- import { createDevelopmentPageModuleLoader } from './development-page-module-loader.js';
9
+ import { createPageModuleLoader } from './page-module-loader.js';
10
+ import { matchPageFeedPath } from './feeds.js';
10
11
  import { PageRuntime, PageRuntimeError } from './page-runtime.js';
11
12
  import {
12
13
  PUBLIC_ASSETS_DIR,
@@ -23,6 +24,9 @@ let pageRegistry = new Map();
23
24
  /** @type {Map<string, Set<string>>} */
24
25
  let modules = new Map();
25
26
 
27
+ /** @type {import('./publicAssets.js').PublicAsset[] | null} */
28
+ let cachedPublicAssets = null;
29
+
26
30
  /** @typedef {import('@rocket/js/types.js').UrlLifecycleConfig} UrlLifecycleConfig */
27
31
  /** @typedef {{ urlLifecycle?: UrlLifecycleConfig; siteHeadMetadata?: import('@rocket/js/types.js').SiteHeadMetadataConfig; siteOrigin?: string; siteDiscoverability?: import('@rocket/js/types.js').SiteDiscoverabilityConfig; iconLibraries?: import('@rocket/js/types.js').IconLibrariesConfig; defaultIconLibrary?: string; captureSocialPreviewImage?: import('./socialPreviewImages.js').SocialPreviewCapture; watch?: boolean }} RocketDevServerPluginOptions */
28
32
  /** @typedef {RocketDevServerPluginOptions | UrlLifecycleConfig} RocketDevServerPluginInput */
@@ -84,6 +88,10 @@ export default (include, exclude, resolverPort, options = {}) => {
84
88
  const publicDir = path.join(process.cwd(), PUBLIC_ASSETS_DIR);
85
89
  if (watchEnabled && fs.existsSync(publicDir)) {
86
90
  fileWatcher?.add(publicDir);
91
+ // re-discover and re-validate Public Assets on the next request
92
+ fileWatcher?.on?.('all', () => {
93
+ cachedPublicAssets = null;
94
+ });
87
95
  }
88
96
  },
89
97
  serverStop() {
@@ -128,7 +136,7 @@ export default (include, exclude, resolverPort, options = {}) => {
128
136
  type: 'image/svg+xml',
129
137
  };
130
138
  }
131
- const publicAssets = validateDevelopmentPublicAssets(pluginOptions);
139
+ const publicAssets = cachedPublicAssets ?? validateDevelopmentPublicAssets(pluginOptions);
132
140
  const publicAsset = findPublicAsset(publicAssets, context.path);
133
141
  if (publicAsset) {
134
142
  return /** @type {any} */ ({
@@ -151,6 +159,10 @@ export default (include, exclude, resolverPort, options = {}) => {
151
159
  } else if (context.header.accept === '*/*') {
152
160
  isPage = false;
153
161
  }
162
+ // Feed readers fetch Page Feeds without document Accept headers.
163
+ if (!isPage && matchPageFeedPath(context.path, pageRegistry)) {
164
+ isPage = true;
165
+ }
154
166
  if (!isPage) {
155
167
  const pathname = new URLPattern().exec(context.header.referer)?.pathname.input;
156
168
  if (!pathname) {
@@ -196,6 +208,7 @@ function validateDevelopmentPublicAssets(pluginOptions) {
196
208
  }),
197
209
  emitRedirectFallbacks: false,
198
210
  });
211
+ cachedPublicAssets = publicAssets;
199
212
  return publicAssets;
200
213
  }
201
214
 
@@ -222,7 +235,7 @@ async function renderPageRuntime(
222
235
  ) {
223
236
  const pageRuntime = new PageRuntime({
224
237
  pages: pageRegistry,
225
- pageModuleLoader: createDevelopmentPageModuleLoader(),
238
+ pageModuleLoader: createPageModuleLoader(),
226
239
  urlLifecycle,
227
240
  siteHeadMetadata,
228
241
  siteOrigin,
@@ -1 +0,0 @@
1
- {"version":3,"file":"development-page-module-loader.d.ts","sourceRoot":"","sources":["../../src/development-page-module-loader.js"],"names":[],"mappings":"AAGA,6FAA6F;AAE7F;IAEI;;OAEG;4BADQ,uBAAuB;;;;;;;EAoBrC;sCAzBa,OAAO,mBAAmB,EAAE,uBAAuB"}
@@ -1,15 +0,0 @@
1
- /** @typedef {import('./page-runtime.js').PageModuleLoaderOptions} PageModuleLoaderOptions */
2
- export function createStaticPageModuleLoader(): {
3
- /**
4
- * @param {PageModuleLoaderOptions} options
5
- */
6
- load({ page, variant }: PageModuleLoaderOptions): Promise<{
7
- kind: "markdown";
8
- contentFn: unknown;
9
- } | {
10
- kind: "javascript";
11
- body: unknown;
12
- }>;
13
- };
14
- export type PageModuleLoaderOptions = import("./page-runtime.js").PageModuleLoaderOptions;
15
- //# sourceMappingURL=static-page-module-loader.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"static-page-module-loader.d.ts","sourceRoot":"","sources":["../../src/static-page-module-loader.js"],"names":[],"mappings":"AAGA,6FAA6F;AAE7F;IAEI;;OAEG;4BADQ,uBAAuB;;;;;;;EAoBrC;sCAzBa,OAAO,mBAAmB,EAAE,uBAAuB"}
@@ -1,29 +0,0 @@
1
- import { normalizeLoadedPageModule } from './loaded-page-module.js';
2
- import { parseComponents } from './components.js';
3
-
4
- /** @typedef {import('./page-runtime.js').PageModuleLoaderOptions} PageModuleLoaderOptions */
5
-
6
- export function createDevelopmentPageModuleLoader() {
7
- return {
8
- /**
9
- * @param {PageModuleLoaderOptions} options
10
- */
11
- async load({ page, variant }) {
12
- if (!page.file.endsWith('.js')) {
13
- const importAttributes = { type: 'rocketLoadMdInitial' };
14
- if (typeof variant === 'object' && variant.kind === 'standalone-demo') {
15
- Object.assign(importAttributes, { singleDemo: variant.demoName });
16
- }
17
- const module = await import(`./${page.file}`, {
18
- with: importAttributes,
19
- });
20
- return normalizeLoadedPageModule({ kind: 'markdown', module, parseComponents });
21
- }
22
-
23
- const module = await import(`./${page.file}`, {
24
- with: { type: 'rocketLoadJsInitial' },
25
- });
26
- return normalizeLoadedPageModule({ kind: 'javascript', module });
27
- },
28
- };
29
- }