184

I'm still confused how to resolve module paths with webpack. Now I write:

myfile = require('../../mydir/myfile.js') 

but I'd like to write

myfile = require('mydir/myfile.js') 

I was thinking that resolve.alias may help since I see a similar example using { xyz: "/some/dir" } as alias then I can require("xyz/file.js").

But if I set my alias to { mydir: '/absolute/path/mydir' }, require('mydir/myfile.js') won't work.

I feel dumb because I've read the doc many times and I feel I'm missing something. What is the right way to avoid writing all the relative requires with ../../ etc?

gpbl
  • 4,721
  • 5
  • 31
  • 45
  • `resolve.alias` works exactly the way you suggested. I wonder if it was failing because of something else in your `resolve` configuration. I use `alias{ mydir: path.resolve( __dirname, 'path', 'to', 'mydir' )` and `require( 'mydir/myfile.js' )` works just fine. – sethro Jan 27 '16 at 20:41

11 Answers11

148

Webpack >2.0

See wtk's answer.

Webpack 1.0

A more straightforward way to do this would be to use resolve.root.

http://webpack.github.io/docs/configuration.html#resolve-root

resolve.root

The directory (absolute path) that contains your modules. May also be an array of directories. This setting should be used to add individual directories to the search path.

In your case:

webpack config

var path = require('path');

// ...

  resolve: {
    root: path.resolve('./mydir'),
    extensions: ['', '.js']
  }

consuming module

require('myfile')

or

require('myfile.js')

see also: http://webpack.github.io/docs/configuration.html#resolve-modulesdirectories

Community
  • 1
  • 1
