Vladimir Shevchuk February 2016

Webpack: How can I create a loader for "webpack" which takes an array of dependencies?

For example, I use AMD definition in my project, and use "webpack" for project building. It's possible to create some loader which will take a dependencies in array format?

define(
    [
        'mySuperLoader![./path/dependency-1, ./path/dependency-2, ...]'
    ],
    function() {
        // ... some logic here
    }
)

Project example: gitHub

Answers


jhnns February 2016

I don't think that you should use a loader for that. Why don't you just write:

require("./path/dependency-1");
require("./path/dependency-2");
require("./path/dependency-3");

It accomplishes the same thing, is much more expressive and requires no extra code/loader/hack/configuration.

If you're still not satisfied, you might be interested in webpack contexts which allow you to require a bulk of files that match a given filter. So, if you write

require("./template/" + name + ".jade");

webpack includes all modules that could be accessed by this expression without accessing parent directories. It's basically the same like writing

require("./table.jade");
require("./table-row.jade");
require("./directory/folder.jade")

You can also create contexts manually like this

var myRequire = require.context(
    "./template",   // search inside this directory
    false,         // false excludes sub-directories
    /\.jade$/      // use this regex to filter files
);

var table = myRequire("./table.jade");


jhnns February 2016

If you want to port the load-plugin's behavior to webpack, you need to do this:

1. Create a custom resolver

This is because mySuperLoader![./path/dependency-1, ./path/dependency-2, ...] does not point to a single file. When webpack tries to load a file, it first:

  • resolves the file path
  • loads the file content
  • matches and resolves all loaders
  • passes the file content to the loader chain

Since [./path/dependency-1, ./path/dependency-2, ...] is not a proper file path, there is some work to do. It is even not a proper JSON.

So, our first goal is to turn this into mySuperLoader!some/random/file?["./path/dependency-1", "./path/dependency-2", ...]. This is usually done by creating a custom resolver:

// webpack.config.js
var customResolverPlugin = {
    apply: function (resolver) {
        resolver.plugin("resolve", function (context, request) {
            const matchLoadRequest = /^\[(.+)]$/.exec(request.path);

            if (matchLoadRequest) {
                request.query = '?' + JSON.stringify(
                    matchLoadRequest[1]
                    .split(", ")
                );
                request.path = __filename;
            }
        });
    }
};

module.exports = {
    ...
    plugins: [
        {
            apply: function (compiler) {
                compiler.resolvers.normal.apply(customResolverPlugin);
            }
        }
    ]
};

Notice request.path = __filename;? We just need to give webpack an existing file so that it does not throw an error. We will generate all the content anyway. Probably not the most elegant solution, but it works.

2. Create our own load-loader (yeah!)

// loadLoader.js
const path = require("path");

function loadLoader() {
    return JSON.parse(this.request.match(/\?(.+?)$/)[1])
        .map( 

Post Status

Asked in February 2016
Viewed 1,517 times
Voted 10
Answered 2 times

Search




Leave an answer