Webpack alternate require loader
JavaScript Shell
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
demo
lib
test
.editorconfig
.eslintrc
.gitignore
.travis.yml
HISTORY.md
LICENSE.txt
README.md
package.json

README.md

Webpack Alternate Require Loader

Build Status

This loader allows webpack to approximate arcane Node.js require semantics for advanced use cases when a normal require doesn't suffice

Background

The Problem

Let's say you have a project like:

src/index.js
src/outside-of-resolution-path/node_modules/foo

if you try:

// src/index.js
// BAD: Fails
var foo = require("foo");

This will fail, because src/outside-of-resolution-path/node_modules is not in the resolution path, which is:

src/node_modules
node_modules

The Module Pattern

One solution to this problem is called the "module pattern", which adds an extra file to start Node.js module resolution from a different directory. Basically, say we add a simple file in a directory outside of the current Node.js require resolution path:

// src/outside-of-resolution-path/require.js
// Re-export the `require` to start resolution from `src/outside-of-resolution-path/node_modules`
module.exports = require;

And switched our importing code to:

// src/index.js
// GOOD: Module pattern (re-exported `require`) works!
var foo = require("./outside-of-resolution-path/require")("foo");

this works because the Node.js resolution path starts from the re-exported require:

src/outside-of-resolution-path/node_modules
src/node_modules
node_modules

Webpack

The above pattern works just fine for Node.js. Unfortunately, this non-standard require usage fails in Webpack.

Enter this loader, which allows a bridge for webpack builds to also use the module pattern / other non-standard requires.

Installation

The loader is available via npm:

$ npm install --save webpack-alternate-require-loader

Usage

The plugin takes a configuration object of a re-exported module path to search for in code and then a resolved path to that same code on disk like:

{
  "CODE_TO_MATCH": require.resolve("REEXPORTED_CODE_PATH")
  "./outside-of-resolution-path/require": require.resolve("./outside-of-resolution-path/require")
}

It will then effectively transform something like:

var foo = require("CODE_TO_MATCH")("foo");
var foo = require("./outside-of-resolution-path/require")("foo");

to:

var foo = require("/RESOLVED/PATH/TO/foo");

This effectively simulates what Node.js would do at execution time to the code.

Examples

A basic configuration:

module.exports = {
  module: {
    loaders: [
      {
        test: /\.js$/,
        loader: "webpack-alternate-require-loader",
        query: JSON.stringify({
          "./outside-of-resolution-path/require": require.resolve("./outside-of-resolution-path/require")
        })
      }
    ]
  }
};

Additional examples are provided in: demo/webpack.config.js. If you have a clone of this repository with devDependencies, you can run:

$ npm run build-demo-wp

and see the results in the demo directory.

Notes

Do I have to use exactly the module / require pattern above?

Yes. Although Node.js can figure out:

var altRequire = require("./outside-of-resolution-path/require");
var foo = altRequire("foo");

This plugin currently cannot because it is naive and uses regexes. You must follow the form:

var foo = require("./outside-of-resolution-path/require")("foo");

Fortunately, if you are using babel-plugin-replace-require, you can easily produce require expressions that work with this plugin.

Why can't I just prepend the non-standard node_modules path in code?

See the module pattern discussion page. Basically, with top-level dependencies you can. But with nested dependencies and modern npm / yarn the real depended on code can be located anywhere in the tree. And you need the node_modules search path to be different than normal.

You're using regexes? Yuck!

Indeed. But that's basically how webpack / some loaders roll. We stick to an easy pattern and avoid the cost of a full babel install + parsing. But, we may be open to real code parsing in the future.

Contributions

Contributions welcome! Make sure to pass $ npm run check.