Aplikacja create-react-app importuje ograniczenie poza katalog src


150

Używam aplikacji create-react-app. Próbuję wywołać obraz z mojego publicznego folderu z pliku w moim src/components. Otrzymuję ten komunikat o błędzie.

./src/components/website_index.js Nie znaleziono modułu: próbujesz zaimportować ../../public/images/logo/WC-BlackonWhite.jpg, który znajduje się poza katalogiem src / projektu. Względne importowanie poza src / nie jest obsługiwane. Możesz przenieść go do src / lub dodać do niego dowiązanie symboliczne z node_modules / projektu.

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

Przeczytałem wiele rzeczy, w których napisano, że możesz wykonać import do ścieżki, ale to nadal nie działa dla mnie. Każda pomoc byłaby bardzo mile widziana. Wiem, że jest wiele takich pytań, ale wszystkie mówią mi, żebym zaimportował logo lub obraz, więc wyraźnie brakuje mi czegoś w dużym obrazie.


2
Musisz ../public/images/logo_2016.pngdwukrotnie przejść do góry, najpierw z folderu komponentów, a następnie z folderu src.
Chris G

./src/components/website_index.js Nie znaleziono modułu: próbujesz zaimportować ../../public/images/logo/WC-BlackonWhite.jpg, który znajduje się poza katalogiem src / projektu. Względne importowanie poza src / nie jest obsługiwane. Możesz przenieść go do src / lub dodać do niego dowiązanie symboliczne z node_modules / projektu.
David Brierton

Mój komentarz zakłada, że ​​twój publicfolder znajduje się bezpośrednio w twoim srcfolderze. Twój komentarz bez komentarza zawiera starą ścieżkę zaczynającą się od, ../..więc nie wiesz, o co ci chodzi?
Chris G

3
żadna publiczność nie jest na tym samym poziomie co src
David Brierton

Co mają na myśli przez „lub dodać do niego dowiązanie symboliczne z węzła_modules /” projektu?
Julha

Odpowiedzi:


127

Jest to specjalne ograniczenie dodane przez twórców aplikacji create-react-app. Jest zaimplementowany wModuleScopePlugin aby zapewnić, że pliki znajdują się w src/. Ta wtyczka zapewnia, że ​​względne importy z katalogu źródłowego aplikacji nie sięgają poza nią.

Możesz wyłączyć tę funkcję, ale dopiero później eject uruchomieniu projektu create-re-app.

Większość funkcji i ich aktualizacje jest ukryta w wewnętrznych elementach systemu tworzenia i reagowania. Jeśli sprawisz, że ejectnie będziesz już mieć niektórych funkcji i ich aktualizacji. Więc jeśli nie jesteś gotowy do zarządzania i konfigurowania dołączonej aplikacji do konfigurowania webpacka i tak dalej - nie wykonuj ejectoperacji.

Graj według istniejących zasad (przejdź do źródła). Ale teraz możesz już wiedzieć, jak usunąć ograniczenie: zrób ejecti usuń ModuleScopePluginz pliku konfiguracyjnego pakietu internetowego .


Ponieważ tworzenie reagują app v0.4.0 o NODE_PATHzmiennej środowiska pozwala określić drogę absolutnej importu. A ponieważ wersja 3.0.0 NODE_PATH jest przestarzała, na korzyść ustawienia baseUrlw jsconfig.jsonlub tsconfig.json.

Bezwzględny import umożliwia użycie import App from 'App'zamiast tego import App from './App'względem wartości określonej w podstawowym adresie URL.

Ta funkcja jest szczególnie przydatna w przypadku monorepos lub innych pytań konfiguracyjnych, ale nie do importowania obrazów lub czegokolwiek innego z publicfolderu.

Zawartość publicfolderu zostanie umieszczona wbuild folderze i będzie dostępna według względnego adresu URL. Ponadto wszystko zaimportowane zostanie przetworzone przez webpack i zostanie również umieszczone w buildfolderze.

Jeśli zaimportujesz coś z publicfolderu, prawdopodobnie zostanie to zduplikowane w plikubuild folderze i będzie dostępne pod dwoma różnymi adresami URL (lub różnymi sposobami ładowania), co ostatecznie pogorszy rozmiar pobieranego pakietu.

Importowanie z folderu src jest preferowane i ma zalety. Wszystko zostanie zapakowane w paczkę internetową do pakietu z kawałkami o optymalnym rozmiarze i dla najlepszej wydajności ładowania .


