浏览器是无法直接使用模块之间的commonjs或es6,webpack在打包时做了什么处理,才能让浏览器能够执行呢,往下看吧。

使用commonjs语法

先看下写的代码,

app.js



minus.js



webpack.config.js



代码非常简单,没啥可说的,直接上编译后的代码来分析,代码可以直接复制过来在浏览器执行调试

  // 一个IIFE, 方法的形参是一个对象,key是页面的路径,value是页面的代码
;(function (modules) {
// 缓存已经读取过的module,避免重复执行
var installedModules = {} // 核心方法。moduleId以页面的路径作为属性
function __webpack_require__(moduleId) {
// 如果缓存存有moduleId,代表已经执行过,直接把缓存里的值返回
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
}
// Load entry module and return exports
return __webpack_require__((__webpack_require__.s = "./app.js"))
})(
// IIFE的参数,把所有需要的页面转换为对象的key,先读取入口文件app.js,文件内部需要minus.js,所以再次调用__webpack_require__执行
{
"./app.js": function (module, exports, __webpack_require__) {
var minus = __webpack_require__(
/*! ./vendor/minus */ "./vendor/minus.js"
)
console.log("minus(1, 2) = ", minus(1, 2))
}, "./vendor/minus.js": function (module, exports) {
module.exports = function (a, b) {
return a - b
}
},
})

再来看下es6语法有什么区别

;(function (modules) {
// webpackBootstrap
// The module cache
var installedModules = {} // 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__是一个方法,给这个方法加一个属性,内容是页面模块这个对象
__webpack_require__.m = modules // expose the module cache
// 同理也是加了一个读缓存模块的属性
__webpack_require__.c = installedModules // define getter function for harmony exports
// 给这个对象赋值,为什么不直接赋值呢,因为这样子,这个属性是不可变的,怎么改使用还是取的get
__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
// 给使用es6导出的模块打上标记,Symbol.toStringTag
// 请看https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag
// 做这一步的原因是 其他页面导出的时候会判断有没有标记,有的话就会换另一种方式读取,导出看__webpack_require__.n
__webpack_require__.r = function (exports) {
if (typeof Symbol !== "undefined" && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, {
value: "Module",
})
}
Object.defineProperty(exports, "__esModule", { value: true })
} // getDefaultExport function for compatibility with non-harmony modules
// 看导出时的读取方式是采用es6还是commonjs
__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)
} // Load entry module and return exports
return __webpack_require__((__webpack_require__.s = "./app.js"))
})({
"./app.js": function (module, __webpack_exports__, __webpack_require__) {
"use strict"
__webpack_require__.r(__webpack_exports__)
// 这里需要注意,使用es6导入的时候,webpack改变了原变量名字,所以这个变量可以使用可以修改,
// 但是如果变量是对象的情况下,不允许修改变量指向的内存地址 /* harmony import */ var _vendor_sum__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
/*! ./vendor/sum */ "./vendor/sum.js"
) console.log(
"sum(1, 3) = ",
Object(_vendor_sum__WEBPACK_IMPORTED_MODULE_0__["sum"])(1, 3)
)
}, "./vendor/sum.js": function (
module,
__webpack_exports__,
__webpack_require__
) {
"use strict"
// 打上标记是es6语法
__webpack_require__.r(__webpack_exports__)
// 属性赋值
/* harmony export (binding) */ __webpack_require__.d(
__webpack_exports__,
"sum",
function () {
return sum
}
)
function sum(a, b) {
return a + b
}
},
})

如何使用分包懒加载

在某些特定环境比如点击某个按钮才加载,webpack会创建一个script标签来加载内容(vue-cli 有利用prefetch做优化)同时生成一个promise

把resolve和reject放进installedChunks数组里,当页面加载好后会从数组取出resolve执行(利用webpackJsonp重写push方法)

// 加载模块
__webpack_require__.e = function requireEnsure(chunkId) {
var promises = [] // JSONP chunk loading for javascript var installedChunkData = installedChunks[chunkId]
if (installedChunkData !== 0) {
// 0 means "already installed". // a Promise means "currently loading".
if (installedChunkData) {
promises.push(installedChunkData[2])
} else {
// setup Promise in chunk cache
var promise = new Promise(function (resolve, reject) {
installedChunkData = installedChunks[chunkId] = [
resolve,
reject,
]
})
promises.push((installedChunkData[2] = promise)) // start chunk loading
var script = document.createElement("script")
var onScriptComplete script.charset = "utf-8"
script.timeout = 120
if (__webpack_require__.nc) {
script.setAttribute("nonce", __webpack_require__.nc)
}
script.src = jsonpScriptSrc(chunkId) // create error before stack unwound to get useful stacktrace later
var error = new Error()
onScriptComplete = function (event) {
// avoid mem leaks in IE.
script.onerror = script.onload = null
clearTimeout(timeout)
var chunk = installedChunks[chunkId]
if (chunk !== 0) {
if (chunk) {
var errorType =
event &&
(event.type === "load" ? "missing" : event.type)
var realSrc =
event && event.target && event.target.src
error.message =
"Loading chunk " +
chunkId +
" failed.\n(" +
errorType +
": " +
realSrc +
")"
error.name = "ChunkLoadError"
error.type = errorType
error.request = realSrc
chunk[1](error)
}
installedChunks[chunkId] = undefined
}
}
var timeout = setTimeout(function () {
onScriptComplete({ type: "timeout", target: script })
}, 120000)
script.onerror = script.onload = onScriptComplete
document.head.appendChild(script)
}
}
return Promise.all(promises)
} // 设置webpackJsonp
var jsonpArray = (window["webpackJsonp"] = window["webpackJsonp"] || [])
var oldJsonpFunction = jsonpArray.push.bind(jsonpArray)
jsonpArray.push = webpackJsonpCallback
jsonpArray = jsonpArray.slice()
for (var i = 0; i < jsonpArray.length; i++)
webpackJsonpCallback(jsonpArray[i])
var parentJsonpFunction = oldJsonpFunction // 异步加载的模块,加载好后,执行webpackJsonp的push方法
;(window["webpackJsonp"] = window["webpackJsonp"] || []).push([
[0],
{
/***/ "./vendor/sum.js": /***/ function (
module,
__webpack_exports__,
__webpack_require__
) {
"use strict"
__webpack_require__.r(__webpack_exports__)
/* harmony export (binding) */ __webpack_require__.d(
__webpack_exports__,
"sum",
function () {
return sum
}
)
function sum(a, b) {
return a + b
} /***/
},
},
])

