写在前面
笔记内容大多出自于拉勾教育大前端高薪训练营的教程,因此也许会和其他文章雷同较多,请担待。
webpack
- 打包后的文件就是一个自调用函数,当前函数调用时传入一个对象
- 这个对象我们为了方便将之称为是模块定义,他就是一个键值对
- 这个键名就是当前被加载模块的文件名和某个目录的拼接
- 这个键值就是一个函数,和node.js里的模块加载有一些类似,会将被加载模块中的内容包裹于一个函数中
- 这个函数在将来某个时间点上会被调用,同时接收一定的参数,利用这些参数就可以实现模块的加载操作
- 默认commonJS规范
- 两个模块的规范可以不同,但一个模块内只能用一种规范,否则会报错 -> Uncaught TypeError: Cannot assign to read only property ‘exports’ of object ‘#’
$ npm i webapck webpack-cli --dev
$ md webpack.config.js
// webpack.config.js
const path = require('path')
module.exports = {
mode: 'development', // 打包模式 development / production
entry: './src/index.js', // 打包入口文件
output: {
filename: 'bundle.js', // 输出文件名
path: path.join(__dirname, 'dist'), // 输出路径,因为必须绝对路径,所以使用path来生成绝对路径
publicPath: 'dist/' // 网站的根目录,因为在未打包index.html时已完成打包的资源文件会进入dist,但对于没有打包的index.html来说并不会改变引用路径,所以需要重新指定资源文件的路径,从dist下面寻找
},
module: {
rules: [
{
test: /.css$/,
loader: [
'style-loader', // 将css文件打包成的js文件进行引用
'css-loader' // 将css文件打包成js文件
]
},
/* ---------------- start ---------------- */
// 将小文件交给url-loader去转换为Base64,优化加载速率
// 将大文件交给file-loader去生成新资源并修改路径,因为大文件转换为Base64之后也许会更大
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: 'file-loader' // 该loader可以处理图片、音视频、字体的路径
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: {
loader: 'url-loader', // 该loader可以处理图片、音视频、字体的本体,将其转换为Base64
options: {
limit: 10 * 1024 // 10kb
}
}
}
/* ---------------- end ---------------- */
]
}
}
简单打包两个文件,其中index.js引用了header.js
webpack 原理
// dist/main.js
(function (modules) {
// 当模块已被加载则会放入缓存
var installedModules = {
};
// 核心作用是返回模块的exports
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
}
// 将传入的模块缓存到属性 m 上 - modules
__webpack_require__.m = modules
// 将已加载模块缓存到属性 c 上 - cache
__webpack_require__.c = installedModules
// 判断对象身上是否有某属性 - hasOwnProperty
__webpack_require__.o = function (object, property) {
return Object.prototype.hasOwnProperty.call(object, property)
}
// 为exports定义属性 - defineProperty
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, {
enumerable: true,
get: getter
})
}
}
// 为exports挂载__esModule: true属性 - redefine
__webpack_require__.r = function (exports) {
// 判断是否是es6,简而言之就是为了判断是否是ES Module
// Object.property.toString.call(exports) -> Module
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, {
value: 'Module'
})
}
Object.defineProperty(exports, '__esModule', {
value: true
})
}
__webpack_require__.t = function (value, mode) {
if (mode & 1) value = __webpack_require__(value)
if (mode & 8) return value
if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value
var ns = Object.create(null)
__webpack_require__.r(ns)
Object.defineProperty(ns, 'default', {
enumerable: true,
value: value
})
if (mode & 2 && typeof value != 'string') {
for (var key in value) {
__webpack_require__.d(ns, key, function (key) {
return value[key]
}.bind(null, key)
)
}
}
return ns
}
__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
}
// path
__webpack_require__.p = ""
return __webpack_require__(__webpack_require__.s = "./src/index.js")
})
index.js使用require导入模块/module.exports导出模块(CommonJS) <------> header.js使用module.export导出模块(CommonJS)
// index.js
const header = require('./header')
console.log('index 内容 -> next:', header)
module.exports = 'here entry'
// header.js
console.log('header 内容')
module.exports = 'here header'
// dist/main.js
({
"./src/header.js":
(function (module, exports) {
console.log('header 内容')
module.exports = 'here header'
}),
"./src/index.js":
(function (module, exports, __webpack_require__) {
const header = __webpack_require__("./src/header.js")
console.log('index 内容 -> next:', header)
module.exports = 'here entry'
})
})
index.js使用require导入模块/module.exports导出模块(CommonJS) <------> header.js使用export default导出模块(ES Module)
// index.js
const header = require('./header')
console.log('index 内容 -> next:', header)
module.exports = 'here entry'
// header.js
console.log('header 内容')
export default 'here header'
// dist/main.js
({
"./src/header.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict"
__webpack_require__.r(__webpack_exports__)
console.log('header 内容')
__webpack_exports__["default"] = ('here header')
}),
"./src/index.js":
(function (module, exports, __webpack_require__) {
const header = __webpack_require__("./src/header.js")
console.log('index 内容 -> next:', header)
module.exports = 'here entry'
})
})
index.js使用import导入模块/export default导出模块(ES Module) <-----> header.js使用module.export导出模块(CommonJS)
// index.js
import header from './header'
console.log('index 内容 -> next:', header)
export default 'here entry'
// header.js
console.log('header 内容')
module.exports = 'here header'
// dist/main.js
({
"./src/header.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict"
__webpack_require__.r(__webpack_exports__)
console.log('header 内容')
__webpack_exports__["default"] = ('here header')
}),
"./src/index.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict"
__webpack_require__.r(__webpack_exports__)
var _header__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/header.js")
console.log('index 内容 -> next:', _header__WEBPACK_IMPORTED_MODULE_0__["default"])
__webpack_exports__["default"] = ('here entry')
})
})
index.js使用import导入模块/export const导出模块(ES Module) <-------> header.js使用export default导出模块(ES Module)
// index.js
import header from './header'
console.log('index 内容 -> next:', header)
export const message = 'here entry'
// header.js
console.log('header 内容')
export default 'here header'
// dist/main.js
({
"./src/header.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict"
__webpack_require__.r(__webpack_exports__)
console.log('header 内容')
__webpack_exports__["default"] = ('here header')
}),
"./src/index.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict"
__webpack_require__.r(__webpack_exports__)
__webpack_require__.d(__webpack_exports__, "message", function () {
return message
})
var _header__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/header.js")
console.log('index 内容 -> next:', _header__WEBPACK_IMPORTED_MODULE_0__["default"])
const message = 'here entry'
})
})
- import()可以实现模块的懒加载
- 懒加载的核心原理就是jsonp
- webpack_require.t方法可以针对内容进行不同的处理(取决于二进制位运算符的布尔值)
懒加载
webpack 原理
(function (modules) {
function webpackJsonpCallback(data) {
var chunkIds = data[0]
var moreModules = data[1]
var moduleId, chunkId, i = 0, resolves = [];
for (; i < chunkIds.length; i++) {
chunkId = chunkIds[i]
if (Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
resolves.push(installedChunks[chunkId][0])
}
installedChunks[chunkId] = 0
}
for (moduleId in moreModules) {
if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
modules