# 概览
1. 找到入口文件
2. 解析入口文件, 提取它依赖的文件
3. 解析入口文件的依赖的依赖, 递归去创建一个文件间的依赖图, 描述所有文件的依赖关系
4. 把所有文件打包成一个文件
## 开发
1. 新建几个js文件
* name.js
* message.js
* entry.js
2. 三个文件依赖关系
entry 依赖-> message 依赖-> name
3. 创建一个my-webpack.js 我们在这个文件开发
4.了解几个工具库
* babylon 生成ast语法树
* babel-traverse 遍历ast语法树
* babel-core 提取语法树里面的代码
5. 创建一个打包命令在package.json
"scripts": {
"build": "rm -rf dist.js && node my-webpack.js > dist.js"
}
const fs = require('fs')
const babylon = require('babylon')
const path = require('path')
const traverse = require('babel-traverse').default
const babel = require('babel-core')
let ID = 0
function createAsset (filename) {
const content = fs.readFileSync(filename, 'utf-8')
const ast = babylon.parse(content, {
sourceType: 'module'
})
const dependencies = []
traverse(ast, {
ImportDeclaration: ({ node }) => {
dependencies.push(node.source.value)
}
})
const id = ID++
const { code } = babel.transformFromAst(ast, null, {
presets: ['env']
})
return {
id, // 模块唯一标识
filename, // 模块路径
dependencies,// 模块中使用的依赖
code // 模块代码
}
}
function createGraph (entry) {
const mainAsset = createAsset(entry)
const allAsset = [mainAsset]
for (let asset of allAsset) {
const dirname = path.dirname(asset.filename) // 获取绝对路径
asset.mapping = {} // 当前文件的依赖对象, key:路径, 值是id
asset.dependencies.forEach(relativePath => {
const absolutePath = path.join(dirname, relativePath) // 依赖文件的绝对路径
// 获取文件的依赖
const childAsset = createAsset(absolutePath)
asset.mapping[relativePath] = childAsset.id
allAsset.push(childAsset) // 遍历整个依赖图
})
}
return allAsset
}
function bundle (graph) {
let modules = ''
graph.forEach(module => {
modules += `${module.id}:[
function (require, module, exports) {
${module.code}
},
${JSON.stringify(module.mapping)}
],`
})
const result = `
(function(modules){
function require(id) {
const [fn, mapping] = modules[id]
function localRequire(relativePath) {
return require(mapping[relativePath])
}
const module = {exports:{}}
fn(localRequire, module, module.exports)
return module.exports
}
require(0)
})({${modules}})
`
return result
}
const graph = createGraph('source/entry.js')
console.log(bundle(graph))