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

时间:2017-05-22 13:40:37

标签: javascript reactjs webpack create-react-app

我正在使用create-react-app。我试图从我的-(void) provider:(CXProvider *)provider performStartCallAction:(CXStartCallAction *)action内的文件中调用公共文件夹中的图像。我收到此错误消息。

  

./ src / components / website_index.js找不到模块:您试图   导入../../public/images/logo/WC-BlackonWhite.jpg   在项目src /目录之外。相对进口以外的   src /不受支持。您可以在src /中移动它,也可以添加一个   符号链接来自项目的node_modules /.

src/components

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

24 个答案:

答案 0 :(得分:68)

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

您可以在create-react-app项目eject操作之后禁用此功能。

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

按现有规则播放(转到src)。但现在您可以了解如何删除限制:执行eject并从webpack配置文件中删除ModuleScopePlugin

答案 1 :(得分:21)

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

  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请求中单独请求它。

  3. 来源:https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-images-fonts-and-files

答案 2 :(得分:16)

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

答案 3 :(得分:11)

软件包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,但其余部分保持原样,从而无需弹出。

答案 4 :(得分:8)

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

答案 5 :(得分:5)

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

"/images/logo_2016.png"

在您的<img> src中,而不是导入

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

这将起作用

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

答案 6 :(得分:5)

安装这两个软件包

mp4

package.json

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

config-overrides.js

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

答案 7 :(得分:4)

此限制可确保所有文件或模块(导出)都位于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. 或评论/删除const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');中的./node_modules/react-scripts/config/webpack.config.dev.js

PS:谨防eject的后果。

答案 8 :(得分:3)

公用文件夹中的图片

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

  use image inside  js extension
  <img src={process.env.PUBLIC_URL+"/resumepic.png"}/>
  • 在js扩展程序内使用图片

答案 9 :(得分:2)

这可以直接完成,无需使用公用文件夹的路径。 你可以这样做

<img src="/images/image-name" alt=""/>

发生这种情况是因为我们没有在浏览器中使用 App.js。由于 index.html 是在浏览器本身中执行的,并且图像的路径已经在包含 index.html 文件的公共文件夹中

答案 10 :(得分:2)

我不得不在 Truffle 中克服同样的问题。解决方法如下:

由于 Create-React-App 的默认行为不允许从 src 文件夹外部导入文件,我们需要将我们的 build 文件夹中的合约放在 src 中。我们可以在每次编译合约时复制和粘贴它们,但更好的方法是简单地配置 Truffle 以将文件放在那里。

在 truffle-config.js 文件中,将内容替换为以下内容:

const path = require("path");

module.exports = {
  contracts_build_directory: path.join(__dirname, "client/src/contracts")
};

我不知道这是否对您有帮助,但我知道我在 Truffle 遇到同样问题时发现了您的问题,这可能对其他人有帮助。

答案 11 :(得分:2)

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

答案 12 :(得分:2)

有一些答案可以为react-app-rewired提供解决方案,但是customize-cra公开了一个特殊的removeModuleScopePlugin() API,它更加优雅。 (这是相同的解决方案,但通过customize-cra包进行了抽象。)

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

答案 13 :(得分:1)

如果您需要进行多种修改(例如使用蚂蚁设计时),则可以组合以下多种功能:

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

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

答案 14 :(得分:1)

最好的解决方案是派生react-scripts,这在官方文档中实际上已经提到过,请参阅:Alternatives to Ejecting

答案 15 :(得分:1)

在我的项目中遇到了同样的问题,并在官方的 create-react-app 文档中找到了这个:https://create-react-app.dev/docs/using-the-public-folder/

有一个“逃生舱”可以在模块系统之外添加资产:

<块引用>

如果你把一个文件放到 public 文件夹中,它不会被处理 网络包。相反,它将被原封不动地复制到构建文件夹中。到 引用公用文件夹中的资产,需要使用环境 名为 PUBLIC_URL 的变量。

这是他们提供的示例:

render() {
  // Note: this is an escape hatch and should be used sparingly!
  // Normally we recommend using `import` for getting asset URLs
  // as described in “Adding Images and Fonts” above this section.
  return <img src={process.env.PUBLIC_URL + '/img/logo.png'} />;
}

答案 16 :(得分:1)

如果您想从公众访问 CSS 文件,您可能会遇到源目录外

或者,您可以在 index.html 中链接此文件,该文件也位于公共目录中。

<link rel="stylesheet" href="App.css">

答案 17 :(得分:1)

这里有一个在简单情况下效果很好的替代方法(使用 fsncp)。在开发过程中,保持运行脚本以监视 /src 之外的共享文件夹的更改。进行更改时,脚本可以自动将共享文件夹复制到您的项目中。这是一个递归观察单个目录的示例:


// This should be run from the root of your project

