Unified JavaScript module resolution

Hajime Yamasaki Vukelic
3 min readMay 15, 2017

--

How to coordinate module lookup between Webpack, Jest, and TypeScript

In JavaScript we have two types of module references: relative and absolute (‘non-relative’ in some material online). For absolute module references, modules are normally looked for in the node_modules directory.

This is only the default, though, and Webpack has always been offering a way to change this. Here we will take a look at what the alternative setup may be, and how to synchronize different parts of our build to work consistently.

Problem: complicated relative import paths

Say you have a directory structure like this:

src/
views/
Menu/
Menu.ts
Menu.css
List/
List.ts
List.css
util/
assign-path.ts
service/
xhr.ts

Now, say you are in Menu.ts and you want to import List.ts, assign-path.ts, and xhr.ts. It would normally look something like this:

import List from "../List/List";
import assignPath from "../../util/assign-path";
import XHR from "../service/xhr";

I call this double-dot hell. I made a typo, too, and the xhr module could not be imported. I needed to go one more level up.

This is annoying. Even if your build system and editor are able to trap these import issues on time, fixing them is still not so convenient.

Solution: module resolution configuration

What if we could do the imports like this:

import List from "views/List/List";
import assignPath from "util/assign-path";
import XHR from "service/xhr";

What this gives us is we no longer need to remember how many levels we need to go up before we can go back down towards directories like views, util, or service, and thus absolves us from the double-dot hell. Essentially, we’ve converted a bunch of local module references into absolute module references — as if they were installed via NPM.

To get this, we need to configure all the moving parts that deal with modules. This may include Webpack, TypeScript compiler, or Jest, for example. If we configure only one of them, the other parts of the build system will not work correctly, so it’s important that they are all on the same page.

I will show you how to handle these three components in the text that follows.

Webpack configuration

Webpack supports resolve.modules configuration option. It is an array of paths that will used as the base directory for module resolution, when using absolute module references.

In our case, it would look something like this:

// webpack.config.js
module.exports = {
// ....
resolve: {
modules: [path.join(__dirname, "src"), "node_modules"],
}
};

The configuration in the example will instruct Webpack to find absolute module references under the src directory, and fall back on node_modules if not found in src.

Note that doing this means that absolute module references will shadow the modules in node_modules — those that are installed via NPM.

TypeScript configuration

TypeScript is a bit nicer as it will always look at node_modules regardless of the configuration. All we need to do is add the baseUrl option, which is documented in the documentation section for Compiler Options as well as in the section about the Module Resolution.

In our case, baseUrl configuration is quite simple. The tsconfig.json should look like this:

{
"compilerOptions": {
...
"baseUrl": "src"
},
...
}

As with the Webpack configuration, modules in node_modules are shadowed by modules in the src.

Jest configuration

Jest is configured similarly to Webpack. We provide a list of look-up paths using the modulePaths configuration options documented here.

In our package.json, we will add something like this:

{
...
"jest": {
...
"modulePaths": [
"<rootDir>/src/",
"<rootDir>/node_modules/"
]
}
}

Conclusion

To recap what we’ve done:

  • Convert relative module references within our source tree into absolute references
  • Make sure all programs in our build system resolve module references the same way
  • Keep in mind that absolute references of the modules in our code will shadow absolute references of the modules in node_modules

I hope this was useful to you. If so, don’t forget to recommend. :)

--

--

Hajime Yamasaki Vukelic

Helping build an inclusive and accessible web. Web developer and writer. Sometimes annoying, but mostly just looking to share knowledge.