Pembatasan impor buat-reaksi-aplikasi di luar direktori src

149

Saya menggunakan aplikasi create-react-app. Saya mencoba memanggil gambar dari folder publik saya dari file di dalam folder saya src/components. Saya menerima pesan kesalahan ini.

./src/components/website_index.js Modul tidak ditemukan: Anda berusaha mengimpor ../../public/images/logo/WC-BlackonWhite.jpg yang berada di luar direktori src / direktori proyek. Impor relatif di luar src / tidak didukung. Anda dapat memindahkannya di dalam src /, atau menambahkan symlink ke sana dari node_modules proyek /.

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

Saya telah membaca banyak hal yang mengatakan bahwa Anda dapat melakukan impor ke jalan tetapi itu masih tidak berfungsi untuk saya. Bantuan apa pun akan sangat dihargai. Saya tahu ada banyak pertanyaan seperti ini tetapi mereka semua mengatakan kepada saya untuk mengimpor logo atau gambar sehingga jelas saya kehilangan sesuatu di gambar besar.

David Brierton
sumber
2
Anda perlu ../public/images/logo_2016.pngAnda naik dua kali, pertama keluar dari folder komponen, lalu keluar dari folder src.
Chris G
./src/components/website_index.js Modul tidak ditemukan: Anda berusaha mengimpor ../../public/images/logo/WC-BlackonWhite.jpg yang berada di luar direktori src / direktori proyek. Impor relatif di luar src / tidak didukung. Anda dapat memindahkannya di dalam src /, atau menambahkan symlink ke sana dari node_modules proyek /.
David Brierton
Komentar saya mengasumsikan bahwa publicfolder Anda berada langsung di dalam srcfolder Anda . Komentar tanpa komentar Anda menampilkan jalur lama yang dimulai dengan ../..begitu tidak yakin apa maksud Anda?
Chris G
3
tidak ada publik yang setingkat dengan src
David Brierton
Apa yang mereka maksud dengan "atau menambahkan symlink ke sana dari node_modules proyek /"?
Julha

Jawaban:

127

Ini adalah batasan khusus yang ditambahkan oleh pengembang aplikasi create-react-app. Ini diterapkan ModuleScopePluginuntuk memastikan file berada src/. Plugin itu memastikan bahwa impor relatif dari direktori sumber aplikasi tidak mencapai di luarnya.

Anda dapat menonaktifkan fitur ini tetapi hanya setelah ejectoperasi proyek create-react-app.

Sebagian besar fitur dan pembaruannya disembunyikan di bagian dalam sistem create-react-app. Jika Anda membuatnya, ejectAnda tidak akan lagi memiliki beberapa fitur dan pembaruannya. Jadi jika Anda belum siap untuk mengelola dan mengkonfigurasi aplikasi yang disertakan untuk mengkonfigurasi webpack dan sebagainya - jangan lakukan ejectoperasi.

Mainkan dengan aturan yang ada (pindahkan ke src). Tapi sekarang Anda bisa tahu cara menghapus pembatasan: lakukan ejectdan hapus ModuleScopePlugindari file konfigurasi webpack .


Sejak membuat-bereaksi-aplikasi v0.4.0 yang NODE_PATHvariabel lingkungan memungkinkan untuk menentukan path untuk impor mutlak. Dan sejak v3.0.0 NODE_PATH tidak digunakan lagi karena pengaturan baseUrlpada jsconfig.jsonatau tsconfig.json.

Impor absolut memungkinkan penggunaan import App from 'App'alih - alih import App from './App'relatif terhadap nilai yang ditentukan dalam url basis.

Fitur ini secara khusus berguna untuk monorepos atau pertanyaan konfigurasi lain tetapi tidak untuk mengimpor gambar atau apa pun dari publicfolder.

Isi dari public folder akan ditempatkan di buildfolder dan tersedia dengan url relatif. Juga, semua yang diimpor akan diproses oleh webpack dan akan ditempatkan juga di buildfolder.

Jika Anda mengimpor sesuatu dari public folder mungkin benda itu akan diduplikasi dalam buildfolder dan akan tersedia oleh dua url yang berbeda (atau dengan berbagai cara memuat), yang pada akhirnya memperburuk ukuran unduhan paket.

Mengimpor dari folder src lebih disukai dan memiliki kelebihan. Semuanya akan dikemas oleh webpack ke bundel dengan potongan ukuran optimal dan untuk efisiensi pemuatan terbaik .


Ada solusi perantara, yaitu sistem rewire yang memungkinkan Anda untuk memodifikasi konfigurasi webpack secara terprogram. Tapi menghapus yang ModuleScopePluginPlugin tidak baik sebuah solusi; lebih baik menambahkan direktori tambahan yang berfungsi penuh seperti src.

