create-react-app在src目录之外导入限制

Dav*_*ton 93 javascript reactjs webpack create-react-app

我正在使用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" />

我已经阅读了很多东西,说你可以对路径进行导入,但这对我来说仍然不起作用.任何帮助将不胜感激.我知道有很多这样的问题,但他们都告诉我要导入徽标或图像,所以我在大局中遗漏了一些东西.

okl*_*las 86

这是create-react-app的开发人员添加的特殊限制.它在ModuleScopePlugin中实现,以确保文件驻留在src /中.该插件可确保来自应用程序源目录的相对导入不会到达其外部.

您可以在ModuleScopePlugincreate-react-app项目运行后禁用此功能.

大多数功能及其更新都隐藏在create-react-app系统的内部.如果你让src/你不再拥有一些功能及其更新.因此,如果您还没准备好管理和配置包含的应用程序以配置webpack等等 - 请勿执行eject操作.

按现有规则播放(转到src).但现在您可以知道如何删除限制:从webpack配置文件执行eject和删除eject.

  • 如果您在 ./src 中创建符号链接,并从那里导入 - 构建不起作用(babel 插件不会转换符号链接文件夹中的源)。因此,有了这个限制,并且在 src 下没有符号链接,您实际上被置于“无共享代码与其他项目”监狱中(除非您选择完全移出/退出 CRA) (5认同)
  • 有人可以解释一下为什么首先要进行限制吗?知道这一点将决定这个答案是否适合我的用例 (4认同)
  • 这是如何被接受的答案?通过简单地在 `.env` 文件中设置 `NODE_PATH=./src/..` 就可以轻松消除这种虚假限制。通过这样做,您可以从 src 文件夹外部导入,而无需经历与弹出应用程序相关的痛苦。 (4认同)
  • @VP 但错误说“从项目的 node_modules/ 添加符号链接到它。”,这不起作用吗? (2认同)
  • @adrianmc.从项目的node_modules添加符号链接不起作用,因为许多项目使用不是node_modules的共享组件/代码.例如,我在React Native和React native web之间共享代码.那些"代码片段"不是node_modules,这两个项目实际上有不同的node_modules. (2认同)
  • 看起来 baseUrl 不再起作用。任何将其设置在源树之外的尝试都会出现以下错误:_Your 项目的 `baseUrl` 只能设置为 `src` 或 `node_modules`。Create React App 目前不支持其他值。@Flaom 的前置`./src` 技巧也没有帮助。 (2认同)

小智 32

使用 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;
    }
  }
};
Run Code Online (Sandbox Code Playgroud)

  • 与此完美配合 /sf/answers/4102224521/ (3认同)
  • 给克拉科投票吧!Craco支持CRA 3.x (2认同)

Fab*_*one 25

我能够src/通过“复制”具有file:本地依赖关系的外部文件来导入外部文件。

"dependencies": {
    "@my-project/outside-dist": "file:./../../../../dist".
}
Run Code Online (Sandbox Code Playgroud)

然后

import {FooComponent} from "@my-project/outside-dist/components";
Run Code Online (Sandbox Code Playgroud)

不需要ejectreact-app-rewired其他第三方解决方案。

  • 这似乎适用于包,而不适用于独立文件。 (5认同)

dan*_*mly 24

为其他人的答案提供更多信息.关于如何将.png文件传递给用户,您有两种选择.文件结构应符合您选择的方法.这两个选项是:

  1. 使用import x from yreact-create-app提供的模块系统()并将其与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-files


Luk*_*ach 23

软件包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;
};
Run Code Online (Sandbox Code Playgroud)

