2015-07-24 11 views
30

Wie verwende ich Webpack, um unabhängige SPA-Bundles zu erstellen, die während des Betriebs geladen werden können oder nicht, wenn mein Benutzer in meinem SPA navigiert?Erstellen einzelner SPA-Bundles mit Webpack

Ich habe ein Kontakte-Modul und ein Aufgabenmodul. Beide haben zwei Abhängigkeiten. Ich möchte, dass WebPack Bundles für jeden erstellt, der wann (und wenn) benötigt wird.

Der Code ist unten. Das Problem scheint darin zu bestehen, dass jeder dieser Einträge als Anwendungseintrittspunkte betrachtet wird, und somit auch der darin eingefügte Webpack-Bootstrap-Code.

Ich habe verschiedene Beispiele mit CommonsChunkPlugin gesehen, aber ich kann keine API-Referenz/Dokumentation dafür finden, und von dem, was ich vermuten kann, ist das nicht, was ich sowieso will.

Bearbeiten - fand diese Dokumente here, und fügte einen Versuch mit dem Plugin unten in meiner Bearbeitung.


Aktuelle Konfiguration

module.exports = { 
    entry: { 
     contacts: './contacts', 
     tasks: './tasks' 
    }, 
    output: { 
     path: path.resolve(__dirname, 'build'), 
     filename: '[name]-bundle.js' 
    } 
}; 

Contacts.js

define(['./ca', './cb'], function(ca, cb){ 
    var name = 'Contacts'; 
    alert(ca + ' ' + cb); 
}); 

Tasks.js

define(['./ta', './tb'], function(ta, tb){ 
    var name = 'TASKS Main'; 
    alert(ta + ' ' + tb); 
}); 

Aufgaben-bundle.js

/******/ (function(modules) { // webpackBootstrap 
/******/ // The module cache 
/******/ var installedModules = {}; 

/******/ // The require function 
/******/ function __webpack_require__(moduleId) { 

/******/  // Check if module is in cache 
/******/  if(installedModules[moduleId]) 
/******/   return installedModules[moduleId].exports; 

/******/  // Create a new module (and put it into the cache) 
/******/  var module = installedModules[moduleId] = { 
/******/   exports: {}, 
/******/   id: moduleId, 
/******/   loaded: false 
/******/  }; 

/******/  // Execute the module function 
/******/  modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 

/******/  // Flag the module as loaded 
/******/  module.loaded = true; 

/******/  // Return the exports of the module 
/******/  return module.exports; 
/******/ } 


/******/ // expose the modules object (__webpack_modules__) 
/******/ __webpack_require__.m = modules; 

/******/ // expose the module cache 
/******/ __webpack_require__.c = installedModules; 

/******/ // __webpack_public_path__ 
/******/ __webpack_require__.p = ""; 

/******/ // Load entry module and return exports 
/******/ return __webpack_require__(0); 
/******/ }) 
/************************************************************************/ 
/******/ ([ 
/* 0 */ 
/***/ function(module, exports, __webpack_require__) { 

    var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(3), __webpack_require__(4)], __WEBPACK_AMD_DEFINE_RESULT__ = function(ta, tb){ 
     var name = 'TASKS Main'; 
     alert(ta + ' ' + tb); 
    }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 

/***/ }, 
/* 1 */, 
/* 2 */, 
/* 3 */ 
/***/ function(module, exports, __webpack_require__) { 

    var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ 
     var name = 'TASKS - A'; 
     alert('ta'); 
    }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 

/***/ }, 
/* 4 */ 
/***/ function(module, exports, __webpack_require__) { 

    var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ 
     var name = 'TASKS - B'; 
     alert('tb'); 
    }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 

/***/ } 
/******/ ]); 

EDIT

Hier ist mein Versuch Nummer 2 mit dem CommonsChunkPlugin. Ich habe ein Dummy app.js

app.js

var module = window.location.hash.split('/')[0]; 
alert(module); 

