Die Create-React-App importiert Einschränkungen außerhalb des src-Verzeichnisses

149

Ich benutze die Create-React-App. Ich versuche, ein Bild aus meinem öffentlichen Ordner aus einer Datei in meinem Ordner aufzurufen src/components. Ich erhalte diese Fehlermeldung.

./src/components/website_index.js Modul nicht gefunden: Sie haben versucht, ../../public/images/logo/WC-BlackonWhite.jpg zu importieren, das außerhalb des Projektverzeichnisses src / liegt. Relative Importe außerhalb von src / werden nicht unterstützt. Sie können es entweder in src / verschieben oder einen Symlink aus den node_modules / des Projekts hinzufügen.

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

Ich habe viele Dinge gelesen, die besagen, dass Sie einen Import in den Pfad durchführen können, aber das funktioniert bei mir immer noch nicht. Jede Hilfe wäre sehr dankbar. Ich weiß, dass es viele Fragen wie diese gibt, aber alle sagen mir, dass ich ein Logo oder ein Bild so deutlich importieren soll, dass mir etwas im Gesamtbild fehlt.

David Brierton
quelle
2
Sie müssen ../public/images/logo_2016.pngzweimal nach oben gegangen sein, zuerst aus dem Komponentenordner, dann aus dem src-Ordner.
Chris G
./src/components/website_index.js Modul nicht gefunden: Sie haben versucht, ../../public/images/logo/WC-BlackonWhite.jpg zu importieren, das außerhalb des Projektverzeichnisses src / liegt. Relative Importe außerhalb von src / werden nicht unterstützt. Sie können es entweder in src / verschieben oder einen Symlink aus den node_modules / des Projekts hinzufügen.
David Brierton
Mein Kommentar geht davon aus, dass sich Ihr publicOrdner direkt in Ihrem srcOrdner befindet. Ihr kommentarloser Kommentar enthält den alten Pfad, der mit beginnt. Sie sind sich ../..also nicht sicher, worum es Ihnen geht?
Chris G
3
Kein Publikum ist auf dem gleichen Niveau wie src
David Brierton
Was meinen sie mit "oder fügen Sie einen Symlink aus den node_modules /" des Projekts hinzu?
Julha

Antworten:

125

Dies ist eine spezielle Einschränkung, die von Entwicklern der Create-React-App hinzugefügt wurde. Es wird implementiert, ModuleScopePluginum sicherzustellen, dass sich Dateien in befinden src/. Dieses Plugin stellt sicher, dass relative Importe aus dem Quellverzeichnis der App nicht außerhalb davon gelangen.

Sie können diese Funktion deaktivieren, jedoch erst nach dem ejectAusführen des Projekts "App erstellen, reagieren, App".

Die meisten Funktionen und deren Updates sind in den Interna des Create-React-App-Systems verborgen. Wenn Sie machen, werden ejectSie einige Funktionen und deren Update nicht mehr haben. Wenn Sie also nicht bereit sind, die mitgelieferte Anwendung zum Konfigurieren von Webpack usw. zu verwalten und zu konfigurieren, führen Sie keine ejectOperation aus.

Spielen Sie nach den bestehenden Regeln (gehen Sie zu src). Aber jetzt können Sie wissen , wie Einschränkung zu entfernen: tun , ejectund entfernen Sie ModuleScopePluginaus webpack Konfigurationsdatei .


Seit create-react-app v0.4.0 kann mit der NODE_PATHUmgebungsvariablen ein Pfad für den absoluten Import angegeben werden. Und da v3.0.0 NODE_PATH zugunsten der Einstellung baseUrlin jsconfig.jsonoder veraltet ist tsconfig.json.

Beim absoluten Import kann import App from 'App'stattdessen import App from './App'relativ zum in der Basis-URL angegebenen Wert verwendet werden.

Diese Funktion ist besonders nützlich für Monorepos oder andere Konfigurationsfragen, jedoch nicht zum Importieren von Bildern oder anderen Elementen aus Ordnern public.

Der Inhalt des publicOrdners wird im buildOrdner abgelegt und ist über die relative URL verfügbar. Außerdem wird alles, was importiert wird, per Webpack verarbeitet und auch in einem buildOrdner abgelegt .

Wenn Sie etwas aus einem publicOrdner importieren , wird dieses Ding wahrscheinlich im buildOrdner dupliziert und ist über zwei verschiedene URLs (oder mit verschiedenen Möglichkeiten zum Laden) verfügbar, was letztendlich die Downloadgröße des Pakets verschlechtert.

Der Import aus dem src- Ordner ist vorzuziehen und hat Vorteile. Alles wird per Webpack in das Bündel gepackt, wobei die Brocken die optimale Größe und die beste Ladeeffizienz aufweisen .


Es gibt Zwischenlösungen, nämlich das Rewire- System, mit dem Sie die Webpack-Konfiguration programmgesteuert ändern können. Das Entfernen des ModuleScopePluginPlugins ist jedoch keine gute Lösung. Es ist besser, voll funktionsfähige zusätzliche Verzeichnisse hinzuzufügen, die denen ähneln src.