Saat ini, create-react-apptidak mendukung direktori tambahan selain srcdi folder root. Ini dapat dilakukan dengan menggunakan react-app-rewire-alias

oklas
sumber
3
jika Anda membuat symlink di dalam ./src, dan impor dari sana - build tidak berfungsi (plugin babel tidak mengubah sumber dalam folder yang disinkronkan). Jadi dengan pembatasan ini, aktif dan tidak ada-symlink di bawah src, Anda secara efektif ditempatkan di penjara 'tanpa-berbagi-kode-dengan-proyek-lain' (kecuali Anda memilih sepenuhnya beremigrasi / mengeluarkan dari CRA)
VP
2
@ VP tetapi kesalahan mengatakan untuk "menambahkan symlink ke itu dari proyek node_modules /.", Apakah ini tidak berfungsi?
adrianmc
Mereka harus membuat bendera untuk menonaktifkan ini ketika berjalan create-react-appuntuk mereka yang tidak ingin mengeluarkan konfigurasi webpack. Secara pribadi saya selalu mengeluarkan, tetapi beberapa orang tidak merasa nyaman belum mengacaukan konfigurasi webpacks yang menakutkan.
TetraDev
2
@adrianmc. menambahkan symlink dari node_modules proyek tidak berfungsi, karena banyak proyek menggunakan berbagi komponen / kode yang bukan node_modules. Misalnya saya membagikan kode antara Bereaksi Asli dan Bereaksi web asli. 'Potongan' itu bukan node_modules, dan 2 proyek ini sebenarnya memiliki node_modules yang berbeda.
Wakil
1
Bagaimana ini jawaban yang diterima? Pembatasan palsu ini secara sepele dihilangkan dengan hanya mengatur NODE_PATH=./src/..dalam .envfile. Dengan melakukan itu, Anda dapat mengimpor dari luar folder src tanpa melalui rasa sakit yang terkait dengan mengeluarkan aplikasi Anda.
Flaom
47

Paket react-app-rewired dapat digunakan untuk menghapus plugin. Dengan cara ini Anda tidak perlu mengeluarkan.

Ikuti langkah-langkah pada halaman paket npm (instal paket dan balikkan panggilan dalam file package.json) dan gunakan config-overrides.jsfile yang mirip dengan ini:

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

Ini akan menghapus ModuleScopePlugin dari plugin WebPack yang digunakan, tetapi biarkan sisanya seperti semula dan menghapus keharusan untuk mengeluarkan.

