Importing ES6 modules in deep directories - javascript

Given this directory tree:
components
foo
index.js
bar
index.js
Using babel es6, I would like to do this:
import Foo from "./components/foo"
import Bar from "./components/foo/bar"
But it errors with Module build failed: Error: ENOENT: no such file or directory, open '/Users/jemminger/Development/whatever/components/foo/bar.js'
The only way I can get it to work is this:
import Foo from "./components/foo"
import Bar from "./components/foo/bar/index"
or
import Foo from "./components/foo"
import Bar from "./components/foo/bar/"
According to https://nodejs.org/api/modules.html#modules_folders_as_modules I should be able to load the index.js file of a directory by default, which happens for foo but not bar.
Is this expected behavior?

Nodejs imports your files realatively, so you always need to care about current path. If you want to start your import path from the same point, try to use webpack. It has resolve.root option, which do exactly what you want. Just set your components root:
resolve: {
root: [
__dirname
]
}
I am assuming that webpack.config.js will be placed next to components dir. Then you can do imports as you want, but without leading ./:
import Foo from "components/foo"
import Bar from "components/foo/bar"
Be aware that now you have collission between npm-module components and your file. Your code will have priority in that case.

So, I'm not sure what the cause of the problem was, but in attempting to replicate the issue today in the same project, it's working as expected. Perhaps just the fact that webpack-dev-server was restarted fixed it. Apparently I can't computer.

Related

Importing js modules by directory name

I'm upgrading a React application and have found that I need to modify the import statements to get them to work.
For example, in the old version, the following import works without errors:
import { User } from '../System'
Note that System is a directory on my file system that contains User, a js file that ends with export default User.
In my upgraded version of the app, the System directory still exists, but the above import gives me Can't resolve '../System' in 'C:\my app\.
It turns out that to get the import working properly now, I need to change it to the following:
import User from '../System/User';
If I understand correctly, this relates to js module system changes made with ES6.
My question, though, is regarding the specification of a directory in the import statement (System above). Why would it be that I was previously able to name a file directory in the import statement instead of the actual js script/module itself? Is that approach of using a directory in the import statement still possible? And if so, is it ever advisable?
Update: based on AKX's comment, I noticed the System directory does indeed contain an index.js, which apparently is what makes the import from the directory itself possible.
When an import points to a directory, and only a file, Webpack (which most React setups use) follows Node's's conventions and will attempt to import index.js from that directory if it exists. That's the only condition under which importing from a path that points to a directory works - your previous build probably had /System/index.js (which would allow importing with from '../System'). If you rename the file you're importing to anything else - such as to User.js - importing using only the directory path will fail.
And if so, is it ever advisable?
Sure, if you want. It's a style choice but is commonly done.

Next.js imports from root directory: is it valid to start an import with a slash?

This import works, but I can't find any documentation saying that it's valid:
// rather than do a crazy nested import like this
import { myUtil } from '../../../../../lib/utils'
// this appears to work just fine
import { myUtil } from '/lib/utils'
I see where the official answer is to set up a config file with a # alias, so I suppose I will just do that to be compliant. Just thought it was curious that this import worked just fine. I am using the default configuration for a Next.js project set up with create-next-app
Not sure if this is your case, but if the top folder is in the root directory, you can use this
import { myUtil } from './lib/utils'
I'm guessing that's what's happening, even though you don't have the period in yours.

node.js 13 - import is not working properly

$ node --version
v13.8.0
Let's create three files:
// package.json
{
"type": "module"
}
// foobar.js
function foo() { console.log('foo') }
export default {foo}
// index.js
import Foo from './foobar.js';
Foo.foo();
Run index.js
$ node index.js
(node:22768) ExperimentalWarning: The ESM module loader is experimental.
foo
All working.
And now changing './foobar.js'; to './foobar';
// index.js
import Foo from './foobar';
Foo.foo();
And we get an error!
(node:22946) ExperimentalWarning: The ESM module loader is experimental.
internal/modules/esm/resolve.js:58
let url = moduleWrapResolve(specifier, parentURL);
^
Error: Cannot find module /foobar imported from /index.js
There is no other files in directory.
Why does it happens?
Why import without extension doesn't work?
UPDATE:
https://nodejs.org/api/esm.html
package.json "type" field
Files ending with .js or lacking any extension will be loaded as ES modules when the nearest parent package.json file contains a top-level field "type" with a value of "module".
So './foobar' must work.
UPDATE 2:
I believe what the documentation call "extensionless files" are literaly files without extensions, not files imported without extensions.
For example, if you import your file with import Foo from './foobar';, and you file is called foobar without the .js extension, it will work fine.
Thanks to #Seblor
Looking at the documentation, in the category Differences Between ES Modules and CommonJS, and more precisely at the "Mandatory file extensions" section, it says that the .js file extension must be present to make the import work :
A file extension must be provided when using the import keyword. Directory indexes (e.g. './startup/index.js') must also be fully specified.
This behavior matches how import behaves in browser environments, assuming a typically configured server.
I am not sure why your last question is about the import without extention not working anymore. I guess you have been working at some point with a transpiler like babel that will resolve the files without the extensions.
Edit :
I believe what the documentation call "extensionless files" are literaly files without extensions, not files imported without extensions.
For example, if you import your file with import Foo from './foobar';, and you file is called foobar without the .js extension, it will work fine.

