75 votes

Webpack 4 - créer un chunk vendeur

Dans une configuration webpack 3, j'utiliserais le code ci-dessous pour créer des fichiers vendor.js chunk :

entry: {
    client: ['./client.js'],
    vendor: ['babel-polyfill', 'react', 'react-dom', 'redux'],
},

output: {
  filename: '[name].[chunkhash].bundle.js',
  path: '../dist',
  chunkFilename: '[name].[chunkhash].bundle.js',
  publicPath: '/',
},

plugins: [
    new webpack.HashedModuleIdsPlugin(),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'runtime',
    }),
],

Avec tous les changements, je ne suis pas sûr de pouvoir le faire avec Webpack 4. Je sais que CommonChunksPlugin a été supprimé, il y a donc une autre façon d'y parvenir. J'ai également lu ce tutoriel mais je ne suis toujours pas sûr de l'extraction du chunk de l'exécution et de la définition appropriée output propriété.

EDIT : Malheureusement, j'ai eu des problèmes avec la réponse la plus populaire ici. Vérifiez ma réponse .

70voto

swap0129 Points 384

Afin de réduire la taille du paquet de js du fournisseur. Nous pouvons diviser les paquets du module node en différents fichiers bundle. Je me suis référé à ce blog pour diviser le volumineux fichier vendeur généré par webpack. Gist de ce lien que j'ai utilisé initialement :

optimization: {
  runtimeChunk: 'single',
  splitChunks: {
    chunks: 'all',
    maxInitialRequests: Infinity,
    minSize: 0,
    cacheGroups: {
      vendor: {
        test: /[\\/]node_modules[\\/]/,
        name(module) {
          // get the name. E.g. node_modules/packageName/not/this/part.js
          // or node_modules/packageName
          const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];

          // npm package names are URL-safe, but some servers don't like @ symbols
          return `npm.${packageName.replace('@', '')}`;
        },
      },
    },
  },
}

Si l'on veut regrouper plusieurs paquets et les répartir en différents paquets, il faut se référer à la liste suivante.

optimization: {
  runtimeChunk: 'single',
  splitChunks: {
    chunks: 'all',
    maxInitialRequests: Infinity,
    minSize: 0,
    cacheGroups: {
      reactVendor: {
        test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
        name: "reactvendor"
      },
      utilityVendor: {
        test: /[\\/]node_modules[\\/](lodash|moment|moment-timezone)[\\/]/,
        name: "utilityVendor"
      },
      bootstrapVendor: {
        test: /[\\/]node_modules[\\/](react-bootstrap)[\\/]/,
        name: "bootstrapVendor"
      },
      vendor: {
        test: /[\\/]node_modules[\\/](!react-bootstrap)(!lodash)(!moment)(!moment-timezone)[\\/]/,
        name: "vendor"
      },
    },
  },
}

4 votes

Merci @swapnil2993. C'est ce que je cherchais depuis 4 heures.

4 votes

Pourquoi n'excluez-vous pas react et react-dom de votre liste de fournisseurs ?

1 votes

Merci, très utile pour analyser la couverture du code dans une application en cours !

27voto

glued Points 1550

Vous trouverez quelques exemples ici : https://github.com/webpack/webpack/tree/master/examples

Sur la base de votre exemple, je crois que cela se traduit par :

// mode: "development || "production",
entry: {
  client: './client.js',
},
output: {
  path: path.join(__dirname, '../dist'),
  filename: '[name].chunkhash.bundle.js',
  chunkFilename: '[name].chunkhash.bundle.js',
  publicPath: '/',
},
optimization: {
  splitChunks: {
    cacheGroups: {
      vendor: {
        chunks: 'initial',
        name: 'vendor',
        test: 'vendor',
        enforce: true
      },
    }
  },
  runtimeChunk: true
}

2 votes

Ça me donne des résultats bizarres. client.js ne se réduit pas et vendor.js est presque aussi grande que client.js contenant des paquets importés dynamiquement.

2 votes

Intéressant cependant, maintenant la taille des morceaux est plus grande, ce qui me fait me demander si cela en valait la peine.

1 votes

@TomaszMularczyk Je pense que le point est que le code du fournisseur est rarement modifié et est mis en cache alors que votre logique obtient un nouveau hachage de chunk à chaque fois qu'elle est modifiée. Idéalement, l'utilisateur ne télécharge que la partie logique du code lorsqu'il visite le site.

26voto

Carloluis Points 2722

Afin de séparer les vendeurs et le temps de fonctionnement vous devez utiliser le optimization option.

Configuration possible de Webpack 4 :

// mode: 'development' | 'production' | 'none'

entry: {
    client: ['./client.js'],
    vendor: ['babel-polyfill', 'react', 'react-dom', 'redux'],
},

output: {
    filename: '[name].[chunkhash].bundle.js',
    path: '../dist',
    chunkFilename: '[name].[chunkhash].bundle.js',
    publicPath: '/',
},