const fs = require('fs')
const ncp = require('ncp').ncp;

ncp.limit = 16

// Watch for file changes to your shared directory outside of /src
fs.watch('../shared', { recursive: true }, (eventType, filename) => {
    console.log(`${eventType}: ${filename}`)

    // Copy the shared folder straight to your project /src
    // You could be smarter here and only copy the changed file
    ncp('../shared', './src/shared', function(err) {
        if (err) {
          return console.error(err);
        }

        console.log('finished syncing!');
    });
})

答案 18 :(得分:1)

这是相对导入的问题,这可能是因为我们使用了“create-react-app project”命令,该命令形成了一个名为 project 的目录,其中包含 node_modules 文件夹以及其中 public 和 src 文件夹中的几个其他文件. create-react-app 命令有一个限制,即我们不能从 src 外部导入任何内容。

我的问题:

  1. 我必须导入在 src 文件夹外的 node_modules 文件夹中创建的 react-bootstrap css 文件。
  2. 我使用了 import "../node_modules/bootstrap/dist/css/bootstrap.min.css";但我在终端上遇到了错误。
  3. 我发现我可以创建一个新的 React 应用并按照从 A 到 G 的解决方案步骤来解决这个问题。

解决办法: A) 创建一个新的 React 应用,使用 create-react-app new

B) cd 新的

C) 运行此命令:“npm install react-bootstrap bootstrap@4.6.0”(不带“”双引号)

D) 在您的反应文件中将其导入引导程序: D.1) 导入“../node_modules/bootstrap/dist/css/bootstrap.min.css”; 要么 D.2)从“react-bootstrap/Button”导入按钮;

E) 为 D.1) 创建一个 bootstrap 元素,如 Button 或任何你的反应文件中的任何东西) < button className="btn btn-success"> Bootstrap 要么 对于 D.2)

F) 在终端:cd src

G) 在终端:npm start,

这次就编译成功了。

推理: 一旦我按顺序执行了步骤 A 到 G,我就可以看到 react-bootstrap 终于开始工作了,这次我没有收到任何错误。 (我想到这个解决方案是因为:

  1. 我使用了 npm install "@material-ui/icons" 并将其安装在 src 外的 node_modules 文件夹中。
  2. 在我的反应文件中,我使用了 import Add from "@material-ui/icons/Add"
  3. 和 Material-ui 图标对我来说很好用, 但在这里我们也从外部 src 导入,从 node_modules .. 一切正常。为什么这次从外部src导入没有错误)
  4. 这就是为什么我刚刚创建了一个新的 React 应用,并按照解决方案步骤 A 到 G。

答案 19 :(得分:1)

没有为 TypeScript 找到简洁的复制粘贴解决方案。想我会发布一个。

下面的代码使用 craco,但应该很容易用于 react-app-rewired 或类似的解决方案。您只需要找到您拥有 webpackConfig 对象的位置,并将其传递给提供的函数。

给你:

module.exports = {
  plugins: [
    {
      plugin: {
        overrideWebpackConfig: ({ webpackConfig }) => {
          // This is where the fun begins!
          removeModuleScopingPlugin(webpackConfig);
          // Amend this with the root paths you wish to import from
          enableTypescriptImportsFromExternalPaths(webpackConfig, [
            path.resolve(__dirname, "../common/src/"),
          ]);
          return webpackConfig;
        },
      },
    },
  ],
};

被引用的函数 - 随意将它们放在 module.exports 或其他文件之上(之后require):


function removeWebpackPlugin(webpackConfig, pluginName) {
  const scopePluginIndex = webpackConfig.resolve.plugins.findIndex(
    ({ constructor }) => constructor && constructor.name === pluginName
  );
  if (scopePluginIndex > -1) {
    webpackConfig.resolve.plugins.splice(scopePluginIndex, 1);
  }
}

function 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 removeModuleScopingPlugin = (webpackConfig) =>
  removeWebpackPlugin(webpackConfig, "ModuleScopePlugin");

取自herehere?

答案 20 :(得分: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()
      ]),
    ]
  }
}

答案 21 :(得分:0)

我认为Lukas Bach solution使用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;
};

答案 22 :(得分:0)

您不需要弹出,可以使用rescripts library修改react-scripts配置

这将起作用:

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

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

  return config;
};

答案 23 :(得分:0)

您可以尝试使用simlink,但是相反。

React不会遵循simlink,但是您可以将某些内容移至源目录,并为其创建simlink。

在项目的根目录中,我有一个节点服务器目录,其中包含多个架构文件。我想在前端使用它们,所以我:

  • 移动了文件/ src
  • 在术语中,我确定了模式文件在服务器中的位置
  • ln -s SRC_PATH_OF_SCHEMA_FILE

这使所需的内容有所反应,并且节点非常高兴通过simlink包含文件。