Storybook升级后Webpack5未转换TSX为TS文件问题求助
问题描述
将Storybook项目从5.1.8升级至6.5.16后,执行npm run build-lib构建供外部调用的自研组件时,Webpack未将MyComponent文件夹下的TSX文件生成对应的TypeScript类型声明文件(.d.ts)。组件已在index.ts导出并配置为Webpack入口,相关配置文件如下:
package.json
{ "name": "@xxx/components", "version": "0.0.0", "private": false, "main": "build/xxxxx", "types": "build/lib/index", "files": [ "build" ], "scripts": { "build-lib:dev": "cross-env NODE_ENV=development webpack && npm run copy-css-to-lib", "build-lib": "cross-env NODE_ENV=production webpack && npm run copy-css-to-lib", "storybook": "start-storybook -p 6006 -s ./src/public -c .storybook", "build": "npm run build-lib && build-storybook", "build-storybook": "build-storybook", "copy-css-to-lib": "cpx \"./src/**/*.scss\" ./build/lib", "prepublishOnly": "npm run build-lib", "lint": "eslint ./.eslintrc.js" }, "repository": "xxxxx", "license": "UNLICENSED", "peerDependencies": { "bootstrap": "^4.5.3", "react": "^18.2.0", "react-dom": "^18.2.0", "reactstrap": "^8.7.1" }, "devDependencies": { "@storybook/addon-a11y": "^6.5.16", "@storybook/addon-actions": "^6.5.16", "@storybook/addon-essentials": "^6.5.16", "@storybook/addon-interactions": "^6.5.16", "@storybook/addon-links": "^6.5.16", "@storybook/builder-webpack5": "^6.5.16", "@storybook/manager-webpack5": "^6.5.16", "@storybook/node-logger": "^6.5.16", "@storybook/preset-scss": "^1.0.3", "@storybook/react": "^6.5.16", "@storybook/testing-library": "^0.0.13", "@types/query-string": "^6.3.0", "@types/react-router-dom": "^5.3.3", "@typescript-eslint/eslint-plugin": "^5.54.1", "@typescript-eslint/parser": "^5.50.0", "babel-plugin-named-exports-order": "^0.0.2", "clean-webpack-plugin": "^4.0.0", "copy-webpack-plugin": "^11.0.0", "webpack": "^5.75.0", "webpack-bundle-analyzer": "^4.7.0", "webpack-cli": "^5.0.1", "webpack-hot-middleware": "^2.25.3" } }
tsconfig.json
{ "compilerOptions": { "outDir": "build/lib", "noImplicitAny": true, "module": "es6", "target": "es5", "jsx": "react", "allowJs": true, "moduleResolution": "node" }, "include": ["src/**/*", "types/**/*"], "exclude": ["node_modules", "build", "scripts"] }
index.ts
export { MyComponent } from "./components/folder/MyComponent";
webpack.config.js
// Imports const path = require("path"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const IgnoreNotFoundExportPlugin = require("./IgnoreNotFoundExportPlugin"); const StyleLintPlugin = require("stylelint-webpack-plugin"); const CopyPlugin = require("copy-webpack-plugin"); const TerserPlugin = require("terser-webpack-plugin"); const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; const buildPath = path.join(__dirname, "./build"); const env = process.env.NODE_ENV; const isDev = env === "development"; console.log("Env: " + env + "|Dev: " + isDev); module.exports = () => [ { stats: { modules: false }, devtool: "inline-source-map", //devtool: false, entry: { index: ["./src/index.ts"], }, resolve: { extensions: [".js", ".jsx", ".ts", ".tsx"], alias: { react: path.resolve(__dirname, "./node_modules/react"), "react-dom": path.resolve(__dirname, "./node_modules/react-dom"), }, }, externals: { // Don't bundle react or react-dom react: { commonjs: "react", commonjs2: "react", amd: "React", root: "React", }, "react-dom": { commonjs: "react-dom", commonjs2: "react-dom", amd: "ReactDOM", root: "ReactDOM", }, }, mode: isDev ? "development" : "production", output: { path: path.join(__dirname, "./build"), filename: "xxxxx.js", library: "xxxxxxComponents", libraryTarget: "umd", publicPath: "/build/", }, module: { rules: [ { test: /\.tsx?$/, include: /src/, use: "ts-loader", }, { test: /\.scss$/, exclude: /node_modules/, use: [ MiniCssExtractPlugin.loader, "css-loader", "resolve-url-loader", { loader: "sass-loader?sourceMap", options: { includePaths: [path.join(__dirname, "src/styles")], }, }, ], }, { // URL-loader to handle image resources (one URL-loader could be used for both images and fonts) test: /\.(png|jpg|jpeg|gif|svg|ttf|woff|woff2|eot)$/, use: "url-loader?limit=25000", exclude: /node_modules/, }, ], }, optimization: { minimizer: [new TerserPlugin()], }, plugins: [ new IgnoreNotFoundExportPlugin(), new ForkTsCheckerWebpackPlugin({ typescript: { checkSyntacticErrors: true, measureCompilationTime: true } }), new MiniCssExtractPlugin(), new CopyPlugin({ patterns: [ { from: "src/public/fonts", to: "lib/fonts" }, { from: "src/public/images", to: "lib/public/images" }, ], options: { concurrency: 100, }, }), new BundleAnalyzerPlugin({ analyzerMode: isDev ? "static" : "disabled", openAnalyzer: false, }), ], }, ];
缺失配置与修复方案
核心问题是当前配置未生成TypeScript类型声明文件(.d.ts),Webpack的ts-loader默认仅转译TS/TSX为JS,不会输出类型文件,需补充以下配置:
1. 修改tsconfig.json开启类型声明生成
添加declaration、declarationDir和emitDeclarationOnly配置,让TypeScript单独生成类型文件:
{ "compilerOptions": { "outDir": "build/lib", "noImplicitAny": true, "module": "esnext", // 替换es6为esnext,适配现代模块规范 "target": "es5", "jsx": "react", "allowJs": true, "moduleResolution": "node", "declaration": true, // 开启类型声明文件生成 "declarationDir": "build/lib", // 指定类型文件输出目录 "emitDeclarationOnly": true // 仅生成类型文件,不编译JS(Webpack已负责JS编译) }, "include": ["src/**/*", "types/**/*"], "exclude": ["node_modules", "build", "scripts"] }
2. 更新package.json的构建脚本
在build-lib和build-lib:dev脚本中添加tsc命令,确保构建时同步生成类型文件:
"scripts": { "build-lib:dev": "cross-env NODE_ENV=development webpack && tsc && npm run copy-css-to-lib", "build-lib": "cross-env NODE_ENV=production webpack && tsc && npm run copy-css-to-lib", // ...其他脚本保持不变 }
3. 优化webpack.config.js的ts-loader配置
设置transpileOnly: true让Webpack仅转译JS,类型检查交给ForkTsCheckerWebpackPlugin,提升构建速度:
{ test: /\.tsx?$/, include: /src/, use: { loader: "ts-loader", options: { transpileOnly: true // 仅转译,不做类型检查 } } }
4. 验证配置正确性
- 执行
npm run build-lib后,build/lib目录下应同时存在编译后的JS文件和对应的.d.ts类型文件 - 确保
package.json的types字段指向正确的入口类型文件(当前"types": "build/lib/index"已正确配置)
内容的提问来源于stack exchange,提问作者Benjamin
相关产品推荐
相关产品推荐

