webpack编译后的代码如何在浏览器执行
浏览器是无法直接使用模块之间的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编译后的代码如何在浏览器执行的更多相关文章
- php中,如何将编译后的代码,反编译回去。
编译后 <?php /*********************/ /* */ /* Version : 5.1.0 */ /* Author : RM */ /* Comment : 0712 ...
- 分析 webpack 打包后的代码
写在前面的:使用的 webpack 版本 3.0.0 一.开始 1. 准备 当前只创建一个文件 index.js,该文件作为入口文件,代码如下. console.log('hello, world') ...
- KEIL MDK编译后的代码量和RAM使用详解
一般 MCU 包含的存储空间有:片内 Flash 与片内 RAM,RAM 相当于内存,Flash 相当于硬盘.编译器会将一个程序分为好几个部分,分别存储在 MCU 不同的存储区.Keil 工程在编译完 ...
- webpack: webpack简单打包后的代码(1)
源码 本文研究的源码地址为:https://github.com/collect-webpack/practice/tree/master/webpack-01 在本研究的前提是 entry 的配置为 ...
- JD-GUI反编译后代码逻辑分析
一,用jd-gui.exe等工具查看源代码.如何你不会,可以参看此文章: http://blog.csdn.net/hp_2008/article/details/8207879 可以到以下连接下载可 ...
- React系列文章:Babel编译JSX生成代码
上次我们总结了React代码构建后的Webpack模块组织关系,今天来介绍一下Babel编译JSX生成目标代码的一些规则,并且模拟整个生成的过程. 我们还是拿最简单的代码举例: import {gre ...
- Global文件编译发布,代码不执行的问题与解决
问题:在Application_BeginRequest添加防止跨站点注入的过滤代码,VS2005编译成DLL发布后发现代码不会被执行: 环境:windows server 2008 r2 x64位 ...
- git 找回 git reset --hard HEAD 后的代码
下面方法只针对当你本地代码做了 git add 或则 git commit 后又手贱的重置本地代码到上一个版本,导致本地代码丢失的情况. 如果你没有 git add 命令,而直接 git reset ...
- webpack 编译完成执行代码
接收一个项目,由于目录结构的问题,每次编译完成后就需要去修改编译后的 HTML 文件中引用的其它文件的路径. 所以想在编译完成后使用 node 来操作文件修改路径. 然后在 webpack 官网找到了 ...
随机推荐
- maven解析依赖报错:Cannot resolve com.baomidou:mybatis-plus-generator:3.4.2
不能解析依赖: <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plu ...
- Leetcode:面试题 04.04. 检查平衡性
Leetcode:面试题 04.04. 检查平衡性 Leetcode:面试题 04.04. 检查平衡性 Talk is cheap . Show me the code . /** * Definit ...
- windows使用nvm管理node不同版本
最近项目需要升级,新技术需要的node版本较高,而新node不兼容旧版本node,而原项目仍需要继续维护,所以就需要在本地有多个版本的node,基本原理是在环境配置中修改系统变量node的版本文件夹路 ...
- P7324 [WC2021] 表达式求值
P7324 [WC2021] 表达式求值 闲话 WC2021 我只得了 20 分,三道题总共 20 分.我是下场了突然后知后觉这件事的,主要原因是我开了 C++11,然后 T1 T2 都没分了.在洛谷 ...
- powerdesigner连接postgresql数据库生成pdm及word文档
1.准备软件: powerdesigner165与postgresql的驱动:psqlodbc_11_01_0000 2.安装并破解完成powerdesigner165 参看链接:https://ww ...
- 手写RPC
服务端代码 package com.peiyu.rpcs.bios; import java.io.IOException; public interface IRpcServers { void s ...
- Spring Data Commons 远程命令执行漏洞(CVE-2018-1273)
影响版本 Spring Framework 5.0 to 5.0.4 Spring Framework 4.3 to 4.3.14 poc https://github.com/zhzyker/exp ...
- [CISCN2019 华北赛区 Day2 Web1]Hack World(二分法写布尔注入脚本)
记一道布尔注入的题,存在过滤字符. 从题目看应该是一道注入题.提示存在flag表flag列. 输入1和2的返回结果不一样,可能是布尔注入. 简单用万能密码尝试了一下.提示SQL Injection C ...
- 说实话,Android开发月薪3W,谁不酸呢?
近期有个网友在某匿名区晒字节跳动Offfer,毕业一年月薪3W,引发众多读者羡慕,纷纷留言酸了.酸了.但进大厂的要求还是蛮高的,需要在技术实力上有一定的积累,今天给大家分享一份高质量笔记, 助力大家技 ...
- [TensorFow2.0]-MNIST手写数字识别
本人人工智能初学者,现在在学习TensorFlow2.0,对一些学习内容做一下笔记.笔记中,有些内容理解可能较为肤浅.有偏差等,各位在阅读时如有发现问题,请评论或者邮箱(右侧边栏有邮箱地址)提醒. 若 ...