Ich habe mit Webpack angefangen, um gewöhnliche Websites zu entwickeln, die aus mehreren Seiten und unterschiedlichen Seitentypen bestehen. Ich bin an den RequireJs Script Loader gewöhnt, der bei Bedarf alle Abhängigkeiten bei Bedarf lädt. Beim Laden der Seite wird nur ein kleines Stück Javascript heruntergeladen.
Was ich erreichen möchte, ist folgendes:
Ich habe viele Konfigurationen ausprobiert, um dies zu erreichen, jedoch ohne Erfolg.
entry: {
main: 'main.js', //Used on all pages, e.g. mobile menu
'standard-page': 'pages/standard-page.js',
'start-page': 'pages/start-page.js',
'vendor': ['jquery']
},
alias: {
jquery: 'jquery/dist/jquery.js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js"),
new webpack.optimize.CommonsChunkPlugin('common.js')
]
In der HTML-Datei möchte ich die Javascripts folgendermaßen laden:
<script src="/Static/js/dist/common.js"></script>
<script src="/Static/js/dist/main.js" async></script>
Und auf einem bestimmten Seitentyp (Startseite)
<script src="/Static/js/dist/start-page.js" async></script>
common.js sollte eine kleine Datei zum schnellen Laden der Seite sein. main.js lädt async und benötigt ('jquery').
Die Ausgabe von Webpack sieht vielversprechend aus, aber ich kann das Herstellerpaket nicht asynchron laden. Andere Abhängigkeiten (meine eigenen Module und domReady) werden in die automatisch generierten Chunks geladen, nicht jedoch in jquery.
Ich kann viele Beispiele finden, die fast das tun, aber nicht der wichtige Teil des asynchronen Ladens von Anbietern.
Ausgabe vom Webpack-Build:
Asset Size Chunks Chunk Names
main.js.map 570 bytes 0, 7 [emitted] main
main.js 399 bytes 0, 7 [emitted] main
standard-page.js 355 bytes 2, 7 [emitted] standard-page
c6ff6378688eba5a294f.js 348 bytes 3, 7 [emitted]
start-page.js 361 bytes 4, 7 [emitted] start-page
8986b3741c0dddb9c762.js 387 bytes 5, 7 [emitted]
vendor.js 257 kB 6, 7 [emitted] vendor
common.js 3.86 kB 7 [emitted] common.js
2876de041eaa501e23a2.js 1.3 kB 1, 7 [emitted]
Die Lösung für dieses Problem ist zweifach:
CommonsChunkPlugin
verwenden, um das gemeinsam genutzte Bundle zu generieren.Bevor Sie Webpack verwenden, müssen Sie lernen, von der Konfiguration abhängig zu sein. Require.js drehte sich alles um Konfigurationsdateien. Diese Einstellung erschwerte mir den Übergang zu einem Webpack, das CommonJS in node.js, das keine Konfiguration benötigt, genauer nachempfunden ist.
In diesem Sinne ist Folgendes zu beachten. Wenn Sie eine App haben und möchten, dass sie einige andere Teile von Javascript asynchron lädt, müssen Sie eines der folgenden Paradigmen verwenden.
Require.ensure
require.ensure
Ist eine Möglichkeit, einen "Split Point" in Ihrer Anwendung zu erstellen. Auch hier haben Sie vielleicht gedacht, dass Sie dies mit der Konfiguration tun müssen, aber das ist nicht der Fall. Wenn ich in meinem Datei-Webpack auf require.ensure
Drücke, wird automatisch ein zweites Bundle erstellt und bei Bedarf geladen. Jeder Code, der innerhalb dieses Split-Points ausgeführt wird, wird in einer separaten Datei zusammengefasst.
require.ensure(['jquery'], function() {
var $ = require('jquery');
/* ... */
});
Require ([])
Dasselbe können Sie auch mit der AMD-Version von require()
erreichen, die eine Reihe von Abhängigkeiten hat. Dadurch wird auch der gleiche Aufteilungspunkt erstellt:
require(['jquery'], function($) {
/* ... */
});
In Ihrem obigen Beispiel verwenden Sie entry
, um ein vendor
-Bundle mit jQuery zu erstellen. Sie müssen diese Abhängigkeitsbündel nicht manuell angeben. Wenn Sie stattdessen die Trennpunkte über Ihrem Webpack verwenden, wird dies automatisch generiert.
Verwenden Sie entry
nur für separate <script>
- Tags, die Sie auf Ihren Seiten haben möchten.
Jetzt, da Sie all das getan haben, können Sie die CommonsChunkPlugin
verwenden, um Ihre Blöcke zusätzlich zu optimieren, aber wieder wird der größte Teil der Magie für Sie erledigt und Sie müssen nicht mehr angeben, welche Abhängigkeiten geteilt werden sollen mach irgendetwas anderes. webpack
ruft die freigegebenen Blöcke automatisch ab, ohne dass zusätzliche <script>
- Tags oder eine entry
- Konfiguration erforderlich sind.
Das von Ihnen beschriebene Szenario (mehrere <script>
- Tags) entspricht möglicherweise nicht Ihren Wünschen. Mit webpack können alle Abhängigkeiten und Pakete automatisch verwaltet werden, beginnend mit nur einem einzigen <script>
- Tag. Nachdem ich mehrere Iterationen des Re-Factorings von require.js zu webpack durchlaufen habe, habe ich festgestellt, dass dies normalerweise der einfachste und beste Weg ist, um Ihre Abhängigkeiten zu verwalten.
Alles Gute!
Hier ist die Lösung, die ich gefunden habe.
Exportieren Sie zuerst diese beiden Funktionen nach window.*
- Sie möchten sie im Browser.
export function requireAsync(module) {
return new Promise((resolve, reject) => require(`bundle!./pages/${module}`)(resolve));
}
export function runAsync(moduleName, data={}) {
return requireAsync(moduleName).then(module => {
if(module.__esModule) {
// if it's an es6 module, then the default function should be exported as module.default
if(_.isFunction(module.default)) {
return module.default(data);
}
} else if(_.isFunction(module)) {
// if it's not an es6 module, then the module itself should be the function
return module(data);
}
})
}
Wenn Sie dann eines Ihrer Skripts auf einer Seite einfügen möchten, fügen Sie dies einfach Ihrem HTML-Code hinzu:
<script>requireAsync('script_name.js')</script>
Jetzt wird alles im Verzeichnis pages/
in einen separaten Block vorkompiliert, der zur Laufzeit asynchron geladen werden kann, nur wenn dies erforderlich ist.
Darüber hinaus haben Sie mit den oben genannten Funktionen eine bequeme Möglichkeit, serverseitige Daten in Ihre clientseitigen Skripts zu übertragen:
<script>runAsync('script_that_needs_data', {my:'data',wow:'much excite'})</script>
Und jetzt können Sie darauf zugreifen:
// script_that_needs_data.js
export default function({my,wow}) {
console.log(my,wow);
}