From 829d445355e0dd672b85746bd94efe2c6b2c847c Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 27 Nov 2025 08:24:09 +0000 Subject: [PATCH 1/2] Docs: Add FAQ section for extensionless imports --- docs/faq.mdx | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/faq.mdx b/docs/faq.mdx index 929c521d170f..e61542b7ab67 100644 --- a/docs/faq.mdx +++ b/docs/faq.mdx @@ -101,6 +101,32 @@ To fix this, you can wrap the package name inside your Storybook configuration f {/* prettier-ignore-end */} +## Extensionless imports in `.storybook/main.ts` and required `.ts` extensions + +When upgrading, you may see warnings about extensionless relative imports in `.storybook/main.ts` (for example: `import sharedMain from '../main'`). Storybook requires explicit extensions in config imports to avoid this deprecation warning. + +### Context +This is primarily a TypeScript constraint: the TypeScript compiler and language server validate import specifiers. While bundlers may rewrite or resolve extensions at build time, TypeScript does not unless configured. + +Storybook’s config loader surfaces a warning for extensionless imports to keep configuration explicit and predictable. We do not introduce a non-standard runtime mapping from `.js` to `.ts`. Keep imports explicit with `.ts` in configuration files. + +### Recommended setup (use `.ts` extensions) +- Update imports to include the `.ts` extension (e.g., `import sharedMain from '../main.ts'`). +- Configure TypeScript so these imports type-check without emitting JavaScript: + +```json title=".storybook/tsconfig.json" +{ + "extends": "", + "compilerOptions": { + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "noEmit": true + } +} +``` + +Alternatively, if your tooling requires emitting declarations, set `emitDeclarationOnly: true` instead of `noEmit`. + ## How do I setup the new React Context Root API with Storybook? If your installed React Version equals or is higher than 18.0.0, the new React Root API is automatically used and the newest React [concurrent features](https://reactjs.org/docs/concurrent-mode-intro.html) can be used. From a7c639840efaae09691d028e122bc1ff9bdbd52a Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 27 Nov 2025 08:29:00 +0000 Subject: [PATCH 2/2] Update deprecation message for extensionless imports with additional guidance --- code/core/src/bin/loader.test.ts | 5 ----- code/core/src/bin/loader.ts | 7 +++++-- docs/faq.mdx | 25 ++++++++++++++++--------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/code/core/src/bin/loader.test.ts b/code/core/src/bin/loader.test.ts index e282569aae0a..7ca11a7731e6 100644 --- a/code/core/src/bin/loader.test.ts +++ b/code/core/src/bin/loader.test.ts @@ -34,11 +34,6 @@ describe('loader', () => { expect(deprecate).toHaveBeenCalledWith( expect.stringContaining('One or more extensionless imports detected: "./utils"') ); - expect(deprecate).toHaveBeenCalledWith( - expect.stringContaining( - 'For maximum compatibility, you should add an explicit file extension' - ) - ); }); it('should resolve extensionless import to .js extension when file exists', () => { diff --git a/code/core/src/bin/loader.ts b/code/core/src/bin/loader.ts index 37ae944fb492..7c98ffb4df72 100644 --- a/code/core/src/bin/loader.ts +++ b/code/core/src/bin/loader.ts @@ -37,8 +37,11 @@ export function resolveWithExtension(importPath: string, currentFilePath: string return importPath; } - deprecate(dedent`One or more extensionless imports detected: "${importPath}" in file "${currentFilePath}". - For maximum compatibility, you should add an explicit file extension to this import. Storybook will attempt to resolve it automatically, but this may change in the future. If adding the extension results in an error from TypeScript, we recommend setting moduleResolution to "bundler" in tsconfig.json or alternatively look into the allowImportingTsExtensions option.`); + deprecate(dedent` + One or more extensionless imports detected: "${importPath}" in file "${currentFilePath}". + For more information on how to resolve the issue: + https://storybook.js.org/docs/faq#extensionless-imports-in-storybookmaints-and-required-ts-extensions + `); // Resolve the import path relative to the current file const currentDir = path.dirname(currentFilePath); diff --git a/docs/faq.mdx b/docs/faq.mdx index e61542b7ab67..ffd0f9f478cd 100644 --- a/docs/faq.mdx +++ b/docs/faq.mdx @@ -101,18 +101,23 @@ To fix this, you can wrap the package name inside your Storybook configuration f {/* prettier-ignore-end */} -## Extensionless imports in `.storybook/main.ts` and required `.ts` extensions +## Extensionless imports in Storybook main config -When upgrading, you may see warnings about extensionless relative imports in `.storybook/main.ts` (for example: `import sharedMain from '../main'`). Storybook requires explicit extensions in config imports to avoid this deprecation warning. +When upgrading or running Storybook, you may see warnings about extensionless relative imports in `.storybook/main.` (for example: `import sharedMain from '../main'`). +Storybook requires explicit extensions in config imports to avoid this deprecation warning. -### Context -This is primarily a TypeScript constraint: the TypeScript compiler and language server validate import specifiers. While bundlers may rewrite or resolve extensions at build time, TypeScript does not unless configured. +To fix the issue, just make sure to include the extension of the file (TypeScript or Javascript) you're importing: -Storybook’s config loader surfaces a warning for extensionless imports to keep configuration explicit and predictable. We do not introduce a non-standard runtime mapping from `.js` to `.ts`. Keep imports explicit with `.ts` in configuration files. +```ts title=".storybook/main." +// Change from this 👇 +import sharedMain from '../main'; -### Recommended setup (use `.ts` extensions) -- Update imports to include the `.ts` extension (e.g., `import sharedMain from '../main.ts'`). -- Configure TypeScript so these imports type-check without emitting JavaScript: +// To this 👇 +import sharedMain from '../main.js'; // or .ts +``` + +### For TypeScript users (`.storybook/main.ts`) +You will also need to configure TypeScript so these imports type-check without emitting JavaScript: ```json title=".storybook/tsconfig.json" { @@ -125,7 +130,9 @@ Storybook’s config loader surfaces a warning for extensionless imports to keep } ``` -Alternatively, if your tooling requires emitting declarations, set `emitDeclarationOnly: true` instead of `noEmit`. + + It is advisable to add a `.storybook/tsconfig.json` file so that you apply changes only to Storybook config files, and not your entire project. + ## How do I setup the new React Context Root API with Storybook?