web-dev-qa-db-fra.com

Comment regrouper les scripts du fournisseur séparément et en avoir besoin au besoin avec Webpack?

J'essaie de faire quelque chose qui, à mon avis, devrait être possible, mais je ne comprends vraiment pas comment le faire à partir de la documentation de Webpack.

J'écris une bibliothèque JavaScript avec plusieurs modules qui peuvent ou non dépendre les uns des autres. En plus de cela, jQuery est utilisé par tous les modules et certains d'entre eux peuvent nécessiter des plugins jQuery. Cette bibliothèque sera ensuite utilisée sur plusieurs sites Web différents pouvant nécessiter tout ou partie des modules.

Définir les dépendances entre mes modules était très facile, mais définir leurs dépendances tierces semble être plus difficile que prévu.

Ce que je voudrais réaliser: pour chaque application, je souhaite avoir deux fichiers bundle, l'un avec les dépendances tierces nécessaires et l'autre avec les modules nécessaires de ma bibliothèque.

Exemple: Imaginons que ma bibliothèque comporte les modules suivants:

  • a (requires: jquery, jquery.plugin1)
  • b (requires: jquery, a)
  • c (requires: jquery, jquery.ui, a, b)
  • d (requires: jquery, jquery.plugin2, a)

Et j'ai une application (voyez-la comme un fichier d'entrée unique) qui nécessite les modules a, b et c. Webpack pour ce cas devrait générer les fichiers suivants:

  • bundle du vendeur: avec jquery, jquery.plugin1 et jquery.ui;
  • ensemble de sites Web: avec les modules a, b et c;

En fin de compte, je préférerais que jQuery soit global, je n'ai donc pas besoin de l'exiger sur chaque fichier (je ne pourrais l'exiger que sur le fichier principal, par exemple). Et les plugins jQuery étendraient simplement le $ global au cas où ils seraient nécessaires (ce n'est pas un problème s'ils sont disponibles pour d'autres modules qui n'en ont pas besoin).

En supposant que cela soit possible, quel serait un exemple de fichier de configuration webpack pour ce cas? J'ai essayé plusieurs combinaisons de chargeurs, externes et plugins sur mon fichier de configuration, mais je ne comprends pas vraiment ce qu'ils font et lesquels dois-je utiliser. Je vous remercie!

165
Anakin

dans mon fichier webpack.config.js (version 1,2,3), j'ai

function isExternal(module) {
  var context = module.context;

  if (typeof context !== 'string') {
    return false;
  }

  return context.indexOf('node_modules') !== -1;
}

dans mon tableau de plugins

plugins: [
  new CommonsChunkPlugin({
    name: 'vendors',
    minChunks: function(module) {
      return isExternal(module);
    }
  }),
  // Other plugins
]

Maintenant, j’ai un fichier qui n’ajoute que des bibliothèques tierces à un seul fichier selon les besoins.

Si vous souhaitez obtenir plus de précision lorsque vous séparez vos fournisseurs et vos fichiers de points d’entrée:

plugins: [
  new CommonsChunkPlugin({
    name: 'common',
    minChunks: function(module, count) {
      return !isExternal(module) && count >= 2; // adjustable
    }
  }),
  new CommonsChunkPlugin({
    name: 'vendors',
    chunks: ['common'],
    // or if you have an key value object for your entries
    // chunks: Object.keys(entry).concat('common')
    minChunks: function(module) {
      return isExternal(module);
    }
  })
]

Notez que l'ordre des plugins est très important.

En outre, cela va changer dans la version 4. Quand c'est officiel, je mets à jour cette réponse.

Mise à jour: indexOf changement de recherche pour les utilisateurs de Windows

135
Rafael De Leon

Je ne suis pas sûr de bien comprendre votre problème, mais comme je l’ai eu récemment, j’essaierai de vous aider.

Offre groupée.

Vous devriez utiliser CommonsChunkPlugin pour cela. dans la configuration, vous spécifiez le nom du morceau (par exemple, vendor) et le nom du fichier qui sera généré (vendor.js).

new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js", Infinity),

Maintenant, partie importante, vous devez spécifier ce que signifie la bibliothèque vendor et vous le faites dans une section d’entrée. Un élément de plus dans la liste d’entrée avec le même nom que le nom du bloc nouvellement déclaré (c’est-à-dire "fournisseur" dans ce cas). La valeur de cette entrée doit être la liste de tous les modules que vous souhaitez déplacer dans le groupe vendor. dans votre cas, cela devrait ressembler à quelque chose comme:

entry: {
    app: 'entry.js',
    vendor: ['jquery', 'jquery.plugin1']
}

JQuery en tant que global

Avait le même problème et résolu avec ProvidePlugin . Ici, vous ne définissez pas un objet global, mais plutôt des raccourcis vers les modules. c'est-à-dire que vous pouvez le configurer comme ça:

new webpack.ProvidePlugin({
    $: "jquery"
})

Et maintenant, vous pouvez simplement utiliser $ n'importe où dans votre code - webpack le convertira automatiquement en

require('jquery')

J'espère que ça a aidé. vous pouvez aussi regarder mon fichier de configuration webpack qui est ici

J'adore Webpack, mais je conviens que la documentation n'est pas la plus agréable au monde ... mais bon ... les gens disaient la même chose à propos de Angular la documentation au début :)


