浏览器是无法直接使用模块之间的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. 基于 Blazor 打造一款实时字幕

    早先在录制视频的时候一直使用的是 obs-auto-subtitle 作为实时字幕展示功能.不过这个是以 OBS 插件的形式存在,不管是语言和功能上都有一定的限制.故而使用 Blazor server ...

  2. CSAPP:datalab实验记录

    CSAPP:datalab实验记录 bitXor /* * bitXor - x^y using only ~ and & * Example: bitXor(4, 5) = 1 * Lega ...

  3. 标准化R包开发流程

    3个武器: devtools:各种开发小工具的合集,让开发变得简单,非常实用 roxygens:通过注释的方式,生成文档,远离LaTex的烦恼 testthat:单元测试,让R包稳定.健壮.减少升级的 ...

  4. java对接c++发布的webservice接口,其中参数类型有base64Binary格式(无需将图片数据转化为c++中的结构体)

    接口名称: std::string SendVehiclePass(std::string VehiclePassInfo, struct xsd__base64Binary PlatePicData ...

  5. 使用Elastic Job的分片配置加速任务执行和提高资源利用率

    上一篇,我们介绍了如何使用Elastic Job实现定时任务.解决了使用@Scheduled来实现时候存在的竞争问题,同时也实现了定时任务的高可用执行. 然而,还有一类问题是我们在做定时任务时候容易出 ...

  6. 【Lucas组合数定理+中国剩余定理】Mysterious For-HDU 4373

    Mysterious For-HDU 4373 题目描述 MatRush is an ACMer from ZJUT, and he always love to create some specia ...

  7. java中的集合类学习(三)

    JAVA中有许多的集合,常用的有List,Set,Queue,Map. 1.其中List,Set,Queue都是Collection(集合),其每个元素都是单独的一个对象,如List<Strin ...

  8. 第三篇 -- SpringBoot打包成jar包

    本篇介绍怎么将SprintBoot项目打包成jar包. 第一步:点击IDEA右侧的maven. 第二步:双击package,然后就会开始打包,当出现build success时,就打包成功了,一般在t ...

  9. Flask 之linux部署

    1.装python > `[root ~]# yum install gcc [root ~]# wget https://www.python.org/ftp/python/3.6.5/Pyt ...

  10. C语言复习(一)

    类型为void*的指针代表对象的地址,而不是类型 如果需要使用另一个源文件中定义的变量,那么只需要在定义变量前加上extern关键字 ex: extern int x;//x在其他文件中定义 左值表达 ...