Ограничение импорта приложения create-response-app за пределы каталога src


162

Я использую приложение create-response-app. Я пытаюсь вызвать изображение из моей общей папки из файла внутри моего src/components. Я получаю это сообщение об ошибке.

./src/components/website_index.js Модуль не найден: вы попытались импортировать ../../public/images/logo/WC-BlackonWhite.jpg, который находится за пределами каталога проекта src /. Относительный импорт за пределами src / не поддерживается. Вы можете переместить его внутрь src / или добавить на него символическую ссылку из node_modules / проекта.

import logo from '../../public/images/logo_2016.png'; <img className="Header-logo" src={logo} alt="Logo" />

Я читал много вещей, в которых говорилось, что вы можете импортировать путь, но это все еще не работает для меня. Любая помощь будет принята с благодарностью. Я знаю, что есть много подобных вопросов, но все они говорят мне импортировать логотип или изображение настолько ясно, что я упускаю что-то в общей картине.


3
Вам нужно. ../public/images/logo_2016.pngВы поднялись дважды, сначала из папки компонентов, затем из папки src.
Chris G

./src/components/website_index.js Модуль не найден: вы попытались импортировать ../../public/images/logo/WC-BlackonWhite.jpg, который находится за пределами каталога проекта src /. Относительный импорт за пределами src / не поддерживается. Вы можете переместить его в src / или добавить на него символическую ссылку из node_modules / проекта.
Дэвид Бриертон

Мой комментарий предполагает, что ваша publicпапка находится прямо внутри вашей srcпапки. В вашем комментарии без комментариев используется старый путь, начинающийся с, ../..поэтому вы не уверены, о чем вы думаете ?
Chris G

3
нет публики на том же уровне, что и src
Дэвид Бриертон

Что они имеют в виду под "или добавить на него символическую ссылку из node_modules / проекта"?
Julha

Ответы:


143

Это специальное ограничение, добавленное разработчиками create-react-app. Он реализован ModuleScopePluginдля того, чтобы файлы располагались в src/. Этот плагин гарантирует, что относительный импорт из исходного каталога приложения не будет выходить за его пределы.

Вы можете отключить эту функцию (одним из способов) с помощью ejectпроекта create-react-app.

Большинство функций и их обновления скрыты внутри системы create-react-app. Если вы сделаете, у ejectвас больше не будет некоторых функций и его обновления. Так что если вы не готовы управлять и настраивать приложение, включенное для настройки webpack и так далее - не выполняйте ejectоперацию.

Играйте по существующим правилам (переходите в src). Но теперь вы можете узнать, как снять ограничение: сделать ejectи удалить ModuleScopePluginиз файла конфигурации webpack .


Вместо этого ejectесть промежуточные решения, такие как rewire, который позволяет программно изменять конфигурацию webpack без eject. Но удаление в ModuleScopePluginплагин не хорошо - это теряет некоторую защиту и не добавляет некоторые функции , доступные в src.

Лучше всего добавить полностью работающие дополнительные каталоги, подобные src. Это можно сделать с помощью response-app-rewire-alias


Не импортируйте из publicпапки - они будут дублироваться в buildпапке и будут доступны по двум разным URL-адресам (или с разными способами загрузки), что в конечном итоге ухудшит размер загружаемого пакета.

Импорт из srcпапки предпочтительнее и имеет преимущества. Все будет упаковано веб-пакетом в бандл с оптимальным размером чанков и для максимальной эффективности загрузки .


4
если вы создаете символическую ссылку в ./src и импортируете оттуда - сборка не работает (плагин babel не преобразует источники в папках с символическими ссылками). Таким образом, с этим ограничением, включенным и не имеющим символической ссылки в src, вы фактически попадаете в тюрьму без совместного использования кода с другими проектами (если вы не выберете полностью эмигрировать / извлечь из CRA)
вице-президент,

