wake-up-neo.com

Webpack mit kleinem ersten Skript und asynchronem Laden aller anderen Skripte

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:

  • Eine kleine anfängliche Javascript-Datei, die Abhängigkeiten asynchron lädt
  • Jeder Seitentyp kann sein eigenes Javascript haben, das auch Abhängigkeiten haben kann.
  • Bei allgemeinen Modulen sollten Kreditorenskripts in gebräuchlichen Skripts gebündelt sein

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]  
14
erzki

Die Lösung für dieses Problem ist zweifach:

  1. Zuerst müssen Sie verstehen wie Code-Splitting im Webpack funktioniert
  2. Zweitens müssen Sie so etwas wie das CommonsChunkPlugin verwenden, um das gemeinsam genutzte Bundle zu generieren.

Code-Aufteilung

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($) {
    /* ... */
});

Geteilte Bundles

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.

Fazit

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!

12
Jamund Ferguson

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);
}
1
mpen