使用webpack动态需要别名模块

时间:2015-05-05 23:39:43

标签: webpack

我通过resolve.alias通过webpack配置一堆模块别名。然后,在我的应用程序代码中,我想要使用包含别名的变量中的一个模块:

var module = require(moduleAlias);

不幸的是,这会创建一个"上下文模块"包含脚本目录中的所有内容及其后代,这不是我在此特定情况下所追求的内容。此外,由于我的代码中没有任何地方我明确要求所有别名模块,因此它们不会内置到我的应用程序中。

两个问题:

  1. 如何确保所有别名模块都与我的代码捆绑在一起?
  2. 如何使用包含别名的变量访问它们?
  3. 谢谢!

2 个答案:

答案 0 :(得分:8)

这只回答了您问题的第二部分:如果您使用别名捆绑了模块,并且您希望从上下文中获取这些别名:

据我所知,没有正式的方法可以使用webpack。我创建了一个插件,使用Node 4(如果你想使用纯ES5,你可以适应),这将在任何上下文中添加别名列表:

'use strict';

class AddToContextPlugin {
  constructor(extras) {
    this.extras = extras || [];
  }

  apply(compiler) {
    compiler.plugin('context-module-factory', (cmf) => {
      cmf.plugin('after-resolve', (result, callback) => {
        this.newContext = true;
        return callback(null, result);
      });

      // this method is called for every path in the ctx
      // we just add our extras the first call
      cmf.plugin('alternatives', (result, callback) => {
        if (this.newContext) {
          this.newContext = false;

          const extras = this.extras.map((ext) => {
            return {
              context: result[0].context,
              request: ext
            };
          });

          result.push.apply(result, extras);
        }
        return callback(null, result);
      });
    });
  }
}

module.exports = AddToContextPlugin;

您可以使用它:

webpack({
      /*...*/
      resolve: {
        alias: {
          'alias1': 'absolute-path-to-rsc1',
          'alias2$': 'absolute-path-to-rsc2'
        }
      },
      plugins: [
        new AddToContextPlugin(['alias1', 'alias2'])
      ]
    })

结果如以下代码生成:

function(module, exports, __webpack_require__) {

    var map = {
        "./path/to/a/rsc": 2,
        "./path/to/a/rsc.js": 2,
        "./path/to/another/rsc.js": 301,
        "./path/to/another/rsc.js": 301,
        "alias1": 80,
        "alias2": 677
    };
    function webpackContext(req) {
        return __webpack_require__(webpackContextResolve(req));
    };
    function webpackContextResolve(req) {
        return map[req] || (function() { throw new Error("Cannot find module '" + req + "'.") }());
    };
    webpackContext.keys = function webpackContextKeys() {
        return Object.keys(map);
    };
    webpackContext.resolve = webpackContextResolve;
    module.exports = webpackContext;
    webpackContext.id = 1;

}

答案 1 :(得分:6)

我发现最干净的解决方案是覆盖默认模块Id系统。 Webpack似乎默认使用数组索引。我检查文件路径是否在我的别名模块中,然后将其id设置为。

在我需要执行同步动态的代码中,需要使用别名,我可以__webpack_require__(alias)

这是使用私有方法(__webpack_require__)的完全黑客攻击,但我将此视为临时修复,直到我可以将代码库迁移到正确的异步动态需求或正确使用路径而不是别处,就像许多requireJS代码库一样。

var path = require('path');
var _ = require('lodash');

function NamedAliasModules(){};    

NamedAliasModules.prototype.apply = function(compiler){
    compiler.plugin('compilation', function(compilation){
        compilation.plugin("before-module-ids", function(modules) {
            modules.forEach(function(module) {
                if(module.id === null && module.libIdent) {
                    var id = module.libIdent({
                        context: compiler.options.context
                    });
                    var fullpath = path.resolve(__dirname, id);

                    if (_.has(aliasLookup, fullpath) || _.has(aliasLookup, fullpath.replace(/\.js$/,''))){
                        id = aliasLookup[fullpath] || aliasLookup[fullpath.replace(/\.js$/, '')];

                        module.libIdent = function(){
                            return id;
                        }

                    }
                    module.id = id;
                }
            }, this);
        }.bind(this));
    }.bind(this));
}