2
@VP, но в сообщении об ошибке написано «добавить на него символическую ссылку из node_modules / проекта», это не работает?
adrianmc 05

2
@adrianmc. добавление символической ссылки из node_modules проекта не работает, потому что многие проекты используют общие компоненты / код, которые не являются node_modules. Например, я делюсь кодом между React Native и React native web. Эти «фрагменты» не являются node_modules, и эти два проекта фактически имеют разные node_modules.
VP

2
Как это принятый ответ? Это фиктивное ограничение легко устраняется простой настройкой NODE_PATH=./src/..в .envфайле. Таким образом, вы можете импортировать файлы из-за пределов папки src, не испытывая боли, связанной с извлечением вашего приложения.
Flaom

1
Похоже, что baseUrl больше не работает. Любая попытка установить его за пределами исходного дерева ошибки с: Ваш проект baseUrlможет быть установлен только на srcили node_modules. Приложение Create React в настоящее время не поддерживает другие значения. Трюк с добавлением @ Flaom ./srcтоже не помогает.
bluenote10,

50

Пакет react-app-rewired можно использовать для удаления плагина. Таким образом, вам не придется выталкивать.

Следуйте инструкциям на странице пакета npm (установите пакет и переверните вызовы в файле package.json) и используйте config-overrides.jsфайл, похожий на этот:

const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');

module.exports = function override(config, env) {
    config.resolve.plugins = config.resolve.plugins.filter(plugin => !(plugin instanceof ModuleScopePlugin));

    return config;
};

Это удалит ModuleScopePlugin из используемых плагинов WebPack, но оставит все остальное, как было, и устранит необходимость извлечения.


