Javascript Webpack 4 迁移 CommonsChunkPlugin

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/49017682/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 04:18:27  来源:igfitidea点击:

Webpack 4 migration CommonsChunkPlugin

javascriptwebpackwebpack-3commonschunkpluginwebpack-4

提问by Erik Bender

I need help migrating the following code from webpack 3 to 4.

我需要帮助将以下代码从 webpack 3 迁移到 4。

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

I have two entry files and want only the dependencies of the first one to be included in the vendor chunk. The dependencies of the second entry should all stay in its own bundle.

我有两个入口文件,只希望第一个的依赖项包含在供应商块中。第二个条目的依赖项应该都保留在它自己的包中。

回答by Legends

As of webpack v4 the CommonsChunkPlugin is deprecated.

从 webpack v4 开始,不推荐使用 CommonsChunkPlugin。

We have deprecated and removed CommonsChunkPlugin, and have replaced it with a set of defaults and easily overridable API called optimization.splitChunks.

我们已弃用并删除了 CommonsChunkPlugin,并将其替换为一组名为 optimization.splitChunks.

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


Deprecated

已弃用

You no longer need to use these plugins:

您不再需要使用这些插件:

DedupePlugin has been removed too in v4

在 v4 中也删除了 DedupePlugin

NoEmitOnErrorsPlugin-> optimization.noEmitOnErrors (on by default in production mode) ModuleConcatenationPlugin-> optimization.concatenateModules (on by default in prod mode) NamedModulesPlugin-> optimization.namedModules (on by default in dev mode)

NoEmitOnErrorsPlugin- > optimization.noEmitOnErrors(由在生产模式默认) ModuleConcatenationPlugin- > optimization.concatenateModules(默认情况下在PROD模式) NamedModulesPlugin- > optimization.namedModules(默认情况下在开发者模式)



Recommendations for webpack 4

对 webpack 4 的建议

Use mini-css-extract-plugininstead of text-extract-plugin. Use webpack-bundle-analyzerto analyze your bundled output in graphical way.

使用mini-css-extract-plugin代替text-extract-plugin。用于webpack-bundle-analyzer以图形方式分析您的捆绑输出。

Entry scripts are real "Entry-Scripts" to your application, don't add vendor files explicitly to entry:in webpack.config.js. SPA apps have one entry and Multi-Page-Apps like classic ASP.NET MVCapps have multiple entry points. Webpack will build a dependenc graph out of your entry scripts and generate optimized bundles for your app.

进入脚本是真正的“入门脚本”您的应用程序,没有供应商的文件添加明确地entry:webpack.config.js。SPA 应用程序只有一个入口,而经典ASP.NET MVC应用程序等多页应用程序有多个入口点。Webpack 将根据您的入口脚本构建一个依赖图,并为您的应用程序生成优化的包。

If you want to migrate from an older webpack version, it's best to checkout the migration guide

如果你想从旧的 webpack 版本迁移,最好查看迁移指南

Tree shaking (dead code elimination) is only enabled in production mode.

摇树(死代码消除)仅在生产模式下启用。



Webpack 4, the new way of bundling assets

Webpack 4,捆绑资产的新方式

(You have to remove your CommonsChunkPlugin-thinking from your head)

你必须从你的头脑中删除你的 CommonsChunkPlugin-thinking

!!! Meanwhile the webpack doc has been updated, a section SplitChunkswas added !!!

!!!同时更新了 webpack 文档,SplitChunks增加了一个部分!!!

It follows a new philosophy:

它遵循一种新的理念

Webpack 4 now by default does optimizations automatically. It analyzes your dependency graph and creates optimal bundles (output), based on the following conditions:

Webpack 4 现在默认自动进行优化。它会根据以下条件分析您的依赖关系图并创建最佳捆绑包(输出):

  1. New chunk can be shared OR modules are from the node_modules folder
  2. New chunk would be bigger than 30kb (before min+gz)
  3. Maximum number of parallel request when loading chunks on demand <= 5
  4. Maximum number of parallel request at initial page load <= 3
  1. 可以共享新块或模块来自 node_modules 文件夹
  2. 新块将大于 30kb(在 min+gz 之前)
  3. 按需加载块时的最大并行请求数 <= 5
  4. 初始页面加载时的最大并行请求数 <= 3

All this can be tweaked using the SplitChunksPlugin! (see SplitChunksPlugin documentation)

