现实 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}})`
}

实现一个简易版webpack的更多相关文章

  1. .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”

    FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...

  2. 依赖注入[5]: 创建一个简易版的DI框架[下篇]

    为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架.在<依赖注入[4]: 创建一个简易版的DI框架[上篇]> ...

  3. 依赖注入[4]: 创建一个简易版的DI框架[上篇]

    本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章(<控制反转>.<基于IoC的设计模式>和< 依赖注入模式>)从纯理论的角度 ...

  4. .NET CORE学习笔记系列(2)——依赖注入[4]: 创建一个简易版的DI框架[上篇]

    原文https://www.cnblogs.com/artech/p/net-core-di-04.html 本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章从 ...

  5. 手动实现一个简易版SpringMvc

    版权声明:本篇博客大部分代码引用于公众号:java团长,我只是在作者基础上稍微修改一些内容,内容仅供学习与参考 前言:目前mvc框架经过大浪淘沙,由最初的struts1到struts2,到目前的主流框 ...

  6. 如何实现一个简易版的 Spring - 如何实现 Setter 注入

    前言 之前在 上篇 提到过会实现一个简易版的 IoC 和 AOP,今天它终于来了...相信对于使用 Java 开发语言的朋友们都使用过或者听说过 Spring 这个开发框架,绝大部分的企业级开发中都离 ...

  7. 如何实现一个简易版的 Spring - 如何实现 Constructor 注入

    前言 本文是「如何实现一个简易版的 Spring」系列的第二篇,在 第一篇 介绍了如何实现一个基于 XML 的简单 Setter 注入,这篇来看看要如何去实现一个简单的 Constructor 注入功 ...

  8. 如何实现一个简易版的 Spring - 如何实现 @Component 注解

    前言 前面两篇文章(如何实现一个简易版的 Spring - 如何实现 Setter 注入.如何实现一个简易版的 Spring - 如何实现 Constructor 注入)介绍的都是基于 XML 配置文 ...

  9. 使用 js 和 Beacon API 实现一个简易版的前端埋点监控 npm 包

    使用 js 和 Beacon API 实现一个简易版的前端埋点监控 npm 包 前端监控,埋点,数据收集,性能监控 Beacon API https://caniuse.com/beacon 优点,请 ...

随机推荐

  1. 在右键菜单中添加用Jupyter Notebook打开

    在右键菜单中添加用Jupyter Notebook打开 为了把 Jupyter 的工作目录指定到某一个文件夹下,每次都要启动 CMD 终端, 然后激活 Anaconda 环境,再启动 Jupyter ...

  2. FindWindow SendMessage

    FindWindow 用来根据类名和窗口名来得到窗口句柄的.但是这个函数不能查找子窗口,也不区分大小写. 如果要从一个窗口的子窗口中查找需要使用FindWindowEX. 1.在C#中使用方法如下: ...

  3. java报错与解决方法总结

    错误 error:Syntax error, insert ")" to complete MethodDeclaration 解决办法:放到main方法里 错误原因: 错误: e ...

  4. Git使用整理

    [本文由水木桶首发于博客园,原文地址:https://www.cnblogs.com/shuimutong/p/11404664.html,未接允许,严禁转载] 背景 很久之前使用的是svn,直接在E ...

  5. 如何在textarea多行文本框中设置滚动条样式

    其中设置滚动条的组成都有以下部分 ::-webkit-scrollbar 滚动条整体部分 ::-webkit-scrollbar-thumb  滚动条里面的小方块,能向上向下移动(或往左往右移动,取决 ...

  6. [C#]DataTable转string[]

    来源:https://zhidao.baidu.com/question/1754089856824824548.html string[] ary = Array.ConvertAll<Dat ...

  7. 判断是否发生url跳转

    url="https://www.baidu.com/" url='http://www.freebuf.com/fevents/133225.html' # 方法一:禁止跳转:a ...

  8. [极客-Linux] 04 Linux命令

    创建用户: useradd 装文件: CentOS:   (软件管家yum) rpm -i xxx.rpm Ubuntu:   (apt-get) dpkg -i xxx.deb nohup: no ...

  9. linu学习记录--初学linux中的几个基本命令以及比较关键的man指令

    import chardet chardet.detect() #传入参数可以输出查看参数的对应编码 首先是用decode将对象编码转换成unicode,然后用encode将对象编码转换成输出所需,u ...

  10. sqlalchemy之基础操作

    原文链接:https://www.cnblogs.com/DragonFire/p/10166527.html