【问题标题】:How to allowNamespaces in CRA?如何在 CRA 中允许命名空间?
【发布时间】:2020-07-29 03:02:28
【问题描述】:

我使用以下方法创建了一个 TypeScript React 应用程序:

yarn create react-app my-app --template typescript

这样,我的项目用Babel编译,然后用webpack捆绑。现在我想使用 TypeScript namespaces,默认情况下 Babel 不支持,但它们 can be enabled。我安装了所有必要的软件包:

package.json 中,我将react-scripts start 更改为react-app-rewired start

最后,我创建了一个config-overrides.js 文件:

const {
    override,
    addExternalBabelPlugin
  } = require("customize-cra");

module.exports = override(
    addExternalBabelPlugin([
        "@babel/plugin-transform-typescript",
        { allowNamespaces: true }
    ])
);

但是编译还是会抛出语法错误,好像没有启用插件一样:

语法错误:/home/m93a/my-app/script.ts:命名空间未标记为仅类型声明。非声明性命名空间仅在 Babel 中实验性地支持。要启用和查看警告,请参阅:https://babeljs.io/docs/en/babel-plugin-transform-typescript

如何正确设置我的项目,以便它甚至可以编译非声明性命名空间?


编辑:我的项目没有成功的原因实际上与我的想法完全不同。查看我自己的答案以获取更多详细信息。

【问题讨论】:

  • 我建议只使用ts-loader 而不是babel 并在tsconfig.json 中打开jsx
  • @LuketheGeek CRA 使用 Babel 和 @babel/preset-typescript 插件。 ts-loader 与此问题无关,也与 CRA 无关。
  • @m93a 我已在我的答案中添加了一个工作演示存储库。请检查一下我的单个命名空间类(People.Person inside src/lib/Person.ts)是否与您的相同。你试过addBabelPlugin吗?如果它不适合您,请提供您如何声明和使用命名空间的示例。还有.babelrc 选项,如果您想尝试一下,我可以将其添加到我的答案中。

标签: typescript webpack babeljs react-scripts


【解决方案1】:

您必须使用addBabelPlugin 而不是addExternalBabelPlugin

tl;博士

如果我们检查文档,我们会看到:

addExternalBabelPlugin(plugin)

create-react-app 实际上在其webpack 配置中有两条规则用于babel-loader:一条用于addSrc 中的代码(默认为src/),另一条用于代码external 到该文件夹​​(如@987654341 @)。您可以使用 addExternalBabelPlugin 将插件添加到 external 加载程序,就像使用 addBabelPlugin 一样。

如果我们检查 react-scripts/config/webpack.config.js 内部,我们可以看到这两个 babel-loader 条目:

  1. webpack.config.js#L396babel-loader 用于include: paths.appSrc\.(js|mjs|jsx|ts|tsx)$/,其中addBabelPlugin 添加插件,并带有注释:

    // Process application JS with Babel.
    // The preset includes JSX, Flow, TypeScript, and some ESnext features.
    
  2. webpack.config.js#L452babel-loader for /\.(js|mjs)$/addExternalBabelPlugin 为其添加插件,并带有注释:

    // Process any JS outside of the app with Babel.
    // Unlike the application JS, we only compile the standard ES features.
    

我们希望@babel/plugin-transform-typescript 应用于第一个babel-loader 与应用程序src 文件夹有关,因此我们必须使用适用于babel-loader 配置的addBabelPlugin

最后但同样重要的是,确保您已更新您的 package.json 脚本以从 react-app-rewired 运行:

"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject"

您可以在此处使用命名空间中的类检查一个非常简单的 CRA Typescript 项目:https://github.com/clytras/cra-ts-namespaces

【讨论】:

  • 谢谢,这绝对是我提出的确切问题的最佳答案。但是,如果不是因为我自己的回答中提到的原因,Masih 之前的回答也对我有用。 Masih 解决问题的几种不同尝试帮助我发现了这个错误。所以,当我将赏金授予他时,我希望你能理解。再次感谢您的宝贵时间!
【解决方案2】:

使用脚本覆盖 Babel 配置 所以请按照以下步骤操作:

  1. 使用create-react-app my-app --template=typescript 创建新应用或使用现有应用
  2. 安装rescriptsnpm i -D @rescripts/cli
  3. 将 react-scripts 替换为 package.json 中的脚本,例如 rescripts docs
  4. 为 babel config @rescripts/rescript-use-babel-config 安装 rescript 插件
  5. 将此sniper 添加到您的package.json 文件中
"rescripts": [
    [
        "use-babel-config",
            {
                "presets": [
                    "react-app",
                    [
                        "@babel/preset-typescript",
                        {
                            "allowNamespaces": true
                        }
                    ]
                ]
            }
        ]
    ]

Rescripts 将使用插件,它将扩展 babel 配置。我们扩展了默认的 react-app babel 配置,所以我们不会破坏任何东西。然后我们覆盖预设(已经由 react-app 安装),但我们设置了allowNamespaces 标志。

【讨论】:

  • 请避免对一个问题提供多个答案。您可以在一个答案中包含有关解决方案的所有方法和说明。
  • 对不起。你测试这个答案吗?
  • 感谢您的宝贵时间,Masih!您帮助我找到了解决方案,尽管问题并不完全是我认为的问题。尽管另一个答案为确切问题提供了最简单的解决方案,但您的工作有助于解决我遇到的现实问题。
  • @MasihJahangiri - 有没有办法让这也影响 Jest 的测试?
【解决方案3】:

在我的特殊情况下,即使我听从了其他人的建议,我也无法让它工作的原因如下:Babel 中存在一个错误,阻止它合并 enumnamespace。例如,此代码不起作用:

export enum Foo
{
    a, b, c, d
}

export namespace Foo
{
  export function bar()
  {
    return "bar"
  }
}

但是出于某种奇怪的原因,Babel 在遇到这段代码时会抛出一个非常误导性的错误:

SyntaxError:script.ts:命名空间未标记为仅类型声明。非声明性命名空间仅在 Babel 中实验性地支持。要启用和查看警告,请参阅:https://babeljs.io/docs/en/babel-plugin-transform-typescript

我提交了an issue,所以希望这个错误很快得到修复,或者至少得到一个不错的错误消息。同时,可以使用绕行:

export enum Foo_
{
    a, b, c, d
}

export type Foo = Foo_

export namespace Foo
{
  export const a = Foo_.a
  export const b = Foo_.b
  export const c = Foo_.c
  export const d = Foo_.d
  export function bar()
  {
    return "bar"
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-28
    • 1970-01-01
    • 2021-08-11
    • 1970-01-01
    • 2021-01-13
    • 2021-03-12
    • 1970-01-01
    相关资源
    最近更新 更多