webpack编译后的代码如何在浏览器执行的更多相关文章

  1. php中,如何将编译后的代码,反编译回去。

    编译后 <?php /*********************/ /* */ /* Version : 5.1.0 */ /* Author : RM */ /* Comment : 0712 ...

  2. 分析 webpack 打包后的代码

    写在前面的:使用的 webpack 版本 3.0.0 一.开始 1. 准备 当前只创建一个文件 index.js,该文件作为入口文件,代码如下. console.log('hello, world') ...

  3. KEIL MDK编译后的代码量和RAM使用详解

    一般 MCU 包含的存储空间有:片内 Flash 与片内 RAM,RAM 相当于内存,Flash 相当于硬盘.编译器会将一个程序分为好几个部分,分别存储在 MCU 不同的存储区.Keil 工程在编译完 ...

  4. webpack: webpack简单打包后的代码(1)

    源码 本文研究的源码地址为:https://github.com/collect-webpack/practice/tree/master/webpack-01 在本研究的前提是 entry 的配置为 ...

  5. JD-GUI反编译后代码逻辑分析

    一,用jd-gui.exe等工具查看源代码.如何你不会,可以参看此文章: http://blog.csdn.net/hp_2008/article/details/8207879 可以到以下连接下载可 ...

  6. React系列文章:Babel编译JSX生成代码

    上次我们总结了React代码构建后的Webpack模块组织关系,今天来介绍一下Babel编译JSX生成目标代码的一些规则,并且模拟整个生成的过程. 我们还是拿最简单的代码举例: import {gre ...

  7. Global文件编译发布,代码不执行的问题与解决

    问题:在Application_BeginRequest添加防止跨站点注入的过滤代码,VS2005编译成DLL发布后发现代码不会被执行: 环境:windows server 2008 r2 x64位  ...

  8. git 找回 git reset --hard HEAD 后的代码

    下面方法只针对当你本地代码做了 git add 或则 git commit 后又手贱的重置本地代码到上一个版本,导致本地代码丢失的情况. 如果你没有 git add 命令,而直接 git reset ...

  9. webpack 编译完成执行代码

    接收一个项目,由于目录结构的问题,每次编译完成后就需要去修改编译后的 HTML 文件中引用的其它文件的路径. 所以想在编译完成后使用 node 来操作文件修改路径. 然后在 webpack 官网找到了 ...

随机推荐

  1. Python+pytest知识点回顾

    pip install pytest pytest 单元测试框架 pytest高于unittest测试框架 unittest测试类需要继承unittest.TestCase类 pytest不需要继承, ...

  2. npm 安装、卸载模块

    npm安装模块 [npm install xxx]利用 npm 安装xxx模块到当前命令行所在目录:[npm install -g xxx]利用npm安装全局模块xxx:本地安装时将模块写入packa ...

  3. python里面的垃圾回收机制

    文章链接:https://www.jianshu.com/p/1e375fb40506 Garbage collection(GC) 现在的高级语言如java,c#等,都采用了垃圾收集机制,而不再是c ...

  4. macOS下将可执行文件索引位置增添到PATH中

    一.shell中可执行文件的两种执行方式 (1)绝对路径 比如,打开电脑上安装的python3,使用绝对路径方式打开为: /usr/local/bin/python3 (2)使用PATH 将pytho ...

  5. Python入门 -- 001

    在Windows系统下安装python: 从Python的官方网站(http://www.python.org/)下载最新版的程序安装包. 安装完成后设置路径,使得在Windows系统的CMD中能够通 ...

  6. Tr0ll靶机

    一.主机探测 二.信息收集 进入21端口 发现文件并下载 下载文件 作为字典进行登录爆破 用字典爆破 ssh登录 查找信息   /etc/init.d/ssh start scp root@192.1 ...

  7. MERCY靶机

    仅供个人娱乐 靶机信息 下载地址:https://drive.google.com/uc?id=1YzsW1lCKjo_WEr6Pk511DXQBFyMMR14y&export=downloa ...

  8. 三年Android开发,竟只会增删改查,被面试官一顿怼!

    最近看到某公司面试官发的这样一个帖子: 我面试了一个有三年Android开发经验的小伙子,也是我有史以来给别人面试时间最短的一次,不到十分钟就结束了,原因很简单,底子太差只会curd,很多技术性的问题 ...

  9. alpakka-kafka(8)-kafka数据消费模式实现

    上篇介绍了kafka at-least-once消费模式.kafka消费模式以commit-offset的时间节点代表不同的消费模式,分别是:at-least-once, at-most-once, ...

  10. 面试官:MySQL 有哪些锁??

    大家好,我是小林. 这次,来说说 MySQL 的锁,主要是 Q&A 的形式,看起来会比较轻松. 不多 BB 了,发车! 在 MySQL 里,根据加锁的范围,可以分为全局锁.表级锁和行锁三类. ...