Как заставить 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 уже кое-что знает об этих путях.

Другие вопросы по тегам