Webpack 4 migration CommonsChunkPlugin

j'ai besoin d'aide pour migrer le code suivant de webpack 3 à 4.

new webpack.optimize.CommonsChunkPlugin({
    minChunks: module => module.context && module.context.indexOf("node_modules") !== -1,
    name: "vendor",
    chunks: ["main"]
})

j'ai deux fichiers d'entrée et je veux que seules les dépendances du premier soient incluses dans le morceau de fournisseur. Les dépendances de la seconde entrée devraient toutes rester dans son propre paquet.

23
demandé sur Legends 2018-02-27 23:47:25

3 réponses

depuis webpack v4, le CommonsChunkPlugin est déprécié.

nous avons déprécié et enlevé CommonsChunkPlugin, et avons remplacé avec un ensemble de valeurs par défaut et facilement substituables API appelée optimization.splitChunks .

webpack.optimize.CommonsChunkPlugin has been removed, 
please use config.optimization.splitChunks instead.

déprécié

Vous n'avez plus besoin de utilisez ces plugins:

DedupePlugin a également été supprimé dans v4

NoEmitOnErrorsPlugin - > optimisation.noEmitOnErrors (on par défaut en mode production)) ModuleConcatenationPlugin - > optimisation.concatenateModules (par défaut en mode prod) NamedModulesPlugin - > optimisation.namedModules (on par défaut en mode dev)


recommandations pour webpack 4

utiliser mini-css-extract-plugin au lieu de text-extract-plugin . Utilisez webpack-bundle-analyzer pour analyser votre sortie groupée de manière graphique.

les scripts D'entrée sont de véritables " Scripts D'Entrée "pour votre application, n'ajoutez pas explicitement de fichiers vendeur à entry: dans webpack.config.js . Les applications SPA ont une entrée et Multi-Page-applications comme classique ASP.NET MVC applications ont plusieurs points d'entrée. Webpack construira un graphique de dépendance à partir de vos scripts d'entrée et générera des paquets optimisés pour votre application.

si vous souhaitez migrer à partir d'une ancienne version de webpack, il est préférable de consulter le guide de migration

l'Arbre des tremblements (élimination du code mort) est activé uniquement en mode de production.


Webpack 4, la nouvelle façon de regrouper des actifs

( Vous devez supprimer de votre CommonsChunkPlugin-de la pensée à partir de votre tête )

!!! Entre-temps le webpack doc a été mis à jour, une section SplitChunks a été ajoutée !!!

il suit une nouvelle philosophie :

Webpack 4 fait maintenant par défaut des optimisations automatiquement. Il analyse votre graphique de dépendance et crée des paquets optimaux (output), basés sur les conditions suivantes:

  1. nouveau morceau peut être partagé ou les modules sont à partir du dossier node_modules
  2. Nouveau morceau serait plus grand que 30 ko (avant min+gz)
  3. nombre maximal de demandes parallèles lors du chargement de morceaux sur demande <= 5
  4. nombre maximal de parallèles demande à la page initiale charge <= 3

tout cela peut être modifié en utilisant le SplitChunksPlugin! ( voir documentation SplitChunksPlugin )

une explication plus détaillée sur la façon d'utiliser la nouvelle API optimization.splitChunks .




CommonsChunkPlugin a été retiré parce qu'il a beaucoup de problèmes:

  • il peut entraîner le téléchargement de plus de code que nécessaire.
  • c'est inefficace sur les morceaux d'async.
  • C'est difficile à utiliser.
  • La mise en œuvre est difficile à comprendre.

le SplitChunksPlugin a également quelques grandes propriétés:

  • Il n'a jamais téléchargements inutiles module (tant que vous n'imposez pas de segment fusion au moyen du nom)
  • Il fonctionne efficace sur async morceaux trop
  • C'est activé par défaut pour les async morceaux
  • Il gère fournisseur de fractionnement avec plusieurs fournisseurs morceaux
  • c'est plus facile à utiliser
  • Il ne repose pas sur morceau graphique hacks
  • la plupart du temps automatique

--> Source