Derzeit werden create-react-appkeine weiteren Verzeichnisse als srcim Stammordner unterstützt. Dies kann mit dem React-App-Rewire-Alias ​​erfolgen

oklas
quelle
3
Wenn Sie Symlink in ./src erstellen und von dort importieren, funktioniert der Build nicht (das Babel-Plugin transformiert keine Quellen in Symlink-Ordnern). Mit dieser Einschränkung, on und no-symlink unter src, werden Sie effektiv in ein Gefängnis gebracht, in dem kein Code mit anderen Projekten geteilt werden kann (es sei denn, Sie wählen die vollständige Auswanderung / Ausweisung aus der CRA)
VP
2
@VP, aber der Fehler besagt, dass "ein Symlink aus den node_modules /. Des Projekts hinzugefügt werden soll". Funktioniert dies nicht?
Adrianmc
Sie sollten ein Flag setzen, um dies zu deaktivieren, wenn sie create-react-appfür diejenigen ausgeführt werden, die die Webpack-Konfiguration nicht auswerfen möchten. Persönlich werfe ich immer aus, aber einige Leute fühlen sich nicht wohl und spielen doch mit der entmutigenden Konfiguration von Webpacks.
TetraDev
2
@adrianmc. Das Hinzufügen eines Symlinks aus den Knotenmodulen des Projekts funktioniert nicht, da viele Projekte Freigabekomponenten / Code verwenden, die keine Knotenmodule sind. Zum Beispiel teile ich Code zwischen React Native und React Native Web. Diese 'Snippets' sind keine node_modules, und diese beiden Projekte haben tatsächlich unterschiedliche node_modules.
VP
1
Wie ist das die akzeptierte Antwort? Diese falsche Einschränkung wird trivial durch einfaches Einstellen NODE_PATH=./src/..in der .envDatei beseitigt . Auf diese Weise können Sie von außerhalb des src-Ordners importieren, ohne die mit dem Auswerfen Ihrer App verbundenen Probleme zu haben.
Flaom
47

Das Paket react-app-rewired kann verwendet werden, um das Plugin zu entfernen. Auf diese Weise müssen Sie nicht auswerfen.

Befolgen Sie die Schritte auf der npm-Paketseite (installieren Sie das Paket und drehen Sie die Aufrufe in der Datei package.json um) und verwenden Sie eine config-overrides.jsähnliche Datei wie diese:

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

Dadurch wird das ModuleScopePlugin aus den verwendeten WebPack-Plugins entfernt, der Rest bleibt jedoch unverändert, und das Auswerfen entfällt.

Lukas Bach
quelle
5
Gute Antwort. Sie können react-app-rewiredmit [ github.com/arackaf/customize-cra weibl . ( Customize-cra) weiter nutzen . Dann wird die Konfiguration nur babelInclude([path.resolve('src'), path.resolve('../common')])und verwenden removeModuleScopePlugin().
ivosh
Können Sie bitte bestätigen, wo ich dieses Code-Snippet platzieren soll?
Bijayshrestha
1
@bijayshrestha Lesen Sie die Readme-Datei des React-App-Rewired-Projekts. Dort wird erklärt, wie Sie es einrichten. Während des Setups erstellen Sie eine config-overrides.jsDatei, in die Sie den Code einfügen können.
Lukas Bach
Das ModuleScopePluginPlugin zu entfernen ist keine gute Idee. Es ist besser, voll funktionsfähige zusätzliche Verzeichnisse hinzuzufügen, ähnlich wie bei der srcVerwendung des React-App-Rewire-Alias
oklas
Funktioniert diese Lösung mit Typescript? Ich kann es nicht mit TS zum Laufen bringen.
user3053247
27

Um den Antworten anderer ein bisschen mehr Informationen zu bieten. Sie haben zwei Möglichkeiten, wie Sie die PNG-Datei an den Benutzer senden können. Die Dateistruktur sollte der von Ihnen gewählten Methode entsprechen. Die zwei Optionen sind:

  1. Verwenden Sie das import x from ymit der React-Create-App gelieferte Modulsystem ( ) und bündeln Sie es mit Ihrem JS. Legen Sie das Bild in den srcOrdner.

  2. Servieren Sie es aus dem publicOrdner und lassen Sie Node die Datei bereitstellen. create-react-app enthält anscheinend auch eine Umgebungsvariable, z <img src={process.env.PUBLIC_URL + '/img/logo.png'} />;. Dies bedeutet, dass Sie in Ihrer React-App darauf verweisen können, es aber weiterhin über Node bereitstellen können, wobei Ihr Browser es in einer normalen GET-Anforderung separat anfordert.

Quelle: create-react-app

danielgormly
quelle
Vorschlag Nr. 2 verursacht genau den folgenden Fehler: Modul nicht gefunden: Sie haben versucht, ./../../../public/CheersBar-Drinks-147.jpg zu importieren, das außerhalb des Projektverzeichnisses src / liegt . Relative Importe außerhalb von src / werden nicht unterstützt. Sie können es entweder in src / verschieben oder einen Symlink aus den node_modules / des Projekts hinzufügen.
Amos Long
25

Wenn sich Ihre Bilder im öffentlichen Ordner befinden, sollten Sie verwenden

"/images/logo_2016.png"

in Ihrem <img> srcstatt zu importieren

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

Das wird funktionieren

<img className="Header-logo" src="/images/logo_2016.png" alt="Logo" />
Abhinav bhardwaj
quelle
2
Ich arbeite nicht für mich. Die gleiche Nachricht erhalten - 'außerhalb des Projektverzeichnisses src /. Relative Importe außerhalb von src / werden nicht unterstützt. '
Arkady
Ihre Antwort ist richtig, IMO, aber ich habe mir erlaubt zu klären, dass Sie über den Pfad sprechen <img src="...">und ihn nicht importieren
Dmitry Yudakov
1
Genau das habe ich gesucht! Ich habe einfach einen "images" -Ordner zum "src" -Verzeichnis meiner CRA hinzugefügt und konnte dann<img src="/images/logo.png" alt="Logo" />
Amos Long
12

Sie müssen WC-BlackonWhite.jpgin Ihr srcVerzeichnis wechseln . Das publicVerzeichnis ist für statische Dateien vorgesehen, die direkt im HTML-Code verlinkt werden (z. B. das Favicon), und nicht für Inhalte, die Sie direkt in Ihr Bundle importieren möchten.

Joe Clay
quelle
Ich habe gesehen, wie andere es so gemacht haben. Deshalb dachte ich, dass dies der richtige Weg ist
David Brierton
@DavidBrierton: Diese Vorsichtsmaßnahme wurde möglicherweise in einer neueren Version der App "create-react-app" hinzugefügt.
Joe Clay
8

Es gibt einige Antworten, die Lösungen bieten react-app-rewired, aber customize-craeine spezielle removeModuleScopePlugin()API verfügbar machen, die etwas eleganter ist. (Es ist die gleiche Lösung, aber vom customize-craPaket weg abstrahiert .)

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()
Avi Nerenberg
quelle
1
du hast meinen Tag gerettet!
lmiguelvargasf
5

Entfernen Sie es mit 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;
    }
  }
};
Nevace
quelle
Stimmen Sie für den Craco! Craco unterstützt CRA 3.x
Roman Podlinov
4

