Requiring and Resolving Paths

A lot of what Webpack does is require things. As we'll see in this section, Webpack makes a clear yet subtle distinction between those different types of things that it requires: files and modules.

More importantly, Webpack uses different logic and configuration options to resolve files and modules. Thus, it's important to understand how Webpack handles files and modules so you can debug and write your configuration accordingly.

Files and Modules

In the world of Webpack, you're either working with files or modules. Files are the source code files found in your project that you write (though, they could be 3rd party files that you put in a vendor folder).

Modules are external packages, typically added to your project with a package manager like npm or bower.

Stop for a moment and digest the different between files and modules -- Webpack treats them differently, so it's important you understand this distinction.

Paths: Absolute, Relative, and Module

When Webpack parses the string passed require function, it tries to determine whether you're requiring a file or a module based on the structure of the require string.

  • Absolute: require("/var/www/project/shared/assets/app.js")
  • Relative: require("./js/app.js")
  • Module: require('bootstrap') or `require("bootstrap/"

In practice, you're not going to encounter the absolute form very often, if ever. You'll mostly be requiring files with a relative path or a module path.

The reason this is significant is that files and modules are governed by different configuration options.

Consider the example below, in which we have three files, the root App.jsx, which requires components/ListView.jsx, which itself requires the underscore 3rd party module and ItemView.jsx, another file in our project.

// app/App.jsx var ListView = require("./components/ListView"); var App = React.createClass({ render: function() { var objects = [{name: "Alex Sharp"}, {name: "Sammy Hagar"}]; return ( <ListView objects={objects} /> ); } }); // app/components/ListView.jsx var _ = require('underscore'); var ItemView = require('./ItemView.jsx'); var ListView = React.createClass({ propTypes: { objects: React.PropTypes.array }, render: function() { return ( _.map(this.props.objects, function(object) { return <ItemView object={object} /> }) ); } }); module.exports = ListView; // app/components/ItemView.jsx var ItemView = React.createClass({ render: function() { return ( <div> {this.props.object.name} </div> ); } }); module.exports = ItemView;

Breaking It Down: Requiring a File

Let's start at the top, where App.jsx requires ListView with this require:

require("./components/ListView");

There are two things to notice here. First, we're using a relative path by starting the require with ./, which means "relative to the current directory of the location of the requiring file". Second, we haven't specified the file's extension, but by properly configuring resolve.extensions Webpack will be able to find the correct file.

To satisfy this require statement, webpack will use two configuration variables: context and resolve.extensions.

To quote the Webpack documentation:

The context directory is the directory of the resource file that contains the require statement. If there is no resource file the configuration option context is used as context directory. (This can occur for entry points or with loader-generated files).

The relative path is joined to the context directory and the resulting absolute file is resolved according to “Resolving an absolute path”.

Relevant Configuration Options
  • context - Used when there is no resource file.
  • resolve.extensions - Used to find a file when no extension is specified in the require statement.

Breaking It Down: Requiring a Module

Next let's look at ListView.jsx. This component has two require statements, one that requires underscore, and another that requires ItemView.jsx.

var _ = require("underscore");

Because this has no file path at the beginning of the string, webpack will assumes that this is a module. To satisfy module requires, Webpack uses the resolve.modulesDirectories configuration option, and looks for a file or directory named "underscore" in one of those directories. If it finds a directory with that name, it will attempt to resolve it using the NodeJS standard: look for a package.json file at the root of the directory named "underscore" -- if package.json has a main field that points at a file, require that file. If the main is not present, webpack looks for a file called index.js at that root of that directory.

However, you're not limited to resolve.modulesDirectories. You can use resolve.root to specify search paths that will be prepended to resolve.modulesDirectories (e.g. given a higher lookup priority), and resolve.fallback to specify search paths that are appended to resolve.modulesDirectories (given a lower priority).

Here's what the webpack documentation says about resolving module paths:

For resolving a module we first gather all search directories for modules from the context directory. This process is similar to the node.js resolving process, but the search directories are configurable with the configuration option resolve.modulesDirectories. In addition to this the directories in the configuration option resolve.root are prepended and directories in the configuration option resolve.fallback are appended.

The module is looked up in each module directory and resolved according to “Resolving an absolute path”. If the first match has no success, the second is tried and so on.

Relevant Configuration Options

Tying It All Together: Paths, Files, Modules, and Configuration

Resources

results matching ""

    No results matching ""