Geavanceerde JavaScript bundeling

Bij bundeling van JavaScript -modules voor betere prestaties gaat het om het reduceren van twee dingen:

  1. Het aantal serveraanvragen.
  2. De grootte van die serververzoeken.

In een modulaire toepassing, kan het aantal serververzoeken in honderden bereiken. De volgende schermafbeelding toont bijvoorbeeld alleen het begin van de lijst met JavaScript -modules die op de startpagina van een schone installatie zijn geladen.

geen bundeling

Samenvoegen en bundelen

Uit het vak biedt Commerce twee manieren om het aantal serveraanvragen te verminderen: samenvoegen en bundelen. Deze instellingen zijn standaard uitgeschakeld. U kunt hen binnen Admin UI in Stores > Montages > Configuration > Advanced > Developer > JavaScript Settings, of van de bevellijn aanzetten.

het Bundelen

Basisbundeling

Om ingebouwde bundeling van de bevellijn toe te laten:

php -f bin/magento config:set dev/js/enable_js_bundling 1

Dit is een native Commerce mechanisme dat alle elementen in het systeem combineert en deze onder bundels van hetzelfde formaat distribueert (bundle_0.js, bundle_1.js … bundle_x.js):

Commerce bundling

Beter, maar browser laadt nog ALLE JavaScript bundels, niet alleen nodig.

Commerce het bundelen vermindert het aantal verbindingen per pagina, maar voor elke paginaverzoek laadt het alle bundels, zelfs wanneer de gevraagde pagina slechts van dossiers binnen één of twee van de bundels kan afhangen. De prestaties verbeteren nadat de bundels in de cache van de browser zijn geplaatst. Maar omdat de browser deze bundels synchroon laadt, kan het eerste bezoek van de gebruiker aan een Commerce winkel even duren om de gebruikerservaring te renderen en te beschadigen.

Basissamenvoeging

Ingebouwde samenvoeging via de opdrachtregel inschakelen:

php -f bin/magento config:set dev/js/merge_files 1

Met deze opdracht voegt u alle synchrone JavaScript bestanden samen in één bestand. Het inschakelen van samenvoeging zonder dat bundeling wordt ingeschakeld, is niet nuttig omdat Commerce gebruik maakt van RequireJS. Als u bundeling niet inschakelt, voegt Commerce alleen RequireJS en de bijbehorende configuratie samen. Wanneer u zowel bundelen als samenvoegen inschakelt, maakt Commerce één JavaScript -bestand:

Reëel-wereld het samenvoegen

Rendertijden in de praktijk

De vorige gebundelde en samengevoegde laadtijden zien er goed uit in een ontwikkelomgeving. Maar in de echte wereld kunnen veel dingen het renderen vertragen: langzame verbindingen, grote verbindingsdrempels, beperkte netwerken. Bovendien renderen mobiele apparaten niet zo snel als desktops.

Om uw storefront plaatsing voor de echte wereld te testen en voor te bereiden, adviseren wij u met het Chrome inheemse throttling profiel van "Traag 3G." te testen Met Trage 3G weerspiegelen onze vorige gebundelde uitvoertijden nu de verbindingsrealiteiten van veel gebruikers:

Reëel-wereld die bundelt

Bij trage 3G-connectiviteit duurt het ongeveer 44 seconden om alle bundels te laden voor de startpagina van een schone Commerce -installatie.

Dit geldt ook voor het samenvoegen van de bundels in één bestand. Gebruikers konden nog steeds ongeveer 42 seconden wachten op het laden van de eerste pagina, zoals hier wordt getoond:

Reëel-wereld het samenvoegen

Met een geavanceerdere aanpak van JavaScript -bundeling kunnen we deze laadtijden verbeteren.

Geavanceerde bundeling

Het doel van JavaScript -bundeling is het aantal en de grootte van aangevraagde elementen te verminderen voor elke pagina die in de browser wordt geladen. Hiervoor willen we onze bundels maken, zodat elke pagina in onze winkel alleen een gemeenschappelijke bundel en een paginaspecifieke bundel hoeft te downloaden voor elke pagina die wordt geopend.

