Create React App(含Craco)中require.context使用异常的排查与疑问
解决CRA+TypeScript中require.context的调用问题
先直接解答你最后发现的核心疑问:为什么直接在index.js里调用require.context正常,放在被导入的myfile.js里就失败? 这本质是Webpack对require.context的静态分析规则导致的,结合你之前的错误,咱们一步步拆解:
问题根源分析
CRA内置的Webpack原生支持require.context,但它是编译时静态特性,Webpack需要在编译阶段就能确定两个关键信息:
- 要扫描的目录路径(必须是静态字符串,不能是运行时动态计算的)
- 匹配的文件规则
你在myfile.js里的写法有两个致命问题:
const packagesDirectory = path.join(__dirname, '../../../../packages'); const textDataContext = require.context(packagesDirectory, true, /(\w+)\.(\w+)\.(mdx?)/);
path.join(__dirname, ...)是运行时动态计算的路径,Webpack编译时无法提前知晓这个路径的具体指向,因此没法静态扫描目录生成对应的context函数,最终导致运行时出现__webpack_require__(...).context is not a function错误。- 浏览器环境中根本没有
__dirname和fs模块(你后来用babel插件出现fs.readdirSync错误,就是因为这个插件模拟的是Node环境的require.context,完全不兼容浏览器)。
而你在index.js里用的是静态相对路径:
const something = require.context('../../packages/', true, /(\w+)\.(\w+)\.(mdx?)/);
Webpack编译时能直接识别这个路径,扫描对应目录生成context函数,所以运行一切正常。
正确解决方案
方案1:使用静态相对路径(最推荐,符合Webpack设计)
把myfile.js里的动态路径改成相对于当前文件的静态字符串,比如:
// myfile.js // 注意:路径是相对于myfile.js的位置,而非项目根目录 const textDataContext = require.context('../../../../packages', true, /(\w+)\.(\w+)\.(mdx?)/);
这样Webpack编译时就能扫描到目标目录,生成对应的context函数,运行时不会再报错。
方案2:如果必须动态指定路径(不推荐)
如果业务需求确实需要动态路径,那require.context就不再适用了,你可以改用Webpack的动态import结合glob(需要额外配置):
- 安装依赖:
npm install glob --save-dev - 在craco.config.js中配置webpack:
const CracoLessPlugin = require('craco-less'); const glob = require('glob'); module.exports = { plugins: [{ plugin: CracoLessPlugin }], webpack: { configure: (webpackConfig) => { // 添加glob相关解析逻辑 return webpackConfig; } } };
- 在代码中用glob动态获取文件路径,再用动态import加载:
import glob from 'glob'; // glob会在Webpack打包阶段处理路径,而非浏览器运行时 const files = glob.sync('../../../../packages/**/*.mdx', { cwd: __dirname }); files.forEach(file => { import(file).then(module => { // 处理加载的模块 }); });
不过这种方式会失去Webpack的tree-shaking优化,除非必要不建议使用。
避坑总结
- 不要使用
babel-plugin-require-context-hook:它是为Node环境设计的,浏览器环境没有fs模块,必然报错。 - 永远记住
require.context的路径必须是静态字符串:Webpack的静态分析是核心,动态路径会直接导致它失效。 - 浏览器环境没有
__dirname:CRA打包后的代码运行在浏览器,Node的内置变量和模块都不可用。
内容的提问来源于stack exchange,提问作者o01
相关产品推荐
相关产品推荐