Dann zog ich alle meine Kontakte und Aufgaben Dateien in einem Ordner Komponenten, aber ansonsten ließ sie allein. Meine neue Konfiguration:

module.exports = { 
    entry: { 
     app: './app' 
    }, 
    output: { 
     path: path.resolve(__dirname, 'build'), 
     filename: '[name]-bundle.js' 
    }, 
    plugins: [ 
     new webpack.optimize.CommonsChunkPlugin({ 
      name: './components/contacts', 
      filename: 'contacts-component-bundle.js' 
     }), 
     new webpack.optimize.CommonsChunkPlugin({ 
      name: './components/tasks', 
      filename: 'tasks-component-bundle.js' 
     }) 
    ] 
}; 

Bizarely, jetzt app-bundle.js erscheint noch keine Webpack Bootstrap-Code

webpackJsonp([0,1,2],[ 
/* 0 */ 
/***/ function(module, exports) { 

    var module = window.location.hash.split('/')[0]; 
    alert(module); 

/***/ } 
]); 

Kontakte-Komponenten-bundle.js jetzt müssen hat gerade diese

webpackJsonp([1,2],[]); 

und Aufgaben-Komponenten-bundle.js erscheint alle meine webpack Bootstrap-Code zu haben

/******/ (function(modules) { // webpackBootstrap 
/******/ // install a JSONP callback for chunk loading 
/******/ var parentJsonpFunction = window["webpackJsonp"]; 
/******/ window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules) { 
/******/  // add "moreModules" to the modules object, 
/******/  // then flag all "chunkIds" as loaded and fire callback 
/******/  var moduleId, chunkId, i = 0, callbacks = []; 
/******/  for(;i < chunkIds.length; i++) { 
/******/   chunkId = chunkIds[i]; 
/******/   if(installedChunks[chunkId]) 
/******/    callbacks.push.apply(callbacks, installedChunks[chunkId]); 
/******/   installedChunks[chunkId] = 0; 
/******/  } 
/******/  for(moduleId in moreModules) { 
/******/   modules[moduleId] = moreModules[moduleId]; 
/******/  } 
/******/  if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules); 
/******/  while(callbacks.length) 
/******/   callbacks.shift().call(null, __webpack_require__); 
/******/  if(moreModules[0]) { 
/******/   installedModules[0] = 0; 
/******/   return __webpack_require__(0); 
/******/  } 
/******/ }; 

/******/ // The module cache 
/******/ var installedModules = {}; 

/******/ // object to store loaded and loading chunks 
/******/ // "0" means "already loaded" 
/******/ // Array means "loading", array contains callbacks 
/******/ var installedChunks = { 
/******/  2:0, 
/******/  1:0 
/******/ }; 

/******/ // The require function 
/******/ function __webpack_require__(moduleId) { 

/******/  // Check if module is in cache 
/******/  if(installedModules[moduleId]) 
/******/   return installedModules[moduleId].exports; 

/******/  // Create a new module (and put it into the cache) 
/******/  var module = installedModules[moduleId] = { 
/******/   exports: {}, 
/******/   id: moduleId, 
/******/   loaded: false 
/******/  }; 

/******/  // Execute the module function 
/******/  modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 

/******/  // Flag the module as loaded 
/******/  module.loaded = true; 

/******/  // Return the exports of the module 
/******/  return module.exports; 
/******/ } 