U kunt dit bereiken door uw bundels op paginatypen te definiëren. U kunt de pagina's van Commerce indelen in verschillende paginatypen, zoals Categorie, Product, CMS, Klant, Winkel en Afhandeling. Elke pagina die in één van deze paginatypen wordt gecategoriseerd heeft een verschillende reeks module RequireJS gebiedsdelen. Wanneer u uw modules RequireJS door paginatype bundelt, zult u omhoog met slechts een handvol bundels beëindigen die de gebiedsdelen van om het even welke pagina in uw opslag behandelen.

U zou bijvoorbeeld kunnen eindigen met een bundel voor de afhankelijkheden die voor alle pagina's gelden, een bundel voor pagina's met alleen CMS, een bundel voor pagina's met alleen Catalog, een andere bundel voor pagina's met alleen zoeken en een bundel voor pagina's met uitchecken.

U kunt ook pakketten maken op doeleinde: voor algemene functies, productgerelateerde functies, verzendfuncties, afrekenfuncties, belastingen en formuliervalidaties. Hoe u uw bundels bepaalt is aan u en de structuur van uw opslag. Sommige bundelingstrategieën werken mogelijk beter dan andere.

Met een schone Commerce -installatie kunnen voldoende goede prestaties worden bereikt door bundels te splitsen op paginatypen, maar voor sommige aanpassingen kan een diepgaande analyse en andere distributies van elementen nodig zijn.

Vereiste gereedschappen

In de volgende stappen moet u de volgende programma's installeren en vertrouwd zijn met deze programma's:

Voorbeeldcode

Volledige versies van de voorbeeldcode die in dit artikel worden gebruikt, zijn hier beschikbaar:

Deel 1: Een bundelconfiguratie maken

1. Een bestand build.js toevoegen

Maak een build.js -bestand in de hoofdmap van Commerce . Dit dossier zal de volledige bouwstijlconfiguratie voor uw bundels bevatten.

({
    optimize: 'none',
    inlineText: true
})

Later wijzigen we de instelling optimize: van_ none in uglify2 om de uitvoer van de bundel te minimaliseren. Maar voor nu, tijdens de ontwikkeling, kunt u het plaatsen aan none verlaten om snellere bouwstijlen te verzekeren.

2. Vereiste JS-afhankelijkheden, vormen, paden en kaarten toevoegen

Voeg de volgende RequireJS knopen van de bouwstijlconfiguratie, deps, shim, paths, en map, aan uw bouwstijldossier toe:

({
    optimize: 'none',
    inlineText: true,

    deps: [],
    shim: {},
    paths: {},
    map: { "*": {} },
})

3 De eisen-config.js-instantiewaarden samenvoegen

In deze stap moet u alle meerdere deps -, shim -, paths - en map configuratieknooppunten uit het requirejs-config.js -bestand van uw winkel samenvoegen tot de corresponderende knooppunten in uw build.js -bestand. Hiertoe opent u het tabblad Network in het deelvenster Gereedschappen voor ontwikkelaars van uw browser en navigeert u naar elke pagina in uw winkel, zoals de startpagina. Op het tabblad Netwerk ziet u de instantie van het requirejs-config.js -bestand van uw winkel bovenaan, die hier wordt gemarkeerd:

RequireJS configuratie

In dit bestand vindt u meerdere items voor elk van de configuratieknooppunten (deps , shim , paths , map ). U moet deze veelvoudige knoopwaarden in de enige configuratieknooppunt van uw build.js- dossier samenvoegen. Als de requirejs-config.js -instantie van uw winkel bijvoorbeeld items bevat voor 15 aparte map knooppunten, moet u de items voor alle 15 knooppunten samenvoegen tot één map -knooppunt in uw build.js -bestand. Hetzelfde geldt voor de knooppunten deps , shim en paths . Zonder een script om dit proces te automatiseren kan het enige tijd duren.

U moet het pad mage/requirejs/text als volgt wijzigen in requirejs/text in paths -configuratienode:

({
    //...
    paths: {
        //...
        "text": "requirejs/text"
    },
})

