2015-05-05 133 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)); 
}