使用Storybook+TypeScript遇模块未找到/导入路径不能以tsx结尾问题
解决Create React App + Storybook 6.5.x中TSX组件导入的扩展名冲突问题
我之前也碰到过完全一样的困扰——用Create React App(CRA)搭建的项目,配合Storybook 6.5.15,在TSX组件里导入其他组件时,不带扩展名找不到模块,带.tsx扩展名又被Linter报错,MDX故事文件里的表现还不一样。这本质是CRA和Storybook的模块解析规则不一致,再加上TypeScript的导入规范限制导致的冲突,下面给你几个实用的解决办法:
方案1:统一配置,让两者都支持无扩展名导入
这个是最推荐的方案,从根源上解决冲突:
- 调整TypeScript配置:在项目根目录的
tsconfig.json中,确保compilerOptions包含以下设置,让TS允许无扩展名导入并正确解析路径:
{ "compilerOptions": { "module": "ESNext", "moduleResolution": "NodeNext", "allowSyntheticDefaultImports": true, "resolveJsonModule": true, "baseUrl": ".", "paths": { "*": ["src/*"] }, "noEmit": true }, "include": ["src/**/*"] }
- 修改Storybook的Webpack配置:在
.storybook/main.js中添加webpack解析规则,让Storybook能识别无扩展名的TS/TSX文件:
module.exports = { stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"], addons: ["@storybook/addon-links", "@storybook/addon-essentials"], webpackFinal: async (config) => { // 将TS/TSX扩展名加入Webpack的自动解析列表 config.resolve.extensions.push('.ts', '.tsx'); return config; }, };
配置完成后,你就可以用import { Text } from "../Text/Text"正常导入,既不会出现模块找不到的错误,Linter也不会再报错。
方案2:使用绝对路径导入
如果不想折腾配置,改用绝对路径也能避开这个问题,同时让代码更清晰:
- 在
tsconfig.json中配置baseUrl和路径别名:
{ "compilerOptions": { "baseUrl": "src", "paths": { "@/*": ["*"] } } }
- 导入时用绝对路径:
import { Text } from "@/stories/Text/Text";
这种方式下,CRA和Storybook都能正确解析模块,Linter也会认可这种导入方式。
方案3:临时折中(不推荐)
如果上面的配置都没法马上调整,可以用TS注释忽略Linter报错,但这只是临时办法,会掩盖其他潜在的TS错误:
// @ts-ignore import { Text } from "../Text/Text.tsx";
为什么会出现这个问题?
- CRA的默认Webpack配置已经自动把
.ts/.tsx加入了解析扩展名列表,所以普通组件中无扩展名导入是正常的; - Storybook 6.5.x的默认Webpack配置没有自动包含这些扩展名,导致无扩展名导入时找不到模块;
- TypeScript的Linter(不管是TSLint还是ESLint+TypeScript-ESLint)都遵循规范,不允许导入路径带
.tsx扩展名,所以带扩展名会报错; - MDX文件的Linter规则和TSX文件不同,所以带扩展名不会触发报错。
内容的提问来源于stack exchange,提问作者Hedvig
相关产品推荐
相关产品推荐