/******/ // This file contains only the entry chunk. 
/******/ // The chunk loading function for additional chunks 
/******/ __webpack_require__.e = function requireEnsure(chunkId, callback) { 
/******/  // "0" is the signal for "already loaded" 
/******/  if(installedChunks[chunkId] === 0) 
/******/   return callback.call(null, __webpack_require__); 

/******/  // an array means "currently loading". 
/******/  if(installedChunks[chunkId] !== undefined) { 
/******/   installedChunks[chunkId].push(callback); 
/******/  } else { 
/******/   // start chunk loading 
/******/   installedChunks[chunkId] = [callback]; 
/******/   var head = document.getElementsByTagName('head')[0]; 
/******/   var script = document.createElement('script'); 
/******/   script.type = 'text/javascript'; 
/******/   script.charset = 'utf-8'; 
/******/   script.async = true; 

/******/   script.src = __webpack_require__.p + "" + chunkId + "." + ({"0":"app","1":"./components/contacts"}[chunkId]||chunkId) + "-bundle.js"; 
/******/   head.appendChild(script); 
/******/  } 
/******/ }; 

/******/ // expose the modules object (__webpack_modules__) 
/******/ __webpack_require__.m = modules; 

/******/ // expose the module cache 
/******/ __webpack_require__.c = installedModules; 

/******/ // __webpack_public_path__ 
/******/ __webpack_require__.p = ""; 
/******/ }) 
/************************************************************************/ 
/******/ ([]); 

Auch ich versuche nur Webpack zu verwenden, um ein SPA Proof of Concept zu erhalten und läuft, mit einer Art von Wurzel-App.js entry point, und dann eine beliebige Anzahl von Modulen/Komponenten, die bei Bedarf geladen werden. Mit requirejs ist das trivial, also muss ich mir vorstellen, dass mir hier etwas fehlt, vor allem bei all den Artikeln, die ich darüber gesprochen habe, wie großartig Webpack für SPAs ist.


EDIT 2

Per Antwort des bebraw unten habe ich versucht, die folgenden:

app.js

var mod = window.location.hash.split('/')[0]; 
alert(mod); 

require.ensure([], function() { 
    require('./components/' + mod).show(); 
}); 

webpack.config.js

var path = require('path'); 
var webpack = require('webpack'); 

module.exports = { 
    entry: { 
     app: './app' 
    }, 
    output: { 
     path: path.resolve(__dirname, 'build'), 
     filename: '[name]-bundle.js' 
    } 
}; 

Und dann in meinem Build-Ordner bin ich mit app-bundle.js, die alle meine Bootstrap-Code hat, und meine app.js Code und dann 1.1-bundle.js, die alle meiner Aufgaben und Kontakte-Code hat.

Ich habe auch versucht, diese

module.exports = { 
    entry: { 
     app: './app' 
    }, 
    output: { 
     path: path.resolve(__dirname, 'build'), 
     filename: '[name]-bundle.js' 
    }, 
    plugins: [ 
     new webpack.optimize.CommonsChunkPlugin({ 
      name: './components/contacts', 
      filename: 'contacts-component-bundle.js', 
      children: true 
     }), 
     new webpack.optimize.CommonsChunkPlugin({ 
      name: './components/tasks', 
      filename: 'tasks-component-bundle.js', 
      children: true 
     }) 
    ] 
}; 

, die die gleichen wie die oben ergibt, aber jetzt auch hat Aufgaben-Komponenten-bundle.js und Kontakte-Komponenten-bundle.js, beide von denen haben nur einige Webpack-Bootstrap-Code; Der Aufgaben- und Kontaktcode sind alle noch im 1.1-Bundle.

Auch hier möchte ich Webpack auf die eine oder andere Weise sagen können, einzelne Module und ihre Abhängigkeiten für das nachfolgende faule, asynchrone Laden zu bündeln, wenn es benötigt wird.

Die endgültige Antwort wurde von Tobias-Webpack-Schöpfer gegeben, die ich hier für die Nachwelt setzen werde.

Wirklich dynamisch ist nicht möglich. webpack (in constract to require.js) kompiliert Ihre App vor der Ausführung und hat keinen Zugriff auf Laufzeitinformationen. Dynamic benötigt im Webpack einen Tauchgang in jedem möglichen Ordner solange dein dynamischer Ausdruck nicht enthält ... Du solltest es sogar konfigurieren können, um mod + '/' + mod mit dem ContextReplacementPlugin und ein wenig RegExp magic zu verwenden (benutze Rückreferenzen in die RegExp). Standardmäßig würde es zu viele Module enthalten.

