Hạn chế nhập ứng dụng tạo phản ứng bên ngoài thư mục src


149

Tôi đang sử dụng ứng dụng tạo-phản ứng. Tôi đang cố gắng gọi một hình ảnh từ thư mục công cộng của tôi từ một tập tin bên trong tôi src/components. Tôi nhận được thông báo lỗi này.

./src/components/website_index.js Không tìm thấy mô-đun: Bạn đã cố nhập ../../public/images/logo/WC-BlackonWhite.jpg nằm ngoài thư mục src / của dự án. Nhập khẩu tương đối bên ngoài src / không được hỗ trợ. Bạn có thể di chuyển nó bên trong src / hoặc thêm một liên kết tượng trưng đến nó từ node_modules / của dự án.

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

Tôi đã đọc nhiều điều nói rằng bạn có thể thực hiện nhập vào đường dẫn nhưng điều đó vẫn không hiệu quả với tôi. Mọi sự trợ giúp sẽ rất được trân trọng. Tôi biết có rất nhiều câu hỏi như thế này nhưng tất cả họ đều bảo tôi nhập logo hoặc hình ảnh để rõ ràng tôi đang thiếu một cái gì đó trong bức tranh lớn.


2
Bạn cần ../public/images/logo_2016.pngBạn đã đi lên hai lần, đầu tiên ra khỏi thư mục thành phần, sau đó ra khỏi thư mục src.
Chris G

./src/components/website_index.js Không tìm thấy mô-đun: Bạn đã cố nhập ../../public/images/logo/WC-BlackonWhite.jpg nằm ngoài thư mục src / của dự án. Nhập khẩu tương đối bên ngoài src / không được hỗ trợ. Bạn có thể di chuyển nó bên trong src / hoặc thêm một liên kết tượng trưng đến nó từ node_modules / của dự án.
David Brierton

Nhận xét của tôi giả định rằng publicthư mục của bạn nằm ngay trong srcthư mục của bạn . Bình luận không có bình luận của bạn có đường dẫn cũ bắt đầu với ../..vì vậy không chắc quan điểm của bạn là gì?
Chris G

3
không có công chúng nào ở cùng cấp độ với src
David Brierton

Ý nghĩa của chúng là "hoặc thêm một liên kết tượng trưng đến nó từ node_modules /" của dự án?
Julha

Câu trả lời:


126

Đây là hạn chế đặc biệt được thêm bởi các nhà phát triển ứng dụng tạo phản ứng. Nó được thực hiện ModuleScopePluginđể đảm bảo các tập tin cư trú src/. Plugin đó đảm bảo rằng nhập tương đối từ thư mục nguồn của ứng dụng không tiếp cận bên ngoài nó.

Bạn có thể tắt tính năng này nhưng chỉ sau khi ejecthoạt động của dự án ứng dụng tạo phản ứng.

Hầu hết các tính năng và cập nhật của nó được ẩn vào bên trong hệ thống ứng dụng tạo phản ứng. Nếu bạn thực hiện, ejectbạn sẽ không còn có một số tính năng và cập nhật của nó. Vì vậy, nếu bạn chưa sẵn sàng để quản lý và định cấu hình ứng dụng đi kèm để định cấu hình gói web, v.v. - đừng thực hiện ejectthao tác.

Chơi theo các quy tắc hiện có (di chuyển đến src). Nhưng bây giờ bạn có thể biết cách loại bỏ hạn chế: làm ejectvà xóa ModuleScopePluginkhỏi tệp cấu hình webpack .


tạo-Reac-app v0.4.0 , NODE_PATHbiến môi trường cho phép chỉ định một đường dẫn để nhập tuyệt đối. Và vì v3.0.0 NODE_PATH không được dùng để cài đặt baseUrltrong jsconfig.jsonhoặc tsconfig.json.

Nhập tuyệt đối cho phép sử dụng import App from 'App'thay vì import App from './App'liên quan đến giá trị được chỉ định trong url cơ sở.

Tính năng này đặc biệt hữu ích cho các câu hỏi đơn hoặc các câu hỏi cấu hình khác nhưng không phải để nhập hình ảnh hoặc bất cứ thứ gì khác từ publicthư mục.

Nội dung của publicthư mục sẽ được đặt trong buildthư mục và có sẵn theo url tương đối. Ngoài ra, mọi thứ được nhập sẽ được xử lý bởi webpack và cũng sẽ được đặt trong buildthư mục.

Nếu bạn nhập một cái gì đó từ publicthư mục, có thể thứ đó sẽ được sao chép trong buildthư mục và sẽ có sẵn bởi hai url khác nhau (hoặc với các cách tải khác nhau), điều này sẽ làm giảm kích thước tải xuống gói.

Nhập từ thư mục src là tốt hơn và có lợi thế. Tất cả mọi thứ sẽ được đóng gói bởi gói webpack với kích thước tối ưu và có hiệu quả tải tốt nhất .


Có các giải pháp trung gian, cụ thể là hệ thống tua lại cho phép bạn lập trình sửa đổi cấu hình webpack. Nhưng loại bỏ các ModuleScopePluginplugin không phải là một giải pháp tốt ; tốt hơn là thêm các thư mục bổ sung làm việc đầy đủ tương tự như src.