en ce qui concerne votre numéro , vous voulez diviser tous les numéros d'entry1 et entry2 en paquets séparés.

      optimization: {
        splitChunks: {
          cacheGroups: {   
            "entry1-bundle": {
              test: /.../,   // <-- use the test property to specify which deps go here
              chunks: "all",
              name: "entry1-bundle",
 /** Ignore minimum size, minimum chunks and maximum requests and always create chunks for this cache group */
              enforce: true,
              priority: ..  // use the priority, to tell where a shared dep should go
            },
            "entry2-bundle": {
              test: /..../, // <-- use the test property to specify which deps go here
              chunks: "all",
              name: "entry2-bundle",
              enforce: true,
              priority: ..
            }
          }
        }
      },

si vous n'ajoutez pas l'optimisation: splitChunks entry le paramètre par défaut est le suivant :

splitChunks: {
    chunks: "async",
    minSize: 30000,
    minChunks: 1,
    maxAsyncRequests: 5,
    maxInitialRequests: 3,
    automaticNameDelimiter: '~',
    name: true,
    cacheGroups: {
        vendors: {
            test: /[\/]node_modules[\/]/,
            priority: -10
        },
    default: {
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true
        }
    }
}

vous pouvez définir optimisation.splitChunks.cacheGroups. par défaut à false pour désactiver le par défaut cache groupe, de même pour les vendeurs cache groupe!


Des implémentations d'interface à jour pour SplitChunksOptions , CachGroupOptions et Optimization peuvent être trouvées ici .

les définitions d'interface ci-dessous peuvent ne pas être exactes à 100%, mais bon pour un aperçu simple:

SplitChunksOptions interface

interface SplitChunksOptions {
    /** Select chunks for determining shared modules (defaults to \"async\", \"initial\" and \"all\" requires adding these chunks to the HTML) */
    chunks?: "initial" | "async" | "all" | ((chunk: compilation.Chunk) => boolean);
    /** Minimal size for the created chunk */
    minSize?: number;
    /** Minimum number of times a module has to be duplicated until it's considered for splitting */
    minChunks?: number;
    /** Maximum number of requests which are accepted for on-demand loading */
    maxAsyncRequests?: number;
    /** Maximum number of initial chunks which are accepted for an entry point */
    maxInitialRequests?: number;
    /** Give chunks created a name (chunks with equal name are merged) */
    name?: boolean | string | ((...args: any[]) => any);
    /** Assign modules to a cache group (modules from different cache groups are tried to keep in separate chunks) */
    cacheGroups?: false | string | ((...args: any[]) => any) | RegExp | { [key: string]: CacheGroupsOptions };
}

CacheGroupsOptions de l'interface:

interface CacheGroupsOptions {
    /** Assign modules to a cache group */
    test?: ((...args: any[]) => boolean) | string | RegExp;
    /** Select chunks for determining cache group content (defaults to \"initial\", \"initial\" and \"all\" requires adding these chunks to the HTML) */
    chunks?: "initial" | "async" | "all" | ((chunk: compilation.Chunk) => boolean);
    /** Ignore minimum size, minimum chunks and maximum requests and always create chunks for this cache group */
    enforce?: boolean;
    /** Priority of this cache group */
    priority?: number;
    /** Minimal size for the created chunk */
    minSize?: number;
    /** Minimum number of times a module has to be duplicated until it's considered for splitting */
    minChunks?: number;
    /** Maximum number of requests which are accepted for on-demand loading */
    maxAsyncRequests?: number;
    /** Maximum number of initial chunks which are accepted for an entry point */
    maxInitialRequests?: number;
    /** Try to reuse existing chunk (with name) when it has matching modules */
    reuseExistingChunk?: boolean;
    /** Give chunks created a name (chunks with equal name are merged) */
    name?: boolean | string | ((...args: any[]) => any);
}

Optimization Interface

