Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions code/builders/builder-vite/src/vite-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { getProjectRoot } from 'storybook/internal/common';
import type { Options, Presets } from 'storybook/internal/types';

import * as find from 'empathic/find';
import { normalize } from 'pathe';
import { loadConfigFromFile } from 'vite';

import { storybookConfigPlugin } from './plugins/storybook-config-plugin.ts';
Expand Down Expand Up @@ -208,8 +209,11 @@ describe('resolveVitePublicDir', () => {

describe('discovery miss reporting', () => {
it('warns when configDir is nested and the Vite config sits at the project root', async () => {
// `resolve` gives the drive-letter, backslash form on Windows, as `find.any` does there.
const found = resolve('/project/vite.config.mjs');
const printed = normalize(found);
vi.mocked(getProjectRoot).mockReturnValue('/project');
vi.mocked(find.any).mockReturnValueOnce(resolve('/project/vite.config.mjs'));
vi.mocked(find.any).mockReturnValueOnce(found);
loadConfigFromFileMock.mockResolvedValueOnce(null);

await commonConfig(
Expand All @@ -222,13 +226,30 @@ describe('discovery miss reporting', () => {
last: '/project',
});
expect(loggerWarnMock).toHaveBeenCalledTimes(1);
expect(loggerWarnMock.mock.calls[0][0]).toContain('/project/vite.config.mjs');
expect(loggerWarnMock.mock.calls[0][0]).toContain(`found at "${printed}"`);
expect(loggerWarnMock.mock.calls[0][0]).toContain(
"core: { builder: { options: { viteConfigPath: '/project/vite.config.mjs' } } }"
`core: { builder: { options: { viteConfigPath: '${printed}' } } }`
);
expect(loggerWarnMock.mock.calls[0][0]).toContain('viteConfigPath: null');
});

it('prints a Windows config path with forward slashes so the snippet stays pasteable', async () => {
vi.mocked(getProjectRoot).mockReturnValue('/project');
vi.mocked(find.any).mockReturnValueOnce('C:\\project\\vite.config.mjs');
loadConfigFromFileMock.mockResolvedValueOnce(null);

await commonConfig(
{ ...dummyOptions, configDir: '/project/configuration/storybook' },
'development'
);

expect(loggerWarnMock).toHaveBeenCalledTimes(1);
expect(loggerWarnMock.mock.calls[0][0]).toContain('found at "C:/project/vite.config.mjs"');
expect(loggerWarnMock.mock.calls[0][0]).toContain(
"core: { builder: { options: { viteConfigPath: 'C:/project/vite.config.mjs' } } }"
);
});

it('stays quiet when no Vite config exists in the project at all', async () => {
vi.mocked(getProjectRoot).mockReturnValue('/project');
vi.mocked(find.any).mockReturnValueOnce(undefined);
Expand Down
9 changes: 7 additions & 2 deletions code/builders/builder-vite/src/vite-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { once } from 'storybook/internal/node-logger';
import type { Options } from 'storybook/internal/types';

import * as find from 'empathic/find';
import { normalize } from 'pathe';
import { dedent } from 'ts-dedent';
import type {
ConfigEnv,
Expand Down Expand Up @@ -64,15 +65,19 @@ function reportUnloadedUserViteConfig(configDir: string, projectRoot: string): v
return;
}

const unloadedConfig = find.any(DEFAULT_VITE_CONFIG_FILES, {
const found = find.any(DEFAULT_VITE_CONFIG_FILES, {
cwd: projectRoot,
last: root,
});

if (!unloadedConfig) {
if (!found) {
return;
}

// Forward slashes keep the pasteable snippet valid on Windows, where a backslash path inside
// a JS string literal reads as escapes (`'C:\vite.config.ts'` holds a vertical tab).
const unloadedConfig = normalize(found);

warnOnce(
dedent`
No user Vite config was loaded: Storybook auto-discovers a Vite config file in "${projectRoot}" (the directory above your Storybook config dir "${configDir}"), and none was found there.
Expand Down
Loading