zoukankan      html  css  js  c++  java
  • 实现一个简易版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}})`
    }
  • 相关阅读:
    【Oracle 12c】最新CUUG OCP-071考试题库(58题)
    【Oracle 12c】最新CUUG OCP-071考试题库(57题)
    【Oracle 12c】最新CUUG OCP-071考试题库(56题)
    【Oracle 12c】最新CUUG OCP-071考试题库(55题)
    voip,
    处理xmpp 离线信息,
    流程,xmpp发送信息,
    折腾我几天的 消息状态,
    三者的区别,
    bundle,
  • 原文地址:https://www.cnblogs.com/amiezhang/p/11517294.html
Copyright © 2011-2022 走看看