介绍
TS Macro
是一个基于Volar.js
的VSCode
插件提供修改TS
的能力。
最开始做这个项目的想法是两个月前我与智子面基的时候他提出来的,直到前段时间我做defineStyle
的时候发现如果想要实现语法高亮需要写一个textmate
配置文件并写死在vscode
插件的package.json
里,我才开始写这个插件。
没有这个插件之前,需要先使用@vue-macros/volar/script-sfc
在TSX
文件头部添加<script lang="tsx">
把它转成Vue
文件后才能在@vue/language-tools
里运行。这在Vue
项目里运行的很好,没有问题。但这么强大的功能如果能够像vite
一样提供一个插件系统给所有基于TS
或TSX
的框架使用那就太好了。所以这个项目没有内置任何插件,所有的能力都通过插件的形式交给用户去配置。
仓库地址
使用方式
-
安装 VSCode插件。
-
在
tsconfig.json
的同级目录下创建tsm.config.ts
配置文件。ts-macro
支持从 vite.config.ts 里自动注册插件 就像 xxx.d.ts 一样。
对于插件的作者 需要抛出一个volar
文件ts-macro
就会自动加载这个插件 并与vite
插件共享userOptions
。 Example
对于插件的使用者 只需要安装TS Macro
的vscode
插件 可以不用写tsm.config.ts
了。 -
编写第一个插件,声明一个
defineStyle
类型。
// tsm.config.ts
export default {
plugins: [
{
name: 'ts-macro-define-style',
resolveVirtualCode({ codes }){
// 在每个 TS 文件结尾声明一个 defineStyle 函数
codes.push(`declare function defineStyle<T>(style: string): T;`)
}
}
]
}
编写defineStyle
插件
在这里我们使用createPlugin
来定义插件,还可以兼容Vue
。
完整实现的代码
安装 ts-macro
pnpm add ts-macro
编写插件
// define-style.ts
import { createPlugin, replaceSourceRange } from 'ts-macro'
export default createPlugin<{ macro: string } | undefined>(
(
{
ts,
compilerOptions,
vueCompilerOptions // 用于设置 userOptions 👇 只有在 vue 插件里才有值
},
userOptions = vueCompilerOptions?.defineStyle ?? { macro: 'defineStyle' }
) => ({
name: 'ts-macro-define-style',
resolveVirtualCode({ ast, codes, source }){
// 1. 在每个 TS 文件结尾声明一个 defineStyle 函数
codes.push(`declare function defineStyle<T>(style: string): T;`)
// 2. 遍历 ast
walkAst(ast)
function walkAst(
node: import('typescript').Node,
parent?: import('typescript').Node,
) {
if (
ts.isCallExpression(node) &&
ts.isIdentifier(node.expression) &&
node.expression.text === userOptions.macro
) {
// 3. 找到 defineStyle 的范型位置后插入自定义类型.
replaceSourceRange( // 类似于的 Array.splice 方法
codes,
source, // 在vue文件里才有值: 'script' | 'scriptSetup' | undefined
node.arguments.pos - 1,
node.arguments.pos - 1,
// 应该用正则表达式找出 css 里所有的 class,这里为了简单起见就先写死了。
'<{ foo: string }>',
)
}
ts.forEachChild(node, (child) => {
walkAst(child, node)
})
}
}
})
)
使用方式
- 在
TS Macro
里使用
// tsm.config.ts
import defineStyle from './define-style.ts'
export default {
plugins: [
defineStyle({
macro: 'defineStyle'
})
]
}
- 在
Vue
里使用,需要先发布到npm
,并安装到package.json
里。
// tsconfig.json
{
// ...
"vueCompilerOptions": {
"plugins": [
"define-style",
],
"defineStyle": {
"macro": "defineStyle"
}
}
}
效果
TSC
使用tsmc
代替tsc
编译TS。
- 安装
pnpm add @ts-macro/tsc -D
- 在
package.json
里使用
{
"scripts": {
"typecheck": "tsmc --noEmit"
}
}
更多例子
在react
项目里使用vue
指令和vue
宏。
结尾
最后还感谢这些伟大的项目,让我少踩了好多坑。