实现一个简易版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}})`
- }
实现一个简易版webpack的更多相关文章
- .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”
FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...
- 依赖注入[5]: 创建一个简易版的DI框架[下篇]
为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架.在<依赖注入[4]: 创建一个简易版的DI框架[上篇]> ...
- 依赖注入[4]: 创建一个简易版的DI框架[上篇]
本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章(<控制反转>.<基于IoC的设计模式>和< 依赖注入模式>)从纯理论的角度 ...
- .NET CORE学习笔记系列(2)——依赖注入[4]: 创建一个简易版的DI框架[上篇]
原文https://www.cnblogs.com/artech/p/net-core-di-04.html 本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章从 ...
- 手动实现一个简易版SpringMvc
版权声明:本篇博客大部分代码引用于公众号:java团长,我只是在作者基础上稍微修改一些内容,内容仅供学习与参考 前言:目前mvc框架经过大浪淘沙,由最初的struts1到struts2,到目前的主流框 ...
- 如何实现一个简易版的 Spring - 如何实现 Setter 注入
前言 之前在 上篇 提到过会实现一个简易版的 IoC 和 AOP,今天它终于来了...相信对于使用 Java 开发语言的朋友们都使用过或者听说过 Spring 这个开发框架,绝大部分的企业级开发中都离 ...
- 如何实现一个简易版的 Spring - 如何实现 Constructor 注入
前言 本文是「如何实现一个简易版的 Spring」系列的第二篇,在 第一篇 介绍了如何实现一个基于 XML 的简单 Setter 注入,这篇来看看要如何去实现一个简单的 Constructor 注入功 ...
- 如何实现一个简易版的 Spring - 如何实现 @Component 注解
前言 前面两篇文章(如何实现一个简易版的 Spring - 如何实现 Setter 注入.如何实现一个简易版的 Spring - 如何实现 Constructor 注入)介绍的都是基于 XML 配置文 ...
- 使用 js 和 Beacon API 实现一个简易版的前端埋点监控 npm 包
使用 js 和 Beacon API 实现一个简易版的前端埋点监控 npm 包 前端监控,埋点,数据收集,性能监控 Beacon API https://caniuse.com/beacon 优点,请 ...
随机推荐
- oracle中的CURRVAL和NEXTVAL用法
原文:https://blog.csdn.net/qianyiyiding/article/details/51592689 1.什么是sequence?其作用是什么? 在Oracle数据库中,什么 ...
- 记录用到的mssql的几个方法
1.RIGHT ( character_expression , integer_expression ) 返回字符串中从右边开始指定个数的字符 character_expression 字符或二进制 ...
- attr()与prop()区分图
- stack + positioned
stack 下套container, 发现最大的显示,小的都没显示, 把所有都套个POSITIONED, 都正常显示了.
- 关于阿里 iconfont 的使用步骤
第一步: 在iconfont库中,找到你想要的图标,加入到购物车,再在购物车中将图标加入到你的项目中去 第二步: 在项目中,可以看到刚刚加入的图标,这里是你在项目中所有用到的iconfont,选 ...
- STM32F10x芯片类型 STM32F10X_LD STM32F10X_MD STM32F10X_HD STM32F10X_XL STM32F10X_CL
stm32f10x.h 固件库stm32f10x.h中有如下解释 #if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) & ...
- oracle in和exists区别
in和exists http://oraclemine.com/sql-exists-vs-in/ https://www.techonthenet.com/oracle/exists.php htt ...
- Java 进阶面试问题必备
面向对象编程的基本理念与核心设计思想 解释下多态性(polymorphism),封装性(encapsulation),内聚(cohesion)以及耦合(coupling). 继承(Inheritanc ...
- Chrome快捷键统计
Chrome快捷键: Chrome 个人常用快捷键 1 将当前网页保存为书签 Ctrl + d 2 重新加载当前网页 Ctrl + r或F5 3 打开书签管理器 Ctrl + Shift + o 4 ...
- 微信小程序(小游戏)后台开发
小程序开放接口功能,目的是方便小程序接入第三方服务器,比如,商城类小程序,小游戏,需要保存订单数据,玩家信息等.那就需要服务器和数据库, 开发者对于各方关系必须要理清,那就是小程序,用户,开发者服务器 ...