1.UMI3源码解析系列之构建原理
2.dayjs源码解析(一):概念、插件插件locale、源码源码constant、分析分析utils tags
3.这样入门 js 抽象语法树(AST),格式格式从此我来到了一个新世界
4.dayjs源码解析(二):Dayjs 类
5.JS 逆向百例浏览器插件 Hook 实战,插件插件亚航加密参数分析
6.10种JavaScript开发者必备的源码源码整形美容网站源码VS Code插件
UMI3源码解析系列之构建原理
基于前面umi插件机制的原理可以了解到,umi是分析分析一个插件化的企业级前端框架,它配备了完善的格式格式插件体系,这也使得umi具有很好的插件插件可扩展性。umi的源码源码全部功能都是由插件完成的,构建功能同样是分析分析以插件的形式完成的。下面将从以下两个方面来了解umi的格式格式构建原理。UMI命令注册想了解umi命令的插件插件注册流程,咱们就从umi生成的源码源码项目入手。
从umi初始化的分析分析项目package.json文件看,umi执行dev命令,实际执行的是start:dev,而start:dev最终执行的是umidev。
"scripts":{ "dev":"npmrunstart:dev","start:dev":"cross-envREACT_APP_ENV=devMOCK=noneUMI_ENV=devumidev"}根据这里的umi命令,我们找到node_modules里的umi文件夹,看下umi文件夹下的package.json文件:
"name":"umi","bin":{ "umi":"bin/umi.js"}可以看到,这里就是定义umi命令的地方,而umi命令执行的脚本就在bin/umi.js里。接下来咱们看看bin/umi.js都做了什么。
#!/usr/bin/envnoderequire('v8-compile-cache');constresolveCwd=require('@umijs/deps/compiled/resolve-cwd');const{ name,bin}=require('../package.json');constlocalCLI=resolveCwd.silent(`${ name}/${ bin['umi']}`);if(!process.env.USE_GLOBAL_UMI&&localCLI&&localCLI!==__filename){ constdebug=require('@umijs/utils').createDebug('umi:cli');debug('Usinglocalinstallofumi');require(localCLI);}else{ require('../lib/cli');}判断当前是否执行的是本地脚手架,若是,则引入本地脚手架文件,否则引入lib/cli。在这里,我们未开启本地脚手架指令,所以是引用的lib/cli。
//获取进程的版本号constv=process.version;//通过yParser工具对命令行参数进行处理,此处是将version和help进行了简写constargs=yParser(process.argv.slice(2),{ alias:{ version:['v'],help:['h'],},boolean:['version'],});//若参数中有version值,并且args._[0]为空,此时将version字段赋值给args._[0]if(args.version&&!args._[0]){ args._[0]='version';constlocal=existsSync(join(__dirname,简易传源码'../.local'))?chalk.cyan('@local'):'';console.log(`umi@${ require('../package.json').version}${ local}`);//若参数中无version值,并且args._[0]为空,此时将help字段复制给args._[0]}elseif(!args._[0]){ args._[0]='help';}处理完version和help后,紧接着会执行一段自执行代码:
(async()=>{ try{ //读取args._中第一个参数值switch(args._[0]){ case'dev'://若当前运行环境是dev,则调用Node.js的核心模块child_process的fork方法衍生一个新的Node.js进程。scriptPath表示要在子进程中运行的模块,这里引用的是forkedDev.ts文件。constchild=fork({ scriptPath:require.resolve('./forkedDev'),});//ref:///api/process/signal_events.html///post/dayjs源码解析(一):概念、locale、constant、utils tags
深入剖析 Day.js 源码(一):概念、locale、constant、utils
Day.js 是一款轻量级的时间库,由饿了么的开发大佬 iamkun 维护,主打无需引入过多依赖,以减少打包体积的特性。本文将通过解析 Day.js 的源码,揭示其结构与功能的奥秘,旨在为开发者提供深入理解与应用 Day.js 的工具。
目录概览
本文将分五章展开 Day.js 的源码解析,分别从代码结构、基础概念、时间标准、语言(文化)代码以及 locale、constant、utils 的实现进行深入探讨。我们将逐步揭开 Day.js 的核心逻辑与设计思路。
代码结构与依赖分析
Day.js 的源代码目录结构简洁明了,主要依赖集中在入口文件 src/index.js 中。此文件依赖链简单,未直接引用 locale 和 plugin 目录下的语言包与插件,体现出 Day.js 优化体积、按需加载的核心优势。
基础概念与时间标准
在解析源码之前,97源码社区理解以下基础概念至关重要,包括时间标准、GMT、UTC、ISO 等。这些标准与概念为后续分析提供了背景知识。
时间标准解释
格林尼治平均时间(GMT)与协调世界时(UTC)是本文中的核心时间概念。GMT 作为本初子午线上的平太阳时,而 UTC 则是基于原子时标准,与格林威治标准时间(GTM)关系密切。本文详细解释了 UTC 的定义、用途与与 0 度经线平太阳时的关系。
ISO 标准
ISO 是国际标准化组织推荐的日期和时间表示方法。在 JavaScript 中,Date.prototype.toISOString() 方法返回遵循 ISO 标准的字符串,以 UTC 时间为基准。
语言(文化)代码与 locale
不同语言对时间的描述各具特色,Day.js 通过 locale 实现了多语言支持,用户可根据需求引入相应的语言包。本文介绍了语言代码与 locale 的关联,以及如何按需加载特定语言。
constant 与 utils
src/constant.js 和 src/utils.js 分别负责存储常量与工具函数。constant 文件中包含了时间单位与格式化的正则表达式,而 utils.js 则封装了一系列实用工具函数,用于简化时间操作。
总结与展望
本文完成了 Day.js 源码解析的第一部分,深入探讨了概念、locale、constant、utils 的实现。接下来,我们将分析 Day.js 的核心文件 src/index.js,解析 Dayjs 类的实现细节。欢迎关注后续内容,皮影客源码期待与您共同探索 Day.js 的更多奥秘。
这样入门 js 抽象语法树(AST),从此我来到了一个新世界
在搭建一个开源项目环境的过程中,我遇到了使用 TypeScript 自带编译器 tsc 打包 ES 模块的挑战。尽管 Rollup 似乎是一个更好的选择,但出于某些原因,我选择了 tsc。在使用 tsc 过程中,我遇到了三个基本的问题:简化引用路径问题、静态资源未打包问题以及引入样式文件后缀名问题。接下来,我将对这三个问题的解决方法进行阐述。
### 简化引用路径问题
在 tsconfig.json 文件中配置了简化引用路径,例如,对于以下目录结构:
src/
├── index.tsx
├── util/
├── assets/
配置如下:
"paths": {
"util": ["./util", "./util/*"],
"assets": ["./assets", "./assets/*"]
}
在 index.tsx 文件中引入模块或资源时,可以使用简化路径,例如:
import { functionFromUtil } from "util";
import image from "assets/image.png";
期望编译后简化路径为相对路径,实际编译结果未达到预期。在查阅官方文档后,未发现相关配置项。幸运的是,找到了名为 `tscpaths` 的插件,通过在命令行执行如下命令:
tsc --plugin tscpaths
插件会在编译后的 .js 文件中遍历并替换简化路径为相对路径,解决了简化引用路径问题。
### 静态资源未打包问题
在 index.tsx 文件中引入静态资源时,资源文件夹未出现在打包后的目录中。这是 tsc 作为 TypeScript 编译器的正常行为。解决方法是使用 `copyfiles` 命令行工具,执行命令:
postbuild: "copyfiles assets/**/* dist"
在 npm scripts 下的 `build` 命令中,将资源文件夹复制到打包后的目录下。
### 引入样式文件后缀名问题
在引入样式文件时,发现 tsc 编译结果保留了 `.scss` 后缀,作为提供给其他开发者使用的包,应使用 `.css` 格式。人脸打卡源码搜索解决方案时,找到了名为 `jscodeshift` 的工具,它能够基于 AST(抽象语法树)进行字符串替换,解决了后缀名问题。
### 引入抽象语法树(AST)
在处理上述问题时,抽象语法树(AST)的概念逐渐显现。AST 是表示代码结构的特殊对象结构,允许对代码进行解析、修改和转换。以 ESLint 为例,它通过解析代码生成 AST,对代码进行修复或优化。
为了更直观地理解 AST,可以参考以下概念示例:
const value = 1;
AST 表示为:
`{ type: "Program", body: [ { type: "VariableDeclaration", kind: "const", declarations: [ { type: "VariableDeclarator", id: { type: "Identifier", name: "value" }, init: { type: "NumericLiteral", value: "1" } }] }] }`
通过修改 AST 中的节点,可以实现对代码的修改,例如将 `value` 的值更改为 `2`。
在解决实际问题时,我遇到了后缀名问题。起初尝试使用全局正则替换,但考虑到可能影响到开发者自定义的代码逻辑,我转而使用 AST 进行精准替换,避免了代码逻辑的误修改。
### 实战解析:tsccss 工具
为了演示如何使用 AST 解决引入样式文件后缀名问题,我创建了一个命令行工具 `tsccss`。通过 `commander` 框架简化命令行接口,实现自动读取 `dist` 目录下的所有 JS 文件,并将所有样式文件的引入后缀名从 `.scss` 替换为 `.css`。工具通过读取文件、解析为 AST、修改 AST 节点、将修改后的代码写回文件,完成替换任务。
通过 `tsccss` 工具的使用,展示了如何结合 AST 和现代 JavaScript 工具解决实际问题,为开发者提供了更灵活的代码转换和优化手段。
通过这些实践,我深刻理解了 AST 的强大功能及其在代码转换和优化中的应用。AST 的引入使得代码的处理更加直观和精确,无论是在工具开发还是在日常编程中,都能极大地提高代码的可维护性和扩展性。在处理复杂问题时,AST 提供了一种全新的视角,使解决问题的方式更加多样化和高效。
dayjs源码解析(二):Dayjs 类
上篇文章讲述了dayjs的基础知识、locale、constant和utils,本文将继续深入解析dayjs的核心部分——src/index.js中的Dayjs类。
src/index.js文件结构清晰,按照以下步骤构建:
然而,这里存在两个疑问,可能是为了缩减代码体积,由@iamkun提出。
现在开始正式分析代码。
locale相关全局定义
首先默认导入了locale/en.js英文的locale,然后使用L存储当前使用的locale名字,使用Ls(locale Storage)存储locale对象。
工具补充
定义了一个工具方法parseLocale。这个方法处理以下几种情况:
然后将定义好的parseLocale方法补充到Utils中。
相关方法
在Dayjs类中,关于locale的方法有两个,实例私有方法$locale用来返回当前使用的locale对象;实例方法locale本质上就是调用了parseLocale方法,但最后返回的是新的改变了locale的Dayjs实例。
注意:在dayjs中,许多操作都使用clone()方法来返回新的Dayjs实例,这也是这个库的优点之一。
最后同样将parseLocale方法补充到Dayjs类的静态方法中。
补充Utils
上一节和前文中已经分析了一些Util工具,这里将其补充完整:
注意:这些工具方法没有统一定义在utils.js文件中的原因是用到了index.js作用域中的一些变量。
需要特别关注的是wrapper方法,在Dayjs类中大量应用了该方法,其实是通过date和原实例封装了一个新实例,新实例和原实例的主要区别就是关联的时间不同。
Dayjs类
Dayjs类是整个dayjs库的核心,可以给其定义的实例方法分类,也可以查看官网的文档分类。
解析都写在了代码的注释里:
原型链
通常来说,定义在实例中的方法应该在原型链上,但有几个与时间有关的setter/getter方法相似,所以单独将原型链写在了上面。
这几个方法都是不传参数时为getter,传参数时为setter。
静态属性
还有一些方法和属性挂在了dayjs函数对象上,最核心的是加载插件和加载locale的方法,几个方法的用法都能在官方文档中找到。
如果对dayjs函数对象、Dayjs类和原型的关系感到困惑,可以参考下图,最后形成的关系如下图所示:
总结
如果不看插件部分,dayjs库的核心已经解析完成,看一下默认生成dayjs实例长什么样子:
实例本身的属性是一些与时间相关的属性,各种操作方法都在原型__proto__上。
本节结束,下一节将开始解析dayjs的插件。
JS 逆向百例浏览器插件 Hook 实战,亚航加密参数分析
在微信公众号 K哥爬虫(关注获取更多技术干货)和QQ交流群中,我们探讨了如何通过浏览器插件技术实现JS逆向中的Hook实战,以分析亚航加密参数为例。目标是解析航班查询时的参数,尽管该参数在清除cookie或更换浏览器时保持不变,我们通过编写插件来追踪其生成过程。
首先,了解了逆向目标和抓包分析过程,我们发现查询接口的URL结构为xxx/MFM/KUL//0...,其中authorization参数不易改变。文章之前的文章《JS 逆向之Hook》提供了更多关于Hook的基础知识。为了 Hook 这个参数,我们选择了使用浏览器插件,尤其是Chrome的扩展,因为其跨浏览器兼容性较好。
浏览器插件,即扩展,可增强浏览器功能,如广告拦截和代理管理。要编写插件,需遵循Chrome扩展规范,通常包括manifest.json和JavaScript脚本。manifest.json配置了插件的基本信息,而Hook代码则在javascript_hook.js中实现,通过重写XMLHttpRequest.setRequestHeader方法来拦截并观察Authorization参数。
在Chrome中,通过开发者模式加载插件,而在Firefox中,需要将插件压缩成.xpi格式并调试安装。完成插件后,我们能在航班查询页面看到Hook成功工作,接下来是逆向分析加密过程,通过Call Stack定位参数生成位置,如在t.getData函数中找到"Bearer " + r.accessToken。
这个案例展示了Hook技术在复杂情况下的应用,尤其是在参数难以直接搜索或定位时,浏览器插件提供了有力的工具。如果你对完整代码感兴趣,可以参考K哥的GitHub代码库。
种JavaScript开发者必备的VS Code插件
在JavaScript开发的领域,Visual Studio Code(VS Code)以其轻量级的特性、卓越的性能和强大的功能吸引了众多开发者。尤其是其丰富的插件市场,更是为开发者提供了全方位的支持,让代码编辑和开发工作变得更加高效便捷。本文将重点介绍十种VS Code插件,它们是JavaScript开发者不可或缺的助手。
首先,代码片段(Snippet)插件是必不可少的工具,尤其是对于ES6/ES7等更先进的JavaScript代码。在进行前沿开发时,它们能提供丰富的预定义代码片段,大大提高编写代码的效率。
接下来,语法插件对于提升代码可读性至关重要。除了VS Code自带的JavaScript语法高亮功能,安装额外的代码高亮插件可以帮助开发者更清晰地识别代码结构,提升阅读和编写代码的体验。
代码风格检查插件则成为团队协作中的重要工具。其中,ESLint是最受欢迎的选择,它支持多种代码风格规范,如标准、Google和Airbnb等。安装相关插件可以确保代码风格一致性,提升团队协作效率。
对于Node.js开发,专门的插件是必不可少的。它们可以帮助开发者更轻松地管理依赖、运行和调试Node.js项目。
代码格式化插件是解决代码缩进和格式问题的利器,帮助开发者自动调整代码格式,减少手动调整的繁琐操作。
浏览器插件则为开发者提供了一种更高效的方式,无需频繁刷新页面即可实时查看和修改代码,大大提升了开发效率。
框架插件支持了多种主流JavaScript框架,如React、Angular和Vue等,提供了丰富的功能,如代码提示、错误检查等,极大地简化了框架项目开发过程。
测试插件对于保障代码质量至关重要。它们提供了对单元测试、功能测试和集成测试的支持,帮助开发者确保代码的健壮性和稳定性。
最后,一些非常酷的插件虽然不属于上述分类,但它们的功能独特且强大,如自动补全、代码折叠、代码搜索等,为开发者提供了更多便利。
此外,插件包是一个集合多个插件的特殊类型,它们通常相互关联,一起安装使用,能更好地协同工作,为开发者提供一站式解决方案。
总之,通过这些VS Code插件的使用,JavaScript开发者能够显著提升工作效率,优化代码质量,简化开发流程。希望本文介绍的插件能够帮助您更好地利用VS Code进行高效开发。