浏览器是无法直接使用模块之间的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. NOIp 2020

    游记 Day-1 我已经开始慌了. 不知道前路如何.不想回文化课.唯一一次机会,可是这几天却一直在颓,不颓就慌. 没心思写题,导致这几天看的题啥都不会.不知道考试当天又会出什么幺蛾子. 啊啊啊,烦. ...

  2. 前端基础js(四)

    一. js [1] html:用于显示页面 [2] css:用于描述页面的样式 [3] javaScript:用于描述页面的行为 二.js中三大部分内容 [1] 基本语法:函数.对象.事件类型(变量, ...

  3. npm 安装、卸载模块

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

  4. Skywalking-03:Skywalking本地调试

    live-demo 与 skywalking 源码联调 构建项目 找一个目录执行如下命令 git clone https://github.com/apache/skywalking.git # cl ...

  5. 第4天 JavaDoc生成文档&Java流程控制(第一节:用户交互Scanner)

    JavaDoc生成文档 javadoc命令是用来生成自己的API文档 参数信息: @author 作者名 @version 版本号 @since 指明需要最早使用的jdk版本 @param 参数名 @ ...

  6. DNS的原理和解析过程

    DNS的解析原理和过程: 在Internet上域名和IP是对应的,DNS解析有两种:一种是正向解析,另外一种是反向解析. 正向解析:正向解析就是将域名转换成对应的 IP地址的过程,它应用于在浏览器地址 ...

  7. leetcode 987 二叉树的垂序遍历

    题目解析 题目意思很简单,就是给你一个二叉树,然后告诉你每个节点都是有位置信息的,即每个节点可以用(x,y)来表示.然后节点位置信息为(x,y)的节点的左节点位置为(x+1,y-1),右节点位置为(x ...

  8. VUE-router-跳转

    跳转的 // 字符串 this.$router.push('/home/first') // 对象 this.$router.push({ path: '/home/first' }) // 命名的路 ...

  9. ondblclick="return showCodeList 分析思路

    <Div id="divApproveRejectReasonInput" style="display:none"><input class ...

  10. Linux[Manjaro] 小新15笔记本AMD ryzen锐龙4800U,在安装系统后出现的随即死机冻屏问题

    Linux[Manjaro] 小新15AMD ryzen锐龙4800U,在安装系统后出现的随即死机冻屏问题解决办法 年初尝试将manjaro安装在我的笔记本上就存在这个问题,也一度将我劝退.系统安装在 ...