2015-05-05 129 views
7

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

var module = require(moduleAlias); 

不幸的是,这将创建包含脚本的目录及其后代的一切“上下文模块”这不是我在这个特殊情况下所追求的。此外,因为我的代码中没有明确要求所有别名模块,所以它们不会内置到我的应用程序中。

两个问题:

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

谢谢!

+0

为什么导入需要动态?你能描述一下情况好一点吗? –

+0

需要使用的模块取决于从服务器返回的数据。在我给出的例子中,'moduleAlias'的值来自服务器。 – Aaronius

+0

因为依赖是动态的,所以你可能需要经过一个单独的加载器,比如'$ script'。参见[问题150](https://github.com/webpack/webpack/issues/150)。 –

回答

8

这只能回答你的问题的第二部分:如果你已经捆绑了别名模块,并且希望这些别名是从上下文requirable:

据我所知,没有这样做的没有官方途径它与webpack。我创建了一个插件,与节点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; 

} 
+0

非常酷@JBE。我没有尝试过,因为我的项目需求已经改变,但在没有其他答案的情况下,我将其标记为正确。谢谢。 – Aaronius

5

我已经找到了干净的解决方案是,以覆盖默认的模块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)); 
}