现实 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. Throw 和Throws 的区别

    throw语句用在方法体内,表示抛出异常,由方法体内的语句处理.throws语句用在方法声明后面,表示再抛出异常,由该方法的调用者来处理. 和在service中处理异常的方式差不多,并没有什么特别新奇 ...

  2. 易百教程人工智能python修正-人工智能数据准备-标记数据

    我们已经知道,某种格式的数据对于机器学习算法是必需的. 另一个重要的要求是,在将数据作为机器学习算法的输入发送之前,必须正确标记数据. 例如,如果所说的分类,那么数据上会有很多标记. 这些标记以文字, ...

  3. Python简单实现在线更新下载

    Python简单实现 软件在线更新 在线下载(Python simple implementation of software online update and download) 文章来自:htt ...

  4. MySQL Error--存储inode用完后报设备没有空间

    问题描述:磁盘有足够剩余空间,但在创建文件或文件夹时报错,提示“设备没有空间”. 问题原因:当存储设备通过分区格式化为文件系统后,会分为两部分:1.block部分: 存储的最小单位为扇区(Sector ...

  5. Android笔记(三十六) AsyncTask是如何执行的?

    在上一个例子中,我们是在LoadImage的onPostExecute中修改的UI,不是说只允许在主线程中修改UI吗?我们看一下源代码是如何操作的. MainActicity.java package ...

  6. 【DRF框架】认证组件

    DRF框架的认证组件 核心代码:       self.perform_authentication(request)  框架自带模块:    from rest_framework import a ...

  7. XPath知识点【一】

    什么是 XPath? XPath 使用路径表达式在 XML 文档中进行导航 XPath 包含一个标准函数库 XPath 是 XSLT 中的主要元素 XPath 是一个 W3C 标准 XPath 路径表 ...

  8. suse12安装详解

    1.部署步骤 1.1.启动安装程序 在启动页面上选择Installation,然后按Enter键,这将载入SUSE Linux服务器安装程序并以普通模式安装. 1.2.选择安装语言 Language和 ...

  9. qingqing的项目

    1 https://www.cnblogs.com/zhangqing979797/p/10147679.html 2 https://www.cnblogs.com/zhangqing979797/ ...

  10. 获取类范形的Class

    public class Test<T>{ } Type genType = getClass().getGenericSuperclass(); Type[] params = ((Pa ...