探索webpack模块及webpack3新特性
发布时间 - 2026-01-11 03:18:19 点击率:次本文从简单的例子入手,从打包文件去分析以下三个问题:webpack打包文件是怎样的?如何做到兼容各大模块化方案的?webpack3带来的新特性又是什么?

一个简单的例子
webpack配置
// webpack.config.js
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
};
简单的js文件
// src/index.js
console.log('hello world');
webpack打包后的代码
一看你就会想,我就一行代码,你给我打包那么多???(黑人问号)
// dist/bundle.js
/******/ (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__.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, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // 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);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
console.log('hello world');
/***/ })
/******/ ]);
我们来分析一下这部分代码,先精简一下,其实整体就是一个自执行函数,然后传入一个模块数组
(function(modules) {
//...
})([function(module, exports) {
//..
}])
好了,传入模块数组做了什么(其实注释都很明显了,我只是大概翻译一下)
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache 缓存已经load过的模块
/******/ 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, //模块id
/******/ 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 为ES6 exports定义getter
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) { // 假如exports本身不含有name这个属性
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules 解决ES module和Common js module的冲突,ES则返回module['default']
/******/ __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配置下的公共路径
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports 最后执行entry模块并且返回它的暴露内容
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
console.log('hello world');
/***/ })
/******/ ]);
整体流程是怎样的呢
- 传入module数组
- 调用
__webpack_require__(__webpack_require__.s = 0)
构造module对象,放入缓存
调用module,传入相应参数modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); (这里exports会被函数内部的东西修改)
标记module对象已经加载完毕
返回模块暴露的内容(注意到上面函数传入了module.exports,可以对引用进行修改)
- 模块函数中传入
module, module.exports, __webpack_require__ - 执行过程中通过对上面三者的引用修改,完成变量暴露和引用
webpack模块机制是怎样的
我们可以去官网看下webpack模块
doc.webpack-china.org/concepts/mo…
webpack 模块能够以各种方式表达它们的依赖关系,几个例子如下:
- ES2015 import 语句
- CommonJS require() 语句
- AMD define 和 require 语句
- css/sass/less 文件中的 @import 语句。
- 样式(url(...))或 HTML 文件()中的图片链接(image url)
强大的webpack模块可以兼容各种模块化方案,并且无侵入性(non-opinionated)
我们可以再编写例子一探究竟
CommonJS
修改src/index.js
var cj = require('./cj.js');
console.log('hello world');
cj();
新增src/cj.js,保持前面例子其他不变
// src/cj.js
function a() {
console.log("CommonJS");
}
module.exports = a;
再次运行webpack
/******/ (function(modules) { // webpackBootstrap
//... 省略代码
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
let cj = __webpack_require__(1);
console.log('hello world');
cj();
/***/ }),
/* 1 */
/***/ (function(module, exports) {
function a() {
console.log("CommonJS");
}
module.exports = a;
/***/ })
/******/ ]);
我们可以看到模块数组多了个引入的文件,然后index.js模块函数多了个参数__webpack_require__,去引用文件(__webpack_require__在上一节有介绍),整体上就是依赖的模块修改了module.exports,然后主模块执行依赖模块,获取exports即可
ES2015 import
新增src/es.js
// src/es.js
export default function b() {
console.log('ES Modules');
}
修改src/index.js
// src/index.js
import es from './es.js';
console.log('hello world');
es();
webpack.config.js不变,执行webpack
/******/ (function(modules) { // webpackBootstrap
// ... 省略代码
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__es_js__ = __webpack_require__(1);
console.log('hello world');
Object(__WEBPACK_IMPORTED_MODULE_0__es_js__["a" /* default */])();
/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export (immutable) */ __webpack_exports__["a"] = b;
function b() {
console.log('ES Modules');
}
/***/ })
/******/ ]);
我们可以看到它们都变成了严格模式,webpack自动采用的
表现其实跟CommonJS相似,也是传入export然后修改,在主模块再require进来,
我们可以看到这个
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
这个干嘛用的?其实就是标记当前的exports是es模块,还记得之前的__webpack_require__.n吗,我们再拿出来看看
/******/ // getDefaultExport function for compatibility with non-harmony modules 解决ES module和Common js module的冲突,ES则返回module['default']
/******/ __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;
/******/ };
为了避免跟非ES Modules冲突?冲突在哪里呢?
其实这部分如果你看到babel转换ES Modules源码就知道了,为了兼容模块,会把ES Modules直接挂在exports.default上,然后加上__esModule属性,引入的时候判断一次是否是转换模块,是则引入module['default'],不是则引入module
我们再多引入几个ES Modules看看效果
// src/es.js
export function es() {
console.log('ES Modules');
}
export function esTwo() {
console.log('ES Modules Two');
}
export function esThree() {
console.log('ES Modules Three');
}
export function esFour() {
console.log('ES Modules Four');
}
我们多引入esTwo和esFour,但是不使用esFour
// src/index.js
import { es, esTwo, esFour} from './es.js';
console.log('hello world');
es();
esTwo();
得出
/******/ (function(modules) { // webpackBootstrap
// ...
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__es_js__ = __webpack_require__(1);
console.log('hello world');
Object(__WEBPACK_IMPORTED_MODULE_0__es_js__["a" /* es */])();
Object(__WEBPACK_IMPORTED_MODULE_0__es_js__["b" /* esTwo */])();
/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export (immutable) */ __webpack_exports__["a"] = es;
/* harmony export (immutable) */ __webpack_exports__["b"] = esTwo;
/* unused harmony export esThree */
/* unused harmony export esFour */
function es() {
console.log('ES Modules');
}
function esTwo() {
console.log('ES Modules Two');
}
function esThree() {
console.log('ES Modules Three');
}
function esFour() {
console.log('ES Modules Four');
}
/***/ })
/******/ ]);
嗯嗯其实跟前面是一样的,举出这个例子重点在哪里呢,有没有注意到注释中
/* unused harmony export esThree */ /* unused harmony export esFour */
esThree是我们没有引入的模块,esFour是我们引用但是没有使用的模块,webpack均对它们做了unused的标记,其实这个如果你使用了webpack插件uglify,通过标记,就会把esThree和esFour这两个未使用的代码消除(其实它就是tree-shaking)
AMD
我们再来看看webpack怎么支持AMD
新增src/amd.js
// src/amd.js
define([
],function(){
return {
amd:function(){
console.log('AMD');
}
};
});
修改index.js
// src/index.js
define([
'./amd.js'
],function(amdModule){
amdModule.amd();
});
得到
/******/ (function(modules) { // webpackBootstrap
// ... 省略代码
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [
__webpack_require__(1)
], __WEBPACK_AMD_DEFINE_RESULT__ = function(amdModule){
amdModule.amd();
}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [
], __WEBPACK_AMD_DEFINE_RESULT__ = function(){
return {
amd:function(){
console.log('AMD');
}
};
}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ })
/******/ ]);
先看amd.js整理一下代码
function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__,
__WEBPACK_AMD_DEFINE_RESULT__;
!(
__WEBPACK_AMD_DEFINE_ARRAY__ = [],
__WEBPACK_AMD_DEFINE_RESULT__ = function() {
return {
amd: function() {
console.log('AMD');
}
};
}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined &&
(module.exports = __WEBPACK_AMD_DEFINE_RESULT__)
);
})
简单来讲收集define Array然后置入返回函数,根据参数获取依赖
apply对数组拆解成一个一个参数
再看index.js模块部分
function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__,
__WEBPACK_AMD_DEFINE_RESULT__;
!(
__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(1)],
__WEBPACK_AMD_DEFINE_RESULT__ = function(amdModule) {
amdModule.amd();
}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined &&
(module.exports = __WEBPACK_AMD_DEFINE_RESULT__)
);
}
其实就是引入了amd.js暴露的{amd:[Function: amd]}
css/image?
css和image也可以成为webpack的模块,这是令人震惊的,这就不能通过普通的hack commonjs或者函数调用简单去调用了,这就是anything to JS,它就需要借助webpack loader去实现了
像css就是转换成一段js代码,通过处理,调用时就是可以用js将这段css插入到style中,image也类似,这部分就不详细阐述了,有兴趣的读者可以深入去研究
webpack3新特性
我们可以再顺便看下webpack3新特性的表现
具体可以看这里medium.com/webpack/web…
Scope Hoisting
我们可以发现模块数组是一个一个独立的函数然后闭包引用webpack主函数的相应内容,每个模块都是独立的,然后带来的结果是在浏览器中执行速度变慢,然后webpack3学习了Closure Compiler和RollupJS这两个工具,连接所有闭包到一个闭包里,放入一个函数,让执行速度更快,并且整体代码体积也会有所缩小
我们可以实际看一下效果(要注意的是这个特性只支持ES Modules,是不支持CommonJs和AMD的)
使用上面的例子,配置webpack.config.js,增加new webpack.optimize.ModuleConcatenationPlugin()
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
},
plugins: [
new webpack.optimize.ModuleConcatenationPlugin(),
]
};
打包
/******/ (function(modules) { // webpackBootstrap
// ... 省略代码
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
// CONCATENATED MODULE: ./src/es.js
function es() {
console.log('ES Modules');
}
function esTwo() {
console.log('ES Modules Two');
}
function esThree() {
console.log('ES Modules Three');
}
function esFour() {
console.log('ES Modules Four');
}
// CONCATENATED MODULE: ./src/index.js
// src/index.js
console.log('hello world');
es();
/***/ })
/******/ ]);
我们可以惊喜的发现没有什么require了,它们拼接成了一个函数,good!😃
Magic Comments
code splitting是webpack一个重点特性之一,涉及到要动态引入的时候,webpack可以使用 require.ensure去实现,后来webpack2支持使用了符合 ECMAScript 提案 的 import() 语法,但是它有个不足之处,无法指定chunk的名称chunkName,为了解决这个问题,出现了Magic Comments,支持用注释的方式去指定,如下
import(/* webpackChunkName: "my-chunk-name" */ 'module');
小结
webpack是一个强大的模块打包工具,在处理依赖、模块上都很优秀,本文从bundle.js文件分析出发去探索了不同模块方案的加载机制,初步去理解webpack,并且对webpack3特性进行阐述,当然,webpack还有很多地方需要去探索深究,敬请期待以后的文章吧~关于本文如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
# webpack3
# 新特征
# webpack模块
# 关于webpack2和模块打包的新手指南(小结)
# 详解react-webpack2-热模块替换[HMR]
# webpack配置sass模块的加载的方法
# 详解用webpack把我们的业务模块分开打包的方法
# Webpack常见静态资源处理-模块加载器(Loaders)+ExtractTextPlugin插件
# jQuery 移动端拖拽(模块化开发
# 触摸事件
# webpack)
# 我们可以
# 这部
# 是怎样
# 可以看到
# 是一个
# 加载
# 几个
# 如果你
# 新特性
# 这两个
# 注意到
# 都很
# 会把
# 的是
# 都是
# 这是
# 一个函数
# 我就
# 使用了
# 是在
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
,网页ppt怎么弄成自己的ppt?
手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?
JS去除重复并统计数量的实现方法
再谈Python中的字符串与字符编码(推荐)
Python文本处理实践_日志清洗解析【指导】
简单实现Android验证码
Claude怎样写约束型提示词_Claude约束提示词写法【教程】
javascript基本数据类型及类型检测常用方法小结
Win11应用商店下载慢怎么办 Win11更改DNS提速下载【修复】
Laravel如何使用Seeder填充数据_Laravel模型工厂Factory批量生成测试数据【方法】
php增删改查怎么学_零基础入门php数据库操作必知基础【教程】
Laravel怎么实现验证码功能_Laravel集成验证码库防止机器人注册
微信小程序 canvas开发实例及注意事项
Laravel storage目录权限问题_Laravel文件写入权限设置
高端智能建站公司优选:品牌定制与SEO优化一站式服务
详解Android——蓝牙技术 带你实现终端间数据传输
如何用JavaScript实现文本编辑器_光标和选区怎么处理
Android利用动画实现背景逐渐变暗
Zeus浏览器网页版官网入口 宙斯浏览器官网在线通道
高端云建站费用究竟需要多少预算?
Laravel怎么配置自定义表前缀_Laravel数据库迁移与Eloquent表名映射【步骤】
Laravel如何发送系统通知?(Notification渠道示例)
EditPlus中的正则表达式 实战(4)
php后缀怎么变mp4格式错误_修改扩展名提示格式不对怎么办【技巧】
百度输入法ai组件怎么删除 百度输入法ai组件移除工具
微信小程序 五星评分(包括半颗星评分)实例代码
Linux系统命令中tree命令详解
网站制作软件免费下载安装,有哪些免费下载的软件网站?
Laravel如何使用Eloquent ORM进行数据库操作?(CRUD示例)
Laravel如何安装Breeze扩展包_Laravel用户注册登录功能快速实现【流程】
Laravel数据库迁移怎么用_Laravel Migration管理数据库结构的正确姿势
教学论文网站制作软件有哪些,写论文用什么软件
?
Laravel如何优雅地处理服务层_在Laravel中使用Service层和Repository层
Laravel如何使用Facades(门面)及其工作原理_Laravel门面模式与底层机制
Laravel如何配置Horizon来管理队列?(安装和使用)
中山网站推广排名,中山信息港登录入口?
北京网页设计制作网站有哪些,继续教育自动播放怎么设置?
佐糖AI抠图怎样调整抠图精度_佐糖AI精度调整与放大细化操作【攻略】
齐河建站公司:营销型网站建设与SEO优化双核驱动策略
邀请函制作网站有哪些,有没有做年会邀请函的网站啊?在线制作,模板很多的那种?
Laravel如何处理JSON字段_Eloquent原生JSON字段类型操作教程
Python文件操作最佳实践_稳定性说明【指导】
如何用西部建站助手快速创建专业网站?
简历在线制作网站免费版,如何创建个人简历?
最好的网站制作公司,网购哪个网站口碑最好,推荐几个?谢谢?
移动端手机网站制作软件,掌上时代,移动端网站的谷歌SEO该如何做?
香港服务器如何优化才能显著提升网站加载速度?
Laravel PHP版本要求一览_Laravel各版本环境要求对照
laravel怎么使用数据库工厂(Factory)生成带有关联模型的数据_laravel Factory生成关联数据方法
WEB开发之注册页面验证码倒计时代码的实现