4. Een moduleknooppunt toevoegen

Aan het eind van het build.js dossier, voeg de modules [] serie als placeholder voor de bundels toe u voor uw storefront later zult bepalen.

({
    optimize: 'none',
    inlineText: true,

    deps: [],
    shim: {},
    paths: {},
    map: { "*": {} },

    modules: [],
})

5 RequireJS-afhankelijkheden ophalen

U kunt alle RequireJS module gebiedsdelen van de de paginatypen van uw opslag terugwinnen door te gebruiken:

  1. PhantomJS via de opdrachtregel (ervan uitgaande dat u PhantomJS hebt geïnstalleerd).
  2. Vereisen JS bevel in de console van uw browser.

Als u PhantomJS wilt gebruiken:

Maak in de hoofdmap van Commerce een nieuw bestand met de naam deps.js en kopieer het bestand in de onderstaande code. Deze code gebruikt PhantomJS om een pagina te openen en te wachten totdat de browser alle pagina-elementen laadt. Vervolgens worden alle RequireJS -afhankelijkheden voor een bepaalde pagina uitgevoerd.

"use strict";
var page = require('webpage').create(),
    system = require('system'),
    address;

if (system.args.length === 1) {
    console.log('Usage: $phantomjs deps.js url');
    phantom.exit(1);
} else {
    address = system.args[1];
    page.open(address, function (status) {
        if (status !== 'success') {
            console.log('FAIL to load the address');
        } else {
            setTimeout(function () {
                console.log(page.evaluate(function () {
                    return Object.keys(window.require.s.contexts._.defined);
                }));
                phantom.exit();
            }, 5000);
        }
    });
}

Open een terminal in de hoofdmap van Commerce en voer het script uit op elke pagina in uw winkel die een specifiek paginatype vertegenwoordigt:

phantomjs deps.js  url-aan-specifiek-pagina  >  tekst-dossier-vertegenwoordigen-pagina-gebiedsdelen 

Hier ziet u bijvoorbeeld vier pagina's uit de voorbeeldwinkel met het thema Luma die de vier paginatypen vertegenwoordigen die we gebruiken om onze vier pakketten te maken (homepage, categorie, product, winkelwagen):

phantomjs deps.js http://m2.loc/ > bundle/homepage.txt
phantomjs deps.js http://m2.loc/women/tops-women/jackets-women.html > bundle/category.txt
phantomjs deps.js http://m2.loc/beaumont-summit-kit.html > bundle/product.txt
phantomjs deps.js http://m2.loc/checkout/cart/?SID=m2tjdt7ipvep9g0h8pmsgie975 > bundle/cart.txt (prepare a shopping cart)
..............

De browserconsole gebruiken:

Als u PhantomJS niet wilt gebruiken, kunt u het volgende bevel van de console van uw browser in werking stellen terwijl het bekijken van elk paginatype in uw winkel:

Object.keys(window.require.s.contexts._.defined)

Met deze opdracht (gebruikt in het script PhantomJS ) wordt dezelfde lijst met RequireJS -afhankelijkheden gemaakt en weergegeven binnen de browserconsole. Het nadeel van deze benadering is dat u uw eigen bundel-/paginatype tekstbestanden moet maken.

6 De uitvoer opmaken en filteren

Nadat u de RequireJS gebiedsdelen in paginatype tekstdossiers samenvoegt, kunt u het volgende bevel op elk pagina-type gebiedsdeeldossier gebruiken om de komma's in uw dossiers met nieuwe lijnen te vervangen:

sed -i -e $'s/,/\\\n/g' bundle/category.txt
sed -i -e $'s/,/\\\n/g' bundle/homepage.txt
sed -i -e $'s/,/\\\n/g' bundle/product.txt
....

U zou ook alle menins voor elk dossier moeten verwijderen omdat de dubbele gebiedsdelen mengt. Gebruik het volgende bevel op elk gebiedsdeeldossier:

sed -i -e 's/mixins\!.*$//g' bundle/homepage.txt
sed -i -e 's/mixins\!.*$//g' bundle/category.txt
sed -i -e 's/mixins\!.*$//g' bundle/product.txt
...

