web-dev-qa-db-fra.com

Webpack avec petit script initial et chargement asynchrone de tous les autres scripts

J'ai commencé à utiliser Webpack lors du développement de sites Web usuels composés de plusieurs pages et de différents types de pages. Je suis habitué au chargeur de script RequireJs qui charge toutes les dépendances à la demande en cas de besoin. Juste un petit morceau de javascript est téléchargé lors du chargement de la page.

Ce que je veux réaliser est la suivante:

  • Un petit fichier javascript initial qui charge des dépendances asynchrones
  • Chaque type de page peut avoir son propre javascript, qui peut aussi avoir des dépendances.
  • Les modules communs, les scripts du fournisseur doivent être regroupés dans des scripts communs

J'ai essayé de nombreuses configurations pour y parvenir mais sans succès.

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')
]

Dans le code HTML, je veux charger les javascripts comme ceci:

<script src="/Static/js/dist/common.js"></script>
<script src="/Static/js/dist/main.js" async></script>

Et sur un type de page spécifique (page de démarrage)

<script src="/Static/js/dist/start-page.js" async></script>

common.js devrait être un fichier minuscule pour un chargement rapide de la page. main.js se charge async et nécessite ('jquery') à l'intérieur.

La sortie de Webpack semble prometteuse, mais je ne parviens pas à charger le paquet des fournisseurs de manière asynchrone. D'autres dépendances (mes propres modules et domReady) sont chargées dans les morceaux générés automatiquement, mais pas jquery.

Je peux trouver beaucoup d'exemples qui font presque cela, mais pas la partie importante du chargement des fournisseurs de manière asynchrone.

Sortie de la construction du webpack:

                  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

Voici la solution que j'ai trouvée.

Commencez par exporter ces deux fonctions vers window.* - vous les voudrez dans le navigateur.

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

Ensuite, lorsque vous souhaitez inclure l'un de vos scripts sur une page, ajoutez-le simplement à votre code HTML:

<script>requireAsync('script_name.js')</script>

Désormais, tout le contenu du répertoire pages/ sera précompilé dans un bloc distinct pouvant être chargé de manière asynchrone au moment de l'exécution, uniquement lorsque cela est nécessaire.

De plus, en utilisant les fonctions ci-dessus, vous disposez désormais d'un moyen pratique de transférer des données côté serveur dans vos scripts côté client:

<script>runAsync('script_that_needs_data', {my:'data',wow:'much excite'})</script>

Et maintenant vous pouvez y accéder:

// script_that_needs_data.js
export default function({my,wow}) {
    console.log(my,wow);
}
1
mpen