Leo Jiang
Leo Jiang

Reputation: 26075

Make absolute paths relative to the project root in Webpack

I find that I need to type ../ a lot to require() files. My directory structure includes these:

js/
  components/
    ...
  actions/
    ...

From the components folder, I need to do import foo from '../actions/fooAction'. Is it possible to make the root directory the root of the project? I.e. I want to do import foo from '/actions/fooAction' instead. I tried setting Webpack's resolve.root option, but it didn't seem to do anything.

Upvotes: 35

Views: 56894

Answers (6)

vitomadio
vitomadio

Reputation: 1140

With Webpack 5 you have to add the following lines into your webpack.config.js file:

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

Upvotes: 1

Oleg
Oleg

Reputation: 1140

now you should use

resolve: {
    roots: [
        path.resolve(__dirname, 'src', 'components'),
    ],
},

see more https://webpack.js.org/configuration/resolve/#resolveroots

Upvotes: 2

Chesare22
Chesare22

Reputation: 91

Other solution is using resolve.alias to import js like a module (I'm not saying that it's a module, just the syntax is similar).

resolve: {
  alias: {
    js: path.resolve(__dirname, './js'),
  },
}

And you can import fooAction this way:

import foo from 'js/actions/fooAction';

Upvotes: 5

Greg Veres
Greg Veres

Reputation: 1890

I am going to answer this slightly differently without using resolve.root. Everything @dresyecat said is correct. However, I just went through the same exercise of moving from relative paths everywhere to module paths. Here is the doc that explains the three different types of paths you can use in the import statement.

You are asking to use a module path, which I believe is the preferred way to go.

The problem is that by default, module paths only work with things imported via npm because the new modules variable on resolve defaults to ["node_modules"]. This lets you import 3rd party code from npm really easily. But it means importing your code with a module path needs a config change. BTW, the modules used to be called moduleDirectories in previous versions. Here are the docs for the resolve variable configuration.

Ok assuming you have a directory structure like this:

project/
    webpack.config.json
    js/
        components
        actions

You can set the modules directory to be:

resolve: {
    extensions: [ '.ts', '.js', '*' ],
    modules: [ path.resolve(__dirname, "js"), "node_modules"]
}

A couple important points:

  • Be sure to include the "node_modules" if you are using npm to pull in 3rd party code, or your imports of those will start to fail
  • Be sure to import the path component in your configuration so that path is defined

    var path = require('path');

Then you can use the following (as was pointed out - without the leading /) to import your components using the module path form:

import "actions/fooAction";

Upvotes: 16

Frank N
Frank N

Reputation: 10376

The resolving process is basically simple and distinguishes between three variants:

absolute path: require("/home/me/file")

relative path: require("../src/file") or require("./file")

module path: require("module/lib/file")

The first two are pretty obvious, the third deserves a closer look:

  1. Absolute to your filesystem indeed

  2. Relative to the current file (if that file is in src/foo/bar or webpack/config/subconfig, then indeed that's it...)

  3. In contrast to import (which handles 1+2 pretty much the same way, but would send you looking in node_modules right away) path 'module' indeed means your project root for paths without a need to resolve, like output.path in your webpack config... and: (on resolving) Only 3 is subject to resolve.root and resolve.moduleDirectories resolving, see webpack docs here

Upvotes: 4

dreyescat
dreyescat

Reputation: 13798

The resolve.root option does not modifiy how file modules are resolved.

A required module prefixed with '/' is an absolute path to the file. For example, require('/home/marco/foo.js') will load the file at /home/marco/foo.js.

The / resolves to the root of your file system.

Maybe what you want is to resolve your js folder as a modules directory.

webpack.config.js

resolve: {
  root: path.resolve('./js')
}

With this configuration added to your config file will tell webpack to resolve any import or require relative to your js folder. Then, instead of using

import foo from '../actions/fooAction'

you will be able to:

import foo from 'actions/fooAction`

Mind the lack of / at the beginning.

Upvotes: 52

Related Questions