Javascript create react应用程序导入src目录之外的限制

Javascript create react应用程序导入src目录之外的限制,javascript,reactjs,webpack,create-react-app,Javascript,Reactjs,Webpack,Create React App,我正在使用CreateReact应用程序。我正在尝试从我的src/components中的文件调用公用文件夹中的图像。我收到了这个错误消息 ./src/components/website_index.js模块未找到:您试图 导入.././public/images/logo/WC-BlackonWhite.jpg 在项目src/目录之外。境外相对进口 不支持src/src。您可以将其移动到src/内部,也可以添加 从项目的节点_modules/到它的符号链接 从“../../public/im

我正在使用CreateReact应用程序。我正在尝试从我的
src/components
中的文件调用公用文件夹中的图像。我收到了这个错误消息


./src/components/website_index.js模块未找到:您试图 导入.././public/images/logo/WC-BlackonWhite.jpg 在项目src/目录之外。境外相对进口 不支持src/src。您可以将其移动到src/内部,也可以添加 从项目的节点_modules/到它的符号链接

从“../../public/images/logo_2016.png”导入徽标;


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

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

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

  • 使用react create app提供的模块系统(
    从y导入x
    ),并将其与JS捆绑。将图像放入
    src
    文件夹中

  • public
    文件夹中提供该文件,并让节点提供该文件。create-react应用程序显然还附带了一个环境变量,例如
    。这意味着您可以在React应用程序中引用它,但仍然通过节点提供服务,您的浏览器会在正常的GET请求中单独请求它


  • 来源:

    这是CreateReact应用程序开发人员添加的特殊限制。它在
    ModuleScopePlugin
    中实现,以确保文件位于
    src/
    中。该插件确保从应用程序源目录的相对导入不会到达其外部

    您可以通过create react app project的
    eject
    操作禁用此功能(其中一种方法)

    大多数功能及其更新都隐藏在CreateReact应用程序系统的内部。如果您将
    弹出
    ,您将不再拥有某些功能及其更新。所以,如果您还没有准备好管理和配置包含的应用程序以配置网页包等,请不要执行
    弹出
    操作

    按现有规则玩(移动到src)。但现在您可以知道如何删除限制:do
    eject
    并从网页包配置文件中删除
    ModuleScopePlugin


    除了弹出,还有中间解决方案,如 它允许您以编程方式修改网页配置,而无需弹出
    。但是删除
    ModuleScopePlugin
    插件不好-这会失去一些保护,并且不会添加
    src
    中可用的一些功能

    更好的方法是添加完全工作的附加目录,类似于
    src
    。这可以使用


    不要从
    public
    文件夹导入-该文件夹将在
    build
    文件夹中复制,并通过两个不同的url(或不同的加载方式)提供,这最终会使软件包下载量变大


    src
    文件夹导入更可取,并且具有优势。所有内容都将通过webpack打包到捆绑包中,其中包含块最佳大小,并且为了最佳加载效率

    如果您只需要导入单个文件,如README.md或package.json,则可以显式将其添加到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()
          ]),
        ]
      }
    }
    

    此限制确保所有文件或模块(导出)都位于
    src/
    目录中,实现位于
    /node\u 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();
          }
    
    您可以通过以下方式删除此限制:

  • 更改这段代码(不推荐)
  • 或者执行
    弹出
    然后从目录中删除
    ModuleScopePlugin.js
  • 或注释/删除const ModuleScopePlugin=require('react-dev-utils/ModuleScopePlugin')来自
    /node\u modules/react scripts/config/webpack.config.dev.js

  • 注:请注意。

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

    "/images/logo_2016.png"
    
    中,而不是导入

    '../../public/images/logo_2016.png'; 
    
    这会奏效的

    <img className="Header-logo" src="/images/logo_2016.png" alt="Logo" />
    
    
    
    最好的解决方案是fork
    react scripts
    ,这实际上在官方文档中提到过,请参阅:

    该软件包可用于删除插件。这样您就不必弹出

    按照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,但保留其余插件不变,并删除弹出的必要性。

    您不需要弹出,您可以使用

    这样就行了:

    module.exports = config => {
      const scopePluginIndex = config.resolve.plugins.findIndex(
        ({ constructor }) => constructor && constructor.name === "ModuleScopePlugin"
      );
    
      config.resolve.plugins.splice(scopePluginIndex, 1);
    
      return config;
    };
    
    我认为使用来修改webpack配置是一个很好的方法,但是,我不会排除整个ModuleScopePlugin,而是将可以在src之外导入的特定文件列为白名单:

    配置覆盖.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;
    };
    
    const { removeModuleScopePlugin } = require('customize-cra');
    
    module.exports = function override(config, env) {
        if (!config.plugins) {
            config.plugins = [];
        }
        removeModuleScopePlugin()(config);
    
        return config;
    };
    
    

    有一些答案提供了重新布线的
    react应用程序的解决方案
    const { removeModuleScopePlugin } = require('customize-cra')
    
    module.exports = removeModuleScopePlugin()
    
    npm i --save-dev react-app-rewired customize-cra
    
    "scripts": {
        - "start": "react-scripts start"
        + "start": "react-app-rewired start"
    },
    
    const { removeModuleScopePlugin } = require('customize-cra');
    
    module.exports = function override(config, env) {
        if (!config.plugins) {
            config.plugins = [];
        }
        removeModuleScopePlugin()(config);
    
        return config;
    };
    
    
    const {
      override,
      removeModuleScopePlugin,
      fixBabelImports,
    } = require('customize-cra');
    
    module.exports = override(
      fixBabelImports('import', {
        libraryName: 'antd',
        libraryDirectory: 'es',
        style: 'css',
      }),
      removeModuleScopePlugin(),
    );
    
    module.exports = {
      webpack: {
        configure: webpackConfig => {
          const scopePluginIndex = webpackConfig.resolve.plugins.findIndex(
            ({ constructor }) => constructor && constructor.name === 'ModuleScopePlugin'
          );
    
          webpackConfig.resolve.plugins.splice(scopePluginIndex, 1);
          return webpackConfig;
        }
      }
    };
    
      use image inside html extension
      <img src="%PUBLIC_URL%/resumepic.png"/>
    
      use image inside  js extension
      <img src={process.env.PUBLIC_URL+"/resumepic.png"}/>
    
    const path = require("path");
    
    module.exports = {
      contracts_build_directory: path.join(__dirname, "client/src/contracts")
    };
    
    <link rel="stylesheet" href="App.css">
    
    
    // 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!');
        });
    })