全栈前端

webpack4 进阶篇4 ——打包后代码是如何运行

2019-07-04  本文已影响0人  前往悬崖下寻宝的神三算

本文长期更新,如有错误或者补充,欢迎留言
关注一下不迷路~

test.js 代码如下

export default function cc() {
    console.log("cc");
}

index.js 代码如下

import cc from './test.js';
console.log(cc)

打包后的各个模块被转换成一个函数(暂称模块函数)

// test.js
function(module, __webpack_exports__, __webpack_require__) {

    "use strict";
    /* harmony export (binding) */
    __webpack_require__.d(__webpack_exports__, "a",
    function() {
        return cc;
    });
    // 模块中的代码
    function cc() {
        console.log("cc");
    }

}

这个函数代码和模块基本一样,唯有export xx被转换成函数fnfn作用就是形成闭包,后续调用fn时return xx,代替export导出xx。

模块函数在运行时被解析成一个对象obj:

// 'src/test.js'
{
  i: moduleId, // 模块id
  l: false, //  是否已加载
  exports: {
      __esModule: bool, // 是否是es模块
      cc: fn // **
  }
}

并被放在一个大对象installedModules中,缓存起来,避免重复解析,其中key是文件名:

{
    'src/test.js': { // key是文件名
        i: moduleId, // 模块id
        l: false, //  是否已加载
        exports: {
            __esModule: bool,
            cc: fn // **
        }
    }
}

后续其他模块如果要导入变量xx时,其实是通过执行obj.exports.xx()来获取变量的。

大致过程就是如此,附打包后的代码(已删除无用注释):

// part 1 解析模块函数代码
(function(modules) { // webpackBootstrap
    // The module cache
    var installedModules = {
        // 'xx.js': {
        //   i: moduleId, // 模块id
        //   l: false, //  是否已加载
        //   exports: {
        //     __esModule: Boolean,
        //     var: () => "xx", // 利用闭包获取模块中的变量后返回
        //   }
        // }
    };

    // The require function
    function __webpack_require__(moduleId) {

        // Check if module is in cache
        if (installedModules[moduleId]) {
            return installedModules[moduleId].exports;
        }
        // Create a new module (and put it into the cache)
        var module = installedModules[moduleId] = {
            i: moduleId,
            l: false,
            exports: {}
        };

        // Execute the module function
        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

        // Flag the module as loaded
        module.l = true;

        // Return the exports of the module
        return module.exports;
    }

    // expose the modules object (__webpack_modules__)
    __webpack_require__.m = modules;

    // expose the module cache
    __webpack_require__.c = installedModules;

    // define getter function for harmony exports
    // 增加模块导出的变量
    __webpack_require__.d = function(exports, name, getter) {
        if (!__webpack_require__.o(exports, name)) {
            Object.defineProperty(exports, name, {
                enumerable: true,
                get: getter
            });
        }
    };

    // define __esModule on exports
    // 标记是es模块(exports.__esModule:true)
    __webpack_require__.r = function(exports) {
        if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
            Object.defineProperty(exports, Symbol.toStringTag, {
                value: 'Module'
            });
        }
        Object.defineProperty(exports, '__esModule', {
            value: true
        });
    };

    // create a fake namespace object
    // mode & 1: value is a module id, require it
    // mode & 2: merge all properties of value into the ns
    // mode & 4: return value when already ns object
    // mode & 8|1: behave like require
    __webpack_require__.t = function(value, mode) {
        if (mode & 1) value = __webpack_require__(value);
        if (mode & 8) return value;
        if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
        var ns = Object.create(null);
        __webpack_require__.r(ns);
        Object.defineProperty(ns, 'default', {
            enumerable: true,
            value: value
        });
        if (mode & 2 && typeof value != 'string') for (var key in value) __webpack_require__.d(ns, key,
        function(key) {
            return value[key];
        }.bind(null, key));
        return ns;
    };

    // getDefaultExport function for compatibility with non-harmony modules
    __webpack_require__.n = function(module) {
        var getter = module && module.__esModule ?
        function getDefault() {
            return module['default'];
        }: function getModuleExports() {
            return module;
        };
        __webpack_require__.d(getter, 'a', getter);
        return getter;
    };

    // Object.prototype.hasOwnProperty.call
    // 判断增加的导出变量是不是已存在
    __webpack_require__.o = function(object, property) {
        return Object.prototype.hasOwnProperty.call(object, property);
    };

    // __webpack_public_path__
    __webpack_require__.p = "";

    // Load entry module and return exports
    return __webpack_require__(__webpack_require__.s = 0);
})
// part2 模块函数代码
/************************************************************************/
({

    "./src/index.js": (function(module, __webpack_exports__, __webpack_require__) {

        "use strict";
        __webpack_require__.r(__webpack_exports__);
        /* harmony import */
        var _test_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/test.js");

        console.log(Object(_test_js__WEBPACK_IMPORTED_MODULE_0__[
        /* default */
        "a"])());

    }),

    "./src/test.js": (function(module, __webpack_exports__, __webpack_require__) {

        "use strict";
        /* harmony export (binding) */
        __webpack_require__.d(__webpack_exports__, "a",
        function() {
            return cc;
        });
        function cc() {
            console.log("cc");
        }

    }),

    0 : (function(module, exports, __webpack_require__) {

        module.exports = __webpack_require__("./src/index.js");

    })

});

后续上述代码还会被压缩处理,treeshaking,变量名替换成abcd...

上一篇下一篇

猜你喜欢

热点阅读