web-dev-qa-db-fra.com

Comment configurer le webpack 4 pour éviter que des morceaux de la liste des points d'entrée n'apparaissent dans un autre bundle?

Je travaille sur un grand projet et j'essaye de faire atterrir le webpack 3 -> 4 update. Cette application a environ 1 000 points d'entrée, et environ 10 d'entre eux sont considérés comme "mondiaux" ou "de base" et garantis sur chaque page. Ces bundles principaux contiennent un mélange de code fournisseur et non fournisseur. J'ai besoin de configurer le webpack pour créer tous ces actifs afin que les morceaux apparaissant dans l'un de ces bundles n'apparaissent dans aucun autre bundle quelle que soit la taille du morceau, sans créer de nouveaux actifs qui doivent être ajoutés à la page.

Avec webpack 3, nous avons utilisé CommonsChunkPlugin pour y parvenir. Voici un exemple simple:

new webpack.optimize.CommonsChunkPlugin({
  name: 'a-global-bundle',
  minChunks: Infinity,
}),

Maintenant, avec webpack 4 et la suppression de CommonsChunkPlugin, je ne sais pas comment accomplir ce type d'optimisation.

J'aimerais pouvoir donner à webpack une liste de points d'entrée et tous les morceaux qui apparaissent dans l'un de ceux-ci n'apparaîtront dans aucun autre bundle, mais je ne sais pas comment faire. J'ai lu ne documentation à venir sur splitChunks mais je n'ai pas pu reconstituer une solution.

J'ai mis en place un petit repo comme point de départ pour bricoler avec: https://github.com/lencioni/webpack-splitchunks-playground

Une direction intéressante que j'essaie est de configurer cacheGroups avec un groupe pour chacun de ces points d'entrée et d'implémenter l'option test avec une fonction qui effectue cette vérification. Cependant, la documentation est assez clairsemée à ce sujet, donc je ne suis pas vraiment sûr de la bonne façon d'écrire cette fonction de test ou même si cela fonctionnera du tout.

26
Joe Lencioni

Ok, donc je pense que j'ai compris comment faire ça. Mais d'abord, voici à quoi ressemble la construction avec la configuration par défaut de SplitChunks (notez que FOO.bundle.js est un bundle asynchrone créé par une importation dynamique):

            Asset       Size  Chunks                    Chunk Names
   core.bundle.js    605 KiB       0  [emitted]  [big]  core
  coreB.bundle.js    791 KiB       1  [emitted]  [big]  coreB
  coreC.bundle.js    791 KiB       2  [emitted]  [big]  coreC
      a.bundle.js    748 KiB       3  [emitted]  [big]  a
      b.bundle.js    792 KiB       4  [emitted]  [big]  b
      c.bundle.js    674 KiB       5  [emitted]  [big]  c
    FOO.bundle.js  709 bytes       6  [emitted]         FOO
runtime.bundle.js   7.49 KiB       7  [emitted]         runtime

Si l'objectif est de faire en sorte que les modules apparaissant dans core, coreB et coreC n'apparaissent dans aucun autre bundle, cela peut être fait avec la configuration suivante:

function coreBundleCacheGroups(coreBundles) {
  const cacheGroups = {};
  const coreChunkNames = Object.keys(coreBundles);
  const coreChunkNamesSet = new Set(coreChunkNames);


  coreChunkNames.forEach((name) => {
    cacheGroups[name] = {
      name,
      chunks: 'all',
      minSize: 0,
      minChunks: 1,
      reuseExistingChunk: true,
      priority: 10000,
      enforce: true,
      test(module, chunks) {
        if (module.depth === 0) {
          return false;
        }

        // Find first core chunk name that matches
        const partOfGlobalChunks = chunks.filter(chunk => coreChunkNamesSet.has(chunk.name));

        if (!partOfGlobalChunks.length) {
          return false;
        }

        const partOfGlobalChunksSet = new Set(partOfGlobalChunks.map(chunk => chunk.name));
        const firstCoreChunkName = coreChunkNames.find(name => partOfGlobalChunksSet.has(name));
        return firstCoreChunkName === name;
      },
    };
  });

  return cacheGroups;
}

const coreBundles = {
  core: './src/bundles/core.js',
  coreB: './src/bundles/core-b.js',
  coreC: './src/bundles/core-c.js',
};

module.exports = {
  mode: 'none',

  entry: {
    ...coreBundles,
    a: './src/bundles/a.js',
    b: './src/bundles/b.js',
    c: './src/bundles/c.js',
  },

  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },

  optimization: {
    runtimeChunk: 'single',

    splitChunks: {
      cacheGroups: {
        ...coreBundleCacheGroups(coreBundles),
      },
    },
  },
};

qui produit la sortie suivante:

            Asset       Size  Chunks                    Chunk Names
   core.bundle.js    605 KiB       0  [emitted]  [big]  core
  coreB.bundle.js    188 KiB       1  [emitted]         coreB
  coreC.bundle.js    1.5 KiB       2  [emitted]         coreC
      a.bundle.js   76.4 KiB       3  [emitted]         a
      b.bundle.js   2.28 KiB       4  [emitted]         b
      c.bundle.js   1.91 KiB       5  [emitted]         c
    FOO.bundle.js  622 bytes       6  [emitted]         FOO
runtime.bundle.js   7.49 KiB       7  [emitted]         runtime
11
Joe Lencioni

Votre configuration actuelle (en utilisant Webpack 3) utilise CommonsChunkPlugin pour un bloc de fournisseur explicite :

Divisez votre code en fournisseur et application.

Vérification de la sortie Webpack pour votre repo J'ai trouvé que a.bundle.js Contient le code suivant:

// `react`, `react-dom` plus
console.log('core module');     // from core-module.js
console.log('core module b');   // from core-module-b.js
console.log('non-core module'); // from non-core-module.js

Un code similaire se trouve dans b.bundle.js (La différence dans ce script est le dernier console.log Qui est référencé à partir de non-core-module-b.js: console.log('non-core module b');).

Mise à jour de l'option d'optimisation webpack.config.js Pour:

optimization: {
    runtimeChunk: 'single',

    splitChunks: {
        chunks: 'all',

        cacheGroups: {
            default: {
                enforce: true,
                priority: 1
            },
            vendors: {
                test: /[\\/]node_modules[\\/]/,
                priority: 2,
                name: 'vendors',
                enforce: true,
                chunks: 'all'
            }
        }
    }
}

Produisez un code de non duplication entre les bundles.


Vous pouvez vérifier le code de travail ici . J'ai également créé un pull request à votre exemple de projet.

Plus d'informations sur fractionnement de code et optimisation de splitChunks

3
Carloluis

Notre objectif est de configurer le webpack pour créer nos ressources afin que les morceaux qui apparaissent dans l'un de ces bundles n'apparaissent dans aucun autre bundle.

Ce que j'avais avant:

            new webpack.optimize.CommonsChunkPlugin({
                name: 'vendor',
                minChunks: function (module, count) {
                    // this assumes your vendor imports exist in the node_modules directory and module should be required
                    // in at least 3 entries before it moved to common chunk
                    return (module.context && module.context.indexOf('node_modules') !== -1) && count > 2;
                }
            }),

Comment ça marche maintenant:

        optimization: {
            splitChunks: {
                cacheGroups: {
                    vendor: {
                        test: /[\\/]node_modules[\\/]/,
                        chunks: 'all',
                        name: 'vendor',
                        enforce: true,
                        minChunks: 3
                    }
                }
            }
        },
1
MyTitle