@storybook-astro/framework 1.2.0 → 1.3.0-canary.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/dist/{base-IRZo3zgK.d.ts → base-DT67T5pi.d.ts} +1 -0
- package/dist/{chunk-T7NWIO5S.js → chunk-2EABPTOY.js} +5 -5
- package/dist/{chunk-PJEDXZVN.js → chunk-7YBE4TTI.js} +2 -1
- package/dist/chunk-7YBE4TTI.js.map +1 -0
- package/dist/{chunk-POHTFYST.js → chunk-AYYMNFI6.js} +104 -6
- package/dist/chunk-AYYMNFI6.js.map +1 -0
- package/dist/chunk-B5HHF6FC.js +116 -0
- package/dist/chunk-B5HHF6FC.js.map +1 -0
- package/dist/chunk-H3XZHW6Z.js +1402 -0
- package/dist/chunk-H3XZHW6Z.js.map +1 -0
- package/dist/{chunk-DNGQBPT7.js → chunk-PUTCAN6X.js} +5 -2
- package/dist/{chunk-DNGQBPT7.js.map → chunk-PUTCAN6X.js.map} +1 -1
- package/dist/{chunk-OUEDTRBO.js → chunk-TWAO2IQW.js} +229 -67
- package/dist/chunk-TWAO2IQW.js.map +1 -0
- package/dist/{chunk-4SWPVM6R.js → chunk-WUTCMEF5.js} +2 -2
- package/dist/index.d.ts +17 -7
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/integrations/index.d.ts +2 -1
- package/dist/integrations/index.js +1 -1
- package/dist/middleware.js +18 -131
- package/dist/middleware.js.map +1 -1
- package/dist/{types-C-jan6Px.d.ts → preset-BvgHg2of.d.ts} +8 -11
- package/dist/preset.d.ts +2 -10
- package/dist/preset.js +5 -4
- package/dist/renderer/renderer-dev.js +62 -0
- package/dist/renderer/renderer-dev.js.map +1 -0
- package/dist/renderer/renderer-server.js +92 -0
- package/dist/renderer/renderer-server.js.map +1 -0
- package/dist/renderer/renderer-static.js +54 -0
- package/dist/renderer/renderer-static.js.map +1 -0
- package/dist/testing.js +12 -11
- package/dist/testing.js.map +1 -1
- package/dist/{viteStorybookAstroMiddlewarePlugin-2EFKTECT.js → viteStorybookAstroMiddlewarePlugin-UB6ZLJ4B.js} +4 -3
- package/dist/vitest/global-setup.js +6 -5
- package/dist/vitest/global-setup.js.map +1 -1
- package/dist/vitest/index.d.ts +1 -1
- package/dist/vitest/index.js +3 -3
- package/package.json +14 -43
- package/src/astroImageService.ts +57 -0
- package/src/astroRenderHandler.ts +203 -0
- package/src/importAstroConfig.ts +1 -1
- package/src/index.ts +2 -0
- package/src/integrations/alpine.ts +1 -0
- package/src/integrations/base.ts +6 -0
- package/src/middleware.ts +29 -200
- package/src/module-mocks.ts +153 -5
- package/src/preset.ts +38 -8
- package/src/productionRenderRuntime.ts +187 -0
- package/src/rules.test.ts +52 -4
- package/src/rules.ts +54 -7
- package/src/server/index.ts +101 -31
- package/src/storyRulesRuntime.ts +34 -0
- package/src/storySsrVite.ts +240 -0
- package/src/types.ts +0 -9
- package/src/virtual.d.ts +17 -3
- package/src/vite/{astroFilesVirtualModulePlugin.ts → astroFilesPlugin.ts} +4 -4
- package/src/vite/sanitizeConfigPlugin.ts +18 -0
- package/src/vite/{storybookAstroServerAuthConfigVirtualModulePlugin.test.ts → serverAuthPlugin.test.ts} +7 -10
- package/src/vite/{storybookAstroServerAuthConfigVirtualModulePlugin.ts → serverAuthPlugin.ts} +6 -9
- package/src/vite/serverRuntimePlugin.ts +109 -0
- package/src/vite/{storybookAstroRulesConfigVirtualModulePlugin.ts → storyRulesPlugin.ts} +6 -7
- package/src/vite/{createVirtualModulePlugin.test.ts → virtualModulePlugin.test.ts} +5 -5
- package/src/vite/{createVirtualModulePlugin.ts → virtualModulePlugin.ts} +2 -2
- package/src/viteAstroContainerRenderersPlugin.ts +72 -2
- package/src/vitePluginAstroBuildPrerender.ts +75 -646
- package/src/vitePluginAstroBuildServer.ts +217 -165
- package/src/vitePluginAstroBuildShared.test.ts +87 -0
- package/src/vitePluginAstroBuildShared.ts +465 -0
- package/src/vitePluginStoryModuleMocks.ts +29 -0
- package/src/viteStorybookAstroMiddlewarePlugin.ts +8 -0
- package/src/viteStorybookAstroRendererPlugin.ts +13 -6
- package/src/viteStorybookRendererFallbackPlugin.ts +2 -2
- package/dist/chunk-OUEDTRBO.js.map +0 -1
- package/dist/chunk-PBISP7PA.js +0 -1137
- package/dist/chunk-PBISP7PA.js.map +0 -1
- package/dist/chunk-PJEDXZVN.js.map +0 -1
- package/dist/chunk-POHTFYST.js.map +0 -1
- package/dist/node/index.d.ts +0 -10
- package/dist/node/index.js +0 -10
- package/dist/node/index.js.map +0 -1
- package/src/vite/storybookAstroSanitizationConfigVirtualModulePlugin.ts +0 -21
- /package/dist/{chunk-T7NWIO5S.js.map → chunk-2EABPTOY.js.map} +0 -0
- /package/dist/{chunk-4SWPVM6R.js.map → chunk-WUTCMEF5.js.map} +0 -0
- /package/dist/{viteStorybookAstroMiddlewarePlugin-2EFKTECT.js.map → viteStorybookAstroMiddlewarePlugin-UB6ZLJ4B.js.map} +0 -0
|
@@ -1,15 +1,24 @@
|
|
|
1
|
-
import type { Dirent } from 'node:fs';
|
|
2
|
-
import { readdir } from 'node:fs/promises';
|
|
3
1
|
import { dirname, resolve } from 'node:path';
|
|
4
2
|
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
5
4
|
import { build, type Rollup } from 'vite';
|
|
5
|
+
import { resolveRulesConfigFilePath } from './rules-options.ts';
|
|
6
6
|
import type { FrameworkOptions } from './types.ts';
|
|
7
|
+
import {
|
|
8
|
+
buildStaticModuleMap,
|
|
9
|
+
buildSnapshotFilePath,
|
|
10
|
+
collectHydratedComponentPaths,
|
|
11
|
+
copyRuntimeSnapshot,
|
|
12
|
+
collectTrackedSpecifiers,
|
|
13
|
+
emitBuildEntrypoints,
|
|
14
|
+
loadVirtualBuildModule,
|
|
15
|
+
resolveVirtualBuildModuleId,
|
|
16
|
+
} from './vitePluginAstroBuildShared.ts';
|
|
7
17
|
import { mergeWithAstroConfig } from './vitePluginAstro.ts';
|
|
8
18
|
import { viteAstroContainerRenderersPlugin } from './viteAstroContainerRenderersPlugin.ts';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { storybookAstroServerAuthConfigVirtualModulePlugin } from './vite/storybookAstroServerAuthConfigVirtualModulePlugin.ts';
|
|
19
|
+
import { sanitizeConfigPlugin } from './vite/sanitizeConfigPlugin.ts';
|
|
20
|
+
import { serverAuthPlugin } from './vite/serverAuthPlugin.ts';
|
|
21
|
+
import { serverRuntimePlugin } from './vite/serverRuntimePlugin.ts';
|
|
13
22
|
|
|
14
23
|
const moduleRoot = resolve(dirname(fileURLToPath(import.meta.url)), '.');
|
|
15
24
|
// packageRoot works regardless of whether this file is running from src/ or dist/
|
|
@@ -18,10 +27,8 @@ const packageRoot = resolve(moduleRoot, '..');
|
|
|
18
27
|
export function vitePluginAstroBuildServer(options: FrameworkOptions) {
|
|
19
28
|
const integrations = options.integrations ?? [];
|
|
20
29
|
const resolveFrom = options.resolveFrom ?? process.cwd();
|
|
21
|
-
const storiesMap = new Map<string, Set<string>>();
|
|
22
30
|
const trackedSpecifiers = collectTrackedSpecifiers(integrations);
|
|
23
31
|
const staticEntrypointRefs = new Map<string, string>();
|
|
24
|
-
const componentEntrypointRefs = new Map<string, string>();
|
|
25
32
|
let storybookStaticOutDir = resolve(resolveFrom, 'storybook-static');
|
|
26
33
|
|
|
27
34
|
return {
|
|
@@ -33,108 +40,88 @@ export function vitePluginAstroBuildServer(options: FrameworkOptions) {
|
|
|
33
40
|
storybookStaticOutDir = resolve(resolveFrom, config.build.outDir ?? 'storybook-static');
|
|
34
41
|
},
|
|
35
42
|
|
|
36
|
-
resolveId(id: string
|
|
37
|
-
|
|
38
|
-
const absoluteAstroPath = resolve(dirname(importer), id);
|
|
39
|
-
|
|
40
|
-
if (!storiesMap.has(absoluteAstroPath)) {
|
|
41
|
-
storiesMap.set(absoluteAstroPath, new Set());
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
storiesMap.get(absoluteAstroPath)?.add(importer);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (id.startsWith('virtual:astro-static-module/')) {
|
|
48
|
-
return `\0${id}`;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (id.startsWith('virtual:astro-component-module/')) {
|
|
52
|
-
return `\0${id}`;
|
|
53
|
-
}
|
|
43
|
+
resolveId(id: string) {
|
|
44
|
+
return resolveVirtualBuildModuleId(id);
|
|
54
45
|
},
|
|
55
46
|
|
|
56
47
|
load(id: string) {
|
|
57
|
-
|
|
58
|
-
const encodedSpecifier = id.replace('\0virtual:astro-static-module/', '');
|
|
59
|
-
const specifier = decodeURIComponent(encodedSpecifier);
|
|
60
|
-
|
|
61
|
-
if (isClientEntrypoint(specifier)) {
|
|
62
|
-
return [`export { default } from '${specifier}';`, `export * from '${specifier}';`].join('\n');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return [`import '${specifier}';`, 'export default undefined;'].join('\n');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (id.startsWith('\0virtual:astro-component-module/')) {
|
|
69
|
-
const encodedSpecifier = id.replace('\0virtual:astro-component-module/', '');
|
|
70
|
-
const specifier = decodeURIComponent(encodedSpecifier);
|
|
71
|
-
|
|
72
|
-
return [`export { default } from '${specifier}';`, `export * from '${specifier}';`].join('\n');
|
|
73
|
-
}
|
|
48
|
+
return loadVirtualBuildModule(id);
|
|
74
49
|
},
|
|
75
50
|
|
|
76
51
|
async buildStart(this: Rollup.PluginContext) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
trackedSpecifiers.forEach((specifier) => {
|
|
86
|
-
const fileReferenceId = this.emitFile({
|
|
87
|
-
type: 'chunk',
|
|
88
|
-
id: toStaticVirtualId(specifier)
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
staticEntrypointRefs.set(specifier, fileReferenceId);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
const srcRoot = resolve(resolveFrom, 'src/components');
|
|
95
|
-
const specifiers = await collectHydratableSourceModules(srcRoot);
|
|
96
|
-
|
|
97
|
-
specifiers.forEach((specifier) => {
|
|
98
|
-
const fileReferenceId = this.emitFile({
|
|
99
|
-
type: 'chunk',
|
|
100
|
-
id: toComponentVirtualId(specifier)
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
componentEntrypointRefs.set(specifier, fileReferenceId);
|
|
52
|
+
await emitBuildEntrypoints({
|
|
53
|
+
pluginContext: this,
|
|
54
|
+
integrations,
|
|
55
|
+
resolveFrom,
|
|
56
|
+
trackedSpecifiers,
|
|
57
|
+
staticEntrypointRefs
|
|
104
58
|
});
|
|
105
59
|
},
|
|
106
60
|
|
|
107
|
-
async writeBundle(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
staticEntrypointRefs,
|
|
112
|
-
componentEntrypointRefs
|
|
113
|
-
);
|
|
61
|
+
async writeBundle(
|
|
62
|
+
this: Rollup.PluginContext,
|
|
63
|
+
_outputOptions: Rollup.NormalizedOutputOptions
|
|
64
|
+
) {
|
|
114
65
|
const serverOutDir = resolve(dirname(storybookStaticOutDir), 'storybook-server');
|
|
66
|
+
const snapshotDirName = 'project';
|
|
67
|
+
const astroStories = await collectAstroStories(storybookStaticOutDir, resolveFrom);
|
|
68
|
+
const storyAstroComponentPaths = Array.from(new Set(astroStories.map((story) => story.componentPath)));
|
|
69
|
+
const componentPathMap = buildComponentPathMap(storyAstroComponentPaths, resolveFrom, snapshotDirName);
|
|
70
|
+
const storyRulesConfigFilePath = resolveRulesConfigFilePath(options.storyRules, resolveFrom);
|
|
71
|
+
const trackedModuleMap = buildStaticModuleMap(this, staticEntrypointRefs, new Map());
|
|
72
|
+
const hydratedComponentAssets = await buildHydratedComponentAssets({
|
|
73
|
+
componentPaths: storyAstroComponentPaths,
|
|
74
|
+
integrations,
|
|
75
|
+
resolveFrom,
|
|
76
|
+
outDir: storybookStaticOutDir
|
|
77
|
+
});
|
|
78
|
+
const staticModuleMap = addSnapshotModuleAliases({
|
|
79
|
+
...trackedModuleMap,
|
|
80
|
+
...hydratedComponentAssets.staticModuleMap
|
|
81
|
+
}, {
|
|
82
|
+
resolveFrom,
|
|
83
|
+
snapshotRoot: resolve(serverOutDir, snapshotDirName),
|
|
84
|
+
snapshotDirName
|
|
85
|
+
});
|
|
86
|
+
const staticCssMap = hydratedComponentAssets.staticCssMap;
|
|
115
87
|
|
|
116
88
|
await buildAstroServer({
|
|
117
|
-
astroComponents,
|
|
118
89
|
integrations,
|
|
119
90
|
sanitization: options.sanitization,
|
|
120
91
|
storyRules: options.storyRules,
|
|
121
92
|
server: options.server,
|
|
122
93
|
outDir: serverOutDir,
|
|
94
|
+
snapshotDirName,
|
|
95
|
+
componentPathMap,
|
|
123
96
|
staticModuleMap,
|
|
97
|
+
staticCssMap,
|
|
98
|
+
trackedSpecifiers: Array.from(trackedSpecifiers),
|
|
124
99
|
resolveFrom
|
|
125
100
|
});
|
|
101
|
+
|
|
102
|
+
await copyRuntimeSnapshot({
|
|
103
|
+
resolveFrom,
|
|
104
|
+
snapshotRoot: resolve(serverOutDir, snapshotDirName),
|
|
105
|
+
snapshotDirName,
|
|
106
|
+
astroComponents: storyAstroComponentPaths,
|
|
107
|
+
storyRulesConfigFilePath
|
|
108
|
+
});
|
|
126
109
|
}
|
|
127
110
|
};
|
|
128
111
|
}
|
|
129
112
|
|
|
113
|
+
/** Builds the standalone Astro render server used by server-mode Storybook output. */
|
|
130
114
|
async function buildAstroServer(options: {
|
|
131
|
-
|
|
132
|
-
integrations: FrameworkOptions['integrations'];
|
|
115
|
+
integrations: NonNullable<FrameworkOptions['integrations']>;
|
|
133
116
|
sanitization?: FrameworkOptions['sanitization'];
|
|
134
117
|
storyRules?: FrameworkOptions['storyRules'];
|
|
135
118
|
server?: FrameworkOptions['server'];
|
|
136
119
|
outDir: string;
|
|
120
|
+
snapshotDirName: string;
|
|
121
|
+
componentPathMap: Record<string, string>;
|
|
137
122
|
staticModuleMap: Record<string, string>;
|
|
123
|
+
staticCssMap: Record<string, string[]>;
|
|
124
|
+
trackedSpecifiers: string[];
|
|
138
125
|
resolveFrom: string;
|
|
139
126
|
}) {
|
|
140
127
|
const buildConfig = {
|
|
@@ -154,10 +141,18 @@ async function buildAstroServer(options: {
|
|
|
154
141
|
}
|
|
155
142
|
},
|
|
156
143
|
plugins: [
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
144
|
+
sanitizeConfigPlugin(options.sanitization),
|
|
145
|
+
serverAuthPlugin(options.server),
|
|
146
|
+
serverRuntimePlugin({
|
|
147
|
+
integrations: options.integrations,
|
|
148
|
+
storyRules: options.storyRules,
|
|
149
|
+
resolveFrom: options.resolveFrom,
|
|
150
|
+
snapshotDirName: options.snapshotDirName,
|
|
151
|
+
componentPathMap: options.componentPathMap,
|
|
152
|
+
staticModuleMap: options.staticModuleMap,
|
|
153
|
+
staticCssMap: options.staticCssMap,
|
|
154
|
+
trackedSpecifiers: options.trackedSpecifiers
|
|
155
|
+
}),
|
|
161
156
|
viteAstroContainerRenderersPlugin(options.integrations, {
|
|
162
157
|
mode: 'production',
|
|
163
158
|
staticModuleMap: options.staticModuleMap
|
|
@@ -176,114 +171,171 @@ async function buildAstroServer(options: {
|
|
|
176
171
|
await build(finalConfig);
|
|
177
172
|
}
|
|
178
173
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
174
|
+
/** Rewrites Astro component module ids so the standalone server loads them from the snapshot tree. */
|
|
175
|
+
function buildComponentPathMap(
|
|
176
|
+
astroComponents: string[],
|
|
177
|
+
resolveFrom: string,
|
|
178
|
+
snapshotDirName: string
|
|
179
|
+
) {
|
|
180
|
+
// The built render server loads Astro component modules from the snapshot,
|
|
181
|
+
// not from the original project root that existed during the build.
|
|
182
|
+
return Object.fromEntries(
|
|
183
|
+
astroComponents.map((componentPath) => [
|
|
184
|
+
componentPath,
|
|
185
|
+
buildSnapshotFilePath(resolveFrom, componentPath, snapshotDirName).replace(
|
|
186
|
+
new RegExp(`^${snapshotDirName}/`),
|
|
187
|
+
''
|
|
188
|
+
)
|
|
189
|
+
])
|
|
190
|
+
);
|
|
191
|
+
}
|
|
184
192
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
193
|
+
async function collectAstroStories(outDir: string, resolveFrom: string) {
|
|
194
|
+
const indexFile = resolve(outDir, 'index.json');
|
|
195
|
+
const indexRaw = await import('node:fs/promises').then(({ readFile }) => readFile(indexFile, 'utf-8'));
|
|
196
|
+
const indexJson = JSON.parse(indexRaw) as {
|
|
197
|
+
entries?: Record<string, { type?: string; componentPath?: string; importPath?: string; exportName?: string }>
|
|
198
|
+
};
|
|
189
199
|
|
|
190
|
-
return
|
|
200
|
+
return Object.values(indexJson.entries ?? [])
|
|
201
|
+
.filter((entry) => entry.type === 'story' && entry.componentPath?.endsWith('.astro'))
|
|
202
|
+
.map((entry) => ({
|
|
203
|
+
componentPath: entry.componentPath?.startsWith('./') || entry.componentPath?.startsWith('../')
|
|
204
|
+
? resolve(resolveFrom, entry.componentPath)
|
|
205
|
+
: entry.componentPath
|
|
206
|
+
}))
|
|
207
|
+
.filter((entry): entry is { componentPath: string } => Boolean(entry.componentPath));
|
|
191
208
|
}
|
|
192
209
|
|
|
193
|
-
function
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
210
|
+
async function buildHydratedComponentAssets(options: {
|
|
211
|
+
componentPaths: string[];
|
|
212
|
+
integrations: NonNullable<FrameworkOptions['integrations']>;
|
|
213
|
+
resolveFrom: string;
|
|
214
|
+
outDir: string;
|
|
215
|
+
}) {
|
|
216
|
+
const hydratedComponentPaths = Array.from(
|
|
217
|
+
new Set((await Promise.all(options.componentPaths.map((componentPath) => collectHydratedComponentPaths(componentPath)))).flat())
|
|
218
|
+
);
|
|
199
219
|
|
|
200
|
-
|
|
201
|
-
|
|
220
|
+
if (hydratedComponentPaths.length === 0) {
|
|
221
|
+
return {
|
|
222
|
+
staticModuleMap: {},
|
|
223
|
+
staticCssMap: {}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
202
226
|
|
|
203
|
-
|
|
204
|
-
|
|
227
|
+
const clientEntrypoints = Array.from(
|
|
228
|
+
new Set(
|
|
229
|
+
options.integrations
|
|
230
|
+
.map((integration) => integration.renderer.client?.entrypoint)
|
|
231
|
+
.filter((entrypoint): entrypoint is string => Boolean(entrypoint))
|
|
232
|
+
)
|
|
233
|
+
);
|
|
234
|
+
const entryNames = Object.fromEntries(
|
|
235
|
+
[
|
|
236
|
+
...hydratedComponentPaths.map((componentPath, index) => [`component-${index}`, componentPath]),
|
|
237
|
+
...clientEntrypoints.map((entrypoint, index) => [`renderer-${index}`, entrypoint])
|
|
238
|
+
]
|
|
239
|
+
);
|
|
240
|
+
const buildConfig = {
|
|
241
|
+
root: options.resolveFrom,
|
|
242
|
+
build: {
|
|
243
|
+
write: false,
|
|
244
|
+
outDir: options.outDir,
|
|
245
|
+
emptyOutDir: false,
|
|
246
|
+
manifest: false,
|
|
247
|
+
rollupOptions: {
|
|
248
|
+
input: entryNames,
|
|
249
|
+
preserveEntrySignatures: 'strict',
|
|
250
|
+
output: {
|
|
251
|
+
entryFileNames: '_astro/[name]-[hash].js',
|
|
252
|
+
chunkFileNames: '_astro/[name]-[hash].js',
|
|
253
|
+
assetFileNames: '_astro/[name]-[hash][extname]'
|
|
254
|
+
}
|
|
255
|
+
}
|
|
205
256
|
}
|
|
206
|
-
}
|
|
257
|
+
};
|
|
258
|
+
const finalConfig = await mergeWithAstroConfig(
|
|
259
|
+
buildConfig,
|
|
260
|
+
options.integrations,
|
|
261
|
+
options.resolveFrom,
|
|
262
|
+
'production',
|
|
263
|
+
'build'
|
|
264
|
+
);
|
|
265
|
+
const buildOutput = await build(finalConfig);
|
|
266
|
+
const output = Array.isArray(buildOutput) ? buildOutput.flatMap((result) => result.output) : buildOutput.output;
|
|
267
|
+
const staticModuleMap: Record<string, string> = {};
|
|
268
|
+
const staticCssMap: Record<string, string[]> = {};
|
|
207
269
|
|
|
208
|
-
|
|
209
|
-
|
|
270
|
+
for (const item of output) {
|
|
271
|
+
await writeBuildOutputFile(options.outDir, item);
|
|
210
272
|
|
|
211
|
-
if (
|
|
212
|
-
|
|
273
|
+
if (item.type !== 'chunk' || !item.facadeModuleId) {
|
|
274
|
+
continue;
|
|
213
275
|
}
|
|
214
|
-
});
|
|
215
276
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
function toStaticVirtualId(specifier: string) {
|
|
220
|
-
return `virtual:astro-static-module/${encodeURIComponent(specifier)}`;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function toComponentVirtualId(specifier: string) {
|
|
224
|
-
return `virtual:astro-component-module/${encodeURIComponent(specifier)}`;
|
|
225
|
-
}
|
|
277
|
+
const normalizedFacadeId = item.facadeModuleId.replace(/\\/g, '/');
|
|
278
|
+
const originalInputSpecifier = entryNames[item.name];
|
|
226
279
|
|
|
227
|
-
|
|
228
|
-
return specifier.startsWith('@astrojs/') && specifier.endsWith('/client.js');
|
|
229
|
-
}
|
|
280
|
+
staticModuleMap[normalizedFacadeId] = `./${item.fileName}`;
|
|
230
281
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
282
|
+
if (originalInputSpecifier && originalInputSpecifier !== normalizedFacadeId) {
|
|
283
|
+
staticModuleMap[originalInputSpecifier] = `./${item.fileName}`;
|
|
284
|
+
}
|
|
234
285
|
|
|
235
|
-
|
|
236
|
-
const modules: string[] = [];
|
|
286
|
+
const importedCss = Array.from((item.viteMetadata?.importedCss ?? new Set<string>()).values());
|
|
237
287
|
|
|
238
|
-
|
|
239
|
-
|
|
288
|
+
if (importedCss.length > 0) {
|
|
289
|
+
staticCssMap[normalizedFacadeId] = importedCss.map((fileName) => `./${fileName}`);
|
|
240
290
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
return;
|
|
291
|
+
if (originalInputSpecifier && originalInputSpecifier !== normalizedFacadeId) {
|
|
292
|
+
staticCssMap[originalInputSpecifier] = importedCss.map((fileName) => `./${fileName}`);
|
|
293
|
+
}
|
|
245
294
|
}
|
|
295
|
+
}
|
|
246
296
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
await walk(absolutePath);
|
|
297
|
+
return {
|
|
298
|
+
staticModuleMap,
|
|
299
|
+
staticCssMap
|
|
300
|
+
};
|
|
301
|
+
}
|
|
253
302
|
|
|
254
|
-
|
|
255
|
-
|
|
303
|
+
async function writeBuildOutputFile(outDir: string, item: Rollup.OutputAsset | Rollup.OutputChunk) {
|
|
304
|
+
const outputPath = resolve(outDir, item.fileName);
|
|
256
305
|
|
|
257
|
-
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
306
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
260
307
|
|
|
261
|
-
|
|
308
|
+
if (item.type === 'asset') {
|
|
309
|
+
await writeFile(outputPath, item.source);
|
|
262
310
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
266
313
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
314
|
+
await writeFile(outputPath, item.code);
|
|
315
|
+
}
|
|
270
316
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
317
|
+
function addSnapshotModuleAliases(
|
|
318
|
+
staticModuleMap: Record<string, string>,
|
|
319
|
+
options: {
|
|
320
|
+
resolveFrom: string;
|
|
321
|
+
snapshotRoot: string;
|
|
322
|
+
snapshotDirName: string;
|
|
274
323
|
}
|
|
324
|
+
) {
|
|
325
|
+
const mapWithSnapshotPaths = { ...staticModuleMap };
|
|
275
326
|
|
|
276
|
-
|
|
327
|
+
for (const [sourcePath, builtPath] of Object.entries(staticModuleMap)) {
|
|
328
|
+
if (!sourcePath.startsWith('/')) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
277
331
|
|
|
278
|
-
|
|
279
|
-
|
|
332
|
+
const snapshotPath = resolve(
|
|
333
|
+
dirname(options.snapshotRoot),
|
|
334
|
+
buildSnapshotFilePath(options.resolveFrom, sourcePath, options.snapshotDirName)
|
|
335
|
+
).replace(/\\/g, '/');
|
|
280
336
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
}
|
|
337
|
+
mapWithSnapshotPaths[snapshotPath] = builtPath;
|
|
338
|
+
}
|
|
284
339
|
|
|
285
|
-
|
|
286
|
-
return /\.stories\.[jt]sx?$|\.stories\.vue$|\.stories\.svelte$|\.(spec|test)\.[jt]sx?$/.test(
|
|
287
|
-
input
|
|
288
|
-
);
|
|
340
|
+
return mapWithSnapshotPaths;
|
|
289
341
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, test } from 'vitest';
|
|
5
|
+
import { collectHydratedComponentPaths } from './vitePluginAstroBuildShared.ts';
|
|
6
|
+
|
|
7
|
+
describe('collectHydratedComponentPaths', () => {
|
|
8
|
+
let tmpDir: string;
|
|
9
|
+
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
tmpDir = await mkdtemp(join(tmpdir(), 'storybook-astro-build-test-'));
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
afterEach(async () => {
|
|
15
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('excludes a .tsx file that has only named exports', async () => {
|
|
19
|
+
const astroFile = join(tmpDir, 'Island.astro');
|
|
20
|
+
const namedOnlyTsx = join(tmpDir, 'Helper.tsx');
|
|
21
|
+
|
|
22
|
+
await writeFile(astroFile, `---\nimport Helper from './Helper.tsx';\n---`);
|
|
23
|
+
await writeFile(namedOnlyTsx, `export const Helper = () => <div />;`);
|
|
24
|
+
|
|
25
|
+
const result = await collectHydratedComponentPaths(astroFile);
|
|
26
|
+
|
|
27
|
+
expect(result).not.toContain(namedOnlyTsx.replace(/\\/g, '/'));
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('includes a .tsx file that has a default export', async () => {
|
|
31
|
+
const astroFile = join(tmpDir, 'Island.astro');
|
|
32
|
+
const defaultTsx = join(tmpDir, 'Button.tsx');
|
|
33
|
+
|
|
34
|
+
await writeFile(astroFile, `---\nimport Button from './Button.tsx';\n---`);
|
|
35
|
+
await writeFile(defaultTsx, `export default function Button() { return <div />; }`);
|
|
36
|
+
|
|
37
|
+
const result = await collectHydratedComponentPaths(astroFile);
|
|
38
|
+
|
|
39
|
+
expect(result).toContain(defaultTsx.replace(/\\/g, '/'));
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('includes a .svelte file even though it has no literal export default in source', async () => {
|
|
43
|
+
// Svelte SFCs have no `export default` — the compiler generates one.
|
|
44
|
+
// If the check were applied to .svelte, these files would be falsely excluded.
|
|
45
|
+
const astroFile = join(tmpDir, 'Island.astro');
|
|
46
|
+
const svelteFile = join(tmpDir, 'Counter.svelte');
|
|
47
|
+
|
|
48
|
+
await writeFile(astroFile, `---\nimport Counter from './Counter.svelte';\n---`);
|
|
49
|
+
await writeFile(svelteFile, `<script>\n let count = 0;\n</script>\n<button>{count}</button>`);
|
|
50
|
+
|
|
51
|
+
const result = await collectHydratedComponentPaths(astroFile);
|
|
52
|
+
|
|
53
|
+
expect(result).toContain(svelteFile.replace(/\\/g, '/'));
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('includes a .vue <script setup> file even though it has no literal export default in source', async () => {
|
|
57
|
+
// Vue <script setup> components have no `export default` — the compiler generates one.
|
|
58
|
+
const astroFile = join(tmpDir, 'Island.astro');
|
|
59
|
+
const vueFile = join(tmpDir, 'Counter.vue');
|
|
60
|
+
|
|
61
|
+
await writeFile(astroFile, `---\nimport Counter from './Counter.vue';\n---`);
|
|
62
|
+
await writeFile(
|
|
63
|
+
vueFile,
|
|
64
|
+
`<script setup>\nconst count = ref(0);\n</script>\n<template><button>{{ count }}</button></template>`
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const result = await collectHydratedComponentPaths(astroFile);
|
|
68
|
+
|
|
69
|
+
expect(result).toContain(vueFile.replace(/\\/g, '/'));
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('includes a .tsx file on read error, preserving prior behaviour', async () => {
|
|
73
|
+
// When the file cannot be read, hasDefaultExport returns true so the file
|
|
74
|
+
// is kept rather than silently dropped.
|
|
75
|
+
const astroFile = join(tmpDir, 'Island.astro');
|
|
76
|
+
const missingTsx = join(tmpDir, 'Missing.tsx');
|
|
77
|
+
|
|
78
|
+
// Point the Astro file at a component path that won't exist on disk.
|
|
79
|
+
await writeFile(astroFile, `---\nimport Missing from './Missing.tsx';\n---`);
|
|
80
|
+
|
|
81
|
+
// Don't write missingTsx — resolveLocalImportPath will not find it,
|
|
82
|
+
// so it never reaches hasDefaultExport. Confirm the result is just empty.
|
|
83
|
+
const result = await collectHydratedComponentPaths(astroFile);
|
|
84
|
+
|
|
85
|
+
expect(result).not.toContain(missingTsx.replace(/\\/g, '/'));
|
|
86
|
+
});
|
|
87
|
+
});
|