ES6 import from root
Asked Answered
E

8

81

I'm currently playing around with React Native. I'm trying to structure my app, however it's starting to get messy with imports.

--app/
    -- /components
        -- Loading.js
    -- index.ios.js

Now, within my index.ios.js i'm able to simply do:

import Loading from './components/Loading';

However, when I start to create more components, with a deeper directory struture, it starts to get messy:

import Loading from '.../../../../components/Loading';

I understand the preferred solution would be to make private npm modules for things, but that's overkill for a small project.

You could do a global.requireRoot type solution on the browser, but how do I implement this with import?

Evesham answered 20/4, 2015 at 17:58 Comment(6)
This doesn't seem to have to anything specifically to do with React or ES6.Dyann
Alias, have you found any solution for this?Labe
I did not... The only answer I seem to found was "structure your application better" but it isn't always an option. I just ended up using require....Evesham
How is using require any different from using import here?Aero
Might be able to try NODE_PATH='./app' npm start and then require things like import Loading from 'components/Loading' but haven't tried it myself...Liu
Use an absolute path instead of a relative one?Fondly
B
60

Had the same issue with React. So i wrote some plugin for babel which make it possible to import the modules from the root perspective - the paths are not shorter - but it's clear what you import.

So instead of:

import 'foo' from '../../../components/foo.js';

You can use:

import 'foo' from '~/components/foo.js';

Here is the Plugin (tested and with a clear README)

Bloomery answered 11/8, 2015 at 8:49 Comment(3)
Thanks for this! Incredibly useful :)Diphenyl
This one is very usefulLelia
How to make eslint not complain about not finding the import? (note: trying to use it in a Nodejs app, not React)Copaiba
T
45

The react documentation explain how to do that: https://create-react-app.dev/docs/importing-a-component/#absolute-imports

just add a jsconfig.json in your project root:

{
   "compilerOptions": {
      "baseUrl": "src"
   },
  "include": ["src"]
}
Torrid answered 5/9, 2020 at 8:56 Comment(3)
This is by far the simplest solution. tsconfig.json if TypeScript.Augmenter
This worked like a charm for me! But I had to remember to restart my webpack for it to take effect.Leake
Great. Simple and effective. import {H1} from 'components/tags'Thomism
C
20

If you are using Webpack you can configure it via the resolve property to resolve a your import path.

Webpack 1

resolve: {
  root: [
    path.resolve(__dirname  + '/src')
  ]
}......

Webpack 2

resolve: {
  modules: [
    path.resolve(__dirname + '/src'),
    path.resolve(__dirname + '/node_modules')
  ]
}.....

After that you can use

import configureStore from "store/configureStore";

instead of the:

import configureStore from "../../store/configureStore";

Webpack will configure your import path from the passed resolve param.

The same stuff you can do with System.js loader but with it's own config param (it's can be map or path. Check it in the System.js documentation) (if you would like to use it. It's mostly for a Angular 2 case. But I suggest: don't use standard System.js even if you are working with ng2. Webpack is much better).

Cockspur answered 16/12, 2016 at 9:41 Comment(2)
This answer would be better if the example import statements used the paths/files in op's question.Shindig
This does not seem to work for css or image files. I have my assets in src/assets and I get a Module not found error from react that says I'm attempting to import something that falls outside the src directory. YMMV.Corves
F
11

I just checked out a React project which is more than 6 months old and for some reasons my imports no longer worked. I tried the first answer:

import 'foo' from '~/components/foo.js';

Unfortunately this did not work.

I added an .env file in the root of my project at the same level as my package.json. I added the following line to that file and this fixed my imports in my project.

NODE_PATH=src/
Foray answered 3/4, 2018 at 8:35 Comment(1)
It's import 'foo' from 'components/foo.js';. add this too.Kall
P
8

If you're using Create-React-App, you just need to change the environmental variable NODE_PATH to contain the root of your project.

In your config.json do the following change to set this variable before running the react-scripts commands:

"scripts": {
  "start": "cross-env NODE_PATH=. react-scripts start",
  "build": "cross-env NODE_PATH=. react-scripts build",
  "test": "cross-env NODE_PATH=. react-scripts test",
  "eject": "react-scripts eject"
},

We're using the npm library cross-env because it works on unix and windows. The syntax is cross-env var=value command.

Now instead of import module from '../../my/module' we can do import module from 'src/my/module'

Extra details on implementation

Its important to note that cross-env's scope is limited to the command it executes, so cross-env var=val command1 && command2 will only have var set during command1. Fix this if needed by doing cross-env var=val command1 && cross-env var=val command2

create-react-app gives precedence to folders in node_modules/ over whats in NODE_PATH, which is why we're setting NODE_PATH to "." instead of "./src". Using "." requires all absolute imports to start with "src/" which means there should never be a name conflict, unless you're using some node_module called src.

(Note of caution: The solution described above replaces the variable NODE_PATH. Ideally we would append to it if it already exists. NODE_PATH is a ":" or ";" separated list of paths, depending on if its unix or windows. If anyone finds a cross-platform solution to do this, I can edit my answer.)

Pinkney answered 22/1, 2019 at 18:50 Comment(0)
C
7

With webpack you can also make paths starting with for example ~ resolve to the root, so you can use import Loading from '~/components/Loading';:

resolve: {
  extensions: ['.js'],
  modules: [
    'node_modules', 
    path.resolve(__dirname + '/app')
  ],
  alias: {
    ['~']: path.resolve(__dirname + '/app')
  }
}

The trick is using the javascript bracket syntax to assign the property.

Clardy answered 15/9, 2017 at 18:26 Comment(1)
I doubt that the brackets do anything here. The brackets are for allowing a variable to be passed as a key. Just having quotes around the key should be fine.Galbreath
I
6

In Webpack 3 the config is slightly diffrent:

import webpack from 'webpack';
import {resolve} from 'path';

...

module: {
    loaders: [
        {
            test: /\.js$/,
            use: ["babel-loader"]
        },
        {
            test: /\.scss$|\.css$/,
            use: ["style-loader", "css-loader", "sass-loader"]
        }
    ]
},
resolve: {
    extensions: [".js"],
    alias: {
        ["~"]: resolve(__dirname, "src")
    }
},
Insuppressible answered 3/11, 2017 at 15:12 Comment(0)
S
1

If you're using Create React App you can add paths.appSrc to resolve.modules in config/webpack.config.dev.js and config/webpack.config.prod.js.

From:

resolve: {
    modules: ['node_modules', paths.appNodeModules].concat(...

To:

resolve: {
    modules: [paths.appSrc, 'node_modules', paths.appNodeModules].concat(...

Your code would then work:

import Loading from 'components/Loading';
Syncope answered 5/9, 2018 at 4:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.