webpack是什么?
如果一點(diǎn)不知道webpack是什么的可能不太適合此篇文章爽锥,建議從百度開(kāi)始學(xué)習(xí)皱埠。
一句話總結(jié):webpack就是通過(guò)一個(gè)index.js這樣的入口文件,根據(jù)此入口文件查找各層的js模塊的依賴最終打包成一個(gè)文件爬早,webpack做了依賴收集
主要原理
- 匹配js文件中加載模塊的字段 得到模塊目錄和文件哼丈,讀取模塊代碼并保存
- 如果模塊中還引用了其他模塊,繼續(xù)讀取此模塊引入的模塊
- 將各個(gè)模塊的加載函數(shù)比如require換成__webpack_require字段筛严, __webpack_require這個(gè)方法用作從webpack已保存的模塊中加載模塊
- 所有模塊和他們的依賴加載完畢后醉旦,得到一個(gè)有所有模塊的對(duì)象
- 然后將所有模塊通過(guò)固定模板 打包到一個(gè)js文件中
比如對(duì)入口文件index.js進(jìn)行打包,index.js中引入了a.js和b.js模塊桨啃,并且b.js模塊引入了c.js模塊车胡,webpack都能將各個(gè)模塊依賴關(guān)系以及各個(gè)模塊的功能全部打包到一個(gè)文件中。
webpack使用者只管配置一下入口文件index.js照瘾,就能根據(jù)入口文件以及它的層層依賴得到一個(gè)打好的包匈棘。
直接上代碼
const path = require('path')
const fs = require('fs')
// webpack 的配置
const config = {
mode: 'development',
entry: './src/index.js',// 主文件
output: {
filename: 'bundle2.js' // 輸出文件名字
}
}
// webpack的模板執(zhí)行字符串
const TEMPLATE = `!function start (modules) {
var installModules = {}
function __pack_require_ (moduleId) {
if (installModules[moduleId]) {
return installModules[moduleId]
}
var module = installModules[moduleId] = {
l: false,
exports: {}
}
modules[moduleId].call(module.exports, module, module.exports, __pack_require_)
module.l = true
return module.exports
}
return __pack_require_(__pack_require_.s = '__entry__')
}({__content__})
`
// webpack 的構(gòu)造器
class Pack {
constructor (config) {
this.config = config
this.entry = config.entry
this.root = process.cwd()
this.modules = {}
}
// 查找各個(gè)文件依賴創(chuàng)建模塊
createModles (modulePath, name) {
let fileContent = fs.readFileSync(modulePath, 'utf-8')
let {code, deps} = this.parseModule(fileContent, path.dirname(name))
this.modules[name] = code
deps.forEach(dep => {
this.createModles(path.join(this.root, dep), dep)
})
}
// 存下js文件的require引入的依賴以及替換成自己的__pack_require_
parseModule (code, parent) {
let deps = []
var r = /require\((.*)\)/g
let match
code = code.replace(r, function (match, arg) {
const retPath = path.join(parent, arg.replace(/'|"/g, '')).replace('\\', '/')
deps.push(retPath)
return `__pack_require_("${retPath}")`
})
return {code, deps}
}
// 將各個(gè)模塊生成字文本字符串
generateModuleStr () {
let fmTmp = ''
Object.keys(this.modules).forEach(name => {
fmTmp += `'${name}':function(module, exports, __pack_require_){${this.modules[name]}},`
})
return fmTmp
}
// 根據(jù)已查找模塊生成最終Bundle文件
outputBundleFile () {
let template = TEMPLATE.replace('__entry__', this.entry)
.replace('__content__', this.generateModuleStr())
fs.writeFileSync('./' + this.config.output.filename, template) // 文件生成位置
}
// 開(kāi)始打包
start () {
const entryPath = path.resolve(this.root, this.entry)
this.createModles(entryPath, this.entry)
this.outputBundleFile()
console.log('\n pack success!!!')
}
}
const myPack = new Pack(config)
myPack.start()
調(diào)用示例
入口文件src/index.js
const a = require('./a.js')
const b = require('./b.js')
a.aSayHi()
console.log(b.value)
a.js模塊
module.exports = {
aSayHi () {
console.log('a.js say hi')
}
}
b.js模塊
require('./c.js')
module.exports = {
value: 'this.is B'
}
c.js模塊
console.log('this c.js')
打包結(jié)果bundle2.js
!function start (modules) {
var installModules = {}
function __pack_require_ (moduleId) {
if (installModules[moduleId]) {
return installModules[moduleId]
}
var module = installModules[moduleId] = {
l: false,
exports: {}
}
modules[moduleId].call(module.exports, module, module.exports, __pack_require_)
module.l = true
return module.exports
}
return __pack_require_(__pack_require_.s = './src/index.js')
}({
'./src/index.js': function (module, exports, __pack_require_) {
const a = __pack_require_('src/a.js')
const b = __pack_require_('src/b.js')
a.aSayHi()
console.log(b.value)
}, 'src/a.js': function (module, exports, __pack_require_) {
module.exports = {
aSayHi () {
console.log('a.js say hi')
}
}
}, 'src/b.js': function (module, exports, __pack_require_) {
__pack_require_('src/c.js')
module.exports = {
value: 'this.is B'
}
}, 'src/c.js': function (module, exports, __pack_require_) {
console.log('this c.js')
}
})
執(zhí)行打包結(jié)果bundle2.js得到
this c.js
a.js say hi
this.is B
對(duì)比src/index.js入口文件的內(nèi)容
const a = require('./a.js')
const b = require('./b.js')
a.aSayHi()
console.log(b.value)