这将从使用过的WebPack插件中删除ModuleScopePlugin,但其余部分保持原样,从而无需弹出。

  • 该解决方案适用于 Typescript 吗?我无法让它与 TS 一起工作。 (4认同)
  • 好答案。您可以通过[https://github.com/arackaf/customize-cra](customize-cra)进一步利用“ react-app-rewired”。然后配置将仅使用`babelInclude([path.resolve('src'),path.resolve('../ common')])'和`removeModuleScopePlugin()`。 (2认同)
  • 删除 `ModuleScopePlugin` 插件**不是一个好**主意。最好使用 **[react-app-rewire-alias](https://github.com/oklas/react-app-rewire-alias)** 添加类似于 `src` 的完全工作的附加目录 (2认同)

Avi*_*erg 19

有一些答案提供了 解决方案react-app-rewired,但customize-cra包括一个removeModuleScopePlugin()更优雅的API。(这是相同的解决方案,但被customize-cra包抽象掉了。)

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

包.json

"scripts": {
    - "start": "react-scripts start"
    + "start": "react-app-rewired start",
    ...
},
Run Code Online (Sandbox Code Playgroud)

config-overrides.js

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

module.exports = removeModuleScopePlugin()
Run Code Online (Sandbox Code Playgroud)

  • 这救了我的命!如果您使用类似于 [reactron](https://github.com/infinitered/reactotron) 的东西,这应该是公认的答案! (4认同)

Abh*_*waj 14

如果图像位于公用文件夹中,则应使用

"/images/logo_2016.png"
Run Code Online (Sandbox Code Playgroud)

在您<img> src而不是导入

'../../public/images/logo_2016.png'; 
Run Code Online (Sandbox Code Playgroud)

这会起作用

<img className="Header-logo" src="/images/logo_2016.png" alt="Logo" />
Run Code Online (Sandbox Code Playgroud)

  • 您的回答是正确的 IMO,但我冒昧地澄清您说的是 `&lt;img src="..."&gt;` 中的路径,而不是导入它 (3认同)
  • 这正是我一直在寻找的!我只是将一个“images”文件夹添加到我的 CRA 的“src”目录中,然后我就可以使用 `&lt;img src="/images/logo.png" alt="Logo" /&gt;` (3认同)
  • 不为我工作。得到相同的消息-'在项目src /目录之外。不支持src /以外的相对导入。 (2认同)

Joe*_*lay 11

您需要WC-BlackonWhite.jpg进入您的src目录.该public目录适用于将直接在HTML中链接的静态文件(例如favicon),而不是您要直接导入到捆绑包中的内容.


pan*_*ter 11

复制粘贴打字稿解决方案

(例如,这适用于 CRA/TS 堆栈,与 CRA/JS 相比,它需要额外的步骤。解决方案本身没有类型化。)

添加所需的路径,而ModuleScopePlugin不是直接删除插件。

下面的代码使用craco,但应该可以轻松用于react-app-rewired或类似的解决方案。您只需要找到拥有webpackConfig对象的位置(react-app-rewired:module.exports.webpack在您的 内部config-overrides.js),并将其传递给提供的函数。

craco.config.js

const path = require("path");
const enableImportsFromExternalPaths = require("./src/helpers/craco/enableImportsFromExternalPaths");

// Paths to the code you want to use
const sharedLibOne = path.resolve(__dirname, "../shared-lib-1/src");
const sharedLibTwo = path.resolve(__dirname, "../shared-lib-2/src");

module.exports = {
    plugins: [
        {
            plugin: {
                overrideWebpackConfig: ({ webpackConfig }) => {
                    enableImportsFromExternalPaths(webpackConfig, [
                        // Add the paths here
                        sharedLibOne,
                        sharedLibTwo,
                    ]);
                    return webpackConfig;
                },
            },
        },
    ],
};
Run Code Online (Sandbox Code Playgroud)

帮助者/craco/enableImportsFromExternalPaths.js

const findWebpackPlugin = (webpackConfig, pluginName) =>
    webpackConfig.resolve.plugins.find(
        ({ constructor }) => constructor && constructor.name === pluginName
    );

const enableTypescriptImportsFromExternalPaths = (
    webpackConfig,
    newIncludePaths
) => {
    const oneOfRule = webpackConfig.module.rules.find((rule) => rule.oneOf);
    if (oneOfRule) {
        const tsxRule = oneOfRule.oneOf.find(
            (rule) => rule.test && rule.test.toString().includes("tsx")
        );

        if (tsxRule) {
            tsxRule.include = Array.isArray(tsxRule.include)
                ? [...tsxRule.include, ...newIncludePaths]
                : [tsxRule.include, ...newIncludePaths];
        }
    }
};

const addPathsToModuleScopePlugin = (webpackConfig, paths) => {
    const moduleScopePlugin = findWebpackPlugin(
        webpackConfig,
        "ModuleScopePlugin"
    );
    if (!moduleScopePlugin) {
        throw new Error(
            `Expected to find plugin "ModuleScopePlugin", but didn't.`
        );
    }
    moduleScopePlugin.appSrcs = [...moduleScopePlugin.appSrcs, ...paths];
};

const enableImportsFromExternalPaths = (webpackConfig, paths) => {
    enableTypescriptImportsFromExternalPaths(webpackConfig, paths);
    addPathsToModuleScopePlugin(webpackConfig, paths);
};

module.exports = enableImportsFromExternalPaths;
Run Code Online (Sandbox Code Playgroud)

取自这里这里


小智 8

我认为Lukas Bach 解决方案使用react-app- rewired 来修改 webpack 配置是一个很好的方法,但是,我不会排除整个ModuleScopePlugin而是将可以在 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;
};
Run Code Online (Sandbox Code Playgroud)


小智 7

公共文件夹内的图像

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

  use image inside  js extension
  <img src={process.env.PUBLIC_URL+"/resumepic.png"}/>
Run Code Online (Sandbox Code Playgroud)
  • 在 js 扩展中使用图像


Muh*_*man 6

安装这两个包

npm i --save-dev react-app-rewired customize-cra
Run Code Online (Sandbox Code Playgroud)

包.json

"scripts": {
    - "start": "react-scripts start"
    + "start": "react-app-rewired start"
},
Run Code Online (Sandbox Code Playgroud)

config-overrides.js

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

module.exports = function override(config, env) {
    if (!config.plugins) {
        config.plugins = [];
    }
    removeModuleScopePlugin()(config);

    return config;
};

Run Code Online (Sandbox Code Playgroud)


its*_*oor 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();
      }
Run Code Online (Sandbox Code Playgroud)

您可以通过以下方式删除此限制

  1. 要么改变这段代码(不推荐)
  2. 或者然后ejectModuleScopePlugin.js从目录中删除。
  3. 或评论/const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');删除./node_modules/react-scripts/config/webpack.config.dev.js

PS:谨防弹出后果


adi*_*518 5

添加到 Bartek Maciejiczek 的答案中,这就是 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;
    }
  }
};
Run Code Online (Sandbox Code Playgroud)

我之前的解决方法适用于 Webpack 4,但不适用于 Webpack 5。浏览了此后积累的解决方法后,我发现以下解决方法非常简单(并且看起来可扩展)。

import { CracoAliasPlugin } from 'react-app-alias';

const cracoConfig = {
  plugins: [
    {
      plugin: CracoAliasPlugin,
      options: {
        alias: { '~': './' },
      },
    },
  ],
}
Run Code Online (Sandbox Code Playgroud)

然后像这样导入:

import whatever from '~/<path-to-file>';
Run Code Online (Sandbox Code Playgroud)