Antwort

12

webpack erstellt einen Splitpunkt pro async require-Anweisung (require.ensure oder AMD require([])). Also müssen Sie einen require([]) pro Lazy-Loaded Teil Ihrer App schreiben.

Ihr SPA hat nur einen einzigen Zugangspunkt: den (clientseitigen) Router. Nennen wir es app.js. Die Seiten werden bei Bedarf geladen und sind keine Einstiegspunkte.

webpack.config.js:

module.exports = { 
    entry: { 
     app: './app' 
    }, 
    output: { 
     path: path.resolve(__dirname, 'build'), 
     filename: '[name]-bundle.js' 
    } 
} 

App.js:

var mod = window.location.hash.split('/')[0].toLowerCase(); 
alert(mod); 

switch(mod) { 
    case "contacts": 
     require(["./pages/contacts"], function(page) { 
      // do something with "page" 
     }); 
     break; 
    case "tasks": 
     require(["./pages/tasks"], function(page) { 
      // do something with "page" 
     }); 
     break; 
} 

Alternative: einen "Kontext" Verwendung.

Bei Verwendung einer dynamischen Abhängigkeit i. e require("./pages/" + mod) Sie können keinen Splitpunkt pro Datei schreiben. Für diesen Fall gibt es einen Lader, der eine Datei in einem require.ensure Block Wrapps:

app.js

var mod = window.location.hash.split('/')[0].toLowerCase(); 
alert(mod); 

require("bundle!./pages/" + mod)(function(page) { 
    // do something with "page" 
}); 

Dies ist webpack spezifisch. Vergiss nicht npm install bundle-loader --save. Überprüfen Sie das richtige Gehäuse, es ist Groß-und Kleinschreibung.

+0

Danke ein paar @tobias - Ich werde das ausprobieren, sobald ich etwas Freizeit später finde. –

+0

Danke nochmal Tobias. Das scheint zu funktionieren, aber wenn man das Beispiel nur ein bisschen * realistischer macht, bricht es. 'require ('bundle! ./components/' + mod + '/' + mod) (Funktion (Modul) { });' bewirkt, dass es (verständlicherweise) bricht, vermutlich weil das Plugin nicht statisch auflösen kann schauen, und ist nicht codiert, um in jeden möglichen Ordner zu tauchen. Ich versuche nicht, das Problem zu ändern - aber im wirklichen Leben würde ich (und mache) für jedes Modul separate Ordner haben. Wird so etwas wirklich Dynamisches in Webpack unterstützt, wie es in requireJS ist? –

+0

Wirklich dynamisch ist nicht möglich. webpack (in constract to require.js) kompiliert Ihre App vor der Ausführung und hat keinen Zugriff auf Laufzeitinformationen. Dynamic benötigt im Webpack einen Tauchgang in jedem möglichen Ordner, solange der dynamische Ausdruck kein '..' enthält. Sie sollten es sogar in der Lage sein, 'mod + '/' + mod' mit dem ContextReplacementPlugin und ein wenig RegExp magic zu verwenden (verwenden Sie Rückverweise in der RegExp). Standardmäßig würde es zu viele Module enthalten. –

4

Ich habe ein bisschen davon durchgearbeitet und wollte meine Arbeit hier zum Wohle anderer posten. Die Prämisse ist eine Webanwendung, die aus einer einzelnen Seite besteht, wobei bestimmte Framework-Dienstprogramme anfänglich geladen werden, wobei alle nachfolgenden Abschnitte der Anwendung bei Bedarf geladen werden, wenn der Benutzer navigiert und den URL-Hash ändert.

Der Proof of Concept app.js framework/Einstiegspunkt wie folgt framework.loadModule(mod, moduleLoaded, invalidModule);

app.js

var framework = require('./framework/frameworkLoader'); 