Hiện tại, create-react-appkhông hỗ trợ các thư mục bổ sung ngoài thư srcmục gốc. Điều này có thể được thực hiện bằng cách sử dụng Reac-app-tuaire-alias


3
nếu bạn tạo symlink trong ./src và nhập từ đó - bản dựng không hoạt động (plugin babel không chuyển đổi nguồn trong các thư mục được liên kết). Vì vậy, với hạn chế này, trên và không có liên kết theo src, bạn thực sự được đặt vào nhà tù 'không chia sẻ mã với các dự án khác' (trừ khi bạn chọn hoàn toàn di chuyển / đẩy ra khỏi CRA)
VP

2
@VP nhưng lỗi nói "thêm một liên kết tượng trưng đến nó từ node_modules /." Của dự án, điều này có hoạt động không?
adrianmc

Họ nên tạo một cờ để vô hiệu hóa điều này khi chạy create-react-appcho những người không muốn đẩy cấu hình webpack. Cá nhân tôi luôn đẩy ra, nhưng một số người không cảm thấy thoải mái khi gặp rắc rối với cấu hình webpacks.
TetraDev

2
@adrianmc. việc thêm symlink từ node_modules của dự án không hoạt động, bởi vì nhiều dự án sử dụng các thành phần / mã chia sẻ không phải là node_modules. Ví dụ: tôi chia sẻ mã giữa React Native và React web gốc. Những 'đoạn trích' đó không phải là node_modules và 2 dự án này thực sự có node_modules khác nhau.
VP

1
Làm thế nào đây là câu trả lời được chấp nhận? Hạn chế không có thật này được loại bỏ một cách tầm thường bằng cách chỉ cần thiết lập NODE_PATH=./src/..trong .envtệp. Bằng cách làm như vậy, bạn có thể nhập từ bên ngoài thư mục src mà không phải trải qua nỗi đau liên quan đến việc đẩy ứng dụng của bạn.
Flaom

47

Gói phản ứng-ứng dụng được tua lại có thể được sử dụng để gỡ bỏ plugin. Bằng cách này, bạn không phải đẩy ra.

Thực hiện theo các bước trên trang gói npm (cài đặt gói và lật các cuộc gọi trong tệp pack.json) và sử dụng một config-overrides.jstệp tương tự như gói này:

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

Thao tác này sẽ xóa ModuleScopePlugin khỏi các plugin WebPack đã sử dụng, nhưng để phần còn lại như cũ và loại bỏ sự cần thiết phải đẩy ra.


5
Câu trả lời chính xác. Bạn có thể tận dụng hơn nữa react-app-rewiredvới [ github.com/arackaf/customize-craTHER(customize-cra) . Sau đó, cấu hình sẽ sử dụng chỉ babelInclude([path.resolve('src'), path.resolve('../common')])removeModuleScopePlugin().
ivosh

bạn có thể vui lòng xác nhận nơi tôi nên đặt đoạn mã này không?
bijayshrestha

1
@bijayshrestha Đọc tệp readme của dự án phản ứng lại ứng dụng, nó giải thích cách thiết lập nó. Trong quá trình thiết lập, bạn sẽ tạo một config-overrides.jstệp trong đó bạn có thể đặt mã.
Lukas Bach

Loại bỏ các ModuleScopePluginplugin không phải là một ý tưởng tốt . Tốt hơn là thêm các thư mục bổ sung hoạt động đầy đủ tương tự như srcsử dụng
Reac

1
Giải pháp này có hoạt động với Typecript không? Tôi không thể làm cho nó hoạt động với TS.
dùng3053247

27

Để cung cấp thêm một chút thông tin cho câu trả lời của người khác. Bạn có hai tùy chọn về cách phân phối tệp .png cho người dùng. Cấu trúc tệp phải phù hợp với phương pháp bạn chọn. Hai tùy chọn là:

  1. Sử dụng hệ thống mô-đun ( import x from y) được cung cấp với Reac-created-app và gói nó với JS của bạn. Đặt hình ảnh bên trong srcthư mục.

  2. Phục vụ nó từ publicthư mục và để Node phục vụ tệp. tạo-Reac-app rõ ràng cũng đi kèm với một biến môi trường, vd <img src={process.env.PUBLIC_URL + '/img/logo.png'} />;. Điều này có nghĩa là bạn có thể tham chiếu nó trong ứng dụng React của mình nhưng vẫn được phục vụ thông qua Node, với trình duyệt của bạn yêu cầu riêng nó trong một yêu cầu GET bình thường.

Nguồn: tạo-phản ứng-ứng dụng


Gợi ý số 2 chính xác là nguyên nhân gây ra lỗi sau cho tôi: Không tìm thấy mô-đun: Bạn đã cố nhập ./../../../public/CheersBar-Drinks-147.jpg nằm ngoài thư mục src / của dự án . Nhập khẩu tương đối bên ngoài src / không được hỗ trợ. Bạn có thể di chuyển nó bên trong src / hoặc thêm một liên kết tượng trưng đến nó từ node_modules / của dự án.
Amos Long

25

Nếu hình ảnh của bạn nằm trong thư mục công cộng thì bạn nên sử dụng

"/images/logo_2016.png"

trong bạn <img> src thay vì nhập khẩu

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

Điều này sẽ làm việc

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

2
Không làm việc cho tôi. Nhận cùng một thông điệp - 'bên ngoài thư mục src / của dự án. Nhập khẩu tương đối bên ngoài src / không được hỗ trợ. '
Arkady

Câu trả lời của bạn là đúng IMO nhưng tôi mất sự tự do của việc làm rõ rằng bạn đang nói về con đường trong <img src="...">, không phải nhập khẩu nó
Dmitry Yudakov

1
Đây chính xác là những gì tôi đang tìm kiếm! Tôi chỉ cần thêm thư mục "hình ảnh" vào thư mục "src" của CRA và sau đó tôi có thể sử dụng<img src="/images/logo.png" alt="Logo" />
Amos Long

12

Bạn cần phải di chuyển WC-BlackonWhite.jpgvào srcthư mục của bạn . Thư publicmục dành cho các tệp tĩnh sẽ được liên kết trực tiếp trong HTML (chẳng hạn như favicon), không phải là thứ bạn sẽ nhập trực tiếp vào gói của mình.


Tôi đã thấy những người khác làm theo cách này. Đó là lý do tại sao tôi nghĩ rằng đây là cách thích hợp
David Brierton

@DavidBrierton: Biện pháp phòng ngừa này có thể đã được thêm vào trong phiên bản mới hơn của ứng dụng tạo phản ứng.
Joe Clay

8

Có một vài câu trả lời cung cấp giải pháp react-app-rewired, nhưng customize-crađể lộ một removeModuleScopePlugin()API đặc biệt thanh lịch hơn một chút. (Đó là cùng một giải pháp, nhưng được customize-cragói bởi gói.)

npm i --save-dev react-app-rewired customize-cra

pack.json

"scripts": {
    - "start": "react-scripts start"
    + "start": "react-app-rewired start",
    ...
},

config-overrides.js

const { removeModuleScopePlugin } = require('customize-cra')

module.exports = removeModuleScopePlugin()

1
bạn đã cứu ngày của tôi!
lmiguelvargasf

5

Loại bỏ nó bằng 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;
    }
  }
};