Do not import "index.js" on folder import?

I am wondering if it is possible to re-configure the import behavior (looking for index.js) on importing module folders directly. By default, when you assume this module folder structure:
/components
/Button
/index.js
/style.scss
/Checkbox
/index.js
/style.scss
I can easily import the components like this:
import Button from 'components/Button';
import Checkbox from 'components/Checkbox';
But when I am working on that components, I will have multiple index.js files open in my editor/ide which will lead to confusion very quickly. Same applies for the style files.
What I did now is changing my folder structure to this:
/components
/Button
/Button.js
/Button.scss
/Checkbox
/Checkbox.js
/Checkbox.scss
Which solved that problem and I can see directly where each opened file belongs to.
However, now my component imports look a bit... verbose:
import Button from 'components/Button/Button';
import Checkbox from 'components/Checkbox/Checkbox';
Because obviously, webpack/babel would look for an "index.js" when I am importing a folder directly. Now my question is: can I change that behavior somehow? I'd like to tell webpack/babel that it should try to import a file named the same way as the folder as the index file.
You can re-configure directory indexes on every webserver, so I am hoping the same is possible with webpack/babel but googling didnt show anything up so far.
I went with the following solution:
In each of my folders, I will create a index.js next to the "real" module, that has the follwing content:
import module from './Button.js';
export default module;
This way I am able to keep my code in Button.js but am not required to import Button/Button someplace else.
I created a little script which automates the creation of the index.js files for me, so I don't have any additional work.

Can't resolve module (not found) in React.js