Modifier:

Pour avoir des morceaux de fournisseur spécifiques à un point d’entrée, utilisez simplement CommonsChunkPlugins à plusieurs reprises:

new webpack.optimize.CommonsChunkPlugin("vendor-page1", "vendor-page1.js", Infinity),
new webpack.optimize.CommonsChunkPlugin("vendor-page2", "vendor-page2.js", Infinity),

puis déclarez différentes bibliothèques externes pour différents fichiers:

entry: {
    page1: ['entry.js'],
    page2: ['entry2.js'],
    "vendor-page1": [
        'lodash'
    ],
    "vendor-page2": [
        'jquery'
    ]
},

Si certaines bibliothèques se chevauchent (et pour la plupart d'entre elles) entre des points d'entrée, vous pouvez les extraire dans un fichier commun en utilisant le même plug-in, mais avec une configuration différente. Voir this exemple.

52
Michał Margiel

Si vous souhaitez regrouper automatiquement vos scripts séparément de ceux de l'éditeur:

var webpack = require('webpack'),
    pkg     = require('./package.json'),  //loads npm config file
    html    = require('html-webpack-plugin');

module.exports = {
  context : __dirname + '/app',
  entry   : {
    app     : __dirname + '/app/index.js',
    vendor  : Object.keys(pkg.dependencies) //get npm vendors deps from config
  },
  output  : {
    path      : __dirname + '/dist',
    filename  : 'app.min-[hash:6].js'
  },
  plugins: [
    //Finally add this line to bundle the vendor code separately
    new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.min-[hash:6].js'),
    new html({template : __dirname + '/app/index.html'})
  ]
};

Vous pouvez en savoir plus sur cette fonctionnalité dans documentation officielle .

41
Freezystem

De plus, je ne suis pas sûr de bien comprendre votre cas, mais voici l'extrait de configuration permettant de créer des fragments de fournisseur distincts pour chacun de vos lots:

entry: {
  bundle1: './build/bundles/bundle1.js',
  bundle2: './build/bundles/bundle2.js',
  'vendor-bundle1': [
    'react',
    'react-router'
  ],
  'vendor-bundle2': [
    'react',
    'react-router',
    'flummox',
    'immutable'
  ]
},

plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor-bundle1',
    chunks: ['bundle1'],
    filename: 'vendor-bundle1.js',
    minChunks: Infinity
  }),
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor-bundle2',
    chunks: ['bundle2'],
    filename: 'vendor-bundle2-whatever.js',
    minChunks: Infinity
  }),
]

Et un lien vers CommonsChunkPlugin docs: http://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin

12
Alex Fedoseev