This is special restriction added by developers of create-react-app. It is implemented in ModuleScopePlugin to ensure files reside in src/. That plugin ensures that relative imports from app's source directory don't reach outside of it. This restriction makes sure all files or modules (exports) are inside src/ directory, the implementation is in ./node_modules/react-dev-utils/ModuleScopePlugin.js, in following lines of code. The better way is to add fully working additional directories similar to src also protected by ModuleScopePlugin. This can be done using react-app-alias
export const toAbsoluteUrl = pathname => process.env.PUBLIC_URL + pathname;
<img src={toAbsoluteUrl('/media/png/carte2.png')}
style={{
height:'auto',
maxWidth:'70%',
margin:'auto',display:'block'
}}
/>
The package react-app-rewired can be used to remove the plugin. This way you do not have to eject.
Follow the steps on the npm package page (install the package and flip the calls in the package.json file) and use a config-overrides.js
file similar to this one:
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;
};
Ideally that TypeScript issue should be fixed first to allow for sensible cross-folder imports. It should be noted that this TypeScript issue is a bit of a showstopper for enabling imports outside src. With above setup I want to work on both apps with shared logics inside domain directory. It would be hard to rebuild this logic and setup it as package, then install from package manager in both apps - just to have it in node_modules directory.
"dependencies": {
"@mycore-ui": "file:./../mycore-ui"
}
"dependencies": {
...
"component-ui": "file:./../component-ui",
...
},
const {
removeModuleScopePlugin,
override,
babelInclude,
addWebpackAlias
} = require("customize-cra");
const path = require("path");
module.exports = override(
removeModuleScopePlugin(),
addWebpackAlias({
...["component-ui"]: path.resolve(__dirname, "../component-ui")..
}),
babelInclude([
path.resolve("src"),
path.resolve("../component-ui/src")
])
);
const {
removeModuleScopePlugin,
override
} = require('customize-cra');
module.exports = override(
removeModuleScopePlugin()
);
...
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,
reactRefreshRuntimeEntry,
reactRefreshWebpackPluginRuntimeEntry,
babelRuntimeEntry,
babelRuntimeEntryHelpers,
babelRuntimeRegenerator,
]),
],
...
As we have seen, a large number of examples were utilised in order to solve the The Create-React-App Imports Restriction Outside Of Src Directory problem that was present. The Create-React-App Imports Restriction Outside Of Src Directory With Code Examples To display an image from a local path in React: Download the image and move it into your src directory. Import the image into your file, e.g. import MyImage from ‘./thumbnail. webp’ . Set the src prop of the image element to the imported image, e.g. .21-Apr-2022
With this article, we’ll look at some examples of The Create-React-App Imports Restriction Outside Of Src Directory problems in programming.
export const toAbsoluteUrl = pathname => process.env.PUBLIC_URL + pathname;
<img src={toAbsoluteUrl('/media/png/carte2.png')}
style={{
height:'auto',
maxWidth:'70%',
margin:'auto',display:'block'
}}
/>
This is more than simple alias. This is also a multi-project src directory. Currently, create-react-app (CRA) does not support more than one src directory in the project. Monorepo, multi-repo and library projects with examples require more than one directory like src. This may be a result of some confusion in node_modules folders for multi-repo projects. Same take place in plain create-react-app if somehow one or more additional node_modulest directories appear in src. It provides aliases with the same feature set as the original create-react-app. create-react-app does not support aliases and additional src-like directories as it does not supports aliases outside of the root project directory.
yarn add--dev react - app - rewire - alias
npm install--save - dev react - app - rewire - alias
// jsconfig.paths.json or tsconfig.paths.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"example/*": ["example/src/*"],
"@library/*": ["library/src/*"]
}
}
}
// config-overrides.js
const {
alias,
configPaths
} = require('react-app-rewire-alias')
const aliasMap = configPaths('./tsconfig.paths.json') // or jsconfig.paths.json
module.exports = alias(aliasMap)
module.exports.jest = aliasJest(aliasMap)
// craco.config.js
const {
CracoAliasPlugin,
configPaths
} = require('react-app-rewire-alias')
const aliasMap = configPaths('./tsconfig.paths.json') // or jsconfig.paths.json
module.exports = {
plugins: [{
plugin: CracoAliasPlugin,
options: {
alias: aliasMap
}
}]
}
It provides aliases with the same feature set as the original create-react-app. create-react-app does not support aliases and additional src-like directories as it does not supports aliases outside of the root project directory. Integrating react-app-rewired into your project is simple (see its documentation): Create config-overrides.js mentioned above, in the project's root directory (the same including the package.json and src directory). Install react-app-rewired This may be a result of some confusion in node_modules folders for multi-repo projects. Same take place in plain create-react-app if somehow one or more additional node_modulest directories appear in src.
yarn add--dev react - app - rewire - alias
npm install--save - dev react - app - rewire - alias
// jsconfig.paths.json or tsconfig.paths.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"example/*": ["example/src/*"],
"@library/*": ["library/src/*"]
}
}
}
// config-overrides.js
const {
alias,
configPaths
} = require('react-app-rewire-alias')
const aliasMap = configPaths('./tsconfig.paths.json') // or jsconfig.paths.json
module.exports = alias(aliasMap)
module.exports.jest = aliasJest(aliasMap)
// craco.config.js
const {
CracoAliasPlugin,
configPaths
} = require('react-app-rewire-alias')
const aliasMap = configPaths('./tsconfig.paths.json') // or jsconfig.paths.json
module.exports = {
plugins: [{
plugin: CracoAliasPlugin,
options: {
alias: aliasMap
}
}]
}
This is special restriction added by developers of create-react-app. It is implemented in ModuleScopePlugin to ensure files reside in src/. That plugin ensures that relative imports from app's source directory don't reach outside of it. The better way is to add fully working additional directories similar to src also protected by ModuleScopePlugin. This can be done using react-app-rewire-alias However instead of eject there are much unofficial solutions, based on rewire which allows you to programmatically modify the webpack config without eject. But removing the ModuleScopePlugin plugin is not good - this loses some protection and does not adds some features available in src. ModuleScopePlugin is designed to support multiple folders.
Class Implementation:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
/**
* Component that alerts if you click outside of it
*/
export default class OutsideAlerter extends Component {
constructor(props) {
super(props);
this.wrapperRef = React.createRef();
this.setWrapperRef = this.setWrapperRef.bind(this);
this.handleClickOutside = this.handleClickOutside.bind(this);
}
componentDidMount() {
document.addEventListener('mousedown', this.handleClickOutside);
}
componentWillUnmount() {
document.removeEventListener('mousedown', this.handleClickOutside);
}
/**
* Alert if clicked on outside of element
*/
handleClickOutside(event) {
if (this.wrapperRef && !this.wrapperRef.current.contains(event.target)) {
alert('You clicked outside of me!');
}
}
render() {
return <div ref={this.wrapperRef}>{this.props.children}</div>;
}
}
OutsideAlerter.propTypes = {
children: PropTypes.element.isRequired,
};
Hooks Implementation:
import React, { useRef, useEffect } from "react";
/**
* Hook that alerts clicks outside of the passed ref
*/
function useOutsideAlerter(ref) {
useEffect(() => {
/**
* Alert if clicked on outside of element
*/
function handleClickOutside(event) {
if (ref.current && !ref.current.contains(event.target)) {
alert("You clicked outside of me!");
}
}
// Bind the event listener
document.addEventListener("mousedown", handleClickOutside);
return () => {
// Unbind the event listener on clean up
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref]);
}
/**
* Component that alerts if you click outside of it
*/
export default function OutsideAlerter(props) {
const wrapperRef = useRef(null);
useOutsideAlerter(wrapperRef);
return <div ref={wrapperRef}>{props.children}</div>;
}
example: ./node_modules/packagename/dist/css/styles.css
Import using the path related to node_modules (anything after node_modules/
)
import 'packagename/dist/css/styles.css'
There is a key import limitation in React which we haven’t discussed thus far: you cannot import from files outside the src directory. The src directory is created by ‘create-react-app’, and is meant to encompass all React files in your application. Notice also how we use the relative path of the file, “./importFrom”. This means that we are importing from the same directory. So far, we’ve been exporting and importing from the same directory. What if we have subdirectories that we want to pull React component definitions from?
function printToScreen(message) {
console.log(message);
}
export {
printToScreen
}
import {
printToScreen
} from "./importFrom";
printToScreen("Test Message")
import { ImportComponent } from './ImportElement';
function App() {
return (
<ImportComponent />
);
}
export default App;
class printToScreen {
constructor(message) {
console.log(message);
}
}
export {
printToScreen
}
import {
printToScreen
} from "./importFrom";
var printToScreenElem = printToScreen("Test Message");