zoukankan      html  css  js  c++  java
  • 记录一下学习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)
  • 相关阅读:
    LIBTIFF 配置 (vs2010 + win8 + 32位 )
    minGW、cygwin、gnuwin32 介绍
    LabVIEW发布功能总结
    LabVIEW新手5大错误
    专业功放测试:主要性能指标&信噪比测量
    常用低压电器的主要种类和用途
    LabVIEW是一种通用的编程语言吗?
    LabVIEW TCP/IP 断开重连问题
    LabVIEW 的bool(布尔)按键机械属性
    LabVIEW 远程控制VI
  • 原文地址:https://www.cnblogs.com/xiao-yaolx/p/13385046.html
Copyright © 2011-2022 走看看