interface Optimization {
    /**
     *  Modules are removed from chunks when they are already available in all parent chunk groups.
     *  This reduces asset size. Smaller assets also result in faster builds since less code generation has to be performed.
     */
    removeAvailableModules?: boolean;
    /** Empty chunks are removed. This reduces load in filesystem and results in faster builds. */
    removeEmptyChunks?: boolean;
    /** Equal chunks are merged. This results in less code generation and faster builds. */
    mergeDuplicateChunks?: boolean;
    /** Chunks which are subsets of other chunks are determined and flagged in a way that subsets don’t have to be loaded when the bigger chunk has been loaded. */
    flagIncludedChunks?: boolean;
    /** Give more often used ids smaller (shorter) values. */
    occurrenceOrder?: boolean;
    /** Determine exports for each module when possible. This information is used by other optimizations or code generation. I. e. to generate more efficient code for export * from. */
    providedExports?: boolean;
    /**
     *  Determine used exports for each module. This depends on optimization.providedExports. This information is used by other optimizations or code generation.
     *  I. e. exports are not generated for unused exports, export names are mangled to single char identifiers when all usages are compatible.
     *  DCE in minimizers will benefit from this and can remove unused exports.
     */
    usedExports?: boolean;
    /**
     *  Recognise the sideEffects flag in package.json or rules to eliminate modules. This depends on optimization.providedExports and optimization.usedExports.
     *  These dependencies have a cost, but eliminating modules has positive impact on performance because of less code generation. It depends on your codebase.
     *  Try it for possible performance wins.
     */
    sideEffects?: boolean;
    /** Tries to find segments of the module graph which can be safely concatenated into a single module. Depends on optimization.providedExports and optimization.usedExports. */
    concatenateModules?: boolean;
    /** Finds modules which are shared between chunk and splits them into separate chunks to reduce duplication or separate vendor modules from application modules. */
    splitChunks?: SplitChunksOptions | false;
    /** Create a separate chunk for the webpack runtime code and chunk hash maps. This chunk should be inlined into the HTML */
    runtimeChunk?: boolean | "single" | "multiple" | RuntimeChunkOptions;
    /** Avoid emitting assets when errors occur. */
    noEmitOnErrors?: boolean;
    /** Instead of numeric ids, give modules readable names for better debugging. */
    namedModules?: boolean;
    /** Instead of numeric ids, give chunks readable names for better debugging. */
    namedChunks?: boolean;
    /** Defines the process.env.NODE_ENV constant to a compile-time-constant value. This allows to remove development only code from code. */
    nodeEnv?: string | false;
    /** Use the minimizer (optimization.minimizer, by default uglify-js) to minimize output assets. */
    minimize?: boolean;
    /** Minimizer(s) to use for minimizing the output */
    minimizer?: Array<Plugin | Tapable.Plugin>;
    /** Generate records with relative paths to be able to move the context folder". */
    portableRecords?: boolean;
}
}
36
répondu Legends 2018-07-26 10:57:07

j'ai deux fichiers d'entrée et je veux que seules les dépendances du premier soient incluses dans le morceau de fournisseur. Les dépendances de la seconde entrée devraient toutes rester dans son propre paquet.

si vos points d'entrée sont main et secondary :

entry: {
    main: 'path-to/main.js',
    secondary: 'path-to/secondary.js'
}

en utilisant vous pouvez extraire seulement les modules vendors de main morceau mais laisser l'autre tiers parties modules référencés dans secondary à l'intérieur de ce morceau en utilisant la fonction test de la cacheGroups que vous voulez créer.

optimization: {
    splitChunks: {
        cacheGroups: {
            vendors: {
                name: 'vendors',
                chunks: 'all',
                reuseExistingChunk: true,
                priority: 1,
                enforce: true,
                test(module, chunks) {
                    const name = module.nameForCondition && module.nameForCondition();
                    return chunks.some(chunk => {
                        return chunk.name === 'main' && /[\/]node_modules[\/]/.test(name);
                    });
                }
            },
            secondary: {
                name: 'secondary',
                chunks: 'all',
                priority: 2,
                enforce: true,
                test(module, chunks) {
                    return chunks.some(chunk => chunk.name === 'secondary');
                }
            }
        }
    }
}
4
répondu Carloluis 2018-03-25 04:19:37

cela m'a pris un certain temps à comprendre, mais la réalisation clé pour moi était que l'argument chunks dans webpack 4 prend maintenant une fonction, ce qui vous permet de n'inclure qu'une entrée spécifique. Je suppose que c'est un changement récent, parce qu'au moment de l'affichage il n'était pas dans la documentation officielle.

splitChunks: {
  cacheGroups: {
    vendor: {
      name: 'vendor',
      chunks: chunk => chunk.name == 'main',
      reuseExistingChunk: true,
      priority: 1,
      test: module =>
        /[\/]node_modules[\/]/.test(module.context),
      minChunks: 1,
      minSize: 0,
    },
  },
},
2
répondu Nick B. 2018-06-23 17:27:34