@rocket/js 0.1.0 → 0.1.1
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.
- package/README.md +14 -5
- package/dist-types/exports/components.d.ts +1 -1
- package/dist-types/exports/icons.d.ts +1 -1
- package/dist-types/exports/layout.d.ts +1 -1
- package/dist-types/src/cli/RocketBuild.d.ts.map +1 -1
- package/dist-types/src/cli/RocketInit.d.ts.map +1 -1
- package/dist-types/src/cli/RocketStart.d.ts +34 -2
- package/dist-types/src/cli/RocketStart.d.ts.map +1 -1
- package/dist-types/src/components.d.ts +2 -0
- package/dist-types/src/components.d.ts.map +1 -1
- package/dist-types/src/icons.d.ts +12 -0
- package/dist-types/src/icons.d.ts.map +1 -1
- package/dist-types/src/layouts/atlas/atlasDocLayout.d.ts.map +1 -1
- package/dist-types/src/layouts/atlas/atlasHeroLayout.d.ts.map +1 -1
- package/dist-types/src/layouts/layout.d.ts +2 -4
- package/dist-types/src/layouts/layout.d.ts.map +1 -1
- package/dist-types/src/standalone-demo-url.d.ts.map +1 -1
- package/dist-types/src/transform.d.ts.map +1 -1
- package/dist-types/src/wds-plugin.d.ts +1 -0
- package/dist-types/src/wds-plugin.d.ts.map +1 -1
- package/exports/components.js +1 -1
- package/exports/icons.js +3 -0
- package/exports/layout.js +1 -1
- package/package.json +1 -1
- package/src/cli/RocketBuild.js +38 -2
- package/src/cli/RocketInit.js +337 -24
- package/src/cli/RocketStart.js +96 -30
- package/src/components.js +19 -0
- package/src/icons.js +15 -0
- package/src/layouts/atlas/atlasDocLayout.js +2 -15
- package/src/layouts/atlas/atlasHeroLayout.js +3 -12
- package/src/layouts/layout.js +2 -12
- package/src/main.js +21 -4
- package/src/standalone-demo-url.js +21 -8
- package/src/transform.js +89 -2
- package/src/wds-plugin.js +14 -9
|
@@ -4,6 +4,7 @@ import { resolve } from '../../resolve.js';
|
|
|
4
4
|
import { webAwesomeComponents } from '@rocket/js/components/web-awesome.js';
|
|
5
5
|
import { addBootstrapIconLibrary } from '../layout.js';
|
|
6
6
|
import { renderHeaderLogo, renderHeaderNav, renderSocials } from './atlasDocLayout.js';
|
|
7
|
+
import { rocketDemoComponents } from '../../components.js';
|
|
7
8
|
|
|
8
9
|
/** @type {import('@rocket/js/types.js').Components} */
|
|
9
10
|
export const atlasHeroComponents = {
|
|
@@ -27,21 +28,11 @@ export const atlasHeroComponents = {
|
|
|
27
28
|
className: 'FeatureList',
|
|
28
29
|
loading: 'server',
|
|
29
30
|
},
|
|
31
|
+
...rocketDemoComponents,
|
|
30
32
|
'rocket-code-block': {
|
|
31
|
-
|
|
32
|
-
className: 'RocketCodeBlock',
|
|
33
|
+
...rocketDemoComponents['rocket-code-block'],
|
|
33
34
|
loading: 'hydrate:onClientLoad',
|
|
34
35
|
},
|
|
35
|
-
'rocket-js-demo': {
|
|
36
|
-
file: './RocketJsDemo.js',
|
|
37
|
-
className: 'RocketJsDemo',
|
|
38
|
-
loading: 'client',
|
|
39
|
-
},
|
|
40
|
-
'rocket-request-demo': {
|
|
41
|
-
file: './RocketRequestDemo.js',
|
|
42
|
-
className: 'RocketRequestDemo',
|
|
43
|
-
loading: 'client',
|
|
44
|
-
},
|
|
45
36
|
...webAwesomeComponents,
|
|
46
37
|
};
|
|
47
38
|
|
package/src/layouts/layout.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { html } from 'lit';
|
|
3
3
|
import { document } from './layout-helper.js';
|
|
4
4
|
import { resolve } from '../resolve.js';
|
|
5
|
-
import {
|
|
5
|
+
import { addBootstrapIconLibrary } from '../icons.js';
|
|
6
6
|
|
|
7
7
|
/** @type {import('@rocket/js/types.js').Layout<null>} */
|
|
8
8
|
export const layout = data => {
|
|
@@ -49,14 +49,4 @@ export const singleDemoLayout = data => {
|
|
|
49
49
|
});
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
* @param {import('@rocket/js/PageData.js').PageData} pageData
|
|
54
|
-
*/
|
|
55
|
-
export function addBootstrapIconLibrary(pageData) {
|
|
56
|
-
pageData.addIconLibraries(
|
|
57
|
-
{
|
|
58
|
-
bootstrap: iconsFromPackage('bootstrap-icons', 'icons/*.svg'),
|
|
59
|
-
},
|
|
60
|
-
{ defaultIconLibrary: 'bootstrap' },
|
|
61
|
-
);
|
|
62
|
-
}
|
|
52
|
+
export { addBootstrapIconLibrary };
|
package/src/main.js
CHANGED
|
@@ -6,7 +6,8 @@ import { MessageChannel } from 'node:worker_threads';
|
|
|
6
6
|
import { customElements } from '@lit-labs/ssr-dom-shim';
|
|
7
7
|
import { readConfig } from './config.js';
|
|
8
8
|
|
|
9
|
-
const configFilePath = process.argv
|
|
9
|
+
const configFilePath = process.argv[2] || undefined;
|
|
10
|
+
const startOptions = readStartOptions(process.argv[3]);
|
|
10
11
|
|
|
11
12
|
customElements.define = (name, ctor) => {
|
|
12
13
|
customElements.__definitions.set(name, {
|
|
@@ -37,12 +38,13 @@ let devServerConfig = {
|
|
|
37
38
|
urlLifecycle: config.urlLifecycle,
|
|
38
39
|
iconLibraries: config.iconLibraries,
|
|
39
40
|
defaultIconLibrary: config.defaultIconLibrary,
|
|
41
|
+
watch: startOptions.watch,
|
|
40
42
|
}),
|
|
41
43
|
],
|
|
42
|
-
open: true,
|
|
44
|
+
open: startOptions.open ?? true,
|
|
43
45
|
nodeResolve: { exportConditions: ['browser'] },
|
|
44
|
-
watch: true,
|
|
45
|
-
port: 8888,
|
|
46
|
+
watch: startOptions.watch ?? true,
|
|
47
|
+
port: startOptions.port ?? 8888,
|
|
46
48
|
};
|
|
47
49
|
|
|
48
50
|
devServerConfig = config.adjustDevServerConfig(devServerConfig);
|
|
@@ -53,3 +55,18 @@ const server = await startDevServer({
|
|
|
53
55
|
readCliArgs: false,
|
|
54
56
|
readFileConfig: false,
|
|
55
57
|
});
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @param {string | undefined} value
|
|
61
|
+
* @returns {{ port?: number; open?: boolean; watch?: boolean }}
|
|
62
|
+
*/
|
|
63
|
+
function readStartOptions(value) {
|
|
64
|
+
if (!value) {
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
const parsed = JSON.parse(value);
|
|
68
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
69
|
+
return {};
|
|
70
|
+
}
|
|
71
|
+
return /** @type {{ port?: number; open?: boolean; watch?: boolean }} */ (parsed);
|
|
72
|
+
}
|
|
@@ -89,14 +89,16 @@ export function matchStandaloneDemoUrl(pathname, origin, pages) {
|
|
|
89
89
|
if (!isMarkdownPage(page) || !page.demoNames?.includes(standaloneDemo.demoName)) {
|
|
90
90
|
continue;
|
|
91
91
|
}
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
92
|
+
for (const parentPathname of parentPathnameCandidates(standaloneDemo.parentPathname)) {
|
|
93
|
+
const match = matchPagePath(parentPathname, origin, routePath);
|
|
94
|
+
if (match) {
|
|
95
|
+
return {
|
|
96
|
+
page,
|
|
97
|
+
routePath,
|
|
98
|
+
params: match.pathname.groups,
|
|
99
|
+
variant: { kind: 'standalone-demo', demoName: standaloneDemo.demoName },
|
|
100
|
+
};
|
|
101
|
+
}
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
return null;
|
|
@@ -126,6 +128,17 @@ function matchPagePath(pathname, origin, routePath) {
|
|
|
126
128
|
return pattern.exec(pathname, origin);
|
|
127
129
|
}
|
|
128
130
|
|
|
131
|
+
/**
|
|
132
|
+
* @param {string} parentPathname
|
|
133
|
+
*/
|
|
134
|
+
function parentPathnameCandidates(parentPathname) {
|
|
135
|
+
const documentPath = normalizeDocumentPath(parentPathname);
|
|
136
|
+
if (documentPath === parentPathname) {
|
|
137
|
+
return [parentPathname];
|
|
138
|
+
}
|
|
139
|
+
return [parentPathname, documentPath];
|
|
140
|
+
}
|
|
141
|
+
|
|
129
142
|
/**
|
|
130
143
|
* @param {Page} page
|
|
131
144
|
*/
|
package/src/transform.js
CHANGED
|
@@ -13,6 +13,7 @@ import { visit } from 'unist-util-visit';
|
|
|
13
13
|
import { init, parse as parseExports } from 'es-module-lexer';
|
|
14
14
|
import { headLinesToTree } from './menu.js';
|
|
15
15
|
import { parseRequestDemoMetadata } from './requestDemoMetadata.js';
|
|
16
|
+
import ts from 'typescript';
|
|
16
17
|
|
|
17
18
|
/** @type {import('rehype-autolink-headings').Options} */
|
|
18
19
|
const headingAnchorOptions = {
|
|
@@ -119,13 +120,14 @@ export function contentFn(data, layout) {
|
|
|
119
120
|
*/
|
|
120
121
|
async function makeJsFile(serverCode, clientCode, markdown, headlines) {
|
|
121
122
|
let litImport = "import { html } from 'lit'";
|
|
122
|
-
|
|
123
|
+
const normalizedServerCode = normalizeLayoutExportBindings(serverCode);
|
|
124
|
+
if (/import\s*?{(?:\n|.)*?html(\n|.)*}.*/m.test(normalizedServerCode)) {
|
|
123
125
|
litImport = '';
|
|
124
126
|
}
|
|
125
127
|
return `
|
|
126
128
|
import {render} from '@lit-labs/ssr';
|
|
127
129
|
${litImport}
|
|
128
|
-
${
|
|
130
|
+
${normalizedServerCode}
|
|
129
131
|
export function contentFn(data, defaultLayout) {
|
|
130
132
|
let renderLayout = defaultLayout;
|
|
131
133
|
if (typeof layout !== 'undefined') {
|
|
@@ -143,6 +145,91 @@ export function contentFn(data, defaultLayout) {
|
|
|
143
145
|
}`;
|
|
144
146
|
}
|
|
145
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Direct ESM re-exports do not create local bindings, but the generated Markdown module calls the
|
|
150
|
+
* selected layout from inside contentFn. Rewriting only direct `layout` re-exports keeps the public
|
|
151
|
+
* Page syntax working while preserving the generated function's local binding lookup.
|
|
152
|
+
*
|
|
153
|
+
* @param {string} serverCode
|
|
154
|
+
* @returns {string}
|
|
155
|
+
*/
|
|
156
|
+
function normalizeLayoutExportBindings(serverCode) {
|
|
157
|
+
if (typeof serverCode !== 'string') {
|
|
158
|
+
return '';
|
|
159
|
+
}
|
|
160
|
+
const sourceFile = ts.createSourceFile(
|
|
161
|
+
'page-server.js',
|
|
162
|
+
serverCode,
|
|
163
|
+
ts.ScriptTarget.Latest,
|
|
164
|
+
true,
|
|
165
|
+
ts.ScriptKind.JS,
|
|
166
|
+
);
|
|
167
|
+
/** @type {{start: number; end: number; text: string}[]} */
|
|
168
|
+
const replacements = [];
|
|
169
|
+
|
|
170
|
+
for (const statement of sourceFile.statements) {
|
|
171
|
+
if (
|
|
172
|
+
!ts.isExportDeclaration(statement) ||
|
|
173
|
+
!statement.moduleSpecifier ||
|
|
174
|
+
!statement.exportClause ||
|
|
175
|
+
!ts.isNamedExports(statement.exportClause)
|
|
176
|
+
) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const layoutExport = statement.exportClause.elements.find(
|
|
181
|
+
element => element.name.text === 'layout',
|
|
182
|
+
);
|
|
183
|
+
if (!layoutExport) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const moduleSpecifier = statement.moduleSpecifier.getText(sourceFile);
|
|
188
|
+
const attributes = statement.attributes ? ` ${statement.attributes.getText(sourceFile)}` : '';
|
|
189
|
+
const importedName = (layoutExport.propertyName || layoutExport.name).getText(sourceFile);
|
|
190
|
+
const layoutImportSpecifier =
|
|
191
|
+
importedName === 'layout' ? 'layout' : `${importedName} as layout`;
|
|
192
|
+
const replacementLines = [
|
|
193
|
+
`import { ${layoutImportSpecifier} } from ${moduleSpecifier}${attributes};`,
|
|
194
|
+
'export { layout };',
|
|
195
|
+
];
|
|
196
|
+
|
|
197
|
+
const remainingExports = statement.exportClause.elements.filter(
|
|
198
|
+
element => element !== layoutExport,
|
|
199
|
+
);
|
|
200
|
+
if (remainingExports.length) {
|
|
201
|
+
const remainingSpecifiers = remainingExports.map(element => {
|
|
202
|
+
if (element.propertyName) {
|
|
203
|
+
return `${element.propertyName.getText(sourceFile)} as ${element.name.getText(sourceFile)}`;
|
|
204
|
+
}
|
|
205
|
+
return element.name.getText(sourceFile);
|
|
206
|
+
});
|
|
207
|
+
replacementLines.push(
|
|
208
|
+
`export { ${remainingSpecifiers.join(', ')} } from ${moduleSpecifier}${attributes};`,
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
replacements.push({
|
|
213
|
+
start: statement.getStart(sourceFile),
|
|
214
|
+
end: statement.end,
|
|
215
|
+
text: replacementLines.join('\n'),
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (!replacements.length) {
|
|
220
|
+
return serverCode;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
let normalizedCode = serverCode;
|
|
224
|
+
for (const replacement of replacements.toReversed()) {
|
|
225
|
+
normalizedCode =
|
|
226
|
+
normalizedCode.slice(0, replacement.start) +
|
|
227
|
+
replacement.text +
|
|
228
|
+
normalizedCode.slice(replacement.end);
|
|
229
|
+
}
|
|
230
|
+
return normalizedCode;
|
|
231
|
+
}
|
|
232
|
+
|
|
146
233
|
function parseDemos() {
|
|
147
234
|
/** @type {{name: string, code: string}[]} */
|
|
148
235
|
const demos = [];
|
package/src/wds-plugin.js
CHANGED
|
@@ -24,12 +24,13 @@ let pageRegistry = new Map();
|
|
|
24
24
|
let modules = new Map();
|
|
25
25
|
|
|
26
26
|
/** @typedef {import('@rocket/js/types.js').UrlLifecycleConfig} UrlLifecycleConfig */
|
|
27
|
-
/** @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 }} RocketDevServerPluginOptions */
|
|
27
|
+
/** @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
28
|
/** @typedef {RocketDevServerPluginOptions | UrlLifecycleConfig} RocketDevServerPluginInput */
|
|
29
29
|
|
|
30
30
|
/** @type {(include: string[], exclude: (string | RegExp)[], resolverPort: import('node:worker_threads').MessagePort, options?: RocketDevServerPluginInput) => import('@web/dev-server-core').Plugin} */
|
|
31
31
|
export default (include, exclude, resolverPort, options = {}) => {
|
|
32
32
|
const pluginOptions = normalizePluginOptions(options);
|
|
33
|
+
const watchEnabled = pluginOptions.watch !== false;
|
|
33
34
|
const iconAssetStore = createIconAssetStore();
|
|
34
35
|
/** @type {import('node:fs').FSWatcher[]} */
|
|
35
36
|
const watchers = [];
|
|
@@ -65,19 +66,23 @@ export default (include, exclude, resolverPort, options = {}) => {
|
|
|
65
66
|
} else {
|
|
66
67
|
modules.set(message.url, new Set([message.parent]));
|
|
67
68
|
}
|
|
68
|
-
|
|
69
|
+
if (watchEnabled) {
|
|
70
|
+
watchFileDirectory(message.url);
|
|
71
|
+
}
|
|
69
72
|
resolverPort.postMessage('ok');
|
|
70
73
|
});
|
|
71
74
|
pageRegistry = await getPages(process.cwd(), include, exclude);
|
|
72
75
|
validateDevelopmentPublicAssets(pluginOptions);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
if (watchEnabled) {
|
|
77
|
+
pageRegistry.forEach(page => {
|
|
78
|
+
watchFileDirectory(page.file);
|
|
79
|
+
});
|
|
80
|
+
modules.forEach((_, url) => {
|
|
81
|
+
watchFileDirectory(url);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
79
84
|
const publicDir = path.join(process.cwd(), PUBLIC_ASSETS_DIR);
|
|
80
|
-
if (fs.existsSync(publicDir)) {
|
|
85
|
+
if (watchEnabled && fs.existsSync(publicDir)) {
|
|
81
86
|
fileWatcher?.add(publicDir);
|
|
82
87
|
}
|
|
83
88
|
},
|