2015-05-05 8 views
7

Sto configurando un gruppo di alias di moduli tramite webpack tramite resolve.alias. Poi, nel mio codice app, vorrei richiedere uno di questi moduli utilizzando una variabile che contiene un nome alias:Richiede dinamicamente un modulo con alias tramite webpack

var module = require(moduleAlias); 

Purtroppo, questo crea un "modulo di contesto" che contiene tutto nella directory dello script e dei suoi discendenti che non è quello che cercavo in questo caso particolare. Inoltre, poiché da nessuna parte nel mio codice sto richiedendo esplicitamente tutti i moduli con alias, non vengono incorporati nella mia app.

due domande:

  1. Come faccio a fare in modo tutti i moduli alias sono in bundle con il mio codice?
  2. Come posso accedervi utilizzando una variabile che contiene un alias?

Grazie!

+0

Perché l'importazione deve essere dinamica? Puoi descrivere il contesto un po 'meglio? –

+0

I moduli che devono essere richiesti dipendono dai dati provenienti dal server. Nell'esempio che ho dato, il valore di 'moduleAlias' proviene dal server. – Aaronius

+0

Poiché la dipendenza è dinamica, potrebbe essere necessario eseguire un caricatore separato come '$ script'. Vedi [numero 150] (https://github.com/webpack/webpack/issues/150). –

risposta

8

Questo risponde solo la seconda parte della tua domanda : se si è in bundle modulo con alias e si desidera che tali alias per essere requirable da un contesto:

Per quanto ne so, non c'è modo ufficiale di fare con il webpack. Ho creato un plugin, che lavora con il nodo 4 (si può adattare se si desidera utilizzare puro ES5), che aggiungerà a qualsiasi contesto la lista degli alias:

'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; 

In questo modo si può utilizzare:

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

Ed il risultato sotto forma il seguente codice generato:

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

Very cool @JBE. Non l'ho provato poiché i requisiti del mio progetto sono cambiati, ma in assenza di altre risposte lo contrassegnerò come corretto. Grazie. – Aaronius

5

la soluzione più pulita che ho trovato è quello di sovrascrivere il sistema di modulo ID predefinito. Webpack sembra utilizzare l'indice di array per impostazione predefinita. Faccio un controllo per vedere se il percorso del file è nel mio modulo alias, quindi imposta il suo id su quello.

In questo modo nel mio codice in cui avevo bisogno di fare dinamica sincrona richiede con un alias, ho potuto fare __webpack_require__(alias)

Questo è un hack totale con metodi privati ​​(__webpack_require__), ma vedo questo come un temporanea Correggere fino a quando non riesco a migrare la nostra base di codice su richieste dinamiche asincrone o utilizzare correttamente percorsi anziché alias ovunque, come fanno molte basi di codice 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)); 
} 
Problemi correlati