create-react-app 在 src 目录之外导入限制
The create-react-app imports restriction outside of src directory
我正在使用 create-react-app。我正在尝试从我的 src/components
中的文件调用我的 public 文件夹中的图像。我收到此错误消息。
./src/components/website_index.js Module not found: You attempted to
import ../../public/images/logo/WC-BlackonWhite.jpg which falls
outside of the project src/ directory. Relative imports outside of
src/ are not supported. You can either move it inside src/, or add a
symlink to it from project's node_modules/.
import logo from '../../public/images/logo_2016.png';
<img className="Header-logo" src={logo} alt="Logo" />
我读过很多东西说您可以对路径进行导入,但这对我来说仍然不起作用。任何帮助将不胜感激。我知道有很多这样的问题,但他们都告诉我要导入徽标或图像,所以很明显我在大局中遗漏了一些东西。
您需要将 WC-BlackonWhite.jpg
移动到您的 src
目录中。 public
目录用于直接在 HTML 中链接的静态文件(例如网站图标),而不是您要直接导入到包中的内容。
为其他人的答案提供更多信息。关于如何将 .png 文件交付给用户,您有两种选择。文件结构应符合您选择的方法。两个选项是:
使用 react-create-app 提供的模块系统 (import x from y
) 并将其与您的 JS 捆绑在一起。将图像放入 src
文件夹。
从 public
文件夹中提供它并让 Node 提供文件。 create-react-app 显然也带有一个环境变量,例如<img src={process.env.PUBLIC_URL + '/img/logo.png'} />;
。这意味着您可以在 React 应用程序中引用它,但仍然通过 Node 提供它,您的浏览器会在正常的 GET 请求中单独请求它。
这是create-react-app开发者添加的特殊限制。它在 ModuleScopePlugin
中实现,以确保文件驻留在 src/
中。该插件确保来自应用程序源目录的相对导入不会超出它。
除了使用 eject
和修改 webpack 配置外,没有官方方法可以禁用此功能。
但是,大多数功能及其更新都隐藏在 create-react-app 系统的内部。如果你制作 eject
,你将没有更多的新功能及其更新。因此,如果您还没有准备好管理和配置包含配置 webpack 等的应用程序 - 请不要执行 eject
操作。
按照现有规则播放 - 将资产移动到 src 或基于 public
文件夹 url 使用而不导入。
然而,除了 eject
之外,还有很多非官方的解决方案,基于
rewire 允许您在没有 eject
的情况下以编程方式修改 webpack 配置。但是 删除 ModuleScopePlugin
插件 并不好 - 这会失去一些保护并且不会添加 中可用的某些功能src
。 ModuleScopePlugin
旨在支持多个文件夹。
更好的方法是添加完全可用的额外目录,类似于 src
,也受 ModuleScopePlugin
保护。这可以使用 react-app-alias
来完成
无论如何不要从 public
文件夹导入 - 这将在 build
文件夹中复制,并且可以通过两个不同的 url 获得(并且加载方式不同),这最终使包下载大小变差。
从src
文件夹中导入是可取的并且有优势。所有内容都将由 webpack 打包成块 最佳大小 并获得 最佳加载效率 .
如果您只需要导入单个文件,例如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()
]),
]
}
}
此限制确保所有文件或模块(导出)都在 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();
}
您可以通过
取消此限制
- 要么改这段代码(不推荐)
- 或执行
eject
然后从目录中删除ModuleScopePlugin.js
。
- 或 comment/remove
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
来自 ./node_modules/react-scripts/config/webpack.config.dev.js
PS:谨防.
的后果
如果您的图像在 public 文件夹中,那么您应该使用
"/images/logo_2016.png"
在您的 <img>
src
中而不是导入
'../../public/images/logo_2016.png';
这会起作用
<img className="Header-logo" src="/images/logo_2016.png" alt="Logo" />
最好的解决办法是fork react-scripts
,这个其实官方文档里有提到,看:Alternatives to Ejecting
软件包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,但保留其余部分并消除弹出的必要性。
不需要弹出,可以用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;
};
我认为 to use react-app-rewired 为了修改 webpack 配置是一个很好的方法,但是,我不会排除整个 ModuleScopePlugin 而是将特定的白名单可以在 src 之外导入的文件:
配置-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;
};
有一些答案提供了 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",
...
},
配置-overrides.js
const { removeModuleScopePlugin } = require('customize-cra')
module.exports = removeModuleScopePlugin()
安装这两个包
npm i --save-dev react-app-rewired customize-cra
package.json
"scripts": {
- "start": "react-scripts start"
+ "start": "react-app-rewired start"
},
配置-overrides.js
const { removeModuleScopePlugin } = require('customize-cra');
module.exports = function override(config, env) {
if (!config.plugins) {
config.plugins = [];
}
removeModuleScopePlugin()(config);
return config;
};
如果需要多次修改,比如使用ant design时,可以这样组合多个函数:
const {
override,
removeModuleScopePlugin,
fixBabelImports,
} = require('customize-cra');
module.exports = override(
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: 'css',
}),
removeModuleScopePlugin(),
);
添加到 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;
}
}
};
使用 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;
}
}
};
public 文件夹中的图片
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 扩展中使用图像
您可以尝试使用 simlinks,但反之亦然。
React 不会遵循 simlinks,但您可以将某些内容移动到源目录,并创建一个指向它的 simlink。
在我项目的根目录中,我有一个节点服务器目录,其中包含多个模式文件。我想在前端使用它们,所以我:
- 移动文件/src
- 在终端中,我进入了架构文件在服务器中所属的位置
ln -s SRC_PATH_OF_SCHEMA_FILE
这给了 React 它想要的东西,节点非常高兴通过 simlinks 包含文件。
我不得不在 Truffle 中解决同样的问题。解决方案如下:
由于 Create-React-App 的默认行为不允许从 src 文件夹外部导入文件,我们需要将我们的构建文件夹中的合同放入 src 中。我们可以在每次编译合约时复制和粘贴它们,但更好的方法是简单地配置 Truffle 将文件放在那里。
在 truffle-config.js 文件中,将内容替换为以下内容:
const path = require("path");
module.exports = {
contracts_build_directory: path.join(__dirname, "client/src/contracts")
};
我不知道这是否对你有帮助,但我知道当我在 Truffle 中遇到同样的问题时我发现了你的问题,这可能对其他人有帮助。
在我的项目中遇到了同样的问题,并在官方的 create-react-app 文档中找到了这个:https://create-react-app.dev/docs/using-the-public-folder/
有一个“逃生口”可以在模块系统外添加资产:
If you put a file into the public folder, it will not be processed by
webpack. Instead it will be copied into the build folder untouched. To
reference assets in the public folder, you need to use an environment
variable called 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'} />;
}
如果您想从 public 访问 CSS 个文件,您可能会遇到错误 源目录之外
或者,您可以 link 此文件位于 index.html 中,该文件也位于 public 目录中。
<link rel="stylesheet" href="App.css">
这是一个在简单情况下效果很好的替代方法(使用 fs
和 ncp
)。在开发时,保留一个脚本 运行 来监视 /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!');
});
})
</pre>
这是相对导入的问题,这可能是因为我们使用了“create-react-app project”命令,该命令形成了一个名为 project 的目录,其中包含 node_modules 文件夹和其他几个文件public 和里面的 src 文件夹。
create-react-app 命令有一个限制,我们不能从 src 外部导入任何东西。
我的问题:
- 我必须导入在 src 文件夹外的 node_modules 文件夹中创建的 react-bootstrap css 文件。
- 我用了 import "../node_modules/bootstrap/dist/css/bootstrap.min.css";但我在终端上收到错误消息。
- 我发现我可以创建一个新的 React 应用程序并按照从 A 到 G 的解决步骤来解决这个问题。
解决方法:
A) 创建一个新的 React 应用程序,使用 create-react-app new
B) cd 新
C) 运行 这个命令:“npm install react-bootstrap bootstrap@4.6.0”(没有“”双引号)
D) 在你的反应文件中将其导入 bootstrap:
D.1) 导入“../node_modules/bootstrap/dist/css/bootstrap.min.css”;
要么
D.2) 从“react-bootstrap/Button”导入按钮;
E) 创建一个 bootstrap 元素,例如 Button 或反应文件中的任何内容,对于 D.1) < button className="btn btn-success" > Bootstrap
要么
对于 D.2) < Button variant="primary"> Bootstrap
F) 在终端中:cd src
G) 在终端中:npm start,
这次就编译成功了
推理:
当我按顺序执行步骤 A 到 G 后,我终于看到 react-bootstrap 工作了,这次我没有收到任何错误。
(我想到这个解决方案是因为:
- 我使用了 npm install "@material-ui/icons" 并将它安装在 src 之外的 node_modules 文件夹中。
- 在我的反应文件中,我使用了 import Add from "@material-ui/icons/Add"
- 和 Material-ui 图标对我来说工作正常,
但在这里我们也从外部 src 导入,从 node_modules.. 一切正常。为什么这次从外部src导入没有报错)
- 这就是为什么我刚刚创建了一个新的 React 应用程序,并遵循了解决方案步骤 A 到 G。
复制粘贴 Typescript 解决方案
(例如,这适用于 CRA/TS 堆栈,与 CRA/JS 相比需要额外的步骤。解决方案本身没有输入。)
将所需的路径添加到 ModuleScopePlugin
而不是直截了当地删除插件。
下面的代码使用了 craco, but should be easily usable for react-app-rewired 或类似的解决方案。你只需要找到你有一个 webpackConfig
对象的地方(react-app-rewired: module.exports.webpack
inside your 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;
},
},
},
],
};
helpers/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;
取自 and here
这可以直接完成,无需使用 public 文件夹的路径。
你可以这样做
<img src="/images/image-name" alt=""/>
发生这种情况是因为我们没有在浏览器中使用 App.js
。由于 index.html
是在浏览器本身中执行的,并且图像的路径已经在包含 index.html
文件
的 public 文件夹中
如果要使用CSS设置背景图片。因此,您必须使用本地主机的 URL 设置图像并添加图像的路径。请看下面的例子。
.banner {
width: 100%;
height: 100vh;
background-image: url("http://localhost:3000/img/bg.jpg");
background-size: cover;
background-repeat: no-repeat;
}
显然,使用 Create-react-app
会限制您访问项目根目录之外的图像 - 通常是 src
。
一个快速解决方法是将图像从 public
文件夹移动到 src
文件夹,这样就可以了。
所以你的代码将是这样的,例如:
background-image: URL('/src/images/img-2.jpg');
在这里发布@Flaom 在标记为回复的答案中作为评论写的内容,这实际上挽救了生命:
“这是如何被接受的答案?通过简单地在 .env 文件中设置 NODE_PATH=./src/.. 可以轻松消除这个虚假限制。这样做,你可以从 src 文件夹外部导入,而无需经历与弹出应用程序相关的痛苦。“
- 弗洛姆
编辑 根据@cigien 的要求添加了更多信息。
上面的所有答案都很好地描述了为什么我们在使用 create-react-app 创建 React 应用程序时不能使用 public 文件夹中的图像。我自己遇到了问题并阅读了所有这些答案,我意识到,答案所说的是“破解”应用程序以删除限制我们的模块。有些答案甚至没有撤消选项。对于还可以的“培训”应用程序。
就我个人而言,我不想将改变应用程序概念的解决方案添加到我自己的项目中,尤其是在商业项目中。 @Flaom 解决方案是最简单的,如果将来有任何变化,可以用其他解决方案替换。没有风险,随时可以拆,最简单
我能够通过“复制”具有 file:
作为本地依赖项的外部文件来导入 src/
外部的文件。
"dependencies": {
"@my-project/outside-dist": "file:./../../../../dist".
}
然后
import {FooComponent} from "@my-project/outside-dist/components";
不需要 eject
或 react-app-rewired
或其他第 3 方解决方案。
这是我的代码:
import React from 'react';
import './Navbar.scss';
import {images} from '../../constants';
const Navbar = () => {
return (
<nav>
<div>
< img src = {images.logo} alt = "logo" />
</div>
</nav>
);
}
export default Navbar;
也改了:
import React from 'react';
import './Navbar.scss';
import {images} from '././constants';
const Navbar = () => {
return (
<nav>
<div>
< img src = {images.logo} alt = "logo" />
</div>
</nav>
);
}
export default Navbar;
而且成功了!我越来越擅长修复错误哈哈。
我正在使用 create-react-app。我正在尝试从我的 src/components
中的文件调用我的 public 文件夹中的图像。我收到此错误消息。
./src/components/website_index.js Module not found: You attempted to import ../../public/images/logo/WC-BlackonWhite.jpg which falls outside of the project src/ directory. Relative imports outside of src/ are not supported. You can either move it inside src/, or add a symlink to it from project's node_modules/.
import logo from '../../public/images/logo_2016.png';
<img className="Header-logo" src={logo} alt="Logo" />
我读过很多东西说您可以对路径进行导入,但这对我来说仍然不起作用。任何帮助将不胜感激。我知道有很多这样的问题,但他们都告诉我要导入徽标或图像,所以很明显我在大局中遗漏了一些东西。
您需要将 WC-BlackonWhite.jpg
移动到您的 src
目录中。 public
目录用于直接在 HTML 中链接的静态文件(例如网站图标),而不是您要直接导入到包中的内容。
为其他人的答案提供更多信息。关于如何将 .png 文件交付给用户,您有两种选择。文件结构应符合您选择的方法。两个选项是:
使用 react-create-app 提供的模块系统 (
import x from y
) 并将其与您的 JS 捆绑在一起。将图像放入src
文件夹。从
public
文件夹中提供它并让 Node 提供文件。 create-react-app 显然也带有一个环境变量,例如<img src={process.env.PUBLIC_URL + '/img/logo.png'} />;
。这意味着您可以在 React 应用程序中引用它,但仍然通过 Node 提供它,您的浏览器会在正常的 GET 请求中单独请求它。
这是create-react-app开发者添加的特殊限制。它在 ModuleScopePlugin
中实现,以确保文件驻留在 src/
中。该插件确保来自应用程序源目录的相对导入不会超出它。
除了使用 eject
和修改 webpack 配置外,没有官方方法可以禁用此功能。
但是,大多数功能及其更新都隐藏在 create-react-app 系统的内部。如果你制作 eject
,你将没有更多的新功能及其更新。因此,如果您还没有准备好管理和配置包含配置 webpack 等的应用程序 - 请不要执行 eject
操作。
按照现有规则播放 - 将资产移动到 src 或基于 public
文件夹 url 使用而不导入。
然而,除了 eject
之外,还有很多非官方的解决方案,基于
rewire 允许您在没有 eject
的情况下以编程方式修改 webpack 配置。但是 删除 ModuleScopePlugin
插件 并不好 - 这会失去一些保护并且不会添加 中可用的某些功能src
。 ModuleScopePlugin
旨在支持多个文件夹。
更好的方法是添加完全可用的额外目录,类似于 src
,也受 ModuleScopePlugin
保护。这可以使用 react-app-alias
无论如何不要从 public
文件夹导入 - 这将在 build
文件夹中复制,并且可以通过两个不同的 url 获得(并且加载方式不同),这最终使包下载大小变差。
从src
文件夹中导入是可取的并且有优势。所有内容都将由 webpack 打包成块 最佳大小 并获得 最佳加载效率 .
如果您只需要导入单个文件,例如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()
]),
]
}
}
此限制确保所有文件或模块(导出)都在 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();
}
您可以通过
取消此限制- 要么改这段代码(不推荐)
- 或执行
eject
然后从目录中删除ModuleScopePlugin.js
。 - 或 comment/remove
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
来自./node_modules/react-scripts/config/webpack.config.dev.js
PS:谨防
如果您的图像在 public 文件夹中,那么您应该使用
"/images/logo_2016.png"
在您的 <img>
src
中而不是导入
'../../public/images/logo_2016.png';
这会起作用
<img className="Header-logo" src="/images/logo_2016.png" alt="Logo" />
最好的解决办法是fork react-scripts
,这个其实官方文档里有提到,看:Alternatives to Ejecting
软件包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,但保留其余部分并消除弹出的必要性。
不需要弹出,可以用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;
};
我认为
配置-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;
};
有一些答案提供了 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",
...
},
配置-overrides.js
const { removeModuleScopePlugin } = require('customize-cra')
module.exports = removeModuleScopePlugin()
安装这两个包
npm i --save-dev react-app-rewired customize-cra
package.json
"scripts": {
- "start": "react-scripts start"
+ "start": "react-app-rewired start"
},
配置-overrides.js
const { removeModuleScopePlugin } = require('customize-cra');
module.exports = function override(config, env) {
if (!config.plugins) {
config.plugins = [];
}
removeModuleScopePlugin()(config);
return config;
};
如果需要多次修改,比如使用ant design时,可以这样组合多个函数:
const {
override,
removeModuleScopePlugin,
fixBabelImports,
} = require('customize-cra');
module.exports = override(
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: 'css',
}),
removeModuleScopePlugin(),
);
添加到 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;
}
}
};
使用 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;
}
}
};
public 文件夹中的图片
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 扩展中使用图像
您可以尝试使用 simlinks,但反之亦然。
React 不会遵循 simlinks,但您可以将某些内容移动到源目录,并创建一个指向它的 simlink。
在我项目的根目录中,我有一个节点服务器目录,其中包含多个模式文件。我想在前端使用它们,所以我:
- 移动文件/src
- 在终端中,我进入了架构文件在服务器中所属的位置
ln -s SRC_PATH_OF_SCHEMA_FILE
这给了 React 它想要的东西,节点非常高兴通过 simlinks 包含文件。
我不得不在 Truffle 中解决同样的问题。解决方案如下:
由于 Create-React-App 的默认行为不允许从 src 文件夹外部导入文件,我们需要将我们的构建文件夹中的合同放入 src 中。我们可以在每次编译合约时复制和粘贴它们,但更好的方法是简单地配置 Truffle 将文件放在那里。
在 truffle-config.js 文件中,将内容替换为以下内容:
const path = require("path");
module.exports = {
contracts_build_directory: path.join(__dirname, "client/src/contracts")
};
我不知道这是否对你有帮助,但我知道当我在 Truffle 中遇到同样的问题时我发现了你的问题,这可能对其他人有帮助。
在我的项目中遇到了同样的问题,并在官方的 create-react-app 文档中找到了这个:https://create-react-app.dev/docs/using-the-public-folder/
有一个“逃生口”可以在模块系统外添加资产:
If you put a file into the public folder, it will not be processed by webpack. Instead it will be copied into the build folder untouched. To reference assets in the public folder, you need to use an environment variable called 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'} />;
}
如果您想从 public 访问 CSS 个文件,您可能会遇到错误 源目录之外
或者,您可以 link 此文件位于 index.html 中,该文件也位于 public 目录中。
<link rel="stylesheet" href="App.css">
这是一个在简单情况下效果很好的替代方法(使用 fs
和 ncp
)。在开发时,保留一个脚本 运行 来监视 /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!');
});
})
</pre>
这是相对导入的问题,这可能是因为我们使用了“create-react-app project”命令,该命令形成了一个名为 project 的目录,其中包含 node_modules 文件夹和其他几个文件public 和里面的 src 文件夹。 create-react-app 命令有一个限制,我们不能从 src 外部导入任何东西。
我的问题:
- 我必须导入在 src 文件夹外的 node_modules 文件夹中创建的 react-bootstrap css 文件。
- 我用了 import "../node_modules/bootstrap/dist/css/bootstrap.min.css";但我在终端上收到错误消息。
- 我发现我可以创建一个新的 React 应用程序并按照从 A 到 G 的解决步骤来解决这个问题。
解决方法: A) 创建一个新的 React 应用程序,使用 create-react-app new
B) cd 新
C) 运行 这个命令:“npm install react-bootstrap bootstrap@4.6.0”(没有“”双引号)
D) 在你的反应文件中将其导入 bootstrap: D.1) 导入“../node_modules/bootstrap/dist/css/bootstrap.min.css”; 要么 D.2) 从“react-bootstrap/Button”导入按钮;
E) 创建一个 bootstrap 元素,例如 Button 或反应文件中的任何内容,对于 D.1) < button className="btn btn-success" > Bootstrap 要么 对于 D.2) < Button variant="primary"> Bootstrap
F) 在终端中:cd src
G) 在终端中:npm start,
这次就编译成功了
推理: 当我按顺序执行步骤 A 到 G 后,我终于看到 react-bootstrap 工作了,这次我没有收到任何错误。 (我想到这个解决方案是因为:
- 我使用了 npm install "@material-ui/icons" 并将它安装在 src 之外的 node_modules 文件夹中。
- 在我的反应文件中,我使用了 import Add from "@material-ui/icons/Add"
- 和 Material-ui 图标对我来说工作正常, 但在这里我们也从外部 src 导入,从 node_modules.. 一切正常。为什么这次从外部src导入没有报错)
- 这就是为什么我刚刚创建了一个新的 React 应用程序,并遵循了解决方案步骤 A 到 G。
复制粘贴 Typescript 解决方案
(例如,这适用于 CRA/TS 堆栈,与 CRA/JS 相比需要额外的步骤。解决方案本身没有输入。)
将所需的路径添加到 ModuleScopePlugin
而不是直截了当地删除插件。
下面的代码使用了 craco, but should be easily usable for react-app-rewired 或类似的解决方案。你只需要找到你有一个 webpackConfig
对象的地方(react-app-rewired: module.exports.webpack
inside your 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;
},
},
},
],
};
helpers/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;
取自
这可以直接完成,无需使用 public 文件夹的路径。 你可以这样做
<img src="/images/image-name" alt=""/>
发生这种情况是因为我们没有在浏览器中使用 App.js
。由于 index.html
是在浏览器本身中执行的,并且图像的路径已经在包含 index.html
文件
如果要使用CSS设置背景图片。因此,您必须使用本地主机的 URL 设置图像并添加图像的路径。请看下面的例子。
.banner {
width: 100%;
height: 100vh;
background-image: url("http://localhost:3000/img/bg.jpg");
background-size: cover;
background-repeat: no-repeat;
}
显然,使用 Create-react-app
会限制您访问项目根目录之外的图像 - 通常是 src
。
一个快速解决方法是将图像从 public
文件夹移动到 src
文件夹,这样就可以了。
所以你的代码将是这样的,例如:
background-image: URL('/src/images/img-2.jpg');
在这里发布@Flaom 在标记为回复的答案中作为评论写的内容,这实际上挽救了生命:
“这是如何被接受的答案?通过简单地在 .env 文件中设置 NODE_PATH=./src/.. 可以轻松消除这个虚假限制。这样做,你可以从 src 文件夹外部导入,而无需经历与弹出应用程序相关的痛苦。“
- 弗洛姆
编辑 根据@cigien 的要求添加了更多信息。
上面的所有答案都很好地描述了为什么我们在使用 create-react-app 创建 React 应用程序时不能使用 public 文件夹中的图像。我自己遇到了问题并阅读了所有这些答案,我意识到,答案所说的是“破解”应用程序以删除限制我们的模块。有些答案甚至没有撤消选项。对于还可以的“培训”应用程序。
就我个人而言,我不想将改变应用程序概念的解决方案添加到我自己的项目中,尤其是在商业项目中。 @Flaom 解决方案是最简单的,如果将来有任何变化,可以用其他解决方案替换。没有风险,随时可以拆,最简单
我能够通过“复制”具有 file:
作为本地依赖项的外部文件来导入 src/
外部的文件。
"dependencies": {
"@my-project/outside-dist": "file:./../../../../dist".
}
然后
import {FooComponent} from "@my-project/outside-dist/components";
不需要 eject
或 react-app-rewired
或其他第 3 方解决方案。
这是我的代码:
import React from 'react';
import './Navbar.scss';
import {images} from '../../constants';
const Navbar = () => {
return (
<nav>
<div>
< img src = {images.logo} alt = "logo" />
</div>
</nav>
);
}
export default Navbar;
也改了:
import React from 'react';
import './Navbar.scss';
import {images} from '././constants';
const Navbar = () => {
return (
<nav>
<div>
< img src = {images.logo} alt = "logo" />
</div>
</nav>
);
}
export default Navbar;
而且成功了!我越来越擅长修复错误哈哈。