大家好,我是VoerkaI18n
前端多语言解决方案的作者,以下是我的一波开源项目:
- 全流程一健化React/Vue/Nodejs国际化方案 - VoerkaI18n
- 无以伦比的React表单开发库 - speedform
- 终端界面开发增强库 - Logsets
- 简单的日志输出库 - VoerkaLogger
- 装饰器开发 - FlexDecorators
- 有限状态机库 - FlexState
- 通用函数工具库 - FlexTools
- 小巧优雅的CSS-IN-JS库 - Styledfc
- 为JSON文件添加注释的VSCODE插件 - json_comments_extension
- 开发交互式命令行程序库 - mixed-cli
- 强大的字符串插值变量处理工具库 - flexvars
- 前端link调试辅助工具 - yald
- 异步信号 - asyncsignal
我来给大家分享一下提高自己前端技术段位的一些小技能。
每个前端开发均会使用到Vite/Rollup/webpack/esbuild/Rspack/babel
等前端代码编译工具库,前端代码编译工具负责进行源代码的转译、打包、压缩等工作。
现代主流的前端编译工具一般设计为由一个编译核心
+若干扩展插件
的形式,从而形成一个庞大的生态系统。编译核心
主要负责AST生成
、编译生命周期管理
,以及插件子系统
。而大部份的功能均尽可能使用扩展插件
来实现。
一般情况下,我们只需要使用各编译工作生态内的扩展插件就可以了,但总有一些自动化功能无法满足,或者无法找到合适的插件,此时就需要自已开发一个对应的Vite/Rollup/webpack/esbuild/Rspack/babel
插件。
如何开发编译插件
那么如何开发一个Vite/Rollup/webpack/esbuild/Rspack/babel
插件呢?一般来讲,我们需要了解以下知识:
以Rollup
为例:
- 首先我们得了解编译机制和编译生命周期
下图是Rollup
的编译流程以及命令周期钩子事件,我们得搞懂Rollup
是如何对源代码进行编译, 每个环节分别负责什么,每个插件钩子的参数是什么等等等,这样我们才能够在合适时机注册钩子进行各种操作。
从我个人的角度看,要完全掌握Rollup
编译流程中的各项细节也是要耗不少精力的。
- 接着找到合适的插件扩展点
接下来,我们得了解编译生命周期和流程中的各个钩子的声明、参数以及作用机制等,然后选择一个合适的插件扩展点,注册插件进行处理。
- 操纵源代码
最后在插件代码里面就可以对源码进行各种骚操作了。要操作源代码一般不可避免地会涉及到正则表达式、AST抽象语法树等知识。
通用构建插件开发神器
对于库开源者而言,要让自己开发的库在不同场景下均可以使用,就要分别开发Vite/Rollup/webpack/esbuild/Rspack/babel
插件,想想要花很大的精力去了解各个编译工具的插件开发机制,实在是耗时又耗力。
以笔者开发的VoerkaI18n
多语言解决方案为例,就分别开发babel
、vite
和webpack
三种插件。为了开发这三种不同的插件,笔者也不得已花了不小的时间来了解相应的知识。
现在好了,知名的开源组织unjs
(知名大神Antfu
就是该组织成员)为我们贡献了一个通用构建插件系统 -Unplugin
Unplugin
提供了一个非常简单的API,适配Vite/Rollup/webpack/esbuild/Rspack/
,只需要开发一个unplugin
就可以输出Vite/Rollup/webpack/esbuild/Rspack/
插件。
unplugin
支持以下hook
最简单用法就是使用transformInclude
和transform
进行转码,
transformInclude(id)
:用来匹配哪一个文件要进行转码。transform(code)
: 输入源代码字符串,返回转码后的源代码。
开发unplugin
非常简单,如下:
import type { UnpluginFactory } from 'unplugin'
import { createUnplugin } from 'unplugin'
export interface Options {
// define your plugin options here
}
export const unpluginFactory: UnpluginFactory<Options | undefined> = options => ({
name: 'unplugin-starter',
// webpack's id filter is outside of loader logic,
// an additional hook is needed for better perf on webpack
transformInclude(id) {
return id.endsWith('main.ts')
},
// just like rollup transform
transform(code) {
return code.replace(/<template>/, '<template><div>Injected</div>')
},
// more hooks coming
})
export const unplugin = /* #__PURE__ */ createUnplugin(unpluginFactory)
export default unplugin
export const vitePlugin = unplugin.vite
export const rollupPlugin = unplugin.rollup
export const webpackPlugin = unplugin.webpack
export const rspackPlugin = unplugin.rspack
export const esbuildPlugin = unplugin.esbuild```
小结
使用unplugin
通过transformInclude
和transform
两个API就可以非常容易实现转码功能。
接下插件需要处理的就是如何对transform
传入的code
进行处理的问题。
本系列接下来将分别介绍几种处理源代码的方法:
- 正则表达式匹配处理
- AST抽象语法树
- ast-grep(sg)
- EasyAST