Istnieją rozwiązania pośrednie, a mianowicie system rewire , który pozwala programowo modyfikować konfigurację webpacka. Ale usunięcie ten ModuleScopePluginplugin nie jest dobry rozwiązaniem; lepiej jest dodać w pełni działające dodatkowe katalogi podobne do src.

Obecnie create-react-appnie obsługuje dodatkowych katalogów poza srcfolderem głównym. Można to zrobić za pomocą reagowania na alias aplikacji-rewire


3
jeśli utworzysz dowiązanie symboliczne w ./src i zaimportujesz stamtąd - kompilacja nie działa (wtyczka babel nie przekształca źródeł w folderach dowiązanych symbolicznie). Tak więc z tym ograniczeniem, z włączeniem i brakiem linku symbolicznego pod src, jesteś skutecznie umieszczany w więzieniu `` zakaz dzielenia kodu z innymi-projektami '' (chyba że zdecydujesz się całkowicie wyemigrować / wyrzucić z CRA)
Wiceprezes

2
@VP, ale błąd mówi, aby „dodać do niego link symboliczny z node_modules /.”, Czy to nie działa?
adrianmc,

Powinni zrobić flagę, aby wyłączyć to podczas uruchamiania create-react-appdla tych, którzy nie chcą wysuwać konfiguracji webpacka. Osobiście zawsze wyrzucam, ale niektórzy ludzie nie czują się jeszcze komfortowo, majstrując przy zniechęcającej konfiguracji webpaków.
TetraDev,

2
@adrianmc. dodawanie dowiązania symbolicznego z node_modules projektu nie działa, ponieważ wiele projektów używa współdzielonych komponentów / kodu, które nie są node_modules. Na przykład udostępniam kod między React Native i React native web. Te „fragmenty” nie są modułami węzłów, a te 2 projekty w rzeczywistości mają różne moduły węzłów.
VP

1
Jaka jest akceptowana odpowiedź? To fałszywe ograniczenie można w trywialny sposób wyeliminować, umieszczając je NODE_PATH=./src/..w .envpliku. W ten sposób możesz importować spoza folderu src bez przechodzenia przez ból związany z wysuwaniem aplikacji.
Flaom

47

Do usunięcia wtyczki można użyć pakietu reaguj-app-rewired . W ten sposób nie musisz wysuwać.

Postępuj zgodnie z instrukcjami na stronie pakietu npm (zainstaluj pakiet i odwróć wywołania w pliku package.json) i użyj config-overrides.js pliku podobnego do tego:

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

Spowoduje to usunięcie ModuleScopePlugin z używanych wtyczek WebPack, ale resztę pozostawi bez zmian i wyeliminuje konieczność wysuwania.


5
Świetna odpowiedź. Możesz dalej korzystać react-app-rewiredz [ github.com/arackaf/customize-cra](customize-cra) . Wtedy konfiguracja użyje tylko babelInclude([path.resolve('src'), path.resolve('../common')])i removeModuleScopePlugin().
ivosh

czy możesz potwierdzić, gdzie mam umieścić ten fragment kodu?
bijayshrestha

1
@bijayshrestha Przeczytaj plik readme projektu rewired-app-rewired, w którym wyjaśniono, jak go skonfigurować. Podczas instalacji utworzysz config-overrides.jsplik, w którym możesz umieścić kod.
Lukas Bach

Usunięcie ModuleScopePluginwtyczki nie jest dobrym pomysłem. Lepiej jest dodać w pełni działające dodatkowe katalogi, podobnie jak srcprzy
użyciureak

1
Czy to rozwiązanie działa z programem Typescript? Nie mogę go uruchomić z TS.
user3053247

27

Aby zaoferować trochę więcej informacji na temat odpowiedzi innych osób. Masz dwie opcje dotyczące sposobu dostarczenia pliku .png do użytkownika. Struktura pliku powinna być zgodna z wybraną metodą. Dwie opcje to:

  1. Skorzystaj z modułu system ( import x from y) dostarczonego z aplikacją react-create-i dołącz ją do swojego JS. Umieść obraz wewnątrzsrc folderze.

  2. Podaj go z publicfolderu i pozwól Node udostępnić plik. create-react-app również najwyraźniej zawiera zmienną środowiskową, np<img src={process.env.PUBLIC_URL + '/img/logo.png'} />; . Oznacza to, że możesz odwołać się do niego w swojej aplikacji React, ale nadal możesz go obsługiwać przez Node, z przeglądarką pytającą o to osobno w normalnym żądaniu GET.

Źródło: aplikacja create-react-app


