Upgrade Storybook to version 9

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
Charles de Dreuille
2025-09-14 14:37:55 +01:00
parent f58e7f1d0d
commit ffac5071fe
38 changed files with 506 additions and 729 deletions
+64 -3
View File
@@ -35,15 +35,76 @@ const config: StorybookConfig = {
stories,
addons: [
getAbsolutePath('@storybook/addon-links'),
getAbsolutePath('@storybook/addon-essentials'),
getAbsolutePath('@storybook/addon-interactions'),
getAbsolutePath('@storybook/addon-themes'),
getAbsolutePath('@storybook/addon-storysource'),
getAbsolutePath('@storybook/addon-docs'),
],
framework: {
name: getAbsolutePath('@storybook/react-vite'),
options: {},
},
viteFinal: async config => {
// Add Node.js polyfills for browser compatibility
//
// When upgrading from Storybook 8 to 9 with the react-vite framework,
// Node.js polyfills are no longer automatically included by Vite.
// This causes "ReferenceError: process is not defined" errors in the browser
// when code tries to access Node.js globals like `process` and `util`.
//
// The @vitest/mocker (included with Storybook 9) expects MSW v2 APIs,
// but we want to keep MSW v1 for the rest of the monorepo to avoid
// breaking changes. This configuration provides the necessary polyfills
// and handles the MSW compatibility issue specifically for Storybook.
//
// These polyfills provide browser-compatible versions of Node.js globals:
// - process: Node.js process object with env
// - global -> globalThis: Maps Node.js global to browser's globalThis
//
// Without these, Backstage components that rely on Node.js APIs will fail
// to load in Storybook's browser environment.
config.define = {
...config.define,
global: 'globalThis',
'process.env': '{}',
process: '{ env: {}, browser: true }',
};
config.resolve = {
...config.resolve,
alias: {
...config.resolve?.alias,
// Provide Node.js polyfills for browser
process: 'process/browser',
util: 'util',
buffer: 'buffer',
stream: 'stream-browserify',
// Fix MSW v2 imports for @vitest/mocker compatibility
// @vitest/mocker expects MSW v2 APIs but we want to keep MSW v1 for the rest of the monorepo
'msw/browser': join(__dirname, 'msw-browser-shim.js'),
'msw/core/http': join(__dirname, 'msw-http-shim.js'),
},
};
// Optimize dependencies for better performance
config.optimizeDeps = {
...config.optimizeDeps,
include: [
...(config.optimizeDeps?.include || []),
'process/browser',
'util',
'buffer',
'stream-browserify',
],
// Exclude MSW to prevent optimization conflicts with our shims
exclude: [
...(config.optimizeDeps?.exclude || []),
'msw',
'msw/browser',
'msw/core/http',
],
};
return config;
},
};
export default config;
+47
View File
@@ -0,0 +1,47 @@
// MSW v2 browser compatibility shim for @vitest/mocker
// This provides MSW v2 exports using MSW v1 APIs to maintain compatibility
// while keeping the rest of the monorepo on MSW v1
try {
// Try to import from MSW v1
const { setupWorker, rest } = require('msw');
// Export in MSW v2 format expected by @vitest/mocker
module.exports = {
setupWorker,
// MSW v2 uses 'http' instead of 'rest', but we provide both for compatibility
http: rest,
rest, // Keep rest for any MSW v1 code
};
} catch (error) {
// Fallback if MSW is not available - provide minimal mock
console.warn(
'MSW not available, providing minimal mock for @vitest/mocker compatibility',
);
module.exports = {
setupWorker: () => ({
start: () => Promise.resolve(),
stop: () => {},
use: () => {},
resetHandlers: () => {},
}),
http: {
get: () => {},
post: () => {},
put: () => {},
delete: () => {},
patch: () => {},
head: () => {},
options: () => {},
},
rest: {
get: () => {},
post: () => {},
put: () => {},
delete: () => {},
patch: () => {},
head: () => {},
options: () => {},
},
};
}
+47
View File
@@ -0,0 +1,47 @@
// MSW v2 http compatibility shim for @vitest/mocker
// This provides MSW v2 http exports using MSW v1 APIs
try {
// Try to import from MSW v1
const { rest } = require('msw');
// Export MSW v1 'rest' as MSW v2 'http' for @vitest/mocker compatibility
module.exports = {
http: rest,
// Provide individual methods that @vitest/mocker might expect
get: rest.get,
post: rest.post,
put: rest.put,
delete: rest.delete,
patch: rest.patch,
head: rest.head,
options: rest.options,
all: rest.all,
};
} catch (error) {
// Fallback if MSW is not available
console.warn(
'MSW not available, providing minimal http mock for @vitest/mocker compatibility',
);
const noop = () => {};
module.exports = {
http: {
get: noop,
post: noop,
put: noop,
delete: noop,
patch: noop,
head: noop,
options: noop,
all: noop,
},
get: noop,
post: noop,
put: noop,
delete: noop,
patch: noop,
head: noop,
options: noop,
all: noop,
};
}
+10 -2
View File
@@ -2,8 +2,8 @@ import React, { useEffect } from 'react';
import { TestApiProvider } from '@backstage/test-utils';
import { Content, AlertDisplay } from '@backstage/core-components';
import { apis } from './support/apis';
import type { Decorator, Preview } from '@storybook/react';
import { useGlobals } from '@storybook/preview-api';
import type { Decorator, Preview } from '@storybook/react-vite';
import { useGlobals } from 'storybook/preview-api';
import { UnifiedThemeProvider, themes } from '@backstage/theme';
// Default Backstage theme CSS (from packages/ui)
@@ -52,20 +52,24 @@ const preview: Preview = {
},
parameters: {
layout: 'fullscreen',
backgrounds: {
disable: true,
},
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
options: {
storySort: {
order: ['Backstage UI', 'Plugins', 'Layout', 'Navigation'],
},
},
viewport: {
viewports: {
initial: {
@@ -82,6 +86,10 @@ const preview: Preview = {
},
},
},
docs: {
codePanel: true,
},
},
decorators: [
Story => {