Ограничение импорта приложений create-react-app вне каталога src

Я использую приложение create-react-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" />

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

Ответы

Ответ 1

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

Вы можете отключить эту функцию, но только после операции eject проекта create-реагировать на приложение.

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

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


Поскольку create-реагировать-приложение v0.4.0 переменная среды NODE_PATH позволяет указать путь для абсолютного импорта.

Абсолютный импорт позволяет использовать import App from 'App' вместо import App from './App' относительно значения, указанного в переменной NODE_PATH.

Эта функция особенно полезна для monorepos или других вопросов конфигурации, но не для импорта изображений или чего-либо еще из папки public.

Содержимое папки public будет помещено в папку build и доступно по относительному URL. Кроме того, все импортированное будет обработано веб-пакетом и будет также помещено в папку build.

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

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

Ответ 2

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

  1. Используйте модульную систему (import x from y), поставляемую с Reaction-Create-App, и объедините ее с JS. Поместите изображение в папку src.

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

Источник: создать-реагировать-приложение

Ответ 3

Пакет response-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, но оставит все как есть и устранит необходимость извлечения.

Ответ 4

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

"/images/logo_2016.png"

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

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

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

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

Ответ 5

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

Ответ 6

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

// Resolve the issuer from our appSrc and make sure it one of our files
// Maybe an indexOf === 0 would be better?
     const relative = path.relative(appSrc, request.context.issuer);
// If it 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: остерегайтесь последствий выброса.

Ответ 7

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

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

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

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

  return config;
};

Ответ 8

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

конфиг /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()
      ]),
    ]
  }
}

Ответ 9

Лучшее решение - это разветкить react-scripts, это на самом деле упоминается в официальной документации, см. Альтернативы Ejecting.

Ответ 10

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

конфиг-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;
};