Создание-реакция-приложение импортирует ограничение вне каталога 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 пользователю. Структура файла должна соответствовать выбранному вами методу. Два варианта:
Используйте модульную систему (
import x from y
) поставляется с response-create-app и связывает его с вашим JS. Поместите изображение внутрьsrc
папка.Подавать это от
public
папку и пусть Node обслуживает файл. create-реагировать-приложение также, очевидно, поставляется с переменной среды, например<img src={process.env.PUBLIC_URL + '/img/logo.png'} />;
, Это означает, что вы можете ссылаться на него в своем приложении React, но при этом он будет обслуживаться через Node, а ваш браузер запрашивает его отдельно в обычном GET-запросе.
Есть несколько ответов, которые предлагают решения с 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();
}
Вы можете снять это ограничение с помощью
- либо изменить этот кусок кода (не рекомендуется)
- или сделать
eject
затем удалитеModuleScopePlugin.js
из каталога. - или комментарий / удалить
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-scripts
config с библиотекой 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.
Моя проблема:
- Мне пришлось импортировать файлы css response-bootstrap, которые создаются в папке node_modules вне папки src.
- Я использовал import "../node_modules/bootstrap/dist/css/bootstrap.min.css"; но я получил ошибку на терминале.
- Я обнаружил, что могу создать новое приложение для реагирования и выполнить шаги решения от 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 по порядку, и на этот раз я не получил никакой ошибки. (Я подумал об этом решении, потому что:
- Я использовал npm install "@material-ui / icons", который был установлен в папке node_modules вне src.
- В моем файле реакции я использовал import Add из "@material-ui / icons / Add"
- и значки Material-ui у меня работали нормально, но здесь мы также импортируем извне src, из node_modules .. и все работает нормально. Почему на этот раз нет ошибки импорта из-за пределов src)
- Вот почему я просто создал новое приложение для реагирования и выполнил шаги решения от 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 является самым простым, и если что-то изменится в будущем, его можно будет заменить другим решением. В нем нет риска, его можно удалить в любое время и он самый простой.