5

webpack模块化原理简析

1.webpack的核心原理

  • 一切皆模块:在webpack中,css,html.js,静态资源文件等都可以视作模块;便于管理,利于重复利用;

  • 按需加载:进行代码分割,实现按需加载。

2. webpack模块化原理:以js为例,分析webpack构建common.js的模块化方式。

    • ①构建示例代码

      //b.js
      let b =3
      export {b};
      
      //a.js
      let b = require('./b.js')
      let  a = b+123;
      
      //webpack.config.js
      let path = require("path")
      module.exports = {
        entry: './a.js',
        output: {
            filename: 'bundle.js',
           path: path.resolve(__dirname, 'build')},
       module: {
          loaders: [{
           test: /\.js$/,
           loader: 'babel-loader',
           query: {
                    presets: ['es2015']}}}}
      
    • ②分析bundle.js

      • a.整体结构:整个bundle.js整个是一个执行函数,传进去的参数是一个个的模块,也是一个的函数,通过函数的作用于达到模块化的效果。

        (function (modules) {………………})([  //模块初始化
          function (module, exports, __webpack_require__) {
            /* 模块a.js的代码 */},  
          function (module, exports, __webpack_require__) {
            /* 模块b.js的代码 */}]);
      • b.模块初始化

         //1.定义一个模块缓存的容器
        var installedModules = {};
        
        //2.webpack的require实现
        function __webpack_require__(moduleId) {//传参是模块ID
        
         //3.判断模块是否缓存,若是缓存了就不用加载,直接返还这个已缓存的模块
         if(installedModules[moduleId]) {
             return installedModules[moduleId].exports;}
             
         // 4.若是没有被缓存,则缓存这个模块
         var module = installedModules[moduleId] = {
             i: moduleId, //模块ID
             l: false,    //标识模块是否加载
             exports: {}
         };
        
         //5.执行模块函数,modules代表一系列的模块函数,要动态绑定module.exports,绑定this;可以交叉连续引用。     
         modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
        
         // 6.标记模块已经被加载
         module.l = true;
        
         // 7.返回该模块的exports
         return module.exports;}
         
         //8.require第一个 模块
         return __webpack_require__(0);
        }
      • c.模块函数

         //a.js模块
         function(module, exports, __webpack_require__) {
          "use strict";
           var b = __webpack_require__(1);//重复调用
           var a = b + 123;}
           
         //b.js模块
         function(module, exports, __webpack_require__) {
           "use strict";
           var b = 3;
           exports.b = b;}     
      • d.下面是执行的流程图,指定一个初始模块,所有被引用的模块会响应的循环加载。

        clipboard.png

    • ps几个小问题

      • 1.在模块加载的时候,最后传递的一个参数是__webpack_require__,是全局定义的函数,为什么是全局的呢,因为自执行函数的this指向全局。

      • 2.commond.js需要注意模块导出的问题

        • exports不能直接赋值,无用,因为源码中返回的是module.exports

        • ②可以在exports上增加属性,比如exports.fn=;这样module.exports会变化,最终导出的是module.exports也会变化;

          //node.js部分源码,node也是通过闭包实现模块的隔离
          (function(exports,module,require,__dirname,__filename){
                 this = module.exports  //this是指向module.exports的
                 module.exports = exports = {}
          return module.exports})()

    何凯
    966 声望174 粉丝

    Never too late to learn!