使用 TypeScript 和 NPM Link 创建 React App:枚举导致模块解析失败

Create React App with TypeScript and NPM Link: Enums causing Module parse failed

我有一个基本的 create-react-app TypeScript 项目 (client)。只是目录,我有一个 server 和一个 shared 文件夹。在 shared 文件夹中,我有一些 interfaceenum 我在 serverclient 之间共享。

我希望 link 这个 shared 文件夹到 clientserver 包。

首先,我去了 shared 和 运行 $ yarn link,然后 运行 $ yarn link sharedclientserver 个文件夹。

服务器非常开心,而且在大多数情况下,客户端也是如此。但是,一旦我在 client 中使用 shared 目录中的 enum 之一,我就会收到错误消息:

../shared/src/models/Roles.ts 4:0
Module parse failed: The keyword 'enum' is reserved (4:0)
File was processed with these loaders:
 * ./node_modules/@pmmmwh/react-refresh-webpack-plugin/loader/index.js
You may need an additional loader to handle the result of these loaders.
| $RefreshSetup$(module.id);
| 
> enum Roles {
|     RW_ORG = "rw_org", // can modifiy organization and it's users, nothing else

我是这样导入的: import {Roles} from "shared"; 但也尝试了许多其他方法。

我正在从 shared index.ts 导出它,就像这样

import Roles from "./models/Roles";

export type { 
    // all of my interfaces
};
export { Roles }

我的interface都是可以用的,不懂。这到底是怎么回事?

嗯,原来这些错误都是create-react-app默认造成的webpack.config.js。如果您导航到 code node_modules/react-scripts/config/webpack.config.js,您会找到一行 include: paths.appSrc,它基本上将 Babel 限制在 React 应用程序本身的 src/ 文件夹中。

这意味着,如果你 yarn link 在它之外编辑了一个文件夹,Babel 不会将它转换为普通的 JS,因此 React 无法使用它。

有两个 hacky 解决方案,但我想要一个更好的解决方案。

  1. 每次安装节点模块时手动(或通过构建脚本)从 react-scripts 中删除 include: paths.appSrc
  2. 制作一个脚本,在每次修改外部目录时将外部目录复制到您的 React src 目录中。

我真的希望有一个正式的方法来解决这个问题...

可以自动删除 using react-app-rewired 中提到的包含路径设置。

以下 config-overrides.js 适用于 react-scripts:4.0.3 并导致 babel 也转译节点模块中的文件。

// config-overrides.js
module.exports = function override(config, env) {
  // This line might break with other react-script versions
  delete config.module.rules[1].oneOf[2].include
  return config
}

根据@foxtrotuniform6969 的回答,我创建了一个 @cracro/craco 配置,可以自行消除错误设置。

module.exports = {
  webpack: {
    configure: (webpackConfig) => ({
      ...webpackConfig,
      module: {
        ...webpackConfig.module,
        rules: webpackConfig.module.rules.map((rule) => {
          if (!rule.oneOf) return rule;
          return {
            ...rule,
            oneOf: rule.oneOf.map((ruleObject) => {
              if (
                !new RegExp(ruleObject.test).test('.ts') ||
                !ruleObject.include
              )
                return ruleObject;
              return { ...ruleObject, include: undefined };
            }),
          };
        }),
      },
    }),
  },
};

https://gist.github.com/PhilippMolitor/00f427d12a9c5bca84309058d88846b7

此问题的其他答案建议删除 react-scripts' webpack.config 中的 include(使用 cracoreact-app-rewired)。我发现这适用于 yarn start,但是当我使用 yarn build 进行生产构建时,我在运行时收到错误 Uncaught ReferenceError: exports is not defined

除了现有的 src 目录之外,我不得不添加其他项目的 src,而不是删除包含。 这是我要与 react-app-rewired 一起使用的 config-overrides.js

对于react-scripts 4:

const path = require("path");

module.exports = function override(config) {
    // See 
    config.module.rules[1].oneOf[2].include = [
        path.join(__dirname, './src'),
        path.join(__dirname, '../backend/src')
    ];
    return config
}

对于react-scripts 5:

const path = require("path");

module.exports = function override(config) {
    // See 
    config.module.rules[1].oneOf[3].include = [
        path.join(__dirname, './src'),
        path.join(__dirname, '../backend/src')
    ];
    return config
}

据我所知,我的 craco 配置与 Phil Mo 的版本功能相同,但更容易理解

module.exports = {
    webpack: {
        configure: (webpackConfig) => {
            webpackConfig.module.rules[0].oneOf.find(
                ({ test: t }) =>
                    t != null &&
                    !Array.isArray(t) &&
                    t.toString().includes('ts')
            ).include = undefined

            return webpackConfig
        }
    }
}