Создание-реакция-приложение импортирует ограничение вне каталога src

Я использую приложение create-реагировать. Я пытаюсь вызвать изображение из моей общей папки из файла внутри моего 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" />

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

32 ответа

Решение

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

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

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

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

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

Удалите его с помощью 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;
    }
  }
};

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

"/images/logo_2016.png"

вместо

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

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

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

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

Источник: https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-images-fonts-and-files

Есть несколько ответов, которые предлагают решения с 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()

Мне удалось импортировать файлы за пределы src/путем «копирования» внешних файлов с помощью file:как локальная зависимость.

      "dependencies": {
    "@my-project/outside-dist": "file:./../../../../dist".
}

тогда

      import {FooComponent} from "@my-project/outside-dist/components";

Нет ejectили же react-app-rewiredили другое стороннее решение.

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

Не нашел краткого решения для копирования и вставки TypeScript. Подумал, что выложу один.

В приведенном ниже коде используется , но его можно легко использовать для Cracoповторного подключения приложения или аналогичных решений. Вам просто нужно найти место, где у вас есть webpackConfig объект и передайте его предоставленным функциям.

Ну вот:

      module.exports = {
  plugins: [
    {
      plugin: {
        overrideWebpackConfig: ({ webpackConfig }) => {
          // This is where the fun begins!
          removeModuleScopingPlugin(webpackConfig);
          // Amend this with the root paths you wish to import from
          enableTypescriptImportsFromExternalPaths(webpackConfig, [
            path.resolve(__dirname, "../common/src/"),
          ]);
          return webpackConfig;
        },
      },
    },
  ],
};

Упомянутые функции - можете просто поместить их над module.exports, или какой-нибудь другой файл ( requireдобавив их потом):

      
function removeWebpackPlugin(webpackConfig, pluginName) {
  const scopePluginIndex = webpackConfig.resolve.plugins.findIndex(
    ({ constructor }) => constructor && constructor.name === pluginName
  );
  if (scopePluginIndex > -1) {
    webpackConfig.resolve.plugins.splice(scopePluginIndex, 1);
  }
}

function enableTypescriptImportsFromExternalPaths(
  webpackConfig,
  newIncludePaths
) {
  const oneOfRule = webpackConfig.module.rules.find((rule) => rule.oneOf);
  if (oneOfRule) {
    const tsxRule = oneOfRule.oneOf.find(
      (rule) => rule.test && rule.test.toString().includes("tsx")
    );

    if (tsxRule) {
      tsxRule.include = Array.isArray(tsxRule.include)
        ? [...tsxRule.include, ...newIncludePaths]
        : [tsxRule.include, ...newIncludePaths];
    }
  }
}

const removeModuleScopingPlugin = (webpackConfig) =>
  removeWebpackPlugin(webpackConfig, "ModuleScopePlugin");

Взято отсюда и здесь 🙏

Я думаю, что решение Лукаса Баха по использованию 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;
};

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

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;
};

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

  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

Добавляя к ответу Бартека Мацейчека, вот как это выглядит с 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;
    }
  }
};

Это ограничение гарантирует, что все файлы или модули (экспорт) находятся внутри 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: остерегайтесь последствий выброса.

Мне пришлось преодолеть ту же проблему в Truffle. Решение было таким:

Поскольку поведение по умолчанию Create-React-App запрещает импорт файлов из-за пределов папки src, нам нужно перенести контракты в нашу папку сборки внутри src. Мы можем копировать и вставлять их каждый раз, когда составляем наши контракты, но лучший способ - просто настроить Truffle так, чтобы файлы туда помещались.

В файле truffle-config.js замените содержимое следующим:

      const path = require("path");

module.exports = {
  contracts_build_directory: path.join(__dirname, "client/src/contracts")
};

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

Вот альтернатива, которая хорошо работает в простых случаях (используя fs а также ncp). Во время разработки не выключайте скрипт, который отслеживает изменения в ваших общих папках за пределами / src. После внесения изменений сценарий может автоматически скопировать общие папки в ваш проект. Вот пример рекурсивного просмотра одного каталога:

      
// This should be run from the root of your project