5
Отличный ответ. Вы можете использовать дополнительные возможности react-app-rewiredс помощью [ github.com/arackaf/customize-crapting(customize-cra) . Тогда конфиг будет использовать только babelInclude([path.resolve('src'), path.resolve('../common')])и removeModuleScopePlugin().
ivosh

не могли бы вы подтвердить, где мне разместить этот фрагмент кода?
bijayshrestha

1
@bijayshrestha Прочтите файл readme проекта с переустановкой react-app, там объясняется, как его настроить. Во время установки вы создадите config-overrides.jsфайл, в который сможете поместить код.
Лукас Бах

Удаление ModuleScopePluginплагина - не лучшая идея. Лучше добавить полностью рабочие дополнительные каталоги, аналогичные srcиспользованию
response

2
Это решение работает с Typescript? Я не могу заставить его работать с TS.

32

Если ваши изображения находятся в общей папке, вам следует использовать

"/images/logo_2016.png"

в вашем <img> srcвместо импорта

'../../public/images/logo_2016.png'; 

Это будет работать

<img className="Header-logo" src="/images/logo_2016.png" alt="Logo" />

2
У меня не работает. Получение того же сообщения - 'вне каталога проекта src /. Относительный импорт за пределами src / не поддерживается. '
Аркадий

Ваш ответ правильный, ИМО, но я взял на себя смелость пояснить, что вы говорите о пути <img src="...">
Дмитрий Юдаков

1
Это было именно то, что я искал! Я просто добавил папку «images» в каталог «src» моего CRA, а затем смог использовать<img src="/images/logo.png" alt="Logo" />
Амос Лонг

1
@Arkady, у вас все еще может быть заявление об импорте вашей фотографии. Удалите этот оператор импорта и просто укажите прямой путь в атрибуте src.
Яшвин Мунсадвала,

27

Чтобы предложить немного больше информации к другим ответам. У вас есть два варианта доставки файла .png пользователю. Структура файла должна соответствовать выбранному вами методу. Есть два варианта:

  1. Используйте модуль system ( import x from y), поставляемый с react-create-app, и свяжите его со своим JS. Поместите изображение в srcпапку.

  2. Обслуживайте его из publicпапки и позвольте Node обслуживать файл. create-response-app также явно поставляется с переменной окружения, например <img src={process.env.PUBLIC_URL + '/img/logo.png'} />;. Это означает, что вы можете ссылаться на него в своем приложении React, но при этом он будет обслуживаться через Node, а ваш браузер запрашивает его отдельно в обычном запросе GET.

Источник: create-response-app


Предложение №2 - это именно то, что вызывает у меня следующую ошибку: Модуль не найден: вы пытались импортировать ./../../../public/CheersBar-Drinks-147.jpg, который находится за пределами каталога проекта src / . Относительный импорт за пределами src / не поддерживается. Вы можете переместить его в src / или добавить на него символическую ссылку из node_modules / проекта.
Амос Лонг

14

Удалите его с помощью Craco:

module.exports = {
  webpack: {
    configure: webpackConfig => {
      const scopePluginIndex = webpackConfig.resolve.plugins.findIndex(
        ({ constructor }) => constructor && constructor.name === 'ModuleScopePlugin'
      );

      webpackConfig.resolve.plugins.splice(scopePluginIndex, 1);
      return webpackConfig;
    }
  }
};

1
Голосуй за крако! Craco поддерживает CRA 3.x
Роман Подлинов

12

Вам нужно перейти WC-BlackonWhite.jpgв свой srcкаталог. publicКаталог для статических файлов , который будет связан непосредственно в HTML (например , как фавиконка), а не вещи , которые вы собираетесь импортировать непосредственно в пачку.


Я видел, как другие поступали таким образом. Вот почему я подумал, что это правильный путь,
Дэвид Бриертон

@DavidBrierton: эта мера предосторожности могла быть добавлена ​​в более позднюю версию приложения create-response-app.
Джо Клей

11

Есть несколько ответов, которые предоставляют решения react-app-rewired, но customize-craпредоставляют специальный removeModuleScopePlugin()API, который немного более элегантен. (Это то же самое решение, но абстрагированное customize-craпакетом.)

npm i --save-dev react-app-rewired customize-cra

package.json

"scripts": {
    - "start": "react-scripts start"
    + "start": "react-app-rewired start",
    ...
},

config-overrides.js

const { removeModuleScopePlugin } = require('customize-cra')

module.exports = removeModuleScopePlugin()

2
ты спас мне день!
lmiguelvargasf

5

Я думаю, что решение Лукаса Баха по использованию response-app- rewired для изменения конфигурации webpack - хороший способ, однако я бы не исключил весь ModuleScopePlugin, а вместо этого внес бы в белый список конкретный файл, который можно импортировать за пределами src:

config-overrides.js

const ModuleScopePlugin = require("react-dev-utils/ModuleScopePlugin");
const path = require("path");

module.exports = function override(config) {
  config.resolve.plugins.forEach(plugin => {
    if (plugin instanceof ModuleScopePlugin) {
      plugin.allowedFiles.add(path.resolve("./config.json"));
    }
  });

  return config;
};

На данный момент это лучшее решение.
adi518

5

установите эти два пакета

npm i --save-dev react-app-rewired customize-cra

package.json

"scripts": {
    - "start": "react-scripts start"
    + "start": "react-app-rewired start"
},

config-overrides.js

const { removeModuleScopePlugin } = require('customize-cra');

module.exports = function override(config, env) {
    if (!config.plugins) {
        config.plugins = [];
    }
    removeModuleScopePlugin()(config);

    return config;
};


4

Это ограничение гарантирует, что все файлы или модули (экспорт) находятся внутри src/каталога, в котором находится реализация ./node_modules/react-dev-utils/ModuleScopePlugin.js, в следующих строках кода.

// Resolve the issuer from our appSrc and make sure it's one of our files
// Maybe an indexOf === 0 would be better?
     const relative = path.relative(appSrc, request.context.issuer);
// If it's not in src/ or a subdirectory, not our request!
     if (relative.startsWith('../') || relative.startsWith('..\\')) {
        return callback();
      }

Вы можете снять это ограничение,

  1. либо изменить этот фрагмент кода (не рекомендуется)
  2. или сделатьeject потом удалить ModuleScopePlugin.jsиз каталога.
  3. или прокомментировать / удалить const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');из./node_modules/react-scripts/config/webpack.config.dev.js

PS: опасайтесь последствий выброса .


Спасибо @SurajRao, я переместил его сюда. Надеюсь, так лучше.
its4zahoor

@PattycakeJr Да, поэтому ниже я сказал остерегаться последствий выброса.
its4zahoor

3

Изображение в общей папке

  use image inside html extension
  <img src="%PUBLIC_URL%/resumepic.png"/>

  use image inside  js extension
  <img src={process.env.PUBLIC_URL+"/resumepic.png"}/>
  • использовать изображение внутри расширения js

2

Извлекать не нужно, вы можете изменить react-scriptsконфигурацию с помощью библиотеки rescripts

Тогда это сработает:

module.exports = config => {
  const scopePluginIndex = config.resolve.plugins.findIndex(
    ({ constructor }) => constructor && constructor.name === "ModuleScopePlugin"
  );

  config.resolve.plugins.splice(scopePluginIndex, 1);

  return config;
};

1

Если вам нужно импортировать только один файл, например README.md или package.json, его можно явно добавить в ModuleScopePlugin ().

config / paths.js

const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
module.exports = {
  appPackageJson: resolveApp('package.json'),
  appReadmeMD:    resolveApp('README.md'),
};

config / webpack.config.dev.js + config / webpack.config.prod.js

module.exports = {
  resolve: {
    plugins: [
      // Prevents users from importing files from outside of src/ (or node_modules/).
      // This often causes confusion because we only process files within src/ with babel.
      // To fix this, we prevent you from importing files out of src/ -- if you'd like to,
      // please link the files into your node_modules/ and let module-resolution kick in.
      // Make sure your source files are compiled, as they will not be processed in any way.
      new ModuleScopePlugin(paths.appSrc, [
          paths.appPackageJson,
          paths.appReadmeMD         // README.md lives outside of ./src/ so needs to be explicitly included in ModuleScopePlugin()
      ]),
    ]
  }
}

3
Для этого нужно сначала извлечь из приложения create-react-app, не так ли?
Бо Смит


1

Если вам нужно несколько модификаций, например, при использовании дизайна муравьев , вы можете комбинировать несколько функций следующим образом:

const {
  override,
  removeModuleScopePlugin,
  fixBabelImports,
} = require('customize-cra');

module.exports = override(
  fixBabelImports('import', {
    libraryName: 'antd',
    libraryDirectory: 'es',
    style: 'css',
  }),
  removeModuleScopePlugin(),
);

1

Добавляя к ответу Бартека Мацейчека, вот как это выглядит с Craco:

const ModuleScopePlugin = require("react-dev-utils/ModuleScopePlugin");
const path = require("path");

module.exports = {
  webpack: {
    configure: webpackConfig => {
      webpackConfig.resolve.plugins.forEach(plugin => {
        if (plugin instanceof ModuleScopePlugin) {
          plugin.allowedFiles.add(path.resolve("./config.json"));
        }
      });
      return webpackConfig;
    }
  }
};


0

Вы можете попробовать использовать симлинки, но в обратном порядке.

React не будет следовать симлинкам, но вы можете переместить что-нибудь в исходный каталог и создать на него симлинк.

В корне моего проекта у меня был каталог сервера узлов, в котором было несколько файлов схемы. Я хотел использовать их во внешнем интерфейсе, поэтому я:

  • переместил файлы / src
  • в термине я cd'ed туда, где файлы схемы принадлежали на сервере
  • ln -s SRC_PATH_OF_SCHEMA_FILE

Это дало возможность отреагировать на то, что он искал, и узел был совершенно счастлив, включая файлы через simlinks.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.