首页 > 解决方案 > 创建一个 Typescript + React 通用库

问题描述

我尝试创建一个通用的 React 和 Typescript 通用库,但在配置项目工作区以同时开发库和应用程序时遇到了太多困难

project
├─ app
│  ├─ package.json
│  ├─ tsconfig.json
│  ├─ webpack.config.js
│  ├─ ... (other config files)
│  ├─ node_modules
│  │  ├─ ...
│  │  ├─ @types
│  │  │  ├─ ...
│  │  │  └─ react
│  │  └─ symlink(lib A)
│  └─ src
│     ├─ *.ts files
│     ├─ *.tsx files
│     └─ index.ts
│
└─ libA
   ├─ package.json
   ├─ tsconfig.json
   ├─ other config files
   ├─ node_modules
   │  ├─ ...
   │  └─ @types
   │     ├─ ...
   │     └─ react
   └─ src
      ├─ *.ts files
      ├─ *.tsx files
      └─ index.ts
../libA/node_modules/@types/react/index.d.ts:2963:13 - error TS2717: Subsequent property declarations must have the same type.  Property 'view' must be of type 'SVGProps<SVGViewElement>', but here has type 'SVGProps<SVGViewElement>'.

一些谷歌搜索建议我应该从 libA 的 node_modules 中删除反应类型但这会破坏开发过程的便利性,因为libA不会编译。


更多细节:

I develop on Mac.
npm: 6.4.1
node: 8.15.0
typescript: 3.3.3333
webpack: 4

tsconfig 库:

{
  "compilerOptions": {
    "strict": true,
    "noUnusedLocals": true,
    "declaration": true,
    "sourceMap": true,
    "target": "es5",
    "module": "commonjs",
    "outDir": "dist",
    "moduleResolution": "node",
    "jsx": "react",
    "experimentalDecorators": true,
    "baseUrl": "src"
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

tsconfig 应用程序:

{
  "compilerOptions": {
    "strict": true,
    "noUnusedLocals": true,
    "removeComments": true,
    "sourceMap": true,
    "target": "es5",
    "module": "commonjs",
    "outDir": "dist",
    "moduleResolution": "node",
    "jsx": "react",
    "lib": [
      "es5",
      "es6",
      "es7",
      "dom"
    ],
    "baseUrl": "src"
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

不想使用skipLibCheck,因为类型是我首先爱上打字稿的原因......

可以安全地假设我做的事情完全错误..因为我断断续续地做了将近一个星期,并且无法确定正确的配置..欢迎任何指导...


经过进一步调查,我发现唯一不同的是我是否通过使用 npm link 来使用libA的符号链接

标签: node.jsreactjstypescriptwebpack

解决方案


最好和最简单的方法就是使用 webpack 或 parcel

你会希望你的配置类似于这样的东西..

const path = require("path");
const fs = require("fs");
const TerserPlugin = require('terser-webpack-plugin');
const appIndex = path.join(__dirname, "../src/main.tsx");
const appBuild = path.join(__dirname, "../build");
const { TsConfigPathsPlugin } = require('awesome-typescript-loader');

module.exports = {
    context: fs.realpathSync(process.cwd()),
    mode: "production",
    bail: true,
    devtool: false,
    entry: appIndex,
    output: {
        path: appBuild,
        filename: "dist/Components.bundle.js",
        publicPath: "/",
        libraryTarget: "commonjs"
    },
    externals: {
        react: {
            root: 'React',
            commonjs2: 'react',
            commonjs: 'react',
            amd: 'react'
        },
        'react-dom': {
            root: 'ReactDOM',
            commonjs2: 'react-dom',
            commonjs: 'react-dom',
            amd: 'react-dom'
        },
        "styled-components": {
            root: "styled-components",
            commonjs2: "styled-components",
            commonjs: "styled-components",
            amd: "styled-components"
        }
    },
    optimization: {
        minimizer: [
            new TerserPlugin({
                terserOptions: {
                    parse: {
                        ecma: 8,
                    },
                    compress: {
                        ecma: 5,
                        warnings: false,
                        comparisons: false,
                        inline: 2,
                    },
                    mangle: {
                        safari10: true,
                    },
                    output: {
                        ecma: 5,
                        comments: false,
                        ascii_only: true,
                    },
                },
                parallel: true,
                cache: true,
                sourceMap: false,
            })
        ],
    },
    resolve: {
        extensions: [".web.js", ".mjs", ".js", ".json", ".web.jsx", ".jsx", ".ts", ".tsx"],
        alias: {
            "react-native": "react-native-web",
        },
    },
    module: {
        strictExportPresence: true,
        rules: [
            { parser: { requireEnsure: false } },
            {
                test: /\.(ts|tsx)$/,
                loader: require.resolve("tslint-loader"),
                enforce: "pre",
            },
            {
                oneOf: [
                    {
                        test: /\.(tsx?)$/,
                        loader: require.resolve('awesome-typescript-loader'),
                        options: {
                            configFileName: 'tsconfig.prod.json'
                        }
                    },
                ],
            },
        ],
    },
    plugins: [
        new TsConfigPathsPlugin()
    ],
    node: {
        dgram: "empty",
        fs: "empty",
        net: "empty",
        tls: "empty",
        child_process: "empty",
    },
    performance: false,
};

需要了解的重要事项: libraryTarget: commonjs 必须匹配 tsconfig 中的“模块”commonjs。awesome-typescript-loader / webpack-cli 可以是最新版本来运行它。您将需要一个 tsconfig.prod.json 或更改配置的一部分。

react / reactdom / styled-components 被列为“外部”,这意味着它们不会与您的应用程序捆绑在一起,webpack 将在您要导入的包中查找这些模块。

Main.tsx 应该继续只导出到你想要的 commonjs 包中的每个组件,它应该看起来像这样...... // main.tsx

export { Button } from "./components/Button/Button";
export { Checkbox } from "./components/Checkbox/Checkbox";
export { DataTable } from "./components/DataTable/DataTable

测试此构建的一种快速方法是删除所有“外部”构建,然后尝试 require("..path...to..bundle").Button 和 console.log 它。

您需要 index.js 和 index.d.ts 才能发布到私有或公共 npm 包

编辑:您将使用该 webpack 命令与类似..

  "build": "webpack --config ./folder/to/config//webpack.component-prod.js",

推荐阅读