const fs = require('fs')
const ncp = require('ncp').ncp;

ncp.limit = 16

// Watch for file changes to your shared directory outside of /src
fs.watch('../shared', { recursive: true }, (eventType, filename) => {
    console.log(`${eventType}: ${filename}`)

    // Copy the shared folder straight to your project /src
    // You could be smarter here and only copy the changed file
    ncp('../shared', './src/shared', function(err) {
        if (err) {
          return console.error(err);
        }

        console.log('finished syncing!');
    });
})

Это сработало для меня без установки/изменения чего-либо

Контекст: я получил эту ошибку, когда пытался создать сборку, используя

Вещи, которые я сделал между работой и проваломyarn run build

Я обновил свой муравьиный дизайн до последней стабильной версии (v4.23.5).

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

  • Этот решил мою проблему. Но я не изменил импорт, который обращается к чему-то за пределами каталога src.
  • Изменения включают обновленный package.json, yarn.lock, новые реализации Antd (в основном изменение реквизита).
  • Не было смысла, почемуbuild commandсломался / почему ответответ работает.

Решение здесь

Так как все изменения связаны с package.json, yarn.lock. я удалилnode_modulesи начисто установил все пакеты.

Бегать

      yarn

или

      npm install

Это можно сделать напрямую, не используя путь к общей папке. Вы можете сделать это как

      <img src="/images/image-name" alt=""/>

Это происходит потому, что мы не используем App.js в браузере, в браузере выполняется только index.html, а путь к изображениям уже находится в публичной папке, содержащей файл index.html.

Пришел к той же проблеме в моем проекте и нашел это в официальных документах create-response-app: https://create-react-app.dev/docs/using-the-public-folder/

Есть «аварийный люк» для добавления актива вне модульной системы:

Если вы поместите файл в общую папку, он не будет обработан веб-пакетом. Вместо этого он будет скопирован в папку сборки нетронутой. Чтобы ссылаться на ресурсы в общей папке, вам необходимо использовать переменную среды с именем PUBLIC_URL.

Вот пример, который они предоставляют:

Вам не нужно извлекать, вы можете изменить react-scriptsconfig с библиотекой rescripts

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

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

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

  return config;
};

Если ваш файл находится в общей папке и если вы хотите импортировать его без извлечения или без использования react-app-rewired, то в этом случае вы можете получить доступ к файлу через имя домена и путь к файлу, а также используя axios. Пример: в общей папке находится файл шрифта с именем favico.ico. Вы хотите импортировать его в один файл, расположенный в src. Вы можете получить доступ к шрифту, используя следующую логику.

      axios.get('example.com/favico.ico').then(() => {
  // here you can access this file.
})

В приведенном выше примере example.com является доменом. Если у вас другая среда, такая как localhost, staging, production, то в этом случае доменное имя будет другим. Итак, чтобы получить favico.ico, вы можете использовать следующую логику.

      axios.get(`${window.location.origin}/favico.ico`).then(() => {
  // here you can access this file.
})

В приведенном выше примере вы window.location.origin даете вам текущий домен, что означает, что если вы запускаете свой код локально, он даст вам http://localhost:{portnumber}. Если ваш код запускается в рабочей среде, а рабочий домен — example.com, тогда , это даст вам «example.com». Таким образом, используя этот шаблон, вы можете получить доступ к ресурсам, расположенным в общей папке.

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

import photo from "./assets/yourphoto.jpeg"

то вы можете реализовать это следующим образом:

<img className="photo src={photo} alt="installation" />

Итак, дерево приложений выглядит следующим образом: -src папка -- папка ресурсов --- yourphoto.jpeg.

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

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

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

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

You can try using simlinks, but in reverse.

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

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

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

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

Очевидно, используя Create-react-app ограничит вам доступ к изображениям за пределами корневого каталога вашего проекта - обычно.

