如何将 prop 类型捆绑到可重用的 React 组件库中

0xc*_*m1z 5 javascript typescript reactjs webpack

我正在尝试使用 Typescript 和 Storybook 制作一个简单的 React 组件库来获得乐趣,我的第一个愚蠢的Button组件似乎可以工作。我有另一个 CRA 演示应用程序,我正在作为最终用户尝试该库。

但我遇到了一件事:我无法使prop-types我的Button组件在演示应用程序中工作。它只是不打印警告。

一些额外的细节:

库的文件和文件夹当前组织如下:

src/
  index.ts
  controls/
    index.ts
    Button.tsx
babelconfig.js
tsconfig.ts
webpack.config.js

(+ other configuration files and folder for jest and storybook)
Run Code Online (Sandbox Code Playgroud)

我有一个src/index.ts文件,它是我的库的入口点,它只导出来自该controls文件夹的所有内容。

src/
  index.ts
  controls/
    index.ts
    Button.tsx
babelconfig.js
tsconfig.ts
webpack.config.js

(+ other configuration files and folder for jest and storybook)
Run Code Online (Sandbox Code Playgroud)

在我的src/controls文件夹中,有一个index.ts文件可以导出Button组件中的所有内容。

// src/index.ts
export * from './controls'
Run Code Online (Sandbox Code Playgroud)

Button目前,该组件非常简单:

// src/controls/index.ts
export * from './Button'
Run Code Online (Sandbox Code Playgroud)

webpack 4.41一切都与此配置文件捆绑在一起:

import React from 'react'
import t, { InferProps } from 'prop-types'

const propTypes = {
  text: t.string.isRequired
}

const Button = ({ text }: InferProps<typeof propTypes>) => (
  <button>
    { text }
  </button>
)

Button.propTypes = propTypes

export { Button }
Run Code Online (Sandbox Code Playgroud)

我的babel配置是这样的:

// webpack.config.js

const path = require('path')

module.exports = {
  mode: 'production',
  entry: './src/index.ts',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'index.js',
    library: 'sads-ui',
    libraryTarget: 'umd'
  },
  externals: [
    'react'
  ],
  resolve: {
    extensions: [ '.ts', '.tsx', '.js' ]
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  }
}
Run Code Online (Sandbox Code Playgroud)

我不确定这是否重要,但这是我的typescript 3.7配置文件:

// tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "es6",
    "jsx": "react",
    "declaration": true,
    "outDir": "./dist",
    "downlevelIteration": true,
    "strict": true,
    "noImplicitAny": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "baseUrl": ".",
    "typeRoots": [ "node_modules/@types" ],
    "esModuleInterop": true
  }
}
Run Code Online (Sandbox Code Playgroud)

我的文件的主要属性package.json如下:

// other properties

"main": "dist/index.js",
"files": [
  "dist/*",
  "!dist/**/*.stories.d.ts"
],
"scripts": {
  "prebuild": "rimraf ./dist ./*.tgz",
  "build": "webpack",
  "prepack": "npm run build",
  "test": "jest",
  "storybook": "start-storybook"
},

// other properties
Run Code Online (Sandbox Code Playgroud)

期望

在我的演示应用程序中,使用 创建npx create-react-app sadsui-demo,我在 my 中安装了该包package.json,其依赖项如下:

// package.json

"sads-ui": "file:../sads-ui/sads-ui-0.1.0.tgz"
Run Code Online (Sandbox Code Playgroud)

Button我在我的中使用App.js如下:

// babel.config.js

module.exports = {
  presets: [
    '@babel/preset-env',
    '@babel/preset-react',
    '@babel/preset-typescript'
  ],
  env: {
    test: {
      plugins: [ 'require-context-hook' ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我希望收到一条警告,告诉我需要 的text支撑Button,但我什么也没得到。不过,空按钮已正确显示。

我的推理

我不知何故在黑暗中,但我心里有一些想法,不确定它是否有意义,也因为它似乎也不起作用。

我认为在模式下构建库webpack production可能会从库包中剥离出来prop-types,因此当我在最终应用程序中使用组件时,它们不可用。

我尝试以development模式捆绑,我在代码中看到dist/index.jsprop-types但无论如何它们都不起作用......:(

小智 1

在构建库时,您的 webpack 正在将(所有与 *.tsx 匹配的内容)编译为 javascript,当您将其导入到 create-react-app 中时,它只是 javascript(您应该进入您的/node_modules/create-react-app 并实际看到你自己的图书馆是什么样子的)

在您的库中,您可以为未编译为消费者可以导入的 JS 的组件导出单独的index.d.ts(或Button.d.ts其他)文件(总是很高兴查看其他项目并了解他们是如何做到这一点的。这是材料 ui 的 index.d.ts,您可能可以比通过将 Button.d.ts 导入到 index.d.ts 然后导出为一个大库打字稿模块要干净得多