7\ Unieke en algemene bundels identificeren

Het doel is om een gemeenschappelijke bundel JavaScript dossiers tot stand te brengen nodig door alle pagina's. Op die manier hoeft de browser alleen de algemene bundel te laden samen met een of meer specifieke paginatypen.

Open een terminal in de hoofdmap van Commerce en gebruik de volgende opdracht om te controleren of u afhankelijkheden hebt die u in afzonderlijke bundels kunt splitsen:

sort bundle/*.txt |uniq -c |sort -n

Met deze opdracht voegt u de afhankelijkheden die in de bundle/*.txt -bestanden zijn gevonden samen en sorteert u deze. De output toont ook het aantal dossiers die elk gebiedsdeel bevatten:

1 buildTools,
1 jquery/jquery.parsequery,
1 jsbuild,
2 jquery/jquery.metadata,
2 jquery/validate,
2 mage/bootstrap,
3 jquery
3 jquery/ui
3 knockoutjs/knockout
...

Deze uitvoer toont aan dat buildTools afhankelijk is van een bundel/*.txt-bestand. De jquery/jquery.metadata -afhankelijkheid is in twee (2) bestanden en es6-collections is in drie (3) bestanden.

Onze uitvoer toont slechts drie paginatypen (homepage, categorie en product), wat ons het volgende vertelt:

  • Drie gebiedsdelen zijn uniek aan slechts één paginatype (aangetoond door aantal 1).
  • Drie meer gebiedsdelen komen op twee paginatypen voor (die door aantal 2 worden getoond).
  • De laatste drie gebiedsdelen zijn gemeenschappelijk voor alle drie van onze paginatypen (die door aantal 3 worden getoond).

Dit vertelt ons dat wij de pagina-ladingssnelheden van onze opslag waarschijnlijk kunnen verbeteren door onze gebiedsdelen in verschillende bundel te verdelen, zodra wij weten welke paginatypes vereisen welke gebiedsdelen.

8. Een bestand voor afhankelijkheidsverdeling maken

Als u wilt weten welke paginatypen welke afhankelijkheden nodig hebben, maakt u een nieuw bestand in de hoofdmap van Commerce met de naam deps-map.sh en kopieert u dit bestand in de onderstaande code:

awk 'END {
 for (R in rec) {
   n = split(rec[R], t, "/")
   if (n > 1)
     dup[n] = dup[n] ? dup[n] RS sprintf("\t%-20s -->\t%s", rec[R], R) : \
       sprintf("\t%-20s -->\t%s", rec[R], R)
   }
 for (D in dup) {
   printf "records found in %d files:\n\n", D
   printf "%s\n\n", dup[D]
   }
 }
{
 rec[$0] = rec[$0] ? rec[$0] "/" FILENAME : FILENAME
}' bundle/*.txt

U kunt het manuscript in https://www.unix.com/shell-programming-and-scripting/140390-get-common-lines-multiple-files.htmlook vinden

Open een terminal in de hoofdmap van Commerce en voer het bestand uit:

bash deps-map.sh

De uitvoer van dit script, dat wordt toegepast op onze drie voorbeeldpaginatypen, moet er ongeveer als volgt uitzien (maar veel langer):

bundle/product.txt   -->   buildTools,
bundle/category.txt  -->   jquery/jquery.parsequery,
bundle/product.txt   -->   jsbuild,

bundle/category.txt/bundle/homepage.txt -->    jquery/jquery.metadata,
bundle/category.txt/bundle/homepage.txt -->    jquery/validate,
bundle/category.txt/bundle/homepage.txt -->    mage/bootstrap,

bundle/category.txt/bundle/homepage.txt/bundle/product.txt --> jquery,
bundle/category.txt/bundle/homepage.txt/bundle/product.txt --> jquery/ui,
bundle/category.txt/bundle/homepage.txt/bundle/product.txt --> knockoutjs/knockout,

Dit is genoeg informatie om een bundelconfiguratie te bouwen.

9. Maak pakketten in het bestand build.js

Open het configuratiebestand van build.js en voeg uw bundels toe aan het knooppunt modules . Elke bundel moet de volgende eigenschappen definiëren:

  • name— de naam van de bundel. Met de naam bundles/cart wordt bijvoorbeeld een cart.js bundel in een submap bundles gegenereerd.

  • create— een Booleaanse markering om de bundel te maken (waarden: true of false).

  • include— een array met elementen (tekenreeksen) die zijn opgenomen als afhankelijkheden voor de pagina. RequireJS traceert alle gebiedsdelen en omvat hen in de bundel tenzij uitgesloten.

  • exclude— een array van bundels of elementen die van de bundel moeten worden uitgesloten.

{
    name: 'bundles/catalog',
    create: true,
    include: [
        'addToWishlist',
        'priceBundle',
        'priceUtils',
        'priceOptions',
        'sticky',
        'productSummary',
        'slide'
    ],
    exclude: [
        'requirejs/require',
        'bundles/default',
        'mage/bootstrap'
    ],
}

In dit voorbeeld worden elementen mage/bootstrap en requirejs/require opnieuw gebruikt, waarbij een hogere prioriteit wordt ingesteld op de belangrijkste componenten en componenten die synchroon moeten worden geladen. De aanwezige bundels zijn:

  • requirejs/require - de enige synchroon geladen bundel
  • mage/bootstrap - de laarzentrekkerbundel met UI-componenten
  • bundles/default—standaardbundel vereist voor alle pagina's
  • bundles/cart - een bundel die is vereist voor de basispagina
  • bundles/shipping - gebruikelijke bundel voor winkelwagentje en afhandelingspagina (ervan uitgaande dat uitchecken nooit rechtstreeks wordt geopend, wordt de afhandelingspagina nog sneller geladen als de winkelpagina eerder is geopend en de verzendbundel al is geladen)
  • bundles/checkout - alles voor uitchecken
  • bundles/catalog - alles voor product- en categoriepagina's

Deel 2: Bundels genereren

De onderstaande stappen beschrijven het basisproces voor het genereren van efficiëntere Commerce -bundels. U kunt dit proces op elke gewenste manier automatiseren, maar u moet toch nodejs en r.js gebruiken om daadwerkelijk uw bundels te genereren. En als uw thema's zijn aangepast aan JavaScript en hetzelfde build.js -bestand niet opnieuw kunnen gebruiken, moet u mogelijk verschillende build.js configuraties per thema maken.

1. Genereer statische winkelsites

Voordat u bundels genereert, voert u de statische implementatieopdracht uit:

php -f bin/magento setup:static-content:deploy -f -a frontend

Dit bevel produceert statische opslagplaatsingen voor elk thema en elke scène u opstelling hebt. Als u bijvoorbeeld het thema Luma en een aangepast thema met landinstellingen in het Engels en Frans gebruikt, genereert u vier statische implementaties:

  • …luma/nl_NL
  • …luma/fr_FR
  • …custom/nl_NL
  • …custom/fr_FR

Herhaal de onderstaande stappen voor elk winkelthema en elke landinstelling om bundels voor alle winkelthema's en -landinstellingen te genereren.

2. Verplaats de statische opslaginhoud naar een tijdelijke map

Eerst, moet u de statische inhoud van de doelfolder naar één of andere tijdelijke folder verplaatsen omdat RequireJS alle inhoud binnen de doelfolder vervangt.

mv pub/static/frontend/Magento/{theme}/{locale} pub/static/frontend/Magento/{theme}/{locale}_tmp

Bijvoorbeeld:

mv pub/static/frontend/Magento/luma/en_US pub/static/frontend/Magento/luma/en_US_tmp

3. Voer de optimalisatiefunctie voor r.js uit

Voer vervolgens de optimalisator voor r.js uit op het build.js -bestand vanuit de hoofdmap van Commerce . Paden naar alle mappen en bestanden zijn relatief ten opzichte van de werkmap.

r.js -o build.js baseUrl=pub/static/frontend/Magento/luma/en_US_tmp dir=pub/static/frontend/Magento/luma/en_US

Deze opdracht genereert bundels in een submap bundles van de doelmap, wat in dit geval resulteert in pub/static/frontend/Magento/luma/en_US/bundles .

De inhoud van de nieuwe bundelmap weergeven kan er als volgt uitzien:

ll pub/static/frontend/Magento/luma/en_US/bundles
total 1900
drwxr-xr-x  2 root root    4096 Mar 28 11:24 ./
drwxr-xr-x 70 root root    4096 Mar 28 11:24 ../
-rw-r--r--  1 root root  116417 Mar 28 11:24 cart.js
-rw-r--r--  1 root root  187090 Mar 28 11:24 catalog.js
-rw-r--r--  1 root root  307619 Mar 28 11:24 checkout.js
-rw-r--r--  1 root root 1240608 Mar 28 11:24 default.js
-rw-r--r--  1 root root   74233 Mar 28 11:24 shipping.js

4. Configureer RequireJS om bundels te gebruiken

Om RequireJS te krijgen om uw bundels te gebruiken, voeg een onModuleBundleComplete callback na de modules knoop in het build.js dossier toe:

[
    {
       //...
       exclude: [
           'requirejs/require',
           'bundles/default',
           'bundles/checkout',
           'bundles/cart',
           'bundles/shipping',
           'mage/bootstrap'
       ],
   },
],
bundlesConfigOutFile: `${config.dir}/requirejs-config.js`,
onModuleBundleComplete: function(data) {
    if (this.bundleConfigAppended) {
        return;
    }
    this.bundleConfigAppended = true;

    // bundlesConfigOutFile requires a simple require.config call in order to modify the configuration
    const bundleConfigPlaceholder = `
(function (require) {
require.config({});
})(require);
    `;

    fs.appendFileSync(this.bundlesConfigOutFile, bundleConfigPlaceholder);
}

5. Voer de opdracht opnieuw uit

Voer de volgende opdracht uit om te implementeren:

r.js -o app/design/frontend/Magento/luma/build.js baseUrl=pub/static/frontend/Magento/luma/en_US_tmp dir=pub/static/frontend/Magento/luma/en_US

Open requirejs-config.js in de pub/static/frontend/Magento/luma/en_US folder om te verifiëren dat RequireJS het dossier met bundelconfiguratievraag toevoegde:

require.config({
    bundles: {
        "bundles/default": ["mage/template", "mage/apply/scripts", "mage/apply/main", "mage/mage", "mage/translate", "mage/loader"],
        "bundles/cart": ["Magento_Ui/js/lib/validation/utils", "Magento_Ui/js/lib/validation/rules", "Magento_Ui/js/lib/validation/validation"]
    }
}
NOTE
Wanneer het vormen van bundels, zorg ervoor u requirejs.config() vraag in de orde plaatst u hen uitgevoerd wilt, aangezien de vraag in de orde wordt uitgevoerd zij verschijnen.

6. Test de resultaten

Nadat de pagina is geladen, ziet u dat de browser verschillende afhankelijkheden en bundels laadt. Hier volgen bijvoorbeeld de resultaten voor het profiel 'Langzaam 3G':

tweemaal zo snel

De laadtijd van de pagina voor een lege startpagina is nu twee keer zo snel als het gebruik van native Commerce -pakketten. Maar we kunnen nog beter.

7. De bundels optimaliseren

Zelfs als deze worden gecomprimeerd, zijn de JavaScript -bestanden nog steeds groot. U kunt ze miniateren met RequireJS, dat versterker gebruikt om JavaScript tot een goed resultaat te beperken.

Als u de optimalisator in uw build.js -bestand wilt inschakelen, voegt u uglify2 toe als waarde voor de eigenschap optimize boven aan het build.js -bestand:

({
    optimize: 'uglify2',
    inlineText: true
})

De resultaten kunnen significant zijn:
drie keer sneller

De laadtijden zijn nu drie keer sneller dan bij native Commerce -bundeling.

recommendation-more-help
c0c5bbed-4957-4162-81bc-120c837a1894