AndyCunningham
  • 1,678
  • 1
  • 14
  • 5
  • 1
    Thanks, I tried `root`, `modulesDirectories`, and a mix of both, but it didn't work. It seems that submodules (e.g. `require("mydir/file")`) are not accepted. – gpbl Dec 16 '14 at 20:09
  • They should be - can we see your webpack config? – Jeff Ling Dec 18 '14 at 11:16
  • Yay, I made it with `modulesDirectories` adding the name of the `mydir`'s parent directory. Not the best solution yet, since I fear to overwrite some other valid module. But for now it can work. – gpbl Jan 05 '15 at 18:23
  • FYI i got confused since the app is also requiring the same modules via node.js, where changing the `node_modules` path is not a good practice. So at the end, I just use `../` as always. – gpbl Jan 05 '15 at 18:43
  • It's worth noting that this method does not seem to work with dynamic sections: if (process.env.NODE_ENV === "development") { require("my-lib"); // Error: Cannot find module 'my-lib' – Eric Dec 02 '15 at 20:33
  • Note to library authors: Using `resolve.root` may cause [some headaches](https://github.com/TechnologyAdvice/stardust/pull/140). – vhs Dec 28 '15 at 20:42
  • 1
    If I'm understanding this correctly, using this configuration would require that the filenames be unique? – Jonny May 05 '16 at 15:02
  • and 'extensions: ['', '.js']' is not necessary. – sstruct Nov 20 '16 at 08:57
  • 1
    `WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema. - configuration.resolve has an unknown property 'root'.` – Tomáš Zato Jul 30 '17 at 13:54
  • 1
    "webpack 2 removed everything but modules as a way to resolve paths. This means root will not work" https://stackoverflow.com/a/36574982/588759 – rofrol Aug 21 '17 at 16:45
90

For future reference, webpack 2 removed everything but modules as a way to resolve paths. This means root will not work.

https://gist.github.com/sokra/27b24881210b56bbaff7#resolving-options

The example configuration starts with:

{
  modules: [path.resolve(__dirname, "app"), "node_modules"]
  // (was split into `root`, `modulesDirectories` and `fallback` in the old options)
wtk
  • 1,431
  • 15
  • 15
  • 4
    Thanks, this is really helpful. `modulesDirectories` is still used by webpack-dev-server, even with webpack 2, which makes this very confusing. – Evan Nov 03 '16 at 19:50
69

resolve.alias should work exactly the way you described, so I'm providing this as an answer to help mitigate any confusion that may result from the suggestion in the original question that it does not work.

a resolve configuration like the one below will give you the desired results:

// used to resolve absolute path to project's root directory (where web pack.config.js should be located)
var path = require( 'path' );
...
{
  ...
  resolve: {
    // add alias for application code directory
    alias:{
      mydir: path.resolve( __dirname, 'path', 'to', 'mydir' )
    },
    extensions: [ '', '.js' ]
  }
}

require( 'mydir/myfile.js' ) will work as expected. If it does not, there must be some other issue.

If you have multiple modules that you want to add to the search path, resolve.root makes sense, but if you just want to be able to reference components within your application code without relative paths, alias seems to be the most straight-forward and explicit.

An important advantage of alias is that it gives you the opportunity to namespace your requires which can add clarity to your code; just like it is easy to see from other requires what module is being referenced, alias allows you to write descriptive requires that make it obvious you're requiring internal modules, e.g. require( 'my-project/component' ). resolve.root just plops you into the desired directory without giving you the opportunity to namespace it further.

sethro
  • 2,127
  • 1
  • 14
  • 30
  • 49
    I like to alias the tilde: `alias: {'~': path.resolve(__dirname)},` – Daniel Buckmaster Apr 01 '16 at 22:51
  • any hints how to adjust this solution to support sub-directory imports without file extensions? @sethro – Dima Feldman Jun 08 '16 at 09:23
  • @DimaFeldman, you mean no extensions in the require argument (`require('mydir/myfile')`)? That should actually work. You can have multiple entries in `alias`; I use that to import from my `src` directory for JavaScript modules and another to import from my `styles` directory for css. Let me know if I've completely misunderstood your question. – sethro Jun 09 '16 at 22:13
  • @sethro you are right, let me rephrase my question - what I meant is: I have a directory, say Component1, and inside this dir I have a file named Component1.js. before using alias, I could import the file just by calling `import './path/to/Component1';` - simply without the inner file name & extension in the path. webpack somehow managed to detect that the Inner file has the name of the directory, and just imported it. now what I want to do is import it like that: `import 'shared\Component1';` when 'shared' is the alias. but it doesn't work without specifying the Inner file name. Thanks! – Dima Feldman Jun 10 '16 at 10:32
  • 1
    @DimaFeldman Sorry, I'm not familiar with the behavior you are describing; so you'll have to forgive me if I'm just ignorant to some known feature (I can't find documentation for it). I wonder if you have some loader in your config which is providing the ability to import a module by only specifying its location (but not its filename)? Sorry, I'm no help... May be best to ask a new question with your config file included. – sethro Jun 10 '16 at 16:34
  • `extensions` may be omited, because webpack defaults are: `['.js', '.json']` – Arsen K. Jun 20 '18 at 19:53
13

In case anyone else runs into this problem, I was able to get it working like this:

var path = require('path');
// ...
resolve: {
  root: [path.resolve(__dirname, 'src'), path.resolve(__dirname, 'node_modules')],
  extensions: ['', '.js']
};

where my directory structure is:

.
├── dist
├── node_modules
├── package.json
├── README.md
├── src
│   ├── components
│   ├── index.html
│   ├── main.js
│   └── styles
├── webpack.config.js

Then from anywhere in the src directory I can call:

import MyComponent from 'components/MyComponent';
Alex Klibisz
  • 1,313
  • 1
  • 14
  • 21
  • 2
    It's not good to resolve node_modules using path.resolve. This can cause problems with sub-dependencies. Use the string `'node_modules'` instead. `[ path.resolve(__dirname, 'src'), 'node_modules' ],` – spencer.sm Jul 08 '18 at 20:53
  • @spencer.sm what if I only want modules to be resolved from the current project? I have a few projects that import from each other. If projectA imports fileA from projectB, and fileA imports `lodash`, I want `lodash` to be resolved ONLY from `projectA/node_modules`. This is what `resolve.modules: [path.resolve(__dirname, 'node_modules')]` is useful for. However I'm running into problems with sub-dependencies like you said. Is there a way to tell webpack to also find sub-dependencies in addition to restricting node_modules resolution to `projectA/node_modules`? – Eric Guan Aug 06 '19 at 08:17
  • @spencer.sm thanks you! after lot of struggle, finally your solution solved my sub-dependency issues :D – Saad Abdullah May 09 '20 at 18:38
6

I have resolve it with Webpack 2 like this:

module.exports = {
  resolve: {
    modules: ["mydir", "node_modules"]    
  }
}

You can add more directories to array...

Damjan Pavlica
  • 31,277
  • 10
  • 71
  • 76
  • Be careful, absolute and relative paths are not process equally ! Can affect build time https://webpack.js.org/configuration/resolve/#resolve-modules – TeChn4K Jan 25 '17 at 08:26
  • 1
    It will works in both cases, but builds (may) take longer time with relative paths. – TeChn4K Jan 25 '17 at 12:06
5

My biggest headache was working without a namespaced path. Something like this:

./src/app.js
./src/ui/menu.js
./node_modules/lodash/

Before I used to set my environment to do this:

require('app.js')
require('ui/menu')
require('lodash')

I found far more convenient avoiding an implicit src path, which hides important context information.

My aim is to require like this:

require('src/app.js')
require('src/ui/menu')
require('test/helpers/auth')
require('lodash')

As you see, all my app code lives within a mandatory path namespace. This makes quite clear which require call takes a library, app code or a test file.

For this I make sure that my resolve paths are just node_modules and the current app folder, unless you namespace your app inside your source folder like src/my_app

This is my default with webpack

resolve: {
  extensions: ['', '.jsx', '.js', '.json'],
  root: path.resolve(__dirname),
  modulesDirectories: ['node_modules']
}

It would be even better if you set the environment var NODE_PATH to your current project file. This is a more universal solution and it will help if you want to use other tools without webpack: testing, linting...

SystematicFrank
  • 16,555
  • 7
  • 56
  • 102
3

If you're using create-react-app, you can simply add a .env file containing

NODE_PATH=src/

Source: https://medium.com/@ktruong008/absolute-imports-with-create-react-app-4338fbca7e3d

Brian Burns
  • 20,575
  • 8
  • 83
  • 77
3

Got this solved using Webpack 2 :

   resolve: {
      extensions: ['', '.js'],
        modules: [__dirname , 'node_modules']
    }
Aaqib
  • 9,942
  • 4
  • 21
  • 30
2

This thread is old but since no one posted about require.context I'm going to mention it:

You can use require.context to set the folder to look through like this:

var req = require.context('../../mydir/', true)
// true here is for use subdirectories, you can also specify regex as third param

return req('./myfile.js')
altShiftDev
  • 1,564
  • 1
  • 9
  • 20
1

Simply use babel-plugin-module-resolver:

$ npm i babel-plugin-module-resolver --save-dev

Then create a .babelrc file under root if you don't have one already:

{
    "plugins": [
        [
            "module-resolver",
            {
                "root": ["./"]
            }
        ]
    ]
}

And everything under root will be treated as absolute import:

import { Layout } from 'components'

For VSCode/Eslint support, see here.

Lucia
  • 13,033
  • 6
  • 44
  • 50
0

I didn't get why anybody suggested to include myDir's parent directory into modulesDirectories in webpack, that should make the trick easily:

resolve: {
    modulesDirectories: [
      'parentDir',
      'node_modules',
    ],
    extensions: ['', '.js', '.jsx']
  },
daniele bertella
  • 695
  • 1
  • 7
  • 14