Как получить require.context для работы с приложением Create React с / без Craco? - PullRequest
5 голосов
/ 19 января 2020

Я пытаюсь выполнить некоторые требования во время выполнения через require.context в моем проекте CRA (с Typescript), но я получаю только такие ошибки:

TypeError: __webpack_require __ ( ...). context не является функцией

и

Критическая зависимость: функция require используется таким образом, что зависимости не могут быть извлечены статически

Я где-то читал, что теперь это нужно заполнить через Вавилон или 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?)/);

Но тогда я получаю эту ошибку:

Ошибка типа: fs.readdirSyn c не является функцией

?

Обновление 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 Ответ

1 голос
/ 22 января 2020

Require.context это функция веб-пакета, а не cra или что-то еще.

Так почему он не работает с вашими upd1 или upd2 и с upd3?

Ответ довольно прост - потому что здесь используется переменная. Веб-пакет нуждается в статическом анализе вашего кода. Это означает, что когда вы пишете, например, require.context('../src/directory/', true, /.ts$/), веб-пакет думает, что хммм, ОК, мне нужно найти и подготовить все .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 "статичности".

Как получить Динамические c рабочие пути

Один из способов использования динамических c путей - использование DefinePlugin. Но все ваши динамические c пути должны быть известны и рассчитаны на фазе 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'), потому что веб-пакет уже знает что-то об этих путях.

...