Diese Einschränkung stellt sicher, dass sich alle Dateien oder Module (Exporte) im src/Verzeichnis befinden, in dem sich die Implementierung befindet ./node_modules/react-dev-utils/ModuleScopePlugin.js, und zwar in den folgenden Codezeilen.

// 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();
      }

Sie können diese Einschränkung durch aufheben

  1. entweder diesen Code ändern (nicht empfohlen)
  2. oder entfernen Sieeject dann ModuleScopePlugin.jsaus dem Verzeichnis.
  3. oder kommentieren / entfernen const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');von./node_modules/react-scripts/config/webpack.config.dev.js

PS: Vorsicht vor den Folgen des Auswurfs .

its4zahoor
quelle
Danke @SurajRao, ich habe es hierher verschoben. Ich hoffe es ist besser
its4zahoor
@PattycakeJr Ja, deshalb habe ich unten gesagt, dass ich die Konsequenzen des Auswerfens haben soll.
its4zahoor
3

Installieren Sie diese beiden Pakete

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;
};
Muhammad Numan
quelle
2

Sie müssen nicht auswerfen, Sie können die react-scriptsKonfiguration mit der Rescripts-Bibliothek ändern

Das würde dann funktionieren:

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

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

  return config;
};
Lukas
quelle
2

Ich denke, die Lösung von Lukas Bach zur Verwendung von React-App-Rewired zum Ändern der Webpack-Konfiguration ist ein guter Weg. Ich würde jedoch nicht das gesamte ModuleScopePlugin ausschließen, sondern stattdessen die spezifische Datei auf die Whitelist setzen, die außerhalb von src importiert werden kann:

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;
};
Bartek Maciejiczek
quelle
Das ist die bisher beste Lösung.
adi518
2

Bild im öffentlichen Ordner

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

  use image inside  js extension
  <img src={process.env.PUBLIC_URL+"/resumepic.png"}/>
  • Verwenden Sie das Bild in der js-Erweiterung
Yziaf_07
quelle
1

Wenn Sie nur eine einzelne Datei wie README.md oder package.json importieren müssen, kann diese explizit zu ModuleScopePlugin () hinzugefügt werden.

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()
      ]),
    ]
  }
}
James McGuigan
quelle
3
Dies erfordert das erste Auswerfen aus der Create-React-App, nicht wahr?
Beau Smith
1

Die beste Lösung ist das Gabeln react-scripts, dies wird tatsächlich in der offiziellen Dokumentation erwähnt, siehe: Alternativen zum Auswerfen

Fareed Alnamrouti
quelle
1

Wenn Sie mehrere Änderungen benötigen, wie z bei Verwendung des Ameisendesigns , können Sie mehrere Funktionen wie folgt kombinieren:

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

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

Neben der Antwort von Bartek Maciejiczek sieht es bei Craco folgendermaßen aus:

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

adi518
quelle