Webpack-源码一,使用require加载并打包模块
来源:互联网 发布:python append extend 编辑:程序博客网 时间:2024/06/17 22:24
最近有同学致力于写一个脚手架工具,在研究webpack源码,问了我几个问题,然而我完全不能解答。于是开始研究webpack。
webpack做的事情主要是实现前端模块化(即:让前端也可以像node端一样适用require方法加载模块)和借助插件实现编译、热加载等功能。webpack源码系列第一部分,就分享最简单的内容——如何使用require方法加载模块并打包。
__webpack_require__方法
待打包的文件bundle_require.js
// bundle_require.jsconsole.log('success');
仅使用最简单的打包,不使用插件。打包后的文件index.bundle.js
// index.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] = {/******/ exports: {},/******/ id: moduleId,/******/ loaded: false/******/ };/******/ // Execute the module function/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);/******/ // Flag the module as loaded/******/ module.loaded = 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;/******/ // __webpack_public_path__/******/ __webpack_require__.p = "/bundle";/******/ // Load entry module and return exports/******/ return __webpack_require__(0);/******/ })/************************************************************************//******/ ([/* 0 *//***/ function(module, exports, __webpack_require__) { 'use strict'; __webpack_require__(1);/***/ },/* 1 *//***/ function(module, exports) { 'use strict'; /*(function(a){ console.log(a.name); }) ({name: 'hello'})*/ console.log('success');/***/ }/******/ ]);
bundle文件中是一个立即执行函数,形如(function(modules){})([module_1, module_2, ...])
形参modules
对应的实参为一个模块数组[module_1, module_2, ...]
,该模块数组的每个成员都是使用require
加载的一个模块,每个被加载的模块都被封装成一个函数。
var installedModules = {};
是加载模块的缓存,如果已经加载过无需再次加载。
__webpack_require__
方法通过installedModules
对象缓存第一次加载的模块,通过modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
执行形参中的各个模块。使用call
是因为为了确保每个module中的this
指向的是module本身。然后给它传__webpack_require__
函数是想让module有加载其他module的能力。
模块间有简单依赖的情况
模块依赖:bundle_require.js
依赖dependency.js
// bundle_require.jsvar dependency = require('./dependency.js');console.log(dependency.name);console.log('success');
// dependency.jsmodule.exports = { name: 'hello'}
打包后的文件index.bundle.js
// index.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] = {/******/ exports: {},/******/ id: moduleId,/******/ loaded: false/******/ };/******/ // Execute the module function/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);/******/ // Flag the module as loaded/******/ module.loaded = 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;/******/ // __webpack_public_path__/******/ __webpack_require__.p = "/bundle";/******/ // Load entry module and return exports/******/ return __webpack_require__(0);/******/ })/************************************************************************//******/ ([/* 0 *//***/ function(module, exports, __webpack_require__) { 'use strict'; __webpack_require__(1);/***/ },/* 1 *//***/ function(module, exports, __webpack_require__) { 'use strict'; var dependency = __webpack_require__(2); console.log(dependency.name); console.log('success');/***/ },/* 2 *//***/ function(module, exports) { 'use strict'; module.exports = { name: 'hello' };/***/ }/******/ ]);
实参数组的第一个成员是bundle_require.js
,第二个成员是dependency.js
。同时,在第一个成员函数中,使用__webpack_require__(2)
加载下一个模块,形成链式调用。
多个入口文件的情况
需要注意,打包的文件中moudleId是不会重复的,如果有两个入口文件的情况,则入口模块id都为0,其他依赖模块id不重复。
index.js
为入口文件一,index_two.js
为入口文件二,它们共同引用common.js
。此外,入口文件一还引用dependency.js
。
// index.jsvar dependency = require('./src/require/dependency.js');var common = require('./src/require/common.js');console.log('index: ', dependency.name, common.name);
// index_two.jsvar common = require('./src/require/common.js');console.log('index_two', common.name);
// common.jsmodule.exports = { name: 'common'}
// dependency.jsmodule.exports = { name: 'dependency'}
打包以后
// index.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] = {/******/ exports: {},/******/ id: moduleId,/******/ loaded: false/******/ };/******/ // Execute the module function/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);/******/ // Flag the module as loaded/******/ module.loaded = 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;/******/ // __webpack_public_path__/******/ __webpack_require__.p = "/bundle";/******/ // Load entry module and return exports/******/ return __webpack_require__(0);/******/ })/************************************************************************//******/ ([/* 0 *//***/ function(module, exports, __webpack_require__) { 'use strict'; var dependency = __webpack_require__(1); var common = __webpack_require__(2); console.log('index: ', dependency.name, common.name);/***/ },/* 1 *//***/ function(module, exports) { 'use strict'; module.exports = { name: 'dependency' };/***/ },/* 2 *//***/ function(module, exports) { 'use strict'; module.exports = { name: 'common' };/***/ }/******/ ]);
分别加载两个模块,id为1和2,入口文件id为0.
// index_two.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] = {/******/ exports: {},/******/ id: moduleId,/******/ loaded: false/******/ };/******/ // Execute the module function/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);/******/ // Flag the module as loaded/******/ module.loaded = 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;/******/ // __webpack_public_path__/******/ __webpack_require__.p = "/bundle";/******/ // Load entry module and return exports/******/ return __webpack_require__(0);/******/ })/************************************************************************//******/ ([/* 0 *//***/ function(module, exports, __webpack_require__) { 'use strict'; var common = __webpack_require__(2); console.log('index_two', common.name);/***/ },/* 1 */,/* 2 *//***/ function(module, exports) { 'use strict'; module.exports = { name: 'common' };/***/ }/******/ ]);
只加载一个模块,其id为2,入口文件id为0。
这就是说,每个模块都有一个全局唯一的id,当重复require模块时,会使用第一次加载时的id。
其实,入口参数是字符串不管是多入口还是单入口,最后都会将入口模块的导出项导出,没有导出项就导出{},而入口参数是数组,就会将最后一个模块导出(webpackg官网有说明)。
使用CommonsChunkPlugin的情况
上面的依赖情况下,index.js
和 index_two.js
有公共依赖 common.js
,这种情况在开发中我们会使用一个插件CommonsChunkPlugin
,使用该插件的情况下,打包又是怎样的呢。
// index.bundle.jswebpackJsonp([0],[/* 0 *//***/ function(module, exports, __webpack_require__) { 'use strict'; var dependency = __webpack_require__(1); var common = __webpack_require__(2); console.log('index: ', dependency.name, common.name);/***/ },/* 1 *//***/ function(module, exports) { 'use strict'; module.exports = { name: 'dependency' };/***/ }]);
// index_two.bundle.jswebpackJsonp([1],[/* 0 *//***/ function(module, exports, __webpack_require__) { 'use strict'; var common = __webpack_require__(2); console.log('index_two', common.name);/***/ }]);
//common.js (打包公共模块的common.js)/******/ (function(modules) { // webpackBootstrap/******/ // install a JSONP callback for chunk loading/******/ var parentJsonpFunction = window["webpackJsonp"];/******/ window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules) {/******/ // add "moreModules" to the modules object,/******/ // then flag all "chunkIds" as loaded and fire callback/******/ var moduleId, chunkId, i = 0, callbacks = [];/******/ for(;i < chunkIds.length; i++) {/******/ chunkId = chunkIds[i];/******/ if(installedChunks[chunkId])/******/ callbacks.push.apply(callbacks, installedChunks[chunkId]);/******/ installedChunks[chunkId] = 0;/******/ }/******/ for(moduleId in moreModules) {/******/ modules[moduleId] = moreModules[moduleId];/******/ }/******/ if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);/******/ while(callbacks.length)/******/ callbacks.shift().call(null, __webpack_require__);/******/ if(moreModules[0]) {/******/ installedModules[0] = 0;/******/ return __webpack_require__(0);/******/ }/******/ };/******/ // The module cache/******/ var installedModules = {};/******/ // object to store loaded and loading chunks/******/ // "0" means "already loaded"/******/ // Array means "loading", array contains callbacks/******/ var installedChunks = {/******/ 2:0/******/ };/******/ // 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] = {/******/ exports: {},/******/ id: moduleId,/******/ loaded: false/******/ };/******/ // Execute the module function/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);/******/ // Flag the module as loaded/******/ module.loaded = true;/******/ // Return the exports of the module/******/ return module.exports;/******/ }/******/ // This file contains only the entry chunk./******/ // The chunk loading function for additional chunks/******/ __webpack_require__.e = function requireEnsure(chunkId, callback) {/******/ // "0" is the signal for "already loaded"/******/ if(installedChunks[chunkId] === 0)/******/ return callback.call(null, __webpack_require__);/******/ // an array means "currently loading"./******/ if(installedChunks[chunkId] !== undefined) {/******/ installedChunks[chunkId].push(callback);/******/ } else {/******/ // start chunk loading/******/ installedChunks[chunkId] = [callback];/******/ var head = document.getElementsByTagName('head')[0];/******/ var script = document.createElement('script');/******/ script.type = 'text/javascript';/******/ script.charset = 'utf-8';/******/ script.async = true;/******/ script.src = __webpack_require__.p + "" + chunkId + "." + ({"0":"index","1":"index_two"}[chunkId]||chunkId) + ".bundle.js";/******/ head.appendChild(script);/******/ }/******/ };/******/ // expose the modules object (__webpack_modules__)/******/ __webpack_require__.m = modules;/******/ // expose the module cache/******/ __webpack_require__.c = installedModules;/******/ // __webpack_public_path__/******/ __webpack_require__.p = "/bundle";/******/ })/************************************************************************//******/ ({/***/ 2:/***/ function(module, exports) { 'use strict'; module.exports = { name: 'common' };/***/ }/******/ });
index.bundle.js
和index_two.bundle.js
都使用了webpackJsonp
方法来加载模块。下面我们具体看看这个函数。
var parentJsonpFunction = window["webpackJsonp"];/******/ window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules) {/******/ // add "moreModules" to the modules object,/******/ // then flag all "chunkIds" as loaded and fire callback/******/ var moduleId, chunkId, i = 0, callbacks = [];/******/ for(;i < chunkIds.length; i++) {/******/ chunkId = chunkIds[i];/******/ if(installedChunks[chunkId])/******/ callbacks.push.apply(callbacks, installedChunks[chunkId]);/******/ installedChunks[chunkId] = 0;/******/ }/******/ for(moduleId in moreModules) {/******/ modules[moduleId] = moreModules[moduleId];/******/ }/******/ if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);/******/ while(callbacks.length)/******/ callbacks.shift().call(null, __webpack_require__);/******/ if(moreModules[0]) {/******/ installedModules[0] = 0;/******/ return __webpack_require__(0);/******/ }/******/ };/******/ // The module cache/******/ var installedModules = {};/******/ // object to store loaded and loading chunks/******/ // "0" means "already loaded"/******/ // Array means "loading", array contains callbacks/******/ var installedChunks = {/******/ 2:0/******/ };
chunkIds
是待加载模块的id组成的数组,moreModules
是待加载模块封装的函数组成的数组。webpackJsonp
的作用就是把installedChunks //存放公共模块
中的模块通过callbacks.shift().call(null, __webpack_require__);
加载,并把其余模块写进modules
对象,然后通过__webpack_require__(0)
,也就是上文中方式加载。
- Webpack-源码一,使用require加载并打包模块
- webpack的使用(3) ----模块加载器以及webpack打包多个包
- 【webpack】 模块加载器兼打包工具
- webpack构建react应用三:使用webpack Loaders 模块加载器(一)
- 使用require加载非AMD规范的js文件,并在模块中使用。
- 模块打包工具webpack的使用
- Webpack:模块打包原理
- 用webpack打包模块
- webpack 模块打包器
- webpack打包并将文件加载到指定的位置
- 学习React-Native(一):学习React,使用模块加载器webpack
- webpack模块加载介绍
- Require模块入门一
- 使用webpack打包第三方非模块插件
- webpack打包-模块分布解析
- vue项目优化之按需加载组件-使用webpack require.ensure
- vue项目优化之按需加载组件-使用webpack require.ensure
- vue项目优化之按需加载组件-使用webpack require.ensure
- sdut 3260 大数取模
- 运算放大器使用的6个注意事项
- 常用adb命令
- Ubuntu——段错误 核心已转储
- Android 获取屏幕分辨率
- Webpack-源码一,使用require加载并打包模块
- 2017年年初总结
- Glide使用 加载网络图片 圆形图片 圆角图片
- 从今天起,每天一篇,自学转行CS
- 文本域在线编辑功能的实现
- 利用Android自带的DownloadManager实现文件下载进行apk在线升级
- AngularJS中基于cookie的权限认证
- logmnr
- 人大经济论坛SAS入门到高级教程