Skip to content

Commit

Permalink
Serve staticDirs with Vitest server
Browse files Browse the repository at this point in the history
  • Loading branch information
ghengeveld committed Dec 4, 2024
1 parent 1370dc2 commit 49a4bb9
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 81 deletions.
1 change: 1 addition & 0 deletions code/addons/test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"semver": "^7.6.3",
"sirv": "^2.0.4",
"slash": "^5.0.0",
"strip-ansi": "^7.1.0",
"ts-dedent": "^2.2.0",
Expand Down
24 changes: 24 additions & 0 deletions code/addons/test/src/vitest-plugin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import {
loadAllPresets,
validateConfigurationFiles,
} from 'storybook/internal/common';
import { mapStaticDir } from 'storybook/internal/core-server';
import { readConfig, vitestTransform } from 'storybook/internal/csf-tools';
import { MainFileMissingError } from 'storybook/internal/server-errors';
import type { StoriesEntry } from 'storybook/internal/types';

import { join, resolve } from 'pathe';
import sirv from 'sirv';

import type { InternalOptions, UserOptions } from './types';

Expand Down Expand Up @@ -60,6 +62,7 @@ export const storybookTest = (options?: UserOptions): Plugin => {
}

let previewLevelTags: string[];
const statics: ReturnType<typeof mapStaticDir>[] = [];

