记录一下学习webpack原理的过程

1.1 打包的主要流程如下

  1. 需要读到入口文件里面的内容。
  2. 分析入口文件,递归的去读取模块所依赖的文件内容,生成AST语法树。
  3. 根据AST语法树,生成浏览器能够运行的代码

1.2 具体细节

  1. 获取主模块内容
  2. 分析模块
    • 安装@babel/parser包(转AST)
  3. 对模块内容进行处理
    • 安装@babel/traverse包(遍历AST收集依赖)
    • 安装@babel/core和@babel/preset-env包 (es6转ES5)
  4. 递归所有模块
  5. 生成最终代码
  6. 项目目录如下:

  1. 在此目录的基础下,在根目录创建boudle.js 代码如下:
// 获取主入口文件
const fs = require('fs')
// 引入生成ast 关键模块
const parser = require('@babel/parser')
const  path   = require('path')
// 引入遍历ast 得到的import路径 将其放入deps中(将用到的依赖收集起来)
const traverse = require('@babel/traverse').default
// ES6的AST转化成ES5
const babel = require('@babel/core')

// 分析模块的方法
const getModuleInfo = (file)=>{
    const body = fs.readFileSync(file,'utf-8')

    //分析模块  生成AST
    const ast = parser.parse(body, {
        sourceType: 'module'  // 这个类型表示我们要解析ES模块
    })
    
    // 收集依赖
    const deps = {}
    traverse(ast,{
        ImportDeclaration({node}){
            const dirname = path.dirname(file)
            const abspath = './' + path.join(dirname,node.source.value)
            deps[node.source.value] = abspath
        }
    })

    // 将ES6的AST转化成ES5
    const { code } = babel.transformFromAst(ast, null, {
        presets: ['@babel/preset-env']
    })

    // 将获取到的file deps(依赖) ES5 导出 
    const moduleInfo = {file,deps,code}
    return moduleInfo
}

// 递归获取依赖方法
const parseModules = (file) => {
    const entry = getModuleInfo(file)
    const temp = [entry]
    // 将文件路径为key   {code, deps}为值存入对象
    const depsGraph = {}
    for( let i = 0; i<temp.length; i++) {
        const deps = temp[i].deps
        if(deps) {
            for(const key in deps) {
                if (deps.hasOwnProperty(key)) {
                    temp.push(getModuleInfo(deps[key]))
                }
            }
        }
    }
    // 将文件路径为key   {code, deps}为值存入对象
    temp.forEach(item => {
        depsGraph[item.file] = {
            deps: item.deps,
            code: item.code
        }
    })
    return depsGraph
}

//  整合完整的字符串代码
const bundle = (file) =>{
    const depsGraph = JSON.stringify(parseModules(file))
    return `(function (graph) {
        function require(file) {
            function absRequire(relPath) {
                return require(graph[file].deps[relPath])
            }
            var exports = {};
            (function (require,exports,code) {
                eval(code)
            })(absRequire,exports,graph[file].code)
            return exports
        }
        require('${file}')
    })(${depsGraph})`

}
const content = bundle('./src/index.js')
 fs.mkdirSync('./dist');
fs.writeFileSync('./dist/bundle.js',content)

 

posted @ 2020-07-27 13:51  逍丶遥  阅读(120)  评论(0编辑  收藏  举报