小昱个人博客
欢迎来到小昱的世界

勤学如春起之苗,不见其增,日有所长;辍学如磨刀之石,不见其损,日有所亏
使用webpack实现依赖库的分离
  • 首页 > 前端 > 自动构建
  • 作者:小昱
  • 2017年6月22日 10:04 星期四
  • 浏览:141
  • 字号:
  • 评论:0
  • 一、安装

    npm install webpack -g
    npm install webpack-dev-server -g
    npm install webpack --save-dev
    npm install moment --save-dev

    二、基础代码编写

    index.js

    var moment = require('moment');
    console.log(moment().format());

    webpack.config.js

    var path = require('path');
    
    module.exports = function(env) {
        return {
            entry: './index.js',
            output: {
                filename: '[name].[chunkhash].js',
                path: path.resolve(__dirname, 'dist')
            }
        }
    }

    执行webpack,可以看到生成一个唯一哈希值的打包文件,每次在改变index.js之后都会生成不同哈希值的打包文件。

    这对于该应用来说是很不理想的。如果 index.js 中的代码改变了,那么整个 bundle 都会重新构建。浏览器就需要加载新的 bundle,即使其中大部分代码都没改变。

    我们期望从打包文件中提取出moment,利用缓存来缓解每次都需要重新加载index.js的问题。

    三、尝试分离

    尝试一: 多入口

    webpack.config.js

    var path = require('path');
    
    module.exports = function(env) {
        return {
            entry: {
                main: './index.js',
                vendor: 'moment'
            },
            output: {
                filename: '[name].[chunkhash].js',
                path: path.resolve(__dirname, 'dist')
            }
        }
    }

    再次运行 webpack,可以发现生成了两个 bundle。然而如果查看他们的代码,会发现 moment 的代码在两个文件中都出现了!其原因是 moment 是主应用程序(例如 index.js)的依赖模块,每个入口起点都会打包自己的依赖模块。

    尝试二 CommonsChunkPlugin

    webpack.config.js

    var webpack = require('webpack');
    var path = require('path');
    
    module.exports = function(env) {
        return {
            entry: {
                main: './index.js',
                vendor: 'moment'
            },
            output: {
                filename: '[name].[chunkhash].js',
                path: path.resolve(__dirname, 'dist')
            },
            plugins: [
                new webpack.optimize.CommonsChunkPlugin({
                    name: 'vendor' // 指定公共 bundle 的名字。
                })
            ]
        }
    }

    现在运行 webpack。查看结果会发现 moment 代码只会出现在 vendor bundle 中。

    尝试三 隐式公共 vendor chunk

    将 CommonsChunkPlugin 配置为只接受 vendor 库。

    webpack.config.js

    var webpack = require('webpack');
    var path = require('path');
    
    module.exports = function() {
        return {
            entry: {
                main: './index.js'
            },
            output: {
                filename: '[name].[chunkhash].js',
                path: path.resolve(__dirname, 'dist')
            },
            plugins: [
                new webpack.optimize.CommonsChunkPlugin({
                    name: 'vendor',
                    minChunks: function (module) {
                       // 该配置假定你引入的 vendor 存在于 node_modules 目录中
                       return module.context && module.context.indexOf('node_modules') !== -1;
                    }
                })
            ]
        }
    }

    尝试四 Manifest 文件

    但是,如果我们改变应用的代码并且再次运行 webpack,可以看到 vendor 文件的 hash 改变了。即使我们把 vendor 和 main 的 bundle 分开了,也会发现 vendor bundle 会随着应用代码改变。 这意味着我们还是无法从浏览器缓存机制中受益,因为 vendor 的 hash 在每次构建中都会改变,浏览器也必须重新加载文件。

    这里的问题在于,每次构建时,webpack 生成了一些 webpack runtime 代码,用来帮助 webpack 完成其工作。当只有一个 bundle 的时候,runtime 代码驻留在其中。但是当生成多个 bundle 的时候,运行时代码被提取到了公共模块中,在这里就是 vendor 文件。

    为了防止这种情况,我们需要将运行时代码提取到一个单独的 manifest 文件中。尽管我们又创建了另一个 bundle,其开销也被我们在 vendor 文件的长期缓存中获得的好处所抵消。

    webpack.config.js

    var webpack = require('webpack');
    var path = require('path');
    
    module.exports = function(env) {
        return {
            entry: {
                main: './index.js',
                vendor: 'moment'
            },
            output: {
                filename: '[name].[chunkhash].js',
                path: path.resolve(__dirname, 'dist')
            },
            plugins: [
                new webpack.optimize.CommonsChunkPlugin({
                    names: ['vendor', 'manifest'] // 指定公共 bundle 的名字。
                })
            ]
        }
    }

    尝试五 含隐式公共 vendor chunk 的 Manifest 文件

    webpack.config.js

    var webpack = require('webpack');
    var path = require('path');
    
    module.exports = function() {
        return {
            entry: {
                main: './index.js' //Notice that we do not have an explicit vendor entry here
            },
            output: {
                filename: '[name].[chunkhash].js',
                path: path.resolve(__dirname, 'dist')
            },
            plugins: [
                new webpack.optimize.CommonsChunkPlugin({
                    name: 'vendor',
                    minChunks: function (module) {
                       // this assumes your vendor imports exist in the node_modules directory
                       return module.context && module.context.indexOf('node_modules') !== -1;
                    }
                }),
                //CommonChunksPlugin will now extract all the common modules from vendor and main bundles
                new webpack.optimize.CommonsChunkPlugin({
                    name: 'manifest' //But since there are no more common modules between them we end up with just the runtime code included in the manifest file
                })
            ]
        };
    }

    使用上面的 webpack 配置,我们看到生成了三个bundle:vendor、main和manifest。

    改变index.js的内容,vendor的hash值也不回随之改变。

    四、总结

    有了以上尝试,我们可以做出如下代码打包的优化

    index.html

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
      <!-- 注意引入顺序 -->
      <script src="dist/manifest.js"></script>
      <script src="dist/vendor.js"></script>
      <script src="dist/main.js"></script>
    </head>
    <body>
      
    </body>
    </html>

    webpack.config.js

    var webpack = require('webpack');
    var path = require('path');
    
    module.exports = function() {
        return {
            entry: {
                main: './index.js' //Notice that we do not have an explicit vendor entry here
            },
            output: {
                filename: '[name].js',
                path: path.resolve(__dirname, 'dist')
            },
            plugins: [
                new webpack.optimize.CommonsChunkPlugin({
                    name: 'vendor',
                    minChunks: function (module) {
                       // this assumes your vendor imports exist in the node_modules directory
                       return module.context && module.context.indexOf('node_modules') !== -1;
                    }
                }),
                //CommonChunksPlugin will now extract all the common modules from vendor and main bundles
                new webpack.optimize.CommonsChunkPlugin({
                    name: 'manifest' //But since there are no more common modules between them we end up with just the runtime code included in the manifest file
                })
            ]
        };
    }

    index.js 例如:

    var moment = require('moment');
    console.log(moment().format())


      您阅读这篇文章共花了:  
    二维码加载中...
    本文作者:小昱      文章标题: 使用webpack实现依赖库的分离
    本文地址:http://www.xiaoyulive.top/?post=93
    版权声明:若无注明,本文皆为“小昱个人博客”原创,转载请保留文章出处。
    返回顶部| 首页| 碰碰手气| 捐赠支持| 手机版本|后花园

    Copyright © 2016-2017 小昱个人博客 滇ICP备16006294号