return {
name: 'vite-plugin-storybook-test',
Expand Down Expand Up @@ -88,6 +91,15 @@ export const storybookTest = (options?: UserOptions): Plugin => {
const framework = await presets.apply('framework', undefined);
const frameworkName = typeof framework === 'string' ? framework : framework.name;
const storybookEnv = await presets.apply('env', {});
const staticDirs = await presets.apply('staticDirs', []);

for (const staticDir of staticDirs) {
try {
statics.push(mapStaticDir(staticDir, configDir));
} catch (e) {
console.warn(e);
}
}

// If we end up needing to know if we are running in browser mode later
// const isRunningInBrowserMode = config.plugins.find((plugin: Plugin) =>
Expand Down Expand Up @@ -162,6 +174,18 @@ export const storybookTest = (options?: UserOptions): Plugin => {
config.define.__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ = 'false';
}
},
configureServer(server) {
statics.map(({ staticPath, targetEndpoint }) => {
server.middlewares.use(
targetEndpoint,
sirv(staticPath, {
dev: true,
etag: true,
extensions: [],
})
);
});
},
async transform(code, id) {
if (process.env.VITEST !== 'true') {
return code;
Expand Down
1 change: 1 addition & 0 deletions code/core/src/core-server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './build-static';
export * from './build-dev';
export * from './withTelemetry';
export { default as build } from './standalone';
export { mapStaticDir } from './utils/server-statics';
58 changes: 28 additions & 30 deletions code/core/src/core-server/presets/common-preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,39 +67,37 @@ export const favicon = async (
? staticDirsValue.map((dir) => (typeof dir === 'string' ? dir : `${dir.from}:${dir.to}`))
: [];

if (statics && statics.length > 0) {
const lists = await Promise.all(
statics.map(async (dir) => {
const results = [];
const normalizedDir =
staticDirsValue && !isAbsolute(dir)
? getDirectoryFromWorkingDir({
configDir: options.configDir,
workingDir: process.cwd(),
directory: dir,
})
: dir;

const { staticPath, targetEndpoint } = await parseStaticDir(normalizedDir);

if (targetEndpoint === '/') {
const url = 'favicon.svg';
const path = join(staticPath, url);
if (existsSync(path)) {
results.push(path);
}
if (statics.length > 0) {
const lists = statics.map((dir) => {
const results = [];
const normalizedDir =
staticDirsValue && !isAbsolute(dir)
? getDirectoryFromWorkingDir({
configDir: options.configDir,
workingDir: process.cwd(),
directory: dir,
})
: dir;

const { staticPath, targetEndpoint } = parseStaticDir(normalizedDir);

if (targetEndpoint === '/') {
const url = 'favicon.svg';
const path = join(staticPath, url);
if (existsSync(path)) {
results.push(path);
}
if (targetEndpoint === '/') {
const url = 'favicon.ico';
const path = join(staticPath, url);
if (existsSync(path)) {
results.push(path);
}
}
if (targetEndpoint === '/') {
const url = 'favicon.ico';
const path = join(staticPath, url);
if (existsSync(path)) {
results.push(path);
}
}

return results;
})
);
return results;
});
const flatlist = lists.reduce((l1, l2) => l1.concat(l2), []);

if (flatlist.length > 1) {
Expand Down
24 changes: 12 additions & 12 deletions code/core/src/core-server/utils/__tests__/server-statics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ describe('parseStaticDir', () => {
});

it('returns the static dir/path and default target', async () => {
await expect(parseStaticDir('public')).resolves.toEqual({
expect(parseStaticDir('public')).toEqual({
staticDir: './public',
staticPath: resolve('public'),
targetDir: './',
targetEndpoint: '/',
});

await expect(parseStaticDir('foo/bar')).resolves.toEqual({
expect(parseStaticDir('foo/bar')).toEqual({
staticDir: './foo/bar',
staticPath: resolve('foo/bar'),
targetDir: './',
Expand All @@ -31,14 +31,14 @@ describe('parseStaticDir', () => {
});

it('returns the static dir/path and custom target', async () => {
await expect(parseStaticDir('public:/custom-endpoint')).resolves.toEqual({
expect(parseStaticDir('public:/custom-endpoint')).toEqual({
staticDir: './public',
staticPath: resolve('public'),
targetDir: './custom-endpoint',
targetEndpoint: '/custom-endpoint',
});

await expect(parseStaticDir('foo/bar:/custom-endpoint')).resolves.toEqual({
expect(parseStaticDir('foo/bar:/custom-endpoint')).toEqual({
staticDir: './foo/bar',
staticPath: resolve('foo/bar'),
targetDir: './custom-endpoint',
Expand All @@ -47,21 +47,21 @@ describe('parseStaticDir', () => {
});

it('pins relative endpoint at root', async () => {
const normal = await parseStaticDir('public:relative-endpoint');
const normal = parseStaticDir('public:relative-endpoint');
expect(normal.targetEndpoint).toBe('/relative-endpoint');

const windows = await parseStaticDir('C:\\public:relative-endpoint');
const windows = parseStaticDir('C:\\public:relative-endpoint');
expect(windows.targetEndpoint).toBe('/relative-endpoint');
});

it('checks that the path exists', async () => {
existsSyncMock.mockReturnValueOnce(false);
await expect(parseStaticDir('nonexistent')).rejects.toThrow(resolve('nonexistent'));
expect(() => parseStaticDir('nonexistent')).toThrow(resolve('nonexistent'));
});

skipWindows(() => {
it('supports absolute file paths - posix', async () => {
await expect(parseStaticDir('/foo/bar')).resolves.toEqual({
expect(parseStaticDir('/foo/bar')).toEqual({
staticDir: '/foo/bar',
staticPath: '/foo/bar',
targetDir: './',
Expand All @@ -70,7 +70,7 @@ describe('parseStaticDir', () => {
});

it('supports absolute file paths with custom endpoint - posix', async () => {
await expect(parseStaticDir('/foo/bar:/custom-endpoint')).resolves.toEqual({
expect(parseStaticDir('/foo/bar:/custom-endpoint')).toEqual({
staticDir: '/foo/bar',
staticPath: '/foo/bar',
targetDir: './custom-endpoint',
Expand All @@ -81,7 +81,7 @@ describe('parseStaticDir', () => {

onlyWindows(() => {
it('supports absolute file paths - windows', async () => {
await expect(parseStaticDir('C:\\foo\\bar')).resolves.toEqual({
expect(parseStaticDir('C:\\foo\\bar')).toEqual({
staticDir: resolve('C:\\foo\\bar'),
staticPath: resolve('C:\\foo\\bar'),
targetDir: './',
Expand All @@ -90,14 +90,14 @@ describe('parseStaticDir', () => {
});

it('supports absolute file paths with custom endpoint - windows', async () => {
await expect(parseStaticDir('C:\\foo\\bar:/custom-endpoint')).resolves.toEqual({
expect(parseStaticDir('C:\\foo\\bar:/custom-endpoint')).toEqual({
staticDir: expect.any(String), // can't test this properly on unix
staticPath: resolve('C:\\foo\\bar'),
targetDir: './custom-endpoint',
targetEndpoint: '/custom-endpoint',
});

await expect(parseStaticDir('C:\\foo\\bar:\\custom-endpoint')).resolves.toEqual({
expect(parseStaticDir('C:\\foo\\bar:\\custom-endpoint')).toEqual({
staticDir: expect.any(String), // can't test this properly on unix
staticPath: resolve('C:\\foo\\bar'),
targetDir: './custom-endpoint',
Expand Down
4 changes: 2 additions & 2 deletions code/core/src/core-server/utils/copy-all-static-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export async function copyAllStaticFiles(staticDirs: any[] | undefined, outputDi
await Promise.all(
staticDirs.map(async (dir) => {
try {
const { staticDir, staticPath, targetDir } = await parseStaticDir(dir);
const { staticDir, staticPath, targetDir } = parseStaticDir(dir);
const targetPath = join(outputDir, targetDir);

// we copy prebuild static files from node_modules/@storybook/manager & preview
Expand Down Expand Up @@ -54,7 +54,7 @@ export async function copyAllStaticFilesRelativeToMain(
await acc;

const staticDirAndTarget = typeof dir === 'string' ? dir : `${dir.from}:${dir.to}`;
const { staticPath: from, targetEndpoint: to } = await parseStaticDir(
const { staticPath: from, targetEndpoint: to } = parseStaticDir(
getDirectoryFromWorkingDir({
configDir,
workingDir,
Expand Down
74 changes: 37 additions & 37 deletions code/core/src/core-server/utils/server-statics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { existsSync } from 'node:fs';
import { basename, isAbsolute, posix, resolve, sep, win32 } from 'node:path';

import { getDirectoryFromWorkingDir } from '@storybook/core/common';
import type { Options } from '@storybook/core/types';
import type { Options, StorybookConfigRaw } from '@storybook/core/types';

import { logger } from '@storybook/core/node-logger';

Expand All @@ -15,43 +15,31 @@ export async function useStatics(app: Polka.Polka, options: Options): Promise<vo
const staticDirs = (await options.presets.apply('staticDirs')) ?? [];
const faviconPath = await options.presets.apply<string>('favicon');

await Promise.all(
staticDirs
.map((dir) => (typeof dir === 'string' ? dir : `${dir.from}:${dir.to}`))
.map(async (dir) => {
try {
const normalizedDir =
staticDirs && !isAbsolute(dir)
? getDirectoryFromWorkingDir({
configDir: options.configDir,
workingDir: process.cwd(),
directory: dir,
})
: dir;
const { staticDir, staticPath, targetEndpoint } = await parseStaticDir(normalizedDir);
staticDirs.map((dir) => {
try {
const { staticDir, staticPath, targetEndpoint } = mapStaticDir(dir, options.configDir);

// Don't log for the internal static dir
if (!targetEndpoint.startsWith('/sb-')) {
logger.info(
`=> Serving static files from ${picocolors.cyan(staticDir)} at ${picocolors.cyan(targetEndpoint)}`
);
}
// Don't log for the internal static dir
if (!targetEndpoint.startsWith('/sb-')) {
logger.info(
`=> Serving static files from ${picocolors.cyan(staticDir)} at ${picocolors.cyan(targetEndpoint)}`
);
}

app.use(
targetEndpoint,
sirv(staticPath, {
dev: true,
etag: true,
extensions: [],
})
);
} catch (e) {
if (e instanceof Error) {
logger.warn(e.message);
}
}
})
);
app.use(
targetEndpoint,
sirv(staticPath, {
dev: true,
etag: true,
extensions: [],
})
);
} catch (e) {
if (e instanceof Error) {
logger.warn(e.message);
}
}
});

app.get(
`/${basename(faviconPath)}`,
Expand All @@ -63,7 +51,7 @@ export async function useStatics(app: Polka.Polka, options: Options): Promise<vo
);
}

export const parseStaticDir = async (arg: string) => {
export const parseStaticDir = (arg: string) => {
// Split on last index of ':', for Windows compatibility (e.g. 'C:\some\dir:\foo')
const lastColonIndex = arg.lastIndexOf(':');
const isWindowsAbsolute = win32.isAbsolute(arg);
Expand All @@ -90,3 +78,15 @@ export const parseStaticDir = async (arg: string) => {

return { staticDir, staticPath, targetDir, targetEndpoint };
};

export const mapStaticDir = (
staticDir: NonNullable<StorybookConfigRaw['staticDirs']>[number],
configDir: string
) => {
const specifier = typeof staticDir === 'string' ? staticDir : `${staticDir.from}:${staticDir.to}`;
const normalizedDir = isAbsolute(specifier)
? specifier
: getDirectoryFromWorkingDir({ configDir, workingDir: process.cwd(), directory: specifier });

return parseStaticDir(normalizedDir);
};
1 change: 1 addition & 0 deletions code/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6631,6 +6631,7 @@ __metadata:
react: "npm:^18.2.0"
react-dom: "npm:^18.2.0"
semver: "npm:^7.6.3"
sirv: "npm:^2.0.4"
slash: "npm:^5.0.0"
strip-ansi: "npm:^7.1.0"
ts-dedent: "npm:^2.2.0"
Expand Down

0 comments on commit 49a4bb9

Please sign in to comment.