web-dev-qa-db-fra.com

La restriction des importations create-react-app en dehors du répertoire src

J'utilise create-react-app. J'essaie d'appeler une image de mon dossier public à partir d'un fichier dans mon src/components. Je reçois ce message d'erreur.

./src/components/website_index.js Module introuvable: vous avez tenté d'importer le fichier ../../public/images/logo/WC-BlackonWhite.jpg qui se trouve en dehors du répertoire src/du projet. Les importations relatives en dehors de src/ne sont pas prises en charge. Vous pouvez soit le déplacer à l'intérieur de src /, soit lui ajouter un lien symbolique à partir de node_modules/du projet.

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

J'ai lu beaucoup de choses disant que vous pouvez importer le chemin mais cela ne fonctionne toujours pas pour moi. Toute aide serait grandement appréciée. Je sais qu'il y a beaucoup de questions comme celle-ci, mais ils me disent tous d'importer un logo ou une image si clairement que je manque quelque chose dans la grande image.

80
David Brierton

Ceci est une restriction spéciale ajoutée par les développeurs de create-react-app. Il est implémenté dans ModuleScopePlugin pour garantir que les fichiers résident dans src/. Ce plug-in garantit que les importations relatives depuis le répertoire source de l'application ne vont pas en dehors de celui-ci.

Vous pouvez désactiver cette fonctionnalité, mais uniquement après le eject opération du projet create-react-app.

La plupart des fonctionnalités et leurs mises à jour sont cachées dans les composants internes du système create-react-app. Si vous faites eject vous n'aurez plus certaines fonctionnalités et sa mise à jour. Donc, si vous n'êtes pas prêt à gérer et à configurer l'application incluse pour configurer Webpack, etc., ne faites pas l'opération eject.

Jouez selon les règles existantes (déplacez vers src). Mais maintenant, vous pouvez savoir comment supprimer la restriction: faites eject et supprimez ModuleScopePlugin du fichier de configuration de Webpack .


Depuis créer-réagir-application v0.4. la variable d'environnement NODE_PATH permet de spécifier un chemin pour l'importation absolue .

L'importation absolue permet d'utiliser import App from 'App' à la place de import App from './App' par rapport à la valeur spécifiée dans la variable NODE_PATH.

Cette fonctionnalité est particulièrement utile pour les questions de monorepos ou de configuration, mais pas pour importer des images ou toute autre chose du dossier public.

Le contenu du dossier public sera placé dans le dossier build et sera disponible par l'URL relative. De même, tout ce qui est importé sera traité par Webpack et sera également placé dans le dossier build.

Si vous importez quelque chose à partir du dossier public, il sera probablement dupliqué dans le dossier build et sera disponible sous deux URL différentes (ou avec des méthodes de chargement différentes), ce qui aggravera la taille du téléchargement du paquet.

L'importation à partir du dossier src est préférable et présente des avantages. Tout sera emballé par Webpack dans le paquet avec des morceaux de taille optimale et pour la meilleure efficacité de chargement .

76
oklas

Pour offrir un peu plus d'informations aux réponses des autres. Vous avez deux options pour la livraison du fichier .png à l'utilisateur. La structure de fichier doit être conforme à la méthode choisie. Les deux options sont:

  1. Utilisez le système de module (import x from y) fourni avec react-create-app et associez-le à votre JS. Placez l'image dans le dossier src.

  2. Servez-le à partir du dossier public et laissez Node servir le fichier. create-react-app est apparemment livré avec une variable d'environnement, par exemple. <img src={process.env.PUBLIC_URL + '/img/logo.png'} />;. Cela signifie que vous pouvez le référencer dans votre application React tout en le faisant toujours passer par Node, votre navigateur vous le demandant séparément dans une requête GET normale.

Source: create-react-app

22
danielgormly

Le package react-app-rewired peut être utilisé pour supprimer le plugin. De cette façon, vous ne devez pas éjecter.

Suivez les étapes de la page du package npm (installez le package et inversez les appels dans le fichier package.json) et utilisez un fichier config-overrides.js similaire à celui-ci:

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

Cela supprimera le ModuleScopePlugin des plugins WebPack utilisés, mais laissera le reste tel quel et éliminera la nécessité d'éjecter.

17
Lukas Bach

Si vos images sont dans le dossier public, vous devez utiliser

"/images/logo_2016.png"

dans votre <img>src au lieu d'importer

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

Ça va marcher

<img className="Header-logo" src="/images/logo_2016.png" alt="Logo" />
12
Abhinav bhardwaj

Vous devez déplacer WC-BlackonWhite.jpg dans votre répertoire src. Le répertoire public est destiné aux fichiers statiques qui seront liés directement dans le code HTML (tel que le favicon), et non aux éléments que vous allez importer directement dans votre bundle.

10
Joe Clay

Cette restriction garantit que tous les fichiers ou modules (exportations) se trouvent dans le répertoire src/, que l'implémentation est dans ./node_modules/react-dev-utils/ModuleScopePlugin.js, dans les lignes de code suivantes.

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

Vous pouvez supprimer cette restriction en

  1. soit changer ce morceau de code (non recommandé)
  2. ou faites eject puis supprimez ModuleScopePlugin.js du répertoire.
  3. ou commenter/supprimer const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); de ./node_modules/react-scripts/config/webpack.config.dev.js

PS: Méfiez-vous des conséquences de éjecter .

4
its4zahoor

la meilleure solution consiste à bifurquer react-scripts, ce qui est effectivement mentionné dans la documentation officielle, voir: Alternatives à l'éjection

1
Fareed Alnamrouti

Si vous ne devez importer qu'un seul fichier, tel que README.md ou package.json, vous pouvez l'ajouter explicitement à 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()
      ]),
    ]
  }
}
1
James McGuigan

Vous n'avez pas besoin d'éjecter, vous pouvez modifier le react-scripts config avec le bibliothèque de rescripts

Cela fonctionnerait alors:

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

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

  return config;
};
1
Lukas