webpack 用于编译 javascript
模块, 能够把文件格式编译成咱们想要的静态文件格式, 可是处理的过程并非所有由 webpack
自己完成, webpack
只是提供了一个打包机制, 对于各种文件的打包处理须要使用相对应的 预处理模块 loader
来处理, 做为一种机制 webpack
会帮助各类 loader
提供识别入口目录、入口文件、 输出目录, 输出文件。javascript
首先咱们试着打包一个只包含 console.log('hello world')
的 js
文件。java
webpack
环境# 新建 demo 目录
mkdir webpack-demo cd webpack-demo
# 初始化目录
npm init -y
# 本地安装 webpack 工具
npm install webpack webpacl-cli --save-dev
# webpack 默认的入口文件是 .src/index.js 建立 src 目录和 index.js 文件
mkdir src
echo “console.log('hello world')” > src/index.js
# 执行 webpack 命令 须要查看打包后文件, 这里使用 development 模式
npx webpack --mode development
复制代码
因为打包后的文件比较繁琐, 这里咱们简化一下打包后的文件webpack
(function(modules) {
var installedModules = {}
function __webpack_require__(moduleIid) {
}
return __webpack_require__(__webpack_require__.s = "./src/index.js")
})({
"./src/index.js": (function(module, exports) {
eval("console.log('test webpack entry')");
})
})
复制代码
打包后的文件含有大量的注释和
webpack
自己的变量, 为了方便分析能够把这些注释和 相似__webpack_require__.s
的复制语句所有删掉web
从上面的代码能够看到,npm
webpack
打包后的代码经过一个 IIFE
自执行函数, 这个函数接收一个对象参数, 这个对象的 key
为入口文件的目录, value
是一个执行入口文件里面代码的函数modules
传递给 IIFE
函数IIFE
函数里面声明了一个变量 installedModules
用来存放缓存, 一个函数 __webpack_require__
, 用来转化入口文件里面的代码IIFE
最终把 modules
里面的的 key
传递给 __webpack_require__
函数并返回。咱们进一步看 __webpack_require__
函数都作了什么。缓存
__webpack_require__
分析function (modules) {
var installedModules = {}
function __webpack_require__ (moduleId) {
if(installedModules[moduleId]) {
return installedModules[moduleId].exports
}
var module = installedModules[moduleId] = {
i: moduleId,
l:false,
exports: {}
}
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__)
module.l = true
return module.exports
}
}
复制代码
__webpack_require__
函数接收 ./src/index.js
installedModules
中是否包含 key
为 ./src/index.js
的对象, 若是存在直接返回这个对象中的 exports
i
l
exports
modules[moduleId].call
调用 IIFE
参数的 value
函数, 并把 value
对应的函数中的 this
指向赋值给了 module.exports
, 后面的 call
方法的后面三个参数为 value
对应函数的参数module.exports
, 这里的 module.exports
在第四步的时候已赋值为 IIFE
参数对象中的 value
对应的函数。因此能够看出来。 函数 __webpack_require__
实际返回的就是 IIFE
参数对象中的 value
对应的函数, 也就是 eval("\nconsole.log('test webpack entry')\n\n\n//# sourceURL=webpack:///./src/index.js?")
,bash
当咱们运行 webpack
打包后的文件的时候执行的是 "console.log('test webpack entry')"
函数
eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。工具
上面讲的打包过程入口文件中并无引用其余的代码模块, 当入口文件中引用其余的模块的时候, webpack
的打包过程也和上述过程类似。ui
在 ./src/
下新建 main.js
module.exports = () => {
console.log('main module')
}
复制代码
在 ./src/index.js
中引入 main.js
const main = reuiqre('./main.js')
console.log('webpack index entry')
main()
复制代码
运行 npx webpack
打包后的文件
IIFE
参数的变化(function (mudoles) {
})({
'./src/index.js': (function(module,exports, __webpack_require__) {
eval("const main = __webpack_require__(/*! ./main.js */ \"./src/main.js\")\r\nconsole.log('test webpack entry')\r\n\n\n//# sourceURL=webpack:///./src/index.js?");
}),
'./src/main.js': (function(module, exports) {
eval("console.log('main module')\n\n//# sourceURL=webpack:///./src/main.js?");
})
})
复制代码
若是入口文件中引用了其余模块的文件,将会把这些模块添加到 IIFE
的参数对象中, key
为模块的路径, value
执行该模块代码的函数。
IIFE
函数执行逻辑的变化function (modules) {
var installedModules = {}
function __webpack_require__ (moduleId) {
if (installedModules[moduleId]) {
return installedMOdules[mudoleId].exports
}
var module = installedModuled[moduleId] = {
i: moduleId,
l: false,
exports: {}
}
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__)
return module.exports
}
return __webpack_require__(__webpack_require__.s = "./src/index.js")
}
复制代码
上面的代码中依旧返回了以 ./src/index.js
为参数的函数。 可是函数里面的逻辑发生了改变。
installedModules
变量存放缓存./src/index.js
传入 __webpack_require__
函数./src/index.js
不在缓存中, 往下执行module
并在缓存中存放一以 ./src/index.js
为 key
的对象modules[moduleId]
函数,并指明 做用域和参数 也就是function(module,exports, __webpack_require__) {
eval("const main = __webpack_require__(/*! ./main.js */ \"./src/main.js\")\r\nconsole.log('test webpack entry')\r\n\n\n//# sourceURL=webpack:///./src/index.js?")}
复制代码
module.exports
, 因为在第五步调用 modules['./src/index.js']
函数的时候, 已经把 module.exports
做为了函数的 this
做用域, 因此这时 module.exports
实际就是 modules['./src/index.js']
执行的函数。eval
代码中使用了一个函数 __webpack_require__
, 这个函数就是在第五步 modules[moduleId].call(module.exports, module, module.exports, __webpack_require__)
的最后一个参数 __webpack_require__
, 这时继续调用 __webpack__require__
函数并传入 ./src/main.js
./src/main.js
传入 __webpack_require__
中, 依旧不在缓存, 再次声明一个变量 module
并在缓存中新增一个 key
为 ./src/main.js
的对象。modules[moduleId].call
这时调用 IIFE
参数对象中 key
为 ./src/main.js
的函数:(function(module, exports) {
eval("console.log('main module')\n\n//# sourceURL=webpack:///./src/main.js?");
})
复制代码
module.export
, 同第6步类似这时的 module.exports
就是 modules[./src/main.js]
对应的函数。eval
和注释):const main = console.log('main module')
console.log(test webpack entry)
复制代码