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

o01*_*o01 6 javascript typescript webpack create-react-app craco

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

TypeError: __webpack_require__(...).context 不是函数

关键依赖:require函数的使用方式无法静态提取依赖

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

有人知道怎么做吗?

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

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

更新 2:

正如该线程中的一些评论所暗示的那样,我尝试babel-plugin-require-context-hook像这样添加到我的应用程序中:

// craco.config.js

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

module.exports = {
    plugins: [
        {plugin: CracoLessPlugin}
    ],
    babel: {
        plugins: ['require-context-hook']
    }
};
Run Code Online (Sandbox Code Playgroud)

然后我试过这样打电话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?)/);
Run Code Online (Sandbox Code Playgroud)

但是后来我收到了这个错误:

类型错误:fs.readdirSync 不是函数

更新 3:

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

// index.js

import myModules from 'myfile.js';

ReactDOM.render(...);
Run Code Online (Sandbox Code Playgroud)

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

// index.js

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

ReactDOM.render(...);
Run Code Online (Sandbox Code Playgroud)

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

nic*_*ock 4

Require.context这是一个 webpack 功能,而不是cra其他功能。

那么为什么它不能与您的upd1or一起使用upd2而可以与 一起使用upd3

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

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

这条规则也是关于dynamic importsimport('../src/keks/index.ts')会起作用,import(myVar + '../src/keks/index.ts')不会。

请参阅此问题的讨论和一些有关“静态”的提示require.context

如何让动态路径发挥作用

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

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

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