Bình chọn cho craco! Craco hỗ trợ CRA 3.x
Roman Podlinov

4

Hạn chế này đảm bảo tất cả các tệp hoặc mô-đun (xuất) nằm trong src/thư mục, việc triển khai nằm ./node_modules/react-dev-utils/ModuleScopePlugin.jstrong các dòng mã sau.

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

Bạn có thể loại bỏ hạn chế này bằng cách

  1. hoặc thay đổi đoạn mã này (không được khuyến nghị)
  2. hoặc làmeject sau đó loại bỏModuleScopePlugin.js khỏi thư mục.
  3. hoặc bình luận / xóa const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');khỏi./node_modules/react-scripts/config/webpack.config.dev.js

PS: coi chừng hậu quả của việc đẩy ra .


Cảm ơn @SurajRao, tôi đã chuyển nó đến đây. Tôi hy vọng nó tốt hơn.
Its4zahoor

@PattyddingJr Vâng, đó là lý do tại sao dưới đây tôi đã nói là phải giải quyết hậu quả.
Its4zahoor

3

cài đặt hai gói này

npm i --save-dev react-app-rewired customize-cra

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

2

Bạn không cần phải đẩy ra, bạn có thể sửa đổi react-scriptscấu hình với thư viện rescripts

Điều này sẽ làm việc sau đó:

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

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

  return config;
};

2

Tôi nghĩ rằng giải pháp Lukas Bach sử dụng phản ứng lại ứng dụng để sửa đổi cấu hình webpack là một cách tốt để đi, tuy nhiên, tôi sẽ không loại trừ toàn bộ ModuleScopePlugin mà thay vào đó hãy liệt kê danh sách cụ thể có thể được nhập bên ngoài 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;
};

Đó là giải pháp tốt nhất cho đến nay.
adi518

2

Hình ảnh trong thư mục công cộng

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

  use image inside  js extension
  <img src={process.env.PUBLIC_URL+"/resumepic.png"}/>
  • sử dụng hình ảnh bên trong phần mở rộng js

1

Nếu bạn chỉ cần nhập một tệp duy nhất, chẳng hạn như README.md hoặc pack.json, thì điều này có thể được thêm rõ ràng vào ModuleScopePlugin ()

config / path.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()
      ]),
    ]
  }
}

3
Điều này đòi hỏi phải đẩy ra đầu tiên từ ứng dụng tạo-phản ứng, không?
Beau Smith


1

Nếu bạn cần nhiều sửa đổi, như khi sử dụng thiết kế ant , bạn có thể kết hợp nhiều chức năng như thế này:

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

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

1

Thêm vào câu trả lời của Bartek Maciejiczek, đây là giao diện của 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;
    }
  }
};

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.