I can't believe that I'm asking an obvious question, but I still get the error in console log.
Console says that it can't find the module in the directory, but I've checked at least 10 times for typos. Anyways, here's the component code.
I want to render Header in root
import React, { Component } from 'react'
import Header from './src/components/header/header'
import logo from './logo.svg'
import './App.css'
class App extends Component {
render() {
return (
<Header/>
);
}
}
export default App;
This is the Header component
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import navBar from './src/components/header/navBar'
import './src/css/header.css'
class Header extends Component {
render() {
return {
<div>
<div id="particles-js"></div>
<navBar/>
<Title/>
</div>
};
}
}
ReactDOM.render(<Header/>, document.getElementById('header'));
I've checked at least 10 times that the module is at this location ./src/components/header/header, and it is (folder "header" contains "header.js").
Yet, React still throws this error:
Failed to compile
./src/App.js
Module not found: Can't resolve './src/components/header/header' in '/home/wiseman/Desktop/React_Components/github-portfolio/src'
npm test says the same thing.
The way we usually use import is based on relative path.
. and .. are similar to how we use to navigate in terminal like cd .. to go out of directory and mv ~/file . to move a file to current directory.
my-app/
node_modules/
package.json
src/
containers/card.js
components/header.js
App.js
index.js
In your case, App.js is in src/ directory while header.js is in src/components. To import you would do import Header from './components/header'. This roughly translate to in my current directory, find the components folder that contain a header file.
Now, if from header.js, you need to import something from card, you would do this. import Card from '../containers/card'. This translate to, move out of my current directory, look for a folder name containers that have a card file.
As for import React, { Component } from 'react', this does not start with a ./ or ../ or / therefore node will start looking for the module in the node_modules in a specific order till react is found. For a more detail understanding, it can be read here.
If you create an application with react-create-app, don't forget set environment variable:
NODE_PATH=./src
Or add to .env file to your root folder;
Deleted the package-lock.json file & then ran
npm install
Read further
in my case, The error message was
Module not found: Error: Can't resolve '/components/body
While everything was in the correct directory.
I found that renaming body.jsx to body.js resolve the issue!
So I added this code in webpack.config.js to resolve jsx as js
module.exports = {
//...
resolve: {
extensions: ['.js', '.jsx']
}
};
And then build error gone!
Adding NODE_PATH as environment variable in .env is deprecated and is replaced by adding "baseUrl": "./src", to compilerOptions in jsconfig.json or tsconfig.json.
Reference
I think its the double use of header. I just tried something similar myself and also caused issues. I capitalized my component file to match the others and it worked.
import Header from './src/components/header/header';
Should be
import Header from './src/components/header/Header';
There is a better way you can handle the import of modules in your React App.
Consider doing this:
Add a jsconfig.json file to your base folder. That is the same folder containing your package.json. Next define your base URL imports in it:
//jsconfig.json
{
"compilerOptions": {
"baseUrl": "./src"
}
}
Now rather than calling ../../ you can easily do this instead:
import navBar from 'components/header/navBar'
import 'css/header.css'
Notice that 'components/' is different from '../components/'
It's neater this way.
But if you want to import files in the same directory you can do this also:
import logo from './logo.svg'
I solved by putting the file extension
import MyComponent from "src/components/MyComponent";
to
import MyComponent from "src/components/MyComponent.tsx";
I had a similar issue.
Cause:
import HomeComponent from "components/HomeComponent";
Solution:
import HomeComponent from "./components/HomeComponent";
NOTE: ./ was before components. You can read #Zac Kwan's post above on how to use import
You can try to execute 'npm install' in the app folder. This might also solve the problem. It worked for me.
I faced the same issue when I created a new react app, I tried all options in https://github.com/facebook/create-react-app/issues/2534 but it didn't help. I had to change the port for the new app and then it worked. By default, apps use the port 3000.I changed the port to 8001 in package.json as follows:
"scripts": {
"start": "PORT=8001 react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
If you are using create-react-app, and have just added typescript to it, check whether a tsconfig.json has been auto-generated for you. The CRA docs say that it should be, but there seems to be a bug at the moment where it is not being generated.
If the tsconfig.json is missing, there's a few ways to create one yourself.
Copy one off the internet or from another repo
npx tsc --init
Create a fresh project somewhere else using npx create-react-app my-ts-proj --template typescript and then copy the tsconfig over from there
you should change import Header from './src/components/header/header' to
import Header from '../src/components/header/header'
You need to be in project folder, if you are in src or public you have to come out of those folders. Suppose your react-project name is 'hello-react' then cd hello-react
I was facing the same problem and I resolved it.
See if your index.js file is in src folder, then what ever file you are importing, the folder containing that must also be inside the src folder.
That means if your components folder is outside the src folder, just drag it inside the src folder in your editor because the files outside of src folder are not imported.
Then you shall be able to import using ./components/header/header(in this case)
For me, I had the input correct but npm start can be buggy (at least using it with Hyper terminal on Windows and Linux). If I move files to different folders, npm start doesn't pick up on these changes. I need to cancel npm start process, make the move, save and then run npm start and it will see the files now.
replace ReactDOM.render(<Header/>, document.getElementById('header')); by export default Header in Header.js
I just had this issue from auto-importing a component, no type or webpack config issues.
What fixed it was changing the import from relative to the app root directory to relative to the file:
import MyComponent from "src/components/MyComponent";
to
import MyComponent from "../components/MyComponent";
If you're getting this from Visual Studio Code auto-importing via the shortest route, you can change it so it imports relatively. By going here:
menu File → Preferences → Settings → User Settings,
"typescript.preferences.importModuleSpecifier": "relative"
It is working for me just (./) no need src here
import Header from './components/header/header'
You might be importing .tsx file inside a .js file. Ensure that if you are working on a javascript source, you have extensions .js or .jsx not .tsx :)
In my case I rename a component file, an VS Code add the below line of code for me:
import React, { Component } from "./node_modules/react";
So I fixed by removing the: ./node_modules/
import React, { Component } from "react";
Cheers!
I think it may help you-
Read your error carefully-./src/App.js
Module not found: Can't resolve './src/components/header/header' in '/home/wiseman/Desktop/React_Components/github-portfolio/src'
just write- ./header/header instead ./src/components/header/header in App.js
if it doesnt work try to change header file name may be head
Check for the import statements.It should be ended with semicolon. If you miss any, you will get this error.
Also check whether following import statement added in you component.
import { threadId } from 'worker_threads';
If so remove that line. It works for me.

Categories