Lukas Bach
sumber
5
Jawaban yang bagus Anda dapat memanfaatkan lebih lanjut react-app-rewireddengan [ github.com/arackaf/customize-cra[(customize-cra) . Maka konfigurasi akan menggunakan adil babelInclude([path.resolve('src'), path.resolve('../common')])dan removeModuleScopePlugin().
ivosh
dapatkah Anda mengkonfirmasi di mana saya harus menempatkan potongan kode ini?
bijayshrestha
1
@bijayshrestha Baca file readme dari proyek react-app-rewired, di sana dijelaskan cara mengaturnya. Selama pengaturan, Anda akan membuat config-overrides.jsfile tempat Anda dapat menempatkan kode.
Lukas Bach
Menghapus ModuleScopePluginplugin bukanlah ide yang bagus . Lebih baik menambahkan direktori tambahan yang berfungsi penuh seperti srcmenggunakan react-app-rewire-alias
oklas
1
Apakah solusi ini bekerja dengan TypeScript? Saya tidak bisa membuatnya bekerja dengan TS.
user3053247
27

Untuk menawarkan sedikit informasi lebih banyak ke jawaban orang lain. Anda memiliki dua opsi tentang cara mengirim file .png ke pengguna. Struktur file harus sesuai dengan metode yang Anda pilih. Dua opsi tersebut adalah:

  1. Gunakan sistem modul ( import x from y) yang disediakan dengan reaksi-buat-aplikasi dan bundel dengan JS Anda. Tempatkan gambar di dalam srcfolder.

  2. Sajikan dari publicfolder dan biarkan Node melayani file. buat-reaksi-aplikasi juga tampaknya dilengkapi dengan variabel lingkungan mis <img src={process.env.PUBLIC_URL + '/img/logo.png'} />;. Ini berarti Anda dapat mereferensikannya di aplikasi Bereaksi Anda tetapi masih disajikan melalui Node, dengan browser Anda memintanya secara terpisah dalam permintaan GET normal.

Sumber: create-react-app

danielgormly
sumber
Saran # 2 adalah persis apa yang menyebabkan kesalahan berikut untuk saya: Modul tidak ditemukan: Anda berusaha mengimpor ./../../../public/CheersBar-Drinks-147.jpg yang berada di luar direktori src / direktori proyek . Impor relatif di luar src / tidak didukung. Anda dapat memindahkannya di dalam src /, atau menambahkan symlink ke sana dari node_modules proyek /.
Amos Long
25

Jika gambar Anda ada di folder publik maka Anda harus menggunakan

"/images/logo_2016.png"

di <img> srcalih-alih mengimpor

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

Ini akan bekerja

<img className="Header-logo" src="/images/logo_2016.png" alt="Logo" />
Abhinav bhardwaj
sumber
2
Tidak bekerja untukku. Mendapatkan pesan yang sama - 'di luar direktori src / direktori proyek. Impor relatif di luar src / tidak didukung. '
Arkady
Jawaban Anda adalah IMO yang benar, tetapi saya bebas mengklarifikasi bahwa Anda berbicara tentang jalur masuk <img src="...">, bukan mengimpornya
Dmitry Yudakov
1
Ini persis apa yang saya cari! Saya hanya menambahkan folder "gambar" ke direktori "src" CRA saya, dan kemudian saya dapat menggunakan<img src="/images/logo.png" alt="Logo" />
Amos Long
12

Anda harus pindah WC-BlackonWhite.jpgkesrc direktori . The publicdirektori untuk file statis yang akan dihubungkan langsung dalam HTML (seperti favicon), tidak hal-hal yang Anda akan mengimpor langsung ke bundel Anda.

Joe Clay
sumber
Saya telah melihat orang lain melakukannya dengan cara ini. Itulah mengapa saya pikir ini adalah cara yang tepat
David Brierton
@DavidBrierton: Tindakan pencegahan ini mungkin telah ditambahkan dalam versi terbaru dari aplikasi create-react-app.
Joe Clay
8

Ada beberapa jawaban yang memberikan solusi react-app-rewired, tetapi customize-cramemperlihatkan removeModuleScopePlugin()API khusus yang sedikit lebih elegan. (Ini solusi yang sama, tetapi disarikan oleh customize-crapaket.)

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
sumber
1
kamu menyelamatkan hariku!
lmiguelvargasf
5

Hapus menggunakan 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
sumber
Pilih craco! Craco mendukung CRA 3.x
Roman Podlinov
4

Pembatasan ini memastikan semua file atau modul (ekspor) berada di dalam src/direktori, implementasinya dalam ./node_modules/react-dev-utils/ModuleScopePlugin.js, dalam baris kode berikut.

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

Anda dapat menghapus batasan ini dengan

  1. baik mengubah bagian kode ini (tidak disarankan)
  2. atau lakukaneject kemudian hapus ModuleScopePlugin.jsdari direktori.
  3. atau komentar / hapus const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');dari./node_modules/react-scripts/config/webpack.config.dev.js

PS: waspadalah terhadap konsekuensi dari eject .

its4zahoor
sumber
Terima kasih @ SurajRao, saya memindahkannya ke sini. Saya harap ini lebih baik.
its4zahoor
@PattycakeJr Ya, itu sebabnya di bawah ini saya telah diberitahu untuk memiliki konsekuensi eject.
its4zahoor
3

instal kedua paket ini

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
sumber
2

Anda tidak perlu mengeluarkan, Anda dapat memodifikasi react-scriptskonfigurasi dengan pustaka reskrip

Ini akan berhasil kemudian:

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

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

  return config;
};
Lukas
sumber
2

Saya pikir solusi Lukas Bach untuk menggunakan reaksi-aplikasi-rewired untuk memodifikasi konfigurasi webpack adalah cara yang baik untuk pergi, namun, saya tidak akan mengecualikan seluruh ModuleScopePlugin tetapi sebaliknya memasukkan daftar putih file tertentu yang dapat diimpor di luar 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;
};
Bartek Maciejiczek
sumber
Itu solusi terbaik sejauh ini.
adi518
2

Gambar di dalam folder publik

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

  use image inside  js extension
  <img src={process.env.PUBLIC_URL+"/resumepic.png"}/>
  • gunakan gambar di dalam js Extension
Yziaf_07
sumber
1

Jika Anda hanya perlu mengimpor satu file, seperti README.md atau package.json, maka ini dapat secara eksplisit ditambahkan ke 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()
      ]),
    ]
  }
}
James McGuigan
sumber
3
Ini membutuhkan ejecting pertama dari create-react-app, bukan?
Beau Smith
1

solusi terbaik adalah dengan garpu react-scripts, ini sebenarnya disebutkan dalam dokumentasi resmi, lihat: Alternatif untuk Mengeluarkan

Fareed Alnamrouti
sumber
1

Jika Anda memerlukan banyak modifikasi, seperti saat menggunakan desain semut , Anda dapat menggabungkan beberapa fungsi seperti ini:

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

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

Menambah jawaban Bartek Maciejiczek, beginilah tampilannya dengan Craco:

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
sumber