• 实现一个简易版webpack


    现实 webpack 的打包产物

    大概长这样(只把核心代码留下来):

    实现一个简版的webpack

    依葫芦画瓢,实现思路分2步:

    1. 分析入口文件,把所有的依赖找出来(包括所有后代的依赖)

    2. 拼接出类似上面的立即执行函数

    找依赖

    const fs = require('fs');
    const path = require('path');
    const parser = require('@babel/parser');
    const traverse = require('@babel/traverse').default;
    const { transformFromAST } = require('@babel/core');
    
    // 分析一个文件,转成CommonJS Module,并找出它的依赖
    function readCode(filePath) {
        // 读取文件字符串
        const content = fs.readFileSync(filePath, 'utf-8');
        // 语法解析成 AST
        const ast = parser(content, {
            sourceType: 'module'
        })
        // 获取本文件的依赖
        const dependiences = [];
        // 遍历 AST,每当触发依赖钩子,就往依赖数组添加
        traverse(ast, {
            ImportDeclaration({node}) {
                // 把对应的以来路径存起来
                dependiences.push(node.source.value)
            }
        })
        // 把 es6 转成 es5 字符串
        // 最重要的是把 esModule 的 import export,转成 es5 能认识的 commonJs写法
        const { code } = transformFromAST(ast, null, {
            presets: ['@babel/preset-env']
        })
        return {
            filePath,
            code,
            dependiences
        }
    }
    
    // 广度优先算法,深入找出所有的依赖
    function getAllDependencies(filePath) {
        const entryObj = readCode(filePath);
        const dependencies = [entryObj];
        for (const dependency of dependencies) {
            const curDirname = path.dirname(dependency.filePath)
            for (const relativePath dependency.dependencies) {
                const absolutePath = path.join(curDirname, relativePath);
                const child = readCode(absolutePath);
                child.relativePath = relativePath;
                dependencies.push(child);
            }
        }
        return dependencies;
    }

    ps: 我们用的是babel的配套工具来做语法分析和转化,但是真正的webpack用的是webassemblyjs的配套工具

    拼写立即执行函数

    function bundle(fileName) {
        const dependencies = getAllDependencies(fileName);
        const modulesStr = '';
        dependencies.forEach(dependency => {
            const key = dependency.relativePath || dependency.filePath;
            modulesStr += `'${key}': function(module, exports, require) {
                ${ dependency.code }
            }`
        })
        return `(function(modules) {
            const installedModules = {};
            function require(id) {
                // 解决循环依赖
                if (installedModules[id]) {
                    return installedModules[id].exports;
                }
                var module = installedModules[id] = {exports: {}};
                modules[id].call(module.exports, module, module.exports, require);
                return module.exports;
            }
            return require('${fileName}')
        })({${modulesStr}})`
    }
  • 相关阅读:
    Java_Eclipse_Android安装
    deep_learning_Function_os.makedirs()
    deep_learning_Function_ Matplotlib 3D 绘图函数 plot_surface 的 rstride 和 cstride 参数
    deep_learning_Function_ numpy.random.randn()
    deep_learning_Function_list变量前面加星号,字典变量前面加两个星号
    deep_learning_Function_ lambda函数详解
    Unity 3D中C#的性能优化小陷阱
    1.Bacula各组件说明
    vmware修改虚拟机名称
    AWS IoT Greengrass 入门-模块3(第 1 部分):AWS IoT Greengrass 上的 Lambda 函数
  • 原文地址:https://www.cnblogs.com/amiezhang/p/11517294.html
Copyright © 2020-2023  润新知