使用 WebPack CommonsChunkPlugin 提取重复的 javascript 代码

Posted

技术标签:

【中文标题】使用 WebPack CommonsChunkPlugin 提取重复的 javascript 代码【英文标题】:Extract duplicate javascript code using WebPack CommonsChunkPlugin 【发布时间】:2018-01-08 21:56:00 【问题描述】:

我正在使用 WebPack CommonsChunkPlugin 来提取重复代码并减少 javascript 代码大小。我有两个 html 页面和两个条目。我还添加了 ReactJs 供应商条目。到目前为止,在 webpack.config.js 我们有:

var path = require("path");
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = 
    context: __dirname,
    entry: 
        react: ["react", "react-dom"],
        home: './assets/js/home.jsx',
        about: './assets/js/about.jsx',
    ,

    output: 
        path: path.resolve('./assets/bundles/'),
        filename: "[name].js",
    ,

    plugins: [
        new BundleTracker(filename: './webpack-stats.json'),

        new webpack.optimize.CommonsChunkPlugin(
            name: 'react',
            minChunks: Infinity
        ),

        new BundleAnalyzerPlugin(),
    ],

    module: 
        rules: [
            
              test: /\.jsx?$/, 
              exclude: /node_modules/,
              loader: 'babel-loader',
              options:  
                  plugins: [["lodash",  "id": ["semantic-ui-react"] ]],
                  presets: ["es2015", "react"]
                
            ,
        ],
    ,

    resolve: 
        modules: ['node_modules', 'bower_components'],
        extensions: ['*', '.js', '.jsx']
    ,
;

此配置结果与 webpack-bundle-analyzer

如您所见,有一些重复的代码,一些在红色区域,另一些在绿色区域。我想把这个js代码从家里和关于捆绑包中提取到一个单独的包中。为了提取红色区域代码,即 lodash 库,我在 webpack config 中添加了这些行:

new webpack.optimize.CommonsChunkPlugin(
    name: 'lodash',
    minChunks: function(module, count) 
        return module.context.indexOf('node_modules/lodash') >= 0;
    
), 

但它没有按预期工作,并且 lodash 库代码仍然在 home 和 about bundles 中,webpack 还创建了一个名为 lodash 的 bundle,它几乎是空的并且不包含任何 js 库。

关于如何解决它的任何想法?提取绿色代码怎么样?

【问题讨论】:

链接:Split “vendor” chunk using webpack 2 【参考方案1】:

您的问题是您在每个.js/.jsx 文件中导入第三方库,而之前没有将其导入到一个公共文件(通常称为vendor.js)中。 如果你有这个文件来导入你所有的依赖项,并且你将它作为入口包含在 CommonsChunkPlugin 中,webpack 将不会在你的最终包中再次包含你的库(home.jsabout.js)。该技术在 webpack 文档中称为 代码拆分

vendor.js(或适合您情况的名称)

import 'react';
import 'react-dom';
import 'lodash';
import 'semantic-ui-react';
//... all your npm packages

webpack.config.js

var webpack = require('webpack');
var path = require('path');

module.exports = 
    context: __dirname,
    entry: 
        vendor: './assets/js/vendor.js,
        home: './assets/js/home.jsx',
        about: './assets/js/about.jsx',
    ,
    output: 
        path: path.resolve('./assets/bundles/'),
        filename: '[name].js',
    ,
    plugins: [
        new webpack.optimize.CommonsChunkPlugin(
            name: 'vendor',
            minChunks: Infinity
        ),
    ],

    //Rest of Your config ...
;

index.html

<body>
    <!-- AFTER YOUR HTML CODE -->

    <script type="text/javascript" src="/assets/bundles/vendor.js"></script>
    <script type="text/javascript" src="/assets/bundles/home.js"></script>
    <script type="text/javascript" src="/assets/bundles/about.js"></script>
</body>


查看 webpack 代码拆分文档:

旧文档:https://webpack.github.io/docs/code-splitting.html#split-app-and-vendor-code 新文档:https://webpack.js.org/plugins/commons-chunk-plugin/#explicit-vendor-chunk

【讨论】:

我照你说的做了,又运行了 webpack。但是结果还是和之前一样,lodash 库还在这两个文件中,只是 react 和 react-dom 被捆绑到 vendor.js 文件中。这是捆绑分析器的输出:link 使用 require('lodash') 而不是 import 'lodash' 有什么不同吗?使用 import 'lodash' 时,供应商捆绑包中没有 lodash 代码,但是当我使用 require('lodash') 时,供应商捆绑包中有 node_modules/lodash/lodash.js。你知道原因吗? 我注意到我的 webpack.config.js 和你的唯一区别是 plugins: [["lodash", "id": ["semantic-ui-react"] ]], 尝试从 babel-loader 选项中删除它。我想可能就是这样。如果不是,那就奇怪了。 require('lodash')import 'lodash' 具有相同的效果。 import 是 ES6 语法,如果可以,请尝试使用它。我认为如果你有不同的结果,你的 babel 中可能会有一些错误的配置。但如果适合你,请使用require 毕竟,我设法在不删除 babel-lodash 插件的情况下解决了这个问题。我会发布配置。感谢您的所有努力:)【参考方案2】:

我设法通过向插件添加一个公共块来解决这个问题。所以最终的 webpack 配置是:

var path = require("path");
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');

module.exports = 

    context: __dirname,

    entry: 
        react: ["react", "react-dom"],
        home: './assets/js/home.jsx',
        about: './assets/js/about.jsx',
    ,

    output: 
        path: path.resolve('./assets/bundles/'),
        filename: "[name].js",
    ,

    plugins: [

        new BundleTracker(filename: './webpack-stats.json'),

        new webpack.optimize.CommonsChunkPlugin(
            name: 'react',
            filename: '[name].js',
            minChunks: Infinity,
        ),

        new webpack.optimize.CommonsChunkPlugin(
            name: 'common',
            chunks: ['home', 'about'],
            filename: '[name].js',
        ),
    ],

    module: 
        rules: [
            
                test: /\.jsx?$/, 
                exclude: /node_modules/,
                loader: 'babel-loader',
                options:  
                    plugins: [
                      ["lodash",  "id": ["semantic-ui-react"] ]
                    ],
                    presets: ["es2015", "react"]
                
            ,
        ],
    ,

    resolve: 
        modules: ['node_modules', 'bower_components'],
        extensions: ['*', '.js', '.jsx']
    ,
;

现在捆绑分析器的输出是这样的:

如图所示,常见的 semantic-ui-react 和 lodash 库现在只是在公共包中,不再重复。

【讨论】:

以上是关于使用 WebPack CommonsChunkPlugin 提取重复的 javascript 代码的主要内容,如果未能解决你的问题,请参考以下文章

Webpack的使用

# Webpack 学习Webpack 搭建 Vue项目

# Webpack 学习Webpack 搭建 Vue项目

使用webpack---安装webpack和webpack-dev-server

webpack基本使用

Django/Webpack - 如何使用 webpack 开发服务器提供生成的 webpack 包