Обмеження імпорту створення-реагувати на додаток за межами каталогу src


150

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

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


2
Вам потрібно ../public/images/logo_2016.pngВи піднялися двічі, спочатку з папки компонентів, а потім із папки src.
Кріс Г

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

Мій коментар передбачає, що ваша publicпапка знаходиться безпосередньо у вашій srcпапці. У вашому безконтактному коментарі є старий шлях, починаючи з того, ../..щоб не бути впевненим у вашому питанні?
Кріс Г

3
жодна публіка не знаходиться на такому ж рівні, як src
Девід Брієртон

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

Відповіді:


127

Це спеціальне обмеження, яке додають розробники create-react-app. Він реалізований для того, ModuleScopePluginщоб забезпечити перебування файлів src/. Цей плагін гарантує, що відносний імпорт із вихідного каталогу додатка не досягне його.

Ви можете відключити цю функцію, але лише після ejectроботи проекту create-react-app.

Більшість функцій та її оновлення приховані у внутрішній системі системи створення-реагування додатків. Якщо ви зробите це, у ejectвас більше не буде функцій та його оновлення. Тож якщо ви не готові керувати та конфігурувати додаток, що входить до налаштування веб-пакету тощо, - не робіть ejectоперацій.

Грати за існуючими правилами (перейти на src). Але тепер ви можете знати, як видалити обмеження: виконайте ejectта видаліть ModuleScopePluginз конфігураційного файлу webpack .


Так як створити реагують-додаток v0.4.0 в NODE_PATHзмінному оточенні дозволяє вказати шлях для абсолютного імпорту. А оскільки v3.0.0 NODE_PATH застаріло на користь встановлення baseUrlв jsconfig.jsonабо tsconfig.json.

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

Ця функція спеціально корисна для монорепортажів або інших питань конфігурації, але не для імпорту зображень чи чогось іншого з publicпапки.

Вміст publicпапки буде розміщений у buildпапці та доступний за відносною URL-адресою. Крім того, все імпортоване буде оброблено веб-пакетом і буде розміщено також у buildпапці.

Якщо ви імпортуєте щось із publicпапки, можливо, ця річ буде дублюватися у buildпапці та буде доступна двома різними URL-адресами (або з різними способами завантаження), що врешті-решт погіршить розмір завантаження пакета.

Імпорт із папки src є кращим і має переваги. Все буде упаковано веб-пакетом у комплект із шматочками оптимального розміру та для найкращої ефективності завантаження .


Існують проміжні рішення, а саме система перемикання, яка дозволяє програмно змінювати конфігурацію веб-пакету. але видаленняModuleScopePlugin плагін не є хорошим рішенням; краще додати повністю працюючі додаткові каталоги, схожі на src.

Наразі create-react-appне підтримує додаткові каталоги, крім srcкореневої папки. Це можна зробити, використовуючи псевдонім reakct-app-rewire


3
якщо ви створюєте символьне посилання всередині. Таким чином, з цим обмеженням на і без символьної посилання під src ви фактично поміщаєтесь у в'язницю "без спільного використання коду з іншими проектами" (якщо ви не вирішите повністю емігрувати / вилучати з CRA)
VP

2
@VP, але помилка говорить про те, що "додати до нього символьне посилання з node_modules проекту.", Це не працює?
adrianmc

Вони повинні зробити прапор, щоб відключити це під час запуску create-react-appдля тих, хто не хоче вийняти конфігурацію веб-пакету. Особисто я завжди викидаю, але деякі люди не відчувають себе комфортно, але возиться з веб-пакетами, що перешкоджає конфігурації.
TetraDev

2
@adrianmc. додавання символьної посилання з node_modules проекту не працює, оскільки багато проектів використовують компоненти / код спільного доступу, які не є node_modules. Наприклад, я ділюся кодом між рідною веб-програмою React Native та React. Ці фрагменти не є node_modules, і ці 2 проекти насправді мають різні node_modules.
ВП

1
Як це прийнята відповідь? Це хибне обмеження тривіально усувається просто встановленням NODE_PATH=./src/..у .envфайлі. Роблячи це, ви можете імпортувати з-за меж папки src, не переживаючи біль, пов’язану з викиданням програми.
Полум’я

47

Пакет 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-craclear(customize-cra) . Тоді конфігурація використовуватиме як раз babelInclude([path.resolve('src'), path.resolve('../common')])і removeModuleScopePlugin().
ivosh

чи можете ви підтвердити, де я повинен розмістити цей фрагмент коду?
bijayshrestha

1
@bijayshrestha Прочитайте файл readme проекту, що реагує на додаток, там пояснюється, як його налаштувати. Під час налаштування ви створите config-overrides.jsфайл, в який можете розмістити код.
Лукаш Бах

Видалення ModuleScopePluginплагіна не є хорошою ідеєю. Краще додати повністю працюючі додаткові каталоги, схожі на srcвикористання
reakas

1
Чи працює це рішення з Typescript? Я не можу змусити це працювати з TS.
користувач3053247

27

Щоб запропонувати трохи більше інформації на відповіді інших. У вас є два варіанти щодо доставки .png-файлу користувачеві. Структура файлу повинна відповідати обраному вами методу. Два варіанти:

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

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

Джерело: create-react-app


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

25

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

"/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 / не підтримується. "
Аркадій

Ваша відповідь правильна IMO, але я взяв на себе <img src="...">
Дмитро Юдаков

1
Це саме те, що я шукав! Я просто додав папку "images" в каталог "src" моєї CRA, а потім мені вдалося скористатися<img src="/images/logo.png" alt="Logo" />
Amos Long

12

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


Я бачив, як інші роблять це так. Ось чому я подумав, що це правильний шлях
Девід Брієртон

@DavidBrierton: Ця обережність, можливо, була додана в більш новій версії програми create-react-app.
Джо Клей

8

Є кілька відповідей, які пропонують рішення 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()

1
ти врятував мій день!
lmiguelvargasf

6

Видаліть його за допомогою 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;
    }
  }
};

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

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

встановити ці два пакети

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

2

Не потрібно видаляти, ви можете змінити react-scriptsконфігурацію з бібліотекою рескриптів

Це діяло б тоді:

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

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

  return config;
};

2

Я думаю, що рішення Лукаша Баха використовувати реакційне з'єднання з додатком для зміни конфігурації веб-пакету - це хороший шлях, однак я не виключав би весь модуль 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

2

Зображення всередині загальнодоступної папки

  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 Розширення

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, ні?
Beau Smith


1

Якщо вам потрібні кілька модифікацій, як-от при використанні мурашиного дизайну , ви можете комбінувати декілька функцій на зразок цієї:

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

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

1

Додавши до відповіді Бартека Мацейчечка, ось як це виглядає з Крако:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.