optimization: {
    runtimeChunk: 'single',
    splitChunks: {
        cacheGroups: {
            vendor: {
                test: /[\\/]node_modules[\\/]/,
                name: 'vendors',
                enforce: true,
                chunks: 'all'
            }
        }
    }
}

Vous trouverez plus d'informations sur le W4 dans ce document. Webpack-Demo .

Vous pouvez également obtenir le même résultat en changeant le optimization.splitChunks.chunks à la propriété "all" . Lire la suite ici

Note : Vous pouvez le configurer via optimization.splitChunks . Les exemples parlent de chunks, par défaut cela ne fonctionne que pour les chunks asynchrones, mais avec optimization.splitChunks.chunks: "all" il en serait de même pour les morceaux initiaux.

2 votes

Pouvez-vous me dire ce que signifie "initial" ici ?

0 votes

Comment faire pour que le cacheGroup des vendeurs soit compilé avec Babel ? @Carloluis

0 votes

Merci les gars....

25voto

jhamPac Points 1460

Vous pourriez supprimer le vendeur de la propriété d'entrée et définir la propriété d'optimisation comme suit...

entry: {
 client: './client.js'
},

output: {
 path: path.join(__dirname, '../dist'),
 filename: '[name].chunkhash.bundle.js',
 chunkFilename: '[name].chunkhash.bundle.js',
 publicPath: '/',
},

optimization: {
  splitChunks: {
   cacheGroups: {
    vendor: {
     test: /node_modules/,
     chunks: 'initial',
     name: 'vendor',
     enforce: true
    },
   }
  } 
 }

Vérifiez cette source exemples de webpack

6 votes

Mais, comment puis-je spécifier les paquets que je veux dans un paquet de fournisseurs ?

1 votes

@Tomasz webpack vérifiera quels paquets vous utilisez dans votre projet via vos déclarations d'importation, puis il les répartira automatiquement entre les fournisseurs.

10 votes

Cela fonctionne ! Cependant... il regroupe chaque paquet de node_modules ce qui n'est pas idéal. 1. le paquet du vendeur devient grand. 2. si vous mettez à jour ne serait-ce qu'un seul petit paquet, l'ensemble du paquet obtiendra un hachage différent lors de la prochaine construction - ce qui va à l'encontre de l'idée d'avoir un chunk fournisseur pour la mise en cache à long terme.

16voto

Tomasz Mularczyk Points 12030

Après un certain temps, j'ai découvert que cette configuration :

entry: {
  vendor: ['@babel/polyfill', 'react', 'react-dom', 'redux'],
  client: './client.js',
},
optimization: {
  splitChunks: {
    cacheGroups: {
      vendor: {
        chunks: 'initial',
        name: 'vendor',
        test: 'vendor',
        enforce: true
      },
    }
  },
  runtimeChunk: true
}

n'arrivait pas à charger @babel/polyfill qui provoquait des erreurs d'incompatibilité de navigateur... Récemment, j'ai donc levé les yeux vers le mise à jour de la documentation de webpack et a trouvé un moyen pour créer un morceau de vendeur explicite qui chargeait correctement @babel/polyfill :

const moduleList = ["@babel/polyfill", "react", "react-dom"];
...

  entry: {
    client: ["@babel/polyfill", "../src/client.js"]
  }
  optimization: {
    runtimeChunk: "single",
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: new RegExp(
            `[\\/]node_modules[\\/](${moduleList.join("|")})[\\/]`
          ),
          chunks: "initial",
          name: "vendors",
          enforce: true
        }
      }
    }
  }

Remarquez que je crée un entrée avec tous du code inclus et puis Je précise avec splitChunks.cacheGroups.vendor.test quels modules doivent être répartis entre les vendeur chunk.

Cependant, je ne suis pas sûr que ce soit 100% correct ou que cela puisse être amélioré car c'est littéralement l'une des choses les plus confuses qui soient. Cependant, cette méthode semble être la plus proche de la documentation et semble produire des morceaux corrects lorsque je les inspecte avec la commande webpack-bundle-analyzer (ne met à jour que les morceaux qui ont été modifiés et le reste reste reste le même d'une version à l'autre) et corrige le problème avec le fichier polyfill .

32 votes

"c'est littéralement l'une des choses les plus confuses qui soient" webpack en général

4 votes

Je comprends que webpack est conçu pour être très flexible et configurable, donc cela le rend plus complexe à configurer... mais la construction d'un bundle d'applications/vendeur semble être une exigence assez basique/standard. C'est fou qu'il n'y ait pas de description claire sur la façon de réaliser ceci :(

0 votes

Je ne trouve pas ça déroutant du tout. Je vois une solution lisible, logique et appropriée ici. (Mais bien sûr... je suis déjà habitué à la "folie" de webpack :D)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X