如何让 require.context 与 Create React App with/withou Craco 一起工作?

How to get require.context to work with Create React App with/withou Craco?

我试图在我的 CRA(使用 Typescript)项目中通过 require.context 在运行时执行一些要求,但我只收到以下类型的错误:

TypeError: __webpack_require__(...).context is not a function

Critical dependency: require function is used in a way in which dependencies cannot be statically extracted

我在某处读到现在需要通过 Babel 或 cra-rewired 进行 polyfill。好吧,我已经在使用 Craco 来启用 Less-support,但我不知道如何将 require.context 添加到我的 Craco 配置中。

有人知道怎么做吗?

更新: 这就是我调用的方式 require.context:

const packagesDirectory = path.join(__dirname, '../../../../packages');
const textDataContext = require.context(packagesDirectory, true, /(\w+)\.(\w+)\.(mdx?)/);

更新二:

正如 this thread 中的一些评论所建议的那样,我尝试将 babel-plugin-require-context-hook 添加到我的应用程序中,如下所示:

// craco.config.js

const CracoLessPlugin = require('craco-less');

module.exports = {
    plugins: [
        {plugin: CracoLessPlugin}
    ],
    babel: {
        plugins: ['require-context-hook']
    }
};

然后我尝试像这样调用 require.context

// myfile.js

import registerRequireContextHook from 'babel-plugin-require-context-hook/register';
registerRequireContextHook();

const packagesDirectory = path.join(__dirname, '../../../../packages');
const textDataContext = require.context(packagesDirectory, true, /(\w+)\.(\w+)\.(mdx?)/);

但是我得到这个错误:

TypeError: fs.readdirSync is not a function

更新 3:

CRA 似乎 支持 require.context 而根本不需要任何 polyfill。但是当它通过导入的模块执行时看起来失败了。在我之前的尝试中,我一直在 myfile.js 中执行对 require.context 的调用(见上文),它已被 index.js 导入,如下所示:

// index.js

import myModules from 'myfile.js';

ReactDOM.render(...);

但是,如果我将 index.js 更改为:

// index.js

const something = require.context('../../packages/', true, /(\w+)\.(\w+)\.(mdx?)/);
something.keys().forEach(key => console.log(key));

ReactDOM.render(...);

它就像一个魅力! 为什么?!

Require.context 这是一个 webpack 特性,而不是 cra 或其他东西。

那么为什么它不适用于您的 upd1upd2 而它适用于 upd3

答案很简单——因为这里使用了变量。 Webpack 需要你的代码是静态可分析的。这意味着当你编写 require.context('../src/directory/', true, /.ts$/) 时,webpack 认为 hmmm OK 我需要递归地查找和准备 src/directory 中的所有 .ts 文件,因为它可以在进一步的步骤中使用。

它不能使用变量,因为 require.context(myPathVariable, true, /.ts$/) 可以是任何东西。 Webpack 不知道 myPathVariablebuild 阶段是什么,因为它只会在 runtime 阶段计算。

此规则也适用于 dynamic importsimport('../src/keks/index.ts') 有效,import(myVar + '../src/keks/index.ts') 无效。

请参阅此 issue,其中包含有关 require.context "staticness" 的讨论和一些提示。

如何使动态路径工作

使用动态路径的一种方法是使用 DefinePlugin。但是你所有的动态路径都应该在 build 阶段被知道和计算(在 webpack 配置或任何 node.js 脚本中)。
示例:
webpack.config.js

module.exports = {
  plugins: [new DefinePlugin({ PACKAGES_DIR: JSON.stringify('path/to/packages') })]
}

然后:
index.ts
你可以使用 require.context(PACKAGES_DIR, true, /\.ts$/)import(PACKAGES_DIR + 'myfile.ts') 因为 webpack 已经知道一些关于这个路径的信息。