所有这些都可以使用 SplitChunksPlugin 进行调整!(参见 SplitChunksPlugin 文档

A more detailed explanationon how to use the new optimization.splitChunksAPI.

关于如何使用新optimization.splitChunksAPI 的更详细说明




CommonsChunkPlugin was removed because it has a lot of problems:


CommonsChunkPlugin 被删除了,因为它有很多问题:

  • It can result in more code being downloaded than needed.
  • It's inefficient on async chunks.
  • It's difficult to use.
  • The implementation is difficult to understand.
  • 这可能导致下载的代码比需要的多。
  • 它在异步块上效率低下。
  • 很难使用。
  • 实现很难理解。


The SplitChunksPlugin also has some great properties:

SplitChunksPlugin 也有一些很棒的属性:

  • It never downloads unneeded module (as long you don't enforce chunk merging via name)
  • It works efficient on async chunks too
  • It's on by default for async chunks
  • It handles vendor splitting with multiple vendor chunks
  • It's easier to use
  • It doesn't rely on chunk graph hacks
  • Mostly automatic
  • 它永远不会下载不需要的模块(只要您不通过名称强制块合并)
  • 它也适用于异步块
  • 默认情况下为异步块打开
  • 它处理带有多个供应商块的供应商拆分
  • 使用起来更方便
  • 它不依赖于块图黑客
  • 大部分是自动的

--> Source

--> 来源



Regarding your issue, you want to split all deps of entry1 and entry2 into separate bundles.

关于您的问题,您希望将 entry1 和 entry2 的所有 deps 拆分为单独的包。

      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: ..
            }
          }
        }
      },


If you don't add the optimization:splitChunks entry the default settingis as follows:

如果您不添加 optimization:splitChunks 条目,则默认设置如下

splitChunks: {
  chunks: 'async',
  minSize: 30000,
  minRemainingSize: 0,
  maxSize: 0,
  minChunks: 1,
  maxAsyncRequests: 6,
  maxInitialRequests: 4,
  automaticNameDelimiter: '~',
  automaticNameMaxLength: 30,
  cacheGroups: {
    vendors: {
      test: /[\/]node_modules[\/]/,
      priority: -10
    },
    default: {
      minChunks: 2,
      priority: -20,
      reuseExistingChunk: true
    }
  }
}

You can set optimization.splitChunks.cacheGroups.defaultto false to disable the defaultcache group, same for vendorscache group!

您可以设置 optimization.splitChunks.cacheGroups。默认为 false 以禁用默认缓存组,供应商缓存组相同!

Here are some other SplitChunks configuration exampleswith explanation.

以下是一些其他SplitChunks 配置示例并附有说明。



截至到最新的接口实现的SplitChunksOptionsSplitChunksOptionsCachGroupOptionsCachGroupOptions并且OptimizationOptimization可以发现here在这里

The interface definitions below may not be 100% accurate, but good for a simple overview:

下面的接口定义可能不是 100% 准确,但适合简单概述:

SplitChunksOptionsinterface

SplitChunksOptions界面

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

CacheGroupsOptionsinterface:

CacheGroupsOptions界面:

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

OptimizationInterface

Optimization界面

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

回答by Carloluis

I have two entry files and want only the dependencies of the first one to be included in the vendor chunk. The dependencies of the second entry should all stay in its own bundle.

我有两个入口文件,只希望第一个的依赖项包含在供应商块中。第二个条目的依赖项应该都保留在它自己的包中。

Assuming your entrypoints are mainand secondary:

假设您的入口点是mainsecondary

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

Using webpack-4You can extract only the vendorsmodules from mainchunk but leave other third parties modules referenced in secondaryinside that chunk using the testfunction of the cacheGroupsyou want to create.

使用webpack-4您可以只vendorsmain块中提取模块,但secondary使用您要创建的test功能将其他第三方模块留在该块中引用的块中cacheGroups

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

回答by Nick B.

This took me a while to figure out, but the key realization for me was that the chunksargument in webpack 4 now takes a function, which allows you to only include a specific entry. I'm assuming this is a recent change, because at the time of posting it wasn't in the official documentation.

这花了我一段时间才弄明白,但对我来说,关键的实现是chunkswebpack 4中的参数现在接受一个函数,它允许你只包含一个特定的条目。我假设这是最近的更改,因为在发布时它不在官方文档中。

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,
    },
  },
},

回答by user8128167

Please note that I corrected the issue by changing this in my webpack.common.js:

请注意,我通过在 webpack.common.js 中更改此内容来纠正了该问题:

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

To this:

对此:

  optimization: {
      runtimeChunk: "single", // enable "runtime" chunk
      splitChunks: {
          cacheGroups: {
              vendor: {
                  test: /[\/]node_modules[\/]/,
                  name: "vendor",
                  chunks: "all"
              }
          }
      }
  },