create-react-app CRA 5错误:需要软件包的子模块(即my-package/sub-module)返回字符串而不是模块

bq8i3lrv  于 2022-10-28  发布在  React
关注(0)|答案(9)|浏览(160)

描述Bug

执行require('something/something-else')会返回一个字符串-看起来像是带有lib -的捆绑包文件的路径,而不是返回可在代码中使用的实际模块。具体来说,这个问题是在require('nanoid/non-secure')中观察到的。
使用import * as nano from 'nanoid/non-secure'可以正常工作,但require('nanoid/non-secure')不能。问题的主要部分是,如果它是您的项目的依赖项,正在使用它与require,您无法控制您的应用将语法更改为import而不是require来解决此问题。
使用vanilla Webpack 5可以正常工作(react-scripts之外)。降级到react-scripts@^4也可以使它正常工作。我猜是react-scripts@5 Webpack配置中的一些东西。

是否尝试恢复依赖项?

模块树没有问题。问题在新创建的react-app上重现。甚至在版本1.22.17和3.1.0的不同Yarn设置中也会发生。

$ yarn --version
1.22.17

$ yarn --version
3.1.0

您在《用户指南》中搜索了哪些术语?

“子模块”,“要求”,“要求子模块”

环境

$ yarn create react-app --info
yarn create v1.22.17
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
success Installed "create-react-app@5.0.0" with binaries:
      - create-react-app

Environment Info:

  current version of create-react-app: 5.0.0
  running from /Users/rart/.config/yarn/global/node_modules/create-react-app

  System:
    OS: macOS 12.1
    CPU: (12) x64 Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
  Binaries:
    Node: 16.13.0 - /var/folders/5g/4p2kn0ks3x7fj848t3cvt4rw0000gn/T/yarn--1641400000423-0.5498156139928032/node
    Yarn: 1.22.17 - /var/folders/5g/4p2kn0ks3x7fj848t3cvt4rw0000gn/T/yarn--1641400000423-0.5498156139928032/yarn
    npm: 8.1.4 - ~/.nvm/versions/node/v16.13.0/bin/npm
  Browsers:
    Chrome: 97.0.4692.71
    Edge: Not Found
    Firefox: 89.0.2
    Safari: 15.2
  npmPackages:
    react: 17.0.2
    react-dom: 17.0.2
    react-scripts: 5.0.0
  npmGlobalPackages:
    create-react-app: Not Found

✨  Done in 2.29s.

重现步骤

  1. yarn add nanoid
  2. const nano = require('nanoid/non-secure')
  • 检查const nano的值;它应该是一个具有两个函数(nanoidcustomAlphabet)的模块,但实际上是一个类似于/static/media/index.617173a3029a82877c86.cjs的路径
  • 如果您--或者最重要的是您项目的依赖项--使用了nanoid(例如const { nanoid } = require('nanoid/non-secure')),那么nanoid将是未定义的,并且在访问它时会导致运行时异常。

预期行为

require('something/something-else')应返回模块,即包含导出内容的对象,而不是文件的字符串路径。
例如require('nanoid/non-secure'),应返回{ nanoid: ƒ nanoid(), customAlphabet: ƒ customAlphabet() }

实际行为

require('something/something-else')语句返回一个字符串,该字符串看起来像是包含lib的包文件的路径,而不是返回可以在代码中调用的实际模块。
使用import * as nano from 'nanoid/non-secure'可以正常工作,但require('nanoid/non-secure')不能。问题的主要部分是,如果它是您的项目的一个依赖项,正在使用它与require,您无法控制您的应用将语法更改为import,而不是require,以解决此问题。
使用vanilla Webpack 5可以正常工作(不涉及react-scripts)。降级到react-scripts@^4也可以使它正常工作。我猜是react-scripts@5 Webpack配置中的一些东西。

可重现的演示

我附加了3件东西:
1.使用yarn create react-app创建的应用程序显示以下问题:react-scripts-5-issue.zip的最大值
1.显示问题的codesandbox downloadreact-scripts-5-issue-submodules-codesandbox.zip。在codesandbox中运行的代码示例实际上可以正常工作,但是如果您直接从codesandbox下载它,请安装它(即Yarn/npm安装),然后运行react脚本,bug就会被复制。我不认为代码沙箱实际上运行react脚本,这就是它工作的原因。同样的方式,在一个普通的Webpack安装上尝试同样的事情也会工作。或者将应用程序降级为react-script@^4也可以。
1.一个普通的Webpack设置,表明这不是Webpack本身的问题:react-scripts-5-issue-vanilla-webpack.zip

gorkyyrv

gorkyyrv1#

我也遇到了这个问题,有什么解决方法吗?

6fe3ivhb

6fe3ivhb6#

也受到了影响。

mxg2im7a

mxg2im7a7#

我想我找到问题了。为了测试不同的webpack配置,我弹出了它,然后直接修改了config/webpack.config.js。问题出在最后一个模块规则(文件加载器的规则):不排除cjs文件。
如果您按如下方式更改规则,它将起作用(cjs已添加到排除的类JS扩展列表中):

{
  exclude: [/^$/, /\.(js|mjs|jsx|ts|tsx|cjs)$/, /\.html$/, /\.json$/],
  type: 'asset/resource',
},
t5fffqht

t5fffqht8#

在短期内,一种解决方法是使用craco添加排除项。craco.config.js文件将如下所示:

module.exports = {
    webpack: {
        configure: (config) => {
            // ...
            const fileLoaderRule = getFileLoaderRule(config.module.rules);
            if(!fileLoaderRule) {
                throw new Error("File loader not found");
            }
            fileLoaderRule.exclude.push(/\.cjs$/);
            // ...
	    return config;
        }
    }
};

function getFileLoaderRule(rules) {
    for(const rule of rules) {
        if("oneOf" in rule) {
            const found = getFileLoaderRule(rule.oneOf);
            if(found) {
                return found;
            }
        } else if(rule.test === undefined && rule.type === 'asset/resource') {
            return rule;
        }
    }
}
x759pob2

x759pob29#

我猜这个拉取请求也应该解决这个问题:
#12605的最大值

相关问题