Sugestia nr 2 jest dokładnie tym, co powoduje następujący błąd: Nie znaleziono modułu: Próbowałeś zaimportować ./../../../public/CheersBar-Drinks-147.jpg, który znajduje się poza katalogiem src / projektu . Względne importowanie poza src / nie jest obsługiwane. Możesz przenieść go do src / lub dodać do niego dowiązanie symboliczne z node_modules / projektu.
Amos Long

25

Jeśli twoje obrazy znajdują się w folderze publicznym, powinieneś użyć

"/images/logo_2016.png"

w twoim <img> srczamiast importowania

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

To zadziała

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

2
Nie działa dla mnie. Otrzymuję tę samą wiadomość - „poza katalogiem src / projektu. Względne importowanie poza src / nie jest obsługiwane. '
Arkady

Twoja odpowiedź jest poprawna IMO, ale <img src="...">pozwoliłem sobie wyjaśnić, że mówisz o ścieżce , a nie importujesz ją
Dmitry Yudakov

1
To było dokładnie to, czego szukałem! Po prostu dodałem folder „images” do katalogu „src” mojej CRA, a potem mogłem używać<img src="/images/logo.png" alt="Logo" />
Amos Long

12

Musisz przenieść się WC-BlackonWhite.jpgdo swojego srckatalogu. publicKatalog dla plików statycznych, który będzie połączony bezpośrednio w kodzie HTML (takich jak favicon), a nie rzeczy, które masz zamiar importować bezpośrednio do wiązki.


Widziałem, jak inni robią to w ten sposób. Dlatego pomyślałem, że to właściwy sposób
David Brierton

@DavidBrierton: Ten środek ostrożności mógł zostać dodany w nowszej wersji aplikacji create-react-app.
Joe Clay

8

Jest kilka odpowiedzi, które dostarczają rozwiązań react-app-rewired, ale customize-craeksponują specjalne removeModuleScopePlugin()API, które jest nieco bardziej eleganckie. (To to samo rozwiązanie, ale wyodrębnione przez customize-crapakiet).

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()

1
uratowałeś mi dzień!
lmiguelvargasf

6

Usuń go za pomocą 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;
    }
  }
};

Głosuj na craco! Craco wspiera CRA 3.x
Roman Podlinov

4

To ograniczenie zapewnia, że ​​wszystkie pliki lub moduły (eksporty) znajdują się w src/katalogu, w którym znajduje się implementacja ./node_modules/react-dev-utils/ModuleScopePlugin.js, w kolejnych wierszach kodu.

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

Możesz usunąć to ograniczenie przez

  1. zmiana tego fragmentu kodu (niezalecane)
  2. lub nieeject później usunąćModuleScopePlugin.js z katalogu.
  3. lub skomentuj / usuń const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');z./node_modules/react-scripts/config/webpack.config.dev.js

PS: uważaj na konsekwencje wyrzucenia .


Dzięki @SurajRao, przeniosłem to tutaj. Mam nadzieję, że tak jest lepiej.
its4zahoor

@PattycakeJr Tak, dlatego poniżej powiedziałem, żebym uważał na konsekwencje wyrzucenia.
its4zahoor

3

zainstaluj te dwa pakiety

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

2

Nie musisz wysuwać, możesz modyfikować react-scriptskonfigurację za pomocą biblioteki rescripts

To zadziałałoby wtedy:

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

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

  return config;
};

2

Myślę Lukas Bach rozwiązanie do użytku reagują-app-Rewired w celu zmodyfikowania WebPack config to dobra droga, jednak ja nie wyklucza cały ModuleScopePlugin ale zamiast białej listy konkretny plik, który może być importowany z zewnątrz 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;
};

Jak dotąd to najlepsze rozwiązanie.
adi518

2

Obraz w folderze publicznym

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

  use image inside  js extension
  <img src={process.env.PUBLIC_URL+"/resumepic.png"}/>
  • użyj obrazu wewnątrz rozszerzenia js

1

Jeśli potrzebujesz tylko zaimportować pojedynczy plik, taki jak README.md lub package.json, możesz to jawnie dodać do 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()
      ]),
    ]
  }
}

3
Wymaga to najpierw wyrzucenia z aplikacji create-react-app, prawda?
Beau Smith


1

Jeśli potrzebujesz wielu modyfikacji, na przykład podczas korzystania z projektowania Ant , możesz połączyć wiele funkcji, takich jak:

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

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

1

Dodając do odpowiedzi Bartka Maciejiczka, tak to wygląda z 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;
    }
  }
};

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.