zoukankan      html  css  js  c++  java
  • JS打包与代码分割

    参考来源:https://github.com/ruanyf/webpack-demos#demo01-entry-file-source

    后面的代码:https://github.com/947133297/lwj-webpack-demo

    打包AMD和commonJS模块

    webpack默认支持这两种模块的打包

    amd.js

    define('amd',function(){
        return {
           data:'content from amd module'
        }
    });

    commonJS.js

    module.exports = {
        data:'content from commonjs module'
    }

    配置文件

    module.exports = {
      entry: './main.js',
      output: {
        filename: 'bundle.js'
      }
    };

    入口文件

    var amd = require('./js-module/amd');
    var com = require('./js-module/commomJS');
    
    console.log(amd);
    console.log(com);

    运行结果:可正常输出这两个模块,网络请求只有一个bundle.js,可见这两个模块的内容都打包进了一个js文件中

    chunk(这里的理解偏颇)

    entry chunk :包含了 webpackJsonp、__webpack_require__ 的定义 ,__webpack_require__.e用于以promise方式加载依赖后执行组件的代码(入口文件的代码),如:

     

    normal chunk:包含了入口文件所需的模块的代码,里面调用了webpackJsonp来注册依赖,如:

    多组件代码抽取

    如果多个组件中有相同的代码,每个组件都都像上个例子那样完全打包一份,那虽然减少了网络访问次数,但可能导致无谓的流量消耗,因为多个模块是可以共用代码的

    全局JS:

      把要复用的部分抽取到一个额外的全局js中,然后手动引入这个js,其他组件中直接使用这个js即可,如:

    module.exports = {
      entry: {
        bundle1:'./main1.js',
        bundle2:'./main2.js'
      },
      output: {
        filename: '[name].js'
      }
    };
    
    // main1.js
    console.log('组件1获取数据' + data);
    
    //main2.js
    console.log('组件2获取数据' + data);
    
    //commonData.js:
    var data = 'this is common data';
    
    index.html:
    <html>
    <script src="commonData.js"></script>
      <body>
        <script type="text/javascript" src="bundle1.js"></script>
        <script type="text/javascript" src="bundle2.js"></script>
      </body>
    </html>

    有没有办法不全局,而且可以使多个组件共用呢?这个需求可唯一推测出只能使用js模块,但是以上测试中,发现使用模块的话,会完全打包进去,以至于不能实现代码复用。其他webpack提供一个require.ensure可以实现模块的不打包,从而达到复用的目的

    require.ensure

    对以上代码进行改造:

    // commonData.js
    exports.data = 'this is common data';
    
    // mian1.js
    require.ensure(['./commonData'], function(require) {
        var m = require('./commonData');
        console.log('组件1获取数据' + m.data);
    });
    
    //main2.js
    require.ensure(['./commonData'], function(require) {
        var m = require('./commonData');
        console.log('组件2获取数据' + m.data);
    });
    
    //index.html
    <html>
      <body>
        <script type="text/javascript" src="bundle1.js"></script>
        <script type="text/javascript" src="bundle2.js"></script>
      </body>
    </html>

    运行结果一样。只不过这次实现了代码复用:

      以上效果的另外一种实现方式,是使用 bundle-loader ,语法不同但效果一样就不再举例了

    源码分析:

      bundle1、2.js中包含了webpackJsonp、__webpack_require__以及这个函数对象的一系列方法,以及对应入口文件的执行代码

      __webpack_require__.e 函数:用于根据模块id来获取模块,返回一个promise。往header上写一个script标签,这个标签onload的时候,也就是这个新增script中的webpackJsonp函数执行完了,就触发promise的resolve方法(执行了对应入口文件的代码)

    补充测试:

      模块1和2ensure了一个文件,模块3ensure了另一个文件。则会额外生成0.js和1.js。也就是说多少个文件被ensure,就会额外生成多少个文件(名字从0开始计算),重复ensure不会额外生成文件,而是复用之前的

      与ensure具有相同功能的是import。这两者都用于动态代码分割,如果使用import的话需要注意promise的兼容,可以使用响应的垫片库来处理,简单的import使用,可以参考仓库中的demo5

    CommonsChunkPlugin

    代码抽取还可以用这个插件来实现,测试代码如下:

    抽取依赖

    // 配置文件
    var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
    module.exports = {
      entry: {
        bundle1: './main1.js',
        bundle2: './main2.js'
      },
      output: {
        filename: '[name].js'
      },
      plugins: [
        new CommonsChunkPlugin('chunkInit')
      ]
    }
    
    // main1.js
    require('./com');
    require('./comm2');
    
    var data = 'this is differenet1 ';
    
    //main2.js
    require('./com');
    require('./comm2');
    
    var data = 'this is differenet2 ';
    
    //com.js
    exports.data = '这里存放的是公共代码'
    
    //comm2.js
    exports.data = '这里存放的是公共代码2'
    
    //index.html
    <html>
      <body>
        <script src="chunkInit.js"></script>
        <script src="bundle1.js"></script>
        <script src="bundle2.js"></script>
      </body>
    </html>

    运行结果:

      会生成一个chunkinit.js文件(这个名字是我们在new 插件的时候指定的),这个文件中包含了webpackJsonp、__webpack_require__以及这个函数对象的一系列方法以及被依赖的模块的代码,也就是说require进来的东西并不是动态加载的,而且直接写到了这个chunkinit.js文件中。而两个bundle文件调用了webpackjsonP函数,里面的回调函数中执行了对应入口文件的代码

      可见,这个插件实现的功能和require.ensure都是代码抽取,但两者本质上不同:

    组件的初始化定义:包含了webpackJsonp、__webpack_require__以及这个函数对象的一系列方法

    ensure:动态加载代码,抽取的是被依赖的代码,多个组件的初始化定义也还是重复的

    插件:非动态加载代码,抽取的是多个组件的初始化定义到一个文件中,并且里面写好了被依赖的模块代码

      以上两个组件都引用了两个相同的依赖,所以这两个依赖都放到了chuninit中。测试发现,多个组件中相同的依赖会被放到chunkinti中,而差异的部分则放到对应的bundle中,也就是说bundle中可能同时出现出现被依赖的模块代码以及对应的入口文件的代码

    使用jquery

    回顾以下:jq这个库兼容amd和commonJS的导入方式,require.ensure可以以不打包的形式导入一个库

    有了以上的理解,怎么使用jq就很好想象了,以下使用ensure来导入,同样的理解使用上面的插件来导入应该也是可行的

    require.ensure(['./jquery-3.2.1.min'], function(require) {
        var jq = require('./jquery-3.2.1.min');
        jq('body').attr('c2','true');
    });

    运行结果正常。

  • 相关阅读:
    驱动开发环境安装
    FireMonkey下的异形窗体拖动(句柄转换)
    Microsoft Win32 Programmer's Reference.chm
    Qt 访问网络的 HttpClient(封装QNetworkAccessManager,且有服务端)
    JBPM4 安装和配置
    DDD:谈谈数据模型、领域模型、视图模型和命令模型
    多个文件目录下Makefile的写法
    .NET程序集1
    Ajax初步理解
    Kemaswill 机器学习 数据挖掘 推荐系统 Ranking SVM 简介
  • 原文地址:https://www.cnblogs.com/hellohello/p/7625791.html
Copyright © 2011-2022 走看看