window.onhashchange = hashChanged; 
hashChanged(); //handle initial hash 

function hashChanged() { 
    var mod = window.location.hash.split('/')[0].replace('#', ''); 

    if (!mod) return; 

    framework.loadModule(mod, moduleLoaded, invalidModule); 

    function moduleLoaded(moduleClass, moduleHtml){ 
     //empty to remove handlers previously added 
     $('#mainContent').empty(); 

     $('#mainContent').html(moduleHtml); 

     var inst = new moduleClass(); 
     inst.initialize(); 
    } 

    function invalidModule(){ 
     alert('Yo - invalid module'); 
    } 
}; 

Offensichtlich ist der Punkt von Interesse ist aussieht. Wie Tobias sagte, muss es separate, eigenständige AMD-artige require-Anweisungen geben (ich glaube, es gibt eine CommonJS-Alternative, aber ich habe das noch nicht untersucht) für JEDE Möglichkeit. Offensichtlich würde niemand jede Möglichkeit für eine große Anwendung ausschreiben wollen. Daher nehme ich an, dass eine Art einfacher Knoten-Task als Teil des Build-Prozesses existiert, um durch die App-Struktur zu navigieren und all diese erforderlichen Anweisungen automatisch zu generieren Modul für Sie. In diesem Fall wird davon ausgegangen, dass jeder Ordner in ein Modul enthält, dessen Hauptcode und HTML-Code in gleichnamigen Dateien enthalten sind. Zum Beispiel wäre die Moduldefinition für Kontakte in modules/contacts/contacts.js und die html in modules/contacts/contacts.htm.

Ich habe diese Datei nur manuell ausgeschrieben, seit Knoten durch Ordner und Dateistrukturen navigieren und neue Dateien ausgeben, ist einfach.

frameworkLoader.js

//************** in real life this file would be auto-generated******************* 

function loadModule(modName, cb, onErr){ 
    if (modName == 'contacts') require(['../modules/contacts/contacts', 'html!../modules/contacts/contacts.htm'], cb); 
    else if (modName == 'tasks') require(['../modules/tasks/tasks', 'html!../modules/tasks/tasks.htm'], cb); 
    else onErr(); 
} 

module.exports = { 
    loadModule: loadModule 
}; 

Mit dem Rest der Dateien:

webpack.config.js

var path = require('path'); 
var webpack = require('webpack'); 

module.exports = { 
    entry: { 
     app: './app' 
    }, 
    output: { 
     path: path.resolve(__dirname, 'build'), 
     filename: '[name]-bundle.js', 
     publicPath: '/build/', 
    } 
}; 

und die wichtigsten HTML-Datei

default.htm

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
    <head> 
     <title></title> 

     <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.min.js"></script> 
     <script type="text/javascript" src="build/app-bundle.js"></script> 
    </head> 
    <body> 
     <h1>Hello there!</h1> 
     <h2>Sub heading</h2> 

     <h3>Module content below</h3> 
     <div id="mainContent"></div> 
    </body> 
</html> 

