javascript - Die Einschränkung von create-react-app Imports außerhalb des src-Verzeichnisses
Ich benutze create-react-app. Ich versuche, ein Bild aus meinem öffentlichen Ordner von einer Datei innerhalb meines src/components aufzurufen. Ich erhalte diese Fehlermeldung.
./src/components/website_index.js Modul nicht gefunden: Sie haben versucht, ../../public/images/logo/WC-BlackonWhite.jpg zu importieren, das sich außerhalb des Projekt-src/-Verzeichnisses befindet. Relative Importe außerhalb von src/ werden nicht unterstützt. Sie können es entweder in src/ verschieben oder einen Symlink davon aus den node_modules/ des Projekts erstellen.
import logo aus '../../public/images/logo_2016.png';
Ich habe viele Dinge gelesen, die sagen, dass man einen Import zum Pfad machen kann, aber das funktioniert bei mir immer noch nicht. Jede Hilfe wäre sehr willkommen. Ich weiß, dass es viele Fragen wie diese gibt, aber sie alle sagen mir, dass ich logo oder image importieren soll, also fehlt mir offensichtlich etwas im großen Ganzen.
Antwort #1
Dies ist eine spezielle Einschränkung, die von den Entwicklern von create-react-app hinzugefügt wurde. Sie wird im ModuleScopePlugin implementiert, um sicherzustellen, dass sich Dateien im src/ befinden. Dieses Plugin stellt sicher, dass relative Importe aus dem Quellverzeichnis der App nicht darüber hinausgehen.
Es gibt keine offizielle Möglichkeit, diese Funktion zu deaktivieren, außer eject zu verwenden und die Webpack-Konfiguration zu ändern.
Aber die meisten Funktionen und deren Updates sind in den Interna des create-react-app-Systems verborgen. Wenn Sie eject ausführen, erhalten Sie keine neuen Funktionen und deren Updates mehr. Wenn Sie also nicht bereit sind, die Anwendung zu verwalten und zu konfigurieren, einschließlich der Konfiguration von Webpack und so weiter, führen Sie die eject-Operation nicht aus.
Spiele nach den bestehenden Regeln - verschiebe Assets in src oder verwende sie basierend auf der public-Ordner-URL ohne Import.
Es gibt jedoch anstelle von eject viele inoffizielle Lösungen, die auf rewire basieren und es Ihnen erlauben, die Webpack-Konfiguration programmatisch zu ändern, ohne eject zu verwenden. Aber das Entfernen des ModuleScopePlugin-Plugins ist nicht gut - dies verliert einen gewissen Schutz und fügt keine Funktionen hinzu, die im src verfügbar sind. ModuleScopePlugin wurde entwickelt, um mehrere Ordner zu unterstützen.
Der bessere Weg ist es, vollständig funktionierende zusätzliche Verzeichnisse ähnlich wie src hinzuzufügen, die ebenfalls durch ModuleScopePlugin geschützt sind. Dies kann mit react-app-alias gemacht werden.
Importiere auf jeden Fall nicht aus dem public-Ordner - dieser wird im build-Ordner dupliziert und ist über zwei verschiedene URLs verfügbar (und auf unterschiedliche Weise ladbar), was letztendlich die Paket-Download-Größe verschlechtert.
Das Importieren aus dem src-Ordner ist vorzuziehen und hat Vorteile. Alles wird von webpack in das Bundle mit Chunks der optimalen Größe und für die beste Ladeeffizienz gepackt.
Antwort #2
Das Paket react-app-rewired kann verwendet werden, um das Plugin zu entfernen. Auf diese Weise müssen Sie nicht aussteigen.
Folgen Sie den Schritten auf der npm-Paketseite (installieren Sie das Paket und tauschen Sie die Aufrufe in der Datei package.json aus) und verwenden Sie eine config-overrides.js-Datei ähnlich 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;
};
Dies wird das ModuleScopePlugin aus den verwendeten WebPack-Plugins entfernen, aber den Rest unverändert lassen und die Notwendigkeit zum Ejecten beseitigen.
Antwort #3
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;
}
}
};
Antwort #4
Wenn sich Ihre Bilder im öffentlichen Ordner befinden, sollten Sie verwenden
"/images/logo_2016.png"
in deinem <img> src anstelle des Imports
'../../public/images/logo_2016.png';
Das wird funktionieren
<img className="Header-logo" src="/images/logo_2016.png" alt="Logo" />
Antwort #5
Um ein wenig mehr Informationen zu den Antworten anderer zu geben. Sie haben zwei Möglichkeiten, wie Sie die .png-Datei an den Benutzer liefern können. Die Dateistruktur sollte der von Ihnen gewählten Methode entsprechen. Die beiden Optionen sind:
Verwenden Sie das Modulsystem (
import x from y), das mit react-create-app bereitgestellt wird, und bündeln Sie es mit Ihrem JS. Platzieren Sie das Bild imsrc-Ordner.Serviere es aus dem
public-Ordner und lasse Node die Datei bereitstellen. create-react-app scheint auch mit einer Umgebungsvariable zu kommen, z.B.<img src={process.env.PUBLIC_URL + '/img/logo.png'} />;. Das bedeutet, dass du darauf in deiner React-App verweisen kannst, sie aber trotzdem über Node bereitgestellt wird, wobei dein Browser sie separat in einer normalen GET-Anfrage anfordert.
Quelle: create-react-app
Antwort #6
Es gibt einige Antworten, die Lösungen mit react-app-rewired bieten, aber customize-cra enthält eine removeModuleScopePlugin()-API, die ein wenig eleganter ist. (Es ist dieselbe Lösung, aber durch das customize-cra-Paket abstrahiert.)
npm i --save-dev react-app-rewired customize-crapackage.json
"scripts": {
- "start": "react-scripts start"
+ "start": "react-app-rewired start",
...
},
config-overrides.js
const { removeModuleScopePlugin } = require('customize-cra')
module.exports = removeModuleScopePlugin()
Antwort #7
Ich konnte Dateien außerhalb von src/ importieren, indem ich die externen Dateien mit file: als lokale Abhängigkeit "kopierte".
"dependencies": {
"@my-project/outside-dist": "file:./../../../../dist".
}
dann
import {FooComponent} from "@my-project/outside-dist/components";
Es war kein eject oder react-app-rewired oder eine andere Lösung von Drittanbietern erforderlich.
Antwort #8
Sie müssen WC-BlackonWhite.jpg in Ihr src-Verzeichnis verschieben. Das public-Verzeichnis ist für statische Dateien, die direkt im HTML verlinkt werden (wie das Favicon), nicht für Dinge, die Sie direkt in Ihr Bundle importieren werden.
Antwort #9
Copy-Paste TypeScript-Lösung
(z.B. dies funktioniert für einen CRA/TS-Stack, der im Vergleich zu CRA/JS einen zusätzlichen Schritt erfordert. Die Lösung selbst ist nicht typisiert.)
Fügt die erforderlichen Pfade zum ModuleScopePlugin hinzu, anstatt das Plugin einfach zu entfernen.
Der untenstehende Code verwendet craco, sollte aber problemlos für react-app-rewired oder ähnliche Lösungen verwendbar sein. Sie müssen nur die Stelle finden, an der Sie ein webpackConfig-Objekt haben (react-app-rewired: module.exports.webpack innerhalb Ihrer config-overrides.js), und es an die bereitgestellten Funktionen übergeben.
craco.config.js
const path = require("path");
const enableImportsFromExternalPaths = require("./src/helpers/craco/enableImportsFromExternalPaths");
// Paths to the code you want to use
const sharedLibOne = path.resolve(__dirname, "../shared-lib-1/src");
const sharedLibTwo = path.resolve(__dirname, "../shared-lib-2/src");
module.exports = {
plugins: [
{
plugin: {
overrideWebpackConfig: ({ webpackConfig }) => {
enableImportsFromExternalPaths(webpackConfig, [
// Add the paths here
sharedLibOne,
sharedLibTwo,
]);
return webpackConfig;
},
},
},
],
};
Hilfen/craco/ExternePfadImporteAktivieren.js
const findWebpackPlugin = (webpackConfig, pluginName) =>
webpackConfig.resolve.plugins.find(
({ constructor }) => constructor && constructor.name === pluginName
);
const 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 addPathsToModuleScopePlugin = (webpackConfig, paths) => {
const moduleScopePlugin = findWebpackPlugin(
webpackConfig,
"ModuleScopePlugin"
);
if (!moduleScopePlugin) {
throw new Error(
`Expected to find plugin "ModuleScopePlugin", but didn't.`
);
}
moduleScopePlugin.appSrcs = [...moduleScopePlugin.appSrcs, ...paths];
};
const enableImportsFromExternalPaths = (webpackConfig, paths) => {
enableTypescriptImportsFromExternalPaths(webpackConfig, paths);
addPathsToModuleScopePlugin(webpackConfig, paths);
};
module.exports = enableImportsFromExternalPaths;
Hier und hierher genommen 🙏
Antwort #10
Ich denke, Lukas Bachs Lösung, react-app-rewired zu verwenden, um die Webpack-Konfiguration zu ändern, ist ein guter Weg, jedoch würde ich 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;
};
