Sas*_*sha 8 npm typescript reactjs webpack material-ui
我正在尝试构建一个基于 MUI 并使用 Storybook 和 TypeScript 构建的 React 组件库。因为 Storybook(使用 create-react-app)基于 Webpack,并且因为我的组件库包含无法使用以下命令编译的 SASS 文件tsc
,所以我使用 Webpack 来构建捆绑包。然后我将组件库导入到另一个 React 应用程序中,并使用它自己的 React 版本。
为了测试这一点,我构建了一个普通的 TypeScript create-react-app 演示应用程序,并从我托管的 Github 存储库上的特定分支导入我的库。当我尝试包含库中的组件时,TS 类型正确显示,但应用程序抛出这些错误之一,指出在底层 MUI 库中使用了挂钩。在我看来,这极有可能是 React 版本竞争问题,而不是钩子问题,因为 A) MUI 可以工作,B) 组件可以在 Storybook 中工作。
\n这是我的组件库的基本结构。
\n我将与构建无关的应用程序依赖项(React、MUI、MUI 依赖项)放入 中peerDependencies
,这样它们就不会重复。
package.json
{\n "name": "my-component-library",\n "version": "0.1.0",\n "private": true,\n "license": "MIT",\n "main": "dist/index.js",\n "types": "dist/types/index.d.ts",\n "dependencies": {\n "react-scripts": "5.0.0",\n "web-vitals": "^1.0.1"\n },\n "scripts": {\n "build": "webpack"\n // ...\n },\n // ... Lotsa devDependencies\n "peerDependencies": {\n "@emotion/react": "^11.7.1",\n "@emotion/styled": "^11.6.0",\n "@mui/icons-material": "^5.4.1",\n "@mui/material": "^5.4.1",\n "classnames": "^2.3.1",\n "lodash": "^4.17.21",\n "react": "^17.0.2",\n "react-dom": "^17.0.2",\n "react-router-dom": "^6.2.1"\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\nwebpack.config.js
const path = require("path");\n\nmodule.exports = {\n entry: "./src/index.ts",\n devtool: "source-map",\n output: {\n filename: "index.js",\n path: path.resolve(__dirname, "dist"),\n library: "MyComponentLibrary",\n libraryTarget: "umd",\n clean: true,\n },\n mode: "development",\n module: {\n rules: [\n {\n test: /\\.tsx?$/,\n loader: "ts-loader",\n options: { configFile: "tsconfig.build.json" },\n exclude: /node_modules/,\n },\n {\n test: /\\.s[ac]ss$/i,\n use: ["style-loader", "css-loader", "sass-loader"],\n },\n ],\n },\n resolve: {\n extensions: [".tsx", ".ts", ".js"]\n },\n optimization: {\n minimize: false,\n },\n target: "node",\n};\n
Run Code Online (Sandbox Code Playgroud)\ntsconfig.build.json
{\n "compilerOptions": {\n "allowJs": true,\n "allowSyntheticDefaultImports": true,\n "baseUrl": "src",\n "declaration": true,\n "esModuleInterop": true,\n "emitDeclarationOnly": true,\n "forceConsistentCasingInFileNames": true,\n "isolatedModules": true,\n "jsx": "react-jsx",\n "lib": ["es6", "dom"],\n "module": "esnext",\n "moduleResolution": "node",\n "noEmit": false,\n "noFallthroughCasesInSwitch": true,\n "noImplicitAny": true,\n "noImplicitThis": true,\n "outDir": "dist/types",\n "resolveJsonModule": true,\n "skipLibCheck": true,\n "strict": true,\n "strictNullChecks": true,\n "sourceMap": true,\n "target": "es5"\n },\n "include": ["src"],\n "exclude": ["src/**/*.test.tsx", "src/**/*.stories.tsx", "src/__mocks__"]\n}\n
Run Code Online (Sandbox Code Playgroud)\n当我运行时,Webpack会正确地将文件编译npm run build
成.dist/index.js
dist/types
然后,我的消费演示应用程序是一个基本的 CRA 应用程序,带有 TypeScript 模板。这是包文件的关键组成部分:
\npackage.json
{\n "name": "cld",\n "version": "0.1.0",\n "private": true,\n "dependencies": {\n "@types/jest": "^27.4.1",\n "@types/node": "^16.11.27",\n "@types/react": "^17.0.1",\n "@types/react-dom": "^17.0.1",\n "react": "^17.0.1",\n "react-dom": "^17.0.1",\n "react-scripts": "5.0.1",\n "typescript": "^4.6.3",\n "web-vitals": "^2.1.4",\n\n // Note the Github require\n "my-component-library": "github:my-private-handle/component-library#branch"\n },\n}\n
Run Code Online (Sandbox Code Playgroud)\n在我的 App.tsx 文件中:
\nApp.tsx
import React from "react";\nimport { Button } from "my-component-library";\n\nfunction App() {\n return (\n <div className="App">\n <Button>Hello</Button>\n </div>\n );\n}\n\nexport default App;\n
Run Code Online (Sandbox Code Playgroud)\n如果我将鼠标悬停在 上Button
,我会看到组件文档,如果我给它错误的 props,TS 会显示错误。但如果我运行该应用程序,由于 React 版本不匹配(我认为),该文件会抛出上述错误。
然而,React 和 React DOM 似乎都只有一个版本——由使用应用程序定义的版本。
\nnpm list react react-dom\ncld@0.1.0 /Users/sasha/code/cld\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\xac react-dom@17.0.2\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 react@17.0.2 deduped\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\xac react-scripts@5.0.1\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 react@17.0.2 deduped\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 react@17.0.2\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\xac my-component-library@0.1.0 (git+ssh://git@github.com/private-handle/component-library.git#09b5db39d8aa8a76f7c1fecacdc3afaecd57812e)\n \xe2\x94\x9c\xe2\x94\x80\xe2\x94\xac @emotion/react@11.9.0\n \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 react@17.0.2 deduped\n \xe2\x94\x9c\xe2\x94\x80\xe2\x94\xac @emotion/styled@11.8.1\n \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 react@17.0.2 deduped\n \xe2\x94\x9c\xe2\x94\x80\xe2\x94\xac @mui/icons-material@5.6.1\n \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 react@17.0.2 deduped\n \xe2\x94\x9c\xe2\x94\x80\xe2\x94\xac @mui/material@5.6.1\n \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\xac @mui/base@5.0.0-alpha.76\n \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 react-dom@17.0.2 deduped\n \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 react@17.0.2 deduped\n \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\xac @mui/system@5.6.1\n \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\xac @mui/private-theming@5.6.1\n \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 react@17.0.2 deduped\n \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\xac @mui/styled-engine@5.6.1\n \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 react@17.0.2 deduped\n \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 react@17.0.2 deduped\n \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\xac @mui/utils@5.6.1\n \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 react@17.0.2 deduped\n \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 react-dom@17.0.2 deduped\n \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\xac react-transition-group@4.4.2\n \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 react-dom@17.0.2 deduped\n \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 react@17.0.2 deduped\n \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 react@17.0.2 deduped\n \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 react-dom@17.0.2 deduped\n \xe2\x94\x9c\xe2\x94\x80\xe2\x94\xac react-router-dom@6.3.0\n \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 react-dom@17.0.2 deduped\n \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\xac react-router@6.3.0\n \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 react@17.0.2 deduped\n \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 react@17.0.2 deduped\n \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 react@17.0.2 deduped\n
Run Code Online (Sandbox Code Playgroud)\n更新:按照此处的调试建议,我在接收/演示应用程序中执行了此操作:
\nimport React from "react";\nimport { Button } from "my-component-library";\n\nfunction App() {\n return (\n <div className="App">\n <Button>Hello</Button>\n </div>\n );\n}\n\nexport default App;\n
Run Code Online (Sandbox Code Playgroud)\n截至最近一次运行,它返回false
,因为window.React1
未定义 - 并且本地node_modules/react-dom/index.js
文件似乎没有被命中,尽管require("react-dom")
. 该 require 的结果是一个 ReactDOM 对象,所以我不确定它来自哪里。很奇怪,但可能是问题的根源。
更新:我已经验证这是存储库中的唯一问题。不是基于 MUI 构建且不使用钩子(直接或通过 MUI)的组件渲染得很好。从同一个库导出的实用程序可以完美地工作,类型也是如此。只是任何使用 MUI 或其他使用 React hooks 的库的组件都会抛出错误。这对我来说毫无意义,因为应用程序中只有一个版本的 React。
\n问题归结为:Webpack 正在使用React、ReactDOM 和 React Router 构建一个捆绑包。捆绑包中的 React 等版本与“接收”应用程序中的版本冲突,即使 npm list
没有显示多个版本。
为了解决这个问题,我在 webpack 配置中使用了外部功能:
{
...
externals: {
'react': 'react',
'react-dom': 'react-dom',
'react-router-dom': 'react-router-dom',
'react-router': 'react-router'
}
}
Run Code Online (Sandbox Code Playgroud)
然后,这会构建到一个dist
文件夹,但构建中不包含 React 等,而是期望将其安装在接收应用程序中。该构建包已发布。目前,我只是从 Github 拉取它,但这应该可以发布到 NPM 或私有包存储库。
然后,消费/接收应用程序可以很好地导入文件/类型,而不会发生冲突。
归档时间: |
|
查看次数: |
11627 次 |
最近记录: |