web-dev-qa-db-ja.com

create-react-appはsrcディレクトリの外部に制限をインポートします

私はcreate-react-appを使っています。 src/components内のファイルから私のパブリックフォルダから画像を呼び出そうとしています。このエラーメッセージが表示されます。

./src/components/website_index.jsモジュールが見つかりません:プロジェクトsrc /ディレクトリの外にある../../public/images/logo/WC-BlackonWhite.jpgをインポートしようとしました。 src /外への相対インポートはサポートされていません。 src /の中に移動するか、プロジェクトのnode_modules /からシンボリックリンクを追加することができます。

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

私はあなたがパスへのインポートをすることができると言う多くのことを読みました、しかしそれはまだ私のために働いていません。任意の助けは大歓迎です。私はこのような質問がたくさんあることを知っていますが、それらはすべてロゴや画像をインポートするように私に言っているので明らかに私は全体像の中に何かが足りないのです。

69
David Brierton

これはcreate-react-appの開発者によって追加された特別な制限です。ファイルがsrc/に存在することを保証するためにModuleScopePluginに実装されています。そのプラグインは、アプリのソースディレクトリからの相対的なインポートがそれの外側に届かないことを保証します。

この機能を無効にできるのは、create-react-appプロジェクトのeject操作の後に限られます。

ほとんどの機能とそのアップデートはcreate-react-appシステムの内部に隠されています。あなたがejectを作るなら、あなたはもういくつかの機能とその更新を持っていないでしょう。あなたがwebpackなどを設定するために含まれているアプリケーションを管理して設定する準備ができていないのであれば - eject操作をしないでください。

既存の規則に従ってプレーしてください(srcに移動してください)。しかし今、あなたは制限を取り除く方法を知ることができます:do ejectそしてwebpack設定ファイルからModuleScopePluginを取り除きます。


create-react-appv0.4.0 なので、NODE_PATH環境変数でパスを指定できます絶対輸入のため。

絶対インポートでは、変数import App from 'App'で指定された値に対して相対的にimport App from './App'の代わりにNODE_PATHを使用することができます。

この機能はモノレポやその他の設定に関する質問には特に便利ですが、publicフォルダからの画像やその他のもののインポートには役立ちません。

publicフォルダーの内容はbuildフォルダーに配置され、相対URLで使用可能になります。また、インポートされたものはすべてwebpackによって処理され、buildフォルダにも配置されます。

publicフォルダから何かをインポートすると、おそらくそのものがbuildフォルダに複製され、2つの異なるURLで(または異なるロード方法で)使用可能になり、最終的にパッケージのダウンロードサイズが悪化します。

srcフォルダーからインポートするのが好ましく、利点があります。すべてのものはチャンク最適サイズおよびベストロード効率でwebpackによってバンドルにパックされます。

71
oklas

他人の答えにもう少し詳しい情報を提供する。 .pngファイルをユーザーに配信する方法に関して2つの選択肢があります。ファイル構造は、選択した方法に準拠している必要があります。 2つの選択肢があります。

  1. React-create-appで提供されているモジュールシステム(import x from y)を使用して、それをJSとバンドルしてください。 srcフォルダー内に画像を置きます。

  2. publicフォルダからそれを提供し、Nodeにファイルを提供させます。 create-react-appも明らかに環境変数を持っています。 <img src={process.env.PUBLIC_URL + '/img/logo.png'} />;。これはReactアプリでそれを参照することはできますが、それでもNodeを通してそれを提供することができ、通常のGETリクエストであなたのブラウザがそれを別々に要求することを意味します。

出典: https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-images-fonts-andファイル

21
danielgormly

パッケージ 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;
};

これにより、使用されているWebPackプラグインからModuleScopePluginが削除されますが、残りはそのままで、取り出す必要がなくなります。

11
Lukas Bach

WC-BlackonWhite.jpgをあなたのsrcディレクトリに移動する必要があります。 publicディレクトリはHTMLに直接リンクされる静的ファイル(faviconなど)用であり、バンドルに直接インポートするものではありません。

8
Joe Clay

あなたの画像がパブリックフォルダにあるなら、あなたは使うべきです

"/images/logo_2016.png"

インポートする代わりに<img>srcに含める

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

これはうまくいくでしょう

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

この制限により、すべてのファイルまたはモジュール(エクスポート)が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. または./node_modules/react-scripts/config/webpack.config.dev.jsからconst ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');をコメントまたは削除する

シモンズ: eject の影響に注意してください。

4
its4zahoor

最善の解決策はreact-scriptsをforkすることです。これは公式のドキュメントで実際に言及されています。 取り出しの代替方法

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()
      ]),
    ]
  }
}
1
James McGuigan

取り出す必要はありません。 rescripts libraryreact-scripts設定を変更できます

これはその後動作します:

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

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

  return config;
};
1
Lukas