ES6 import from root

Javascriptnode.jsImport

Javascript Problem Overview


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?

Javascript Solutions


Solution 1 - Javascript

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)

Solution 2 - Javascript

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"]
}

Solution 3 - Javascript

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).

Solution 4 - Javascript

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/

Solution 5 - Javascript

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.

Solution 6 - Javascript

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.)

Solution 7 - Javascript

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")
    }
},

Solution 8 - Javascript

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';

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAliasView Question on Stackoverflow
Solution 1 - JavascriptMichael J. ZoidlView Answer on Stackoverflow
Solution 2 - JavascriptFabrice FontaineView Answer on Stackoverflow
Solution 3 - JavascriptVelidanView Answer on Stackoverflow
Solution 4 - JavascriptFasaniView Answer on Stackoverflow
Solution 5 - JavascriptAlexander DerckView Answer on Stackoverflow
Solution 6 - JavascriptScotty JamisonView Answer on Stackoverflow
Solution 7 - JavascriptkeemorView Answer on Stackoverflow
Solution 8 - JavascriptCraig MylesView Answer on Stackoverflow