Как заставить require.context работать с приложением Create React с / без Craco?
Я пытаюсь выполнить некоторые требования во время выполнения через require.context
в моем проекте CRA (с Typescript), но я получаю только такие ошибки:
TypeError: __webpack_require__(...). Контекст не является функцией
а также
Критическая зависимость: функция require используется таким образом, что зависимости не могут быть извлечены статически
Я где-то читал, что теперь это нужно полифилить через Babel или cra-rewired
. Ну, я уже использую Craco для включения Less-поддержки, но я не знаю, как добавитьrequire.context
в мои конфиги Craco.
Кто-нибудь знает, как это сделать?
Обновление: вот как я вызываю require.context:
const packagesDirectory = path.join(__dirname, '../../../../packages');
const textDataContext = require.context(packagesDirectory, true, /(\w+)\.(\w+)\.(mdx?)/);
Обновление 2:
Как показывают некоторые комментарии в этой ветке, я попытался добавить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 не является функцией
Обновление 3:
Кажется, CRA действительно поддерживает require.context без необходимости в полифиллах. Но похоже, что он не работает, когда он выполняется через импортированный модуль. В своих предыдущих попытках я звонил наrequire.context
в myfile.js
(см. выше), который был импортирован 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(...);
Работает как часы! Зачем?!
1 ответ
Require.context
это функция веб-пакета, а не cra
или что-то другое.
Так почему это не работает с вашим upd1
или upd2
и это связано с upd3
?
Ответ довольно прост - потому что здесь используется переменная. Webpack требует, чтобы ваш код был статически анализируемым. Это означает, что когда вы пишете, например,require.context('../src/directory/', true, /.ts$/)
webpack думает, хммм, мне нужно найти и подготовить все .ts
файлы в src/directory
рекурсивно, потому что его можно использовать в дальнейших шагах.
И он не может работать с переменными, потому что require.context(myPathVariable, true, /.ts$/)
может быть что угодно. Webpack не знаю чтоmyPathVariable
Я сидел build
фаза, потому что она будет рассчитана на runtime
только фаза.
Это правило также касается dynamic imports
. import('../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') })]
}
а потом:index.ts
вы можете использовать require.context(PACKAGES_DIR, true, /\.ts$/)
или import(PACKAGES_DIR + 'myfile.ts')
потому что webpack уже кое-что знает об этих путях.