webpack
webpack 是一个 JavaScript 应用程序的模块打包工具。 和 rollup 不同的是,webpack 更关注应用程序的开发体验,不断丰富开发特性,例如模块热替换、Module Federation。
webpack 打包产物
webpack 5 打包区分mode配置:
- 在
development
模式可以查看打包产物和源文件的关系,并使用内置的模块加载器来加载这些产物代码。 - 在
production
模式去除了不必要的模块加载器,默认开启代码压缩等代码优化。
下面以这份源码展示webpack 5默认配置的打包产物
js
// index.js
import { sayHello } from './mod'
sayHello()
// mod.js
export function sayHello(){
console.log('hello')
}
mode: development
js
(() => {
// webpackBootstrap
'use strict'
var __webpack_modules__ = {
'./src/index.js':
/*!**********************!*\
!*** ./src/index.js ***!
\**********************/
(
__unused_webpack_module,
__webpack_exports__,
__webpack_require__
) => {
eval(
'__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _mod__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./mod */ "./src/mod.js");\n\n(0,_mod__WEBPACK_IMPORTED_MODULE_0__.sayHello)()\n\n//# sourceURL=webpack://wbpack/./src/index.js?'
)
},
'./src/mod.js':
/*!********************!*\
!*** ./src/mod.js ***!
\********************/
(
__unused_webpack_module,
__webpack_exports__,
__webpack_require__
) => {
eval(
"__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ sayHello: () => (/* binding */ sayHello)\n/* harmony export */ });\nfunction sayHello(){\n console.log('hello')\n}\n\n//# sourceURL=webpack://wbpack/./src/mod.js?"
)
},
}
/************************************************************************/
// The module cache
var __webpack_module_cache__ = {}
// The require function
function __webpack_require__(moduleId) {
// Check if module is in cache
var cachedModule = __webpack_module_cache__[moduleId]
if (cachedModule !== undefined) {
return cachedModule.exports
}
// Create a new module (and put it into the cache)
var module = (__webpack_module_cache__[moduleId] = {
// no module.id needed
// no module.loaded needed
exports: {},
})
// Execute the module function
__webpack_modules__[moduleId](
module,
module.exports,
__webpack_require__
)
// Return the exports of the module
return module.exports
}
/************************************************************************/
/* webpack/runtime/define property getters */
;(() => {
// define getter functions for harmony exports
__webpack_require__.d = (exports, definition) => {
for (var key in definition) {
if (
__webpack_require__.o(definition, key) &&
!__webpack_require__.o(exports, key)
) {
Object.defineProperty(exports, key, {
enumerable: true,
get: definition[key],
})
}
}
}
})()
/* webpack/runtime/hasOwnProperty shorthand */
;(() => {
__webpack_require__.o = (obj, prop) =>
Object.prototype.hasOwnProperty.call(obj, prop)
})()
/* webpack/runtime/make namespace object */
;(() => {
// define __esModule on exports
__webpack_require__.r = (exports) => {
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, {
value: 'Module',
})
}
Object.defineProperty(exports, '__esModule', { value: true })
}
})()
/************************************************************************/
// startup
// Load entry module and return exports
// This entry module can't be inlined because the eval devtool is used.
var __webpack_exports__ = __webpack_require__('./src/index.js')
})()
mode: production
js
(()=>{"use strict";console.log("hello")})();
默认打包产物如上,关闭默认开启的代码压缩可以往前一步查看打包细节
js
(() => {// webpackBootstrap
'use strict'
var __webpack_exports__ = {}
// CONCATENATED MODULE: ./src/mod.js
function sayHello() {
console.log('hello')
}
// CONCATENATED MODULE: ./src/index.js
sayHello()
})()
代码分割
使用这份代码触发webpack 5的代码分割
js
// index.js
import('./mod').then( m => m.sayHello() )
// mod.js
export function sayHello(){
console.log('hello')
}
由于动态导入需要模块加载器,development
打包产物和production
打包产物的区别只有是否使用eval
的区别。
production
打包产物如下:
index.js
js
;(() => {
// webpackBootstrap
var __webpack_modules__ = {}
/************************************************************************/
// The module cache
var __webpack_module_cache__ = {}
// The require function
function __webpack_require__(moduleId) {
// Check if module is in cache
var cachedModule = __webpack_module_cache__[moduleId]
if (cachedModule !== undefined) {
return cachedModule.exports
}
// Create a new module (and put it into the cache)
var module = (__webpack_module_cache__[moduleId] = {
// no module.id needed
// no module.loaded needed
exports: {},
})
// Execute the module function
__webpack_modules__[moduleId](
module,
module.exports,
__webpack_require__
)
// Return the exports of the module
return module.exports
}
// expose the modules object (__webpack_modules__)
__webpack_require__.m = __webpack_modules__
/************************************************************************/
/* webpack/runtime/define property getters */
;(() => {
// define getter functions for harmony exports
__webpack_require__.d = (exports, definition) => {
for (var key in definition) {
if (
__webpack_require__.o(definition, key) &&
!__webpack_require__.o(exports, key)
) {
Object.defineProperty(exports, key, {
enumerable: true,
get: definition[key],
})
}
}
}
})()
/* webpack/runtime/ensure chunk */
;(() => {
__webpack_require__.f = {}
// This file contains only the entry chunk.
// The chunk loading function for additional chunks
__webpack_require__.e = (chunkId) => {
return Promise.all(
Object.keys(__webpack_require__.f).reduce((promises, key) => {
__webpack_require__.f[key](chunkId, promises)
return promises
}, [])
)
}
})()
/* webpack/runtime/get javascript chunk filename */
;(() => {
// This function allow to reference async chunks
__webpack_require__.u = (chunkId) => {
// return url for filenames based on template
return '' + chunkId + '.js'
}
})()
/* webpack/runtime/global */
;(() => {
__webpack_require__.g = (function () {
if (typeof globalThis === 'object') return globalThis
try {
return this || new Function('return this')()
} catch (e) {
if (typeof window === 'object') return window
}
})()
})()
/* webpack/runtime/hasOwnProperty shorthand */
;(() => {
__webpack_require__.o = (obj, prop) =>
Object.prototype.hasOwnProperty.call(obj, prop)
})()
/* webpack/runtime/load script */
;(() => {
var inProgress = {}
var dataWebpackPrefix = 'wbpack:'
// loadScript function to load a script via script tag
__webpack_require__.l = (url, done, key, chunkId) => {
if (inProgress[url]) {
inProgress[url].push(done)
return
}
var script, needAttach
if (key !== undefined) {
var scripts = document.getElementsByTagName('script')
for (var i = 0; i < scripts.length; i++) {
var s = scripts[i]
if (
s.getAttribute('src') == url ||
s.getAttribute('data-webpack') ==
dataWebpackPrefix + key
) {
script = s
break
}
}
}
if (!script) {
needAttach = true
script = document.createElement('script')
script.charset = 'utf-8'
script.timeout = 120
if (__webpack_require__.nc) {
script.setAttribute('nonce', __webpack_require__.nc)
}
script.setAttribute('data-webpack', dataWebpackPrefix + key)
script.src = url
}
inProgress[url] = [done]
var onScriptComplete = (prev, event) => {
// avoid mem leaks in IE.
script.onerror = script.onload = null
clearTimeout(timeout)
var doneFns = inProgress[url]
delete inProgress[url]
script.parentNode && script.parentNode.removeChild(script)
doneFns && doneFns.forEach((fn) => fn(event))
if (prev) return prev(event)
}
var timeout = setTimeout(
onScriptComplete.bind(null, undefined, {
type: 'timeout',
target: script,
}),
120000
)
script.onerror = onScriptComplete.bind(null, script.onerror)
script.onload = onScriptComplete.bind(null, script.onload)
needAttach && document.head.appendChild(script)
}
})()
/* webpack/runtime/make namespace object */
;(() => {
// define __esModule on exports
__webpack_require__.r = (exports) => {
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, {
value: 'Module',
})
}
Object.defineProperty(exports, '__esModule', { value: true })
}
})()
/* webpack/runtime/publicPath */
;(() => {
var scriptUrl
if (__webpack_require__.g.importScripts)
scriptUrl = __webpack_require__.g.location + ''
var document = __webpack_require__.g.document
if (!scriptUrl && document) {
if (document.currentScript) scriptUrl = document.currentScript.src
if (!scriptUrl) {
var scripts = document.getElementsByTagName('script')
if (scripts.length) {
var i = scripts.length - 1
while (i > -1 && !scriptUrl) scriptUrl = scripts[i--].src
}
}
}
// When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration
// or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic.
if (!scriptUrl)
throw new Error(
'Automatic publicPath is not supported in this browser'
)
scriptUrl = scriptUrl
.replace(/#.*$/, '')
.replace(/\?.*$/, '')
.replace(/\/[^\/]+$/, '/')
__webpack_require__.p = scriptUrl
})()
/* webpack/runtime/jsonp chunk loading */
;(() => {
// no baseURI
// object to store loaded and loading chunks
// undefined = chunk not loaded, null = chunk preloaded/prefetched
// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
var installedChunks = {
179: 0,
}
__webpack_require__.f.j = (chunkId, promises) => {
// JSONP chunk loading for javascript
var installedChunkData = __webpack_require__.o(
installedChunks,
chunkId
)
? installedChunks[chunkId]
: undefined
if (installedChunkData !== 0) {
// 0 means "already installed".
// a Promise means "currently loading".
if (installedChunkData) {
promises.push(installedChunkData[2])
} else {
if (true) {
// all chunks have JS
// setup Promise in chunk cache
var promise = new Promise(
(resolve, reject) =>
(installedChunkData = installedChunks[chunkId] =
[resolve, reject])
)
promises.push((installedChunkData[2] = promise))
// start chunk loading
var url =
__webpack_require__.p +
__webpack_require__.u(chunkId)
// create error before stack unwound to get useful stacktrace later
var error = new Error()
var loadingEnded = (event) => {
if (
__webpack_require__.o(installedChunks, chunkId)
) {
installedChunkData = installedChunks[chunkId]
if (installedChunkData !== 0)
installedChunks[chunkId] = undefined
if (installedChunkData) {
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
installedChunkData[1](error)
}
}
}
__webpack_require__.l(
url,
loadingEnded,
'chunk-' + chunkId,
chunkId
)
}
}
}
}
// no prefetching
// no preloaded
// no HMR
// no HMR manifest
// no on chunks loaded
// install a JSONP callback for chunk loading
var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
var [chunkIds, moreModules, runtime] = data
// add "moreModules" to the modules object,
// then flag all "chunkIds" as loaded and fire callback
var moduleId,
chunkId,
i = 0
if (chunkIds.some((id) => installedChunks[id] !== 0)) {
for (moduleId in moreModules) {
if (__webpack_require__.o(moreModules, moduleId)) {
__webpack_require__.m[moduleId] = moreModules[moduleId]
}
}
if (runtime) var result = runtime(__webpack_require__)
}
if (parentChunkLoadingFunction) parentChunkLoadingFunction(data)
for (; i < chunkIds.length; i++) {
chunkId = chunkIds[i]
if (
__webpack_require__.o(installedChunks, chunkId) &&
installedChunks[chunkId]
) {
installedChunks[chunkId][0]()
}
installedChunks[chunkId] = 0
}
}
var chunkLoadingGlobal = (self['webpackChunkwbpack'] =
self['webpackChunkwbpack'] || [])
chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0))
chunkLoadingGlobal.push = webpackJsonpCallback.bind(
null,
chunkLoadingGlobal.push.bind(chunkLoadingGlobal)
)
})()
/************************************************************************/
var __webpack_exports__ = {}
__webpack_require__
.e(/* import() */ 227)
.then(__webpack_require__.bind(__webpack_require__, 227))
.then((m) => m.sayHello())
})()
227.js
js
'use strict';
(self['webpackChunkwbpack'] = self['webpackChunkwbpack'] || []).push([
[227],
{
227: (
__unused_webpack_module,
__webpack_exports__,
__webpack_require__
) => {
__webpack_require__.r(__webpack_exports__)
__webpack_require__.d(__webpack_exports__, {
sayHello: () => /* binding */ sayHello,
})
function sayHello() {
console.log('hello')
}
},
},
])
webpack除了负责打包器的工作,还内置了模块加载器。
通常开发者无需关心打包细节,只需要按照配置文档即可满足生产环境需求。
示例代码依赖版本
- "webpack": "5.88.1"