Быстрое решение этой проблемы - переместить изображения из public папку в srcпапка, и все готово.
Итак, ваш код будет, например, таким:

      background-image: URL('/src/images/img-2.jpg');

Если вы хотите получить доступ к файлам CSS из общего доступа, вы можете столкнуться с ошибкой ВНЕ КАТАЛОГА ИСТОЧНИКОВ

Кроме того, вы можете связать этот файл в index.html, который также находится в общедоступном каталоге.

      <link rel="stylesheet" href="App.css">

Это проблема с относительным импортом, которая могла быть вызвана тем, что мы использовали команду «create-response-app project», которая формирует каталог с именем project с папкой node_modules и несколькими другими файлами в общедоступных папках и папках src внутри него. Команда create-response-app накладывает ограничение на то, что мы не можем ничего импортировать из-за пределов src.

Моя проблема:

  1. Мне пришлось импортировать файлы css response-bootstrap, которые создаются в папке node_modules вне папки src.
  2. Я использовал import "../node_modules/bootstrap/dist/css/bootstrap.min.css"; но я получил ошибку на терминале.
  3. Я обнаружил, что могу создать новое приложение для реагирования и выполнить шаги решения от A до G, чтобы исправить эту проблему.

Решение: A) Создайте новое приложение для реагирования, используя create-react-app new

Б) cd новый

C) запустите эту команду: "npm install response-bootstrap bootstrap@4.6.0 " (без "" двойных кавычек)

D) в вашем файле реакции поместите это для импорта начальной загрузки: D.1) import "../node_modules/bootstrap/dist/css/bootstrap.min.css"; или D.2) кнопка импорта из "response-bootstrap / Button";

E) создайте элемент начальной загрузки, такой как Button или что-нибудь в вашем файле реакции, для D.1) <button className ="btn btn-success"> Bootstrap </ button> или для D.2) <Button option = "primary" > Bootstrap </ Button>

F) в терминале: cd src

G) в терминале: npm start,

на этот раз он будет успешно скомпилирован.

Обоснование: я наконец увидел, что реакция-бутстрап работает, как только я выполнил шаги от A до G по порядку, и на этот раз я не получил никакой ошибки. (Я подумал об этом решении, потому что:

  1. Я использовал npm install "@material-ui / icons", который был установлен в папке node_modules вне src.
  2. В моем файле реакции я использовал import Add из "@material-ui / icons / Add"
  3. и значки Material-ui у меня работали нормально, но здесь мы также импортируем извне src, из node_modules .. и все работает нормально. Почему на этот раз нет ошибки импорта из-за пределов src)
  4. Вот почему я просто создал новое приложение для реагирования и выполнил шаги решения от A до G.

Если вы хотите установить фоновое изображение с помощью CSS. Таким образом, вы должны установить изображение, используя URL-адрес вашего локального хоста, и добавить путь к вашему изображению. Просто посмотрите пример ниже.

      .banner {
  width: 100%;
  height: 100vh;
  background-image: url("http://localhost:3000/img/bg.jpg");
  background-size: cover;
  background-repeat: no-repeat;
}

Публикация здесь того, что @Flaom написал в качестве комментария в ответе, отмеченном как ответ, и это действительно спасает жизни:

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

  • Флом

РЕДАКТИРОВАТЬ Добавлено больше информации по запросу @cigien.

Все приведенные выше ответы очень хорошо описывают, почему мы не можем использовать изображение из общей папки, когда создаем наше приложение для реагирования с помощью приложения create-реагировать. Имея проблему сам и читая все эти ответы, я понял, что ответы говорят о том, чтобы «взломать» приложение, чтобы удалить модуль, который нас ограничивает. В некоторых ответах даже нет опции отмены. Для «обучающего» приложения это нормально.

Лично я бы не хотел добавлять решение, меняющее концепцию приложения, в свой собственный проект, особенно в коммерческий. Решение @Flaom является самым простым, и если что-то изменится в будущем, его можно будет заменить другим решением. В нем нет риска, его можно удалить в любое время и он самый простой.

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