Der nächste Schritt ist das Hinzufügen von Ad-hoc-Abhängigkeiten zu diesen Modulen.Leider funktioniert das Hinzufügen einer require(['dep1', 'dep2'], function(){ nicht ganz so, wie ich es mir erhofft hätte; das jagt alle Abhängigkeiten in der Liste eifrig und bündelt sie alle mit dem fraglichen Modul, anstatt sie bei Bedarf zu laden. Dies bedeutet, dass, wenn sowohl die Kontakte- als auch die Aufgabenmodule die gleiche Abhängigkeit erfordern (wie es der Fall ist), beide Module mit der gesamten Abhängigkeit gebündelt sind, was bewirkt, dass sie geladen und neu geladen wird, wenn der Benutzer Kontakte und dann Aufgaben durchsucht.

Die Lösung ist der Bündellader npm install bundle-loader --save. Dies ermöglicht es uns, require('bundle!../../libs/alt') zu tun, was eine Funktion zurückgibt, die, wenn sie aufgerufen wird, unsere Abhängigkeit abruft. Die Funktion übernimmt als Argument einen Callback, der unsere neu geladene Abhängigkeit akzeptiert. Offensichtlich erfordert das Laden von N Abhängigkeiten wie dieser unangenehmen Code, um die N Callbacks zu beeinflussen, also werde ich in Kürze die Promise-Unterstützung einbauen. Aber zuerst die Modulstruktur zu aktualisieren, um die Abhängigkeitsspezifikation zu unterstützen.

contacts.js

function ContactsModule(){ 
    this.initialize = function(alt, makeFinalStore){ 
     //use module 
    }; 
} 

module.exports = { 
    module: ContactsModule, 
    deps: [require('bundle!../../libs/alt'), require('bundle!alt/utils/makeFinalStore')] 
}; 

tasks.js

function TasksModule(){ 
    this.initialize = function(alt){ 
     //use module 
    }; 
} 

module.exports = { 
    module: TasksModule, 
    deps: [require('bundle!../../libs/alt')] 
}; 

Nun kehrt jedes Modul ein Objektliteral mit dem Modul selbst, und die Abhängigkeiten es braucht. Offensichtlich wäre es schön gewesen, eine Liste von Strings zu schreiben, aber wir brauchen die require('bundle! Aufrufe genau dort, damit Webpack sehen kann, was wir brauchen.

Jetzt in Versprechen unterstützen unsere app.js zu bauen

app.js

var framework = require('./framework/frameworkLoader'); 

window.onhashchange = hashChanged; 
hashChanged(); //handle initial hash 

function hashChanged() { 
    var mod = window.location.hash.split('/')[0].replace('#', ''); 

    if (!mod) return; 

    framework.loadModule(mod, moduleLoaded, invalidModule); 

    function moduleLoaded(modulePacket, moduleHtml){ 
     var ModuleClass = modulePacket.module, 
      moduleDeps = modulePacket.deps; 

     //empty to remove handlers previous module may have added 
     $('#mainContent').empty(); 

     $('#mainContent').html(moduleHtml); 

     Promise.all(moduleDeps.map(projectBundleToPromise)).then(function(deps){ 
      var inst = new ModuleClass(); 
      inst.initialize.apply(inst, deps); 
     }); 

     function projectBundleToPromise(bundle){ 
      return new Promise(function(resolve){ bundle(resolve); }); 
     } 
    } 

    function invalidModule(){ 
     alert('Yo - invalid module'); 
    } 
}; 

Diese separate einzelne Bundle-Dateien verursacht erstellt für Kontakte, Aufgaben, alt werden, und makeFinalStore . Beim Laden von Aufgaben wird zunächst das Paket mit dem Aufgabenmodul und das Paket mit alt in der Registerkarte "Netzwerk" angezeigt. das Laden von Kontakten danach zeigt, dass das Kontakte-Bundle zusammen mit dem makeFinalStore-Bundle geladen wird. Das Laden von Kontakten zeigt zuerst Kontakte, alt und makeFinalStore-Pakete laden; das Laden von Aufgaben danach zeigt nur das Laden von Tasks.


Zuletzt wollte ich das Modul Kontakte erweitern, so dass es seine eigene dynamische Ad-hoc-Laden unterstützt. Im echten Leben lädt ein Kontaktmodul im laufenden Betrieb möglicherweise die Rechnungsinformationen des Kontakts, Kontaktinformationen, Abonnementinformationen und so weiter. Offensichtlich wird dieser Proof of Concept einfacher sein und grenzwertig an albern sein.

Unter den Kontakteordner ich einen contactDynamic Ordner erstellt, mit den folgenden Dateien

contentA.js 
contentA.htm 
contentB.js 
contentB.htm 
contentC.js 
contentC.htm 

contentA.js

module.exports = { 
    selector: '.aSel', 
    onClick: function(){ alert('Hello from A') } 
}; 

contentA.htm

<h1>Content A</h1> 

<a class="aSel">Click me for a message</a> 

InhaltB.js

module.exports = { 
    selector: '.bSel', 
    onClick: function(){ alert('Hello from B') } 
}; 

contentB.htm

<h1>Content B</h1> 

<a class="bSel">Click me for a message</a> 

contentC.js

module.exports = { 
    selector: '.cSel', 
    onClick: function(){ alert('Hello from C') } 
}; 

contentC.htm

<h1>Content C</h1> 

<a class="cSel">Click me for a message</a> 

Der aktualisierte Code für contacts.js ist unten. Einige Dinge zu beachten. Wir erstellen im Voraus dynamische Kontexte, um Dateien entsprechend ausschließen zu können. Wenn nicht, dann wird unsere dynamische Anforderung mit bundle! fehlschlagen, wenn es zu den HTML-Dateien kommt; Unser Kontext beschränkt Dateien auf *.js. Wir erstellen auch einen Kontext für HTM-Dateien. Beachten Sie, dass wir die beiden Lader bundle! und html! zusammen verwenden. Beachten Sie auch, dass Bestellung Angelegenheiten - bundle!html! funktioniert, aber html!bundle! verursacht diese Bündel nicht gebaut werden, und ich hoffe, dass jemand kommentieren kann, warum. Es werden jedoch separate Bundles für jede einzelne .js- und .htm-Datei erstellt und nur bei Bedarf geladen. Und natürlich wickle ich die bundle! Anrufe in Promises wie vorher ein.

Auch ich verstehe, dass die ContextReplacementPlugin statt dieser Kontexte verwendet werden kann, und ich hoffe, jemand kann mir zeigen, wie: ist eine Instanz von ContextReplacementPlugin in eine dynamische require übergeben?

contacts.js

function ContactsModule(){ 
    this.initialize = function(alt, makeFinalStore){ 
     $('#contacts-content-loader').on('click', '.loader', function(){ 
      loadDynamicContactContent($(this).data('name')); 
     }); 
    }; 
} 

function loadDynamicContactContent(name){ 
    var reqJs = require.context('bundle!./contactDynamic', false, /.js$/); 
    var reqHtml = require.context('bundle!html!./contactDynamic', false, /.htm$/); 

    var deps = [reqJs('./' + name + '.js'), reqHtml('./' + name + '.htm')]; 

    Promise.all(deps.map(projectBundleToPromise)).then(function(deps){ 
     var code = deps[0], 
      html = deps[1]; 

     $('#dynamicPane').empty().html(html); 
     $('#dynamicPane').off().on('click', code.selector, function(){ 
      code.onClick(); 
     }); 
    }); 
} 

function projectBundleToPromise(bundle){ 
    return new Promise(function(resolve){ bundle(resolve); }); 
} 

module.exports = { 
    module: ContactsModule, 
    deps: [require('bundle!../../libs/alt'), require('bundle!alt/utils/makeFinalStore')] 
}; 

contacts.htm

<h1>CONTACTS MODULE</h1> 

<div id="contacts-content-loader"> 
    <a class="loader" data-name="contentA">Load A</a> 
    <a class="loader" data-name="contentB">Load B</a> 
    <a class="loader" data-name="contentC">Load C</a> 
</div> 

<div id="dynamicPane"> 
    Nothing loaded yet 
</div> 

schließlich die endgültige default.htm

default.htm

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
    <head> 
     <title></title> 

     <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.min.js"></script> 
     <script type="text/javascript" src="build/app-bundle.js"></script> 
    </head> 
    <body> 
     <h1>Hello there!</h1> 
     <h2>Sub heading</h2> 

     <a href="#contacts">Load contacts</a> 
     <br><br> 
     <a href="#tasks">Load tasks</a> 

     <h3>Module content below</h3> 
     <div id="mainContent"></div> 
    </body> 
</html>