admin管理员组

文章数量:1430020

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

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

Share Improve this question edited Feb 13, 2016 at 19:50 Volodymyr Shevchuk asked Feb 8, 2016 at 21:50 Volodymyr ShevchukVolodymyr Shevchuk 1052 silver badges9 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 5

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 (piler) {
                piler.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(module =>
            `exports['${path.basename(module, '.js')}'] = require('${module}');`
        )
        .join('\n');
}

module.exports = loadLoader;

This loader parses the request's query we have re-written with our custom resolver and creates a CommonJS module that looks like this

exports['dependency-1'] = require('path/to/dependency-1');
exports['dependency-2'] = require('path/to/dependency-2');

3. Alias our own load-loader

// webpack.config.js

    ...
    resolveLoader: {
        alias: {
            load: require.resolve('./loadLoader.js')
        }
    },

4. Configure root

Since /path/to/dependency-1 is root-relative, we need to add the root to the webpack config

// webpack.config.js
resolve: {
    root: '/absolute/path/to/root' // usually just __dirname
},

This is neither a beautiful nor an ideal solution, but should work as a makeshift until you've ported your modules.

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 acplishes 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");

本文标签: