halo,你们好,我是 132,那个啥,俺又出来诈尸啦vue
此次带来的是一个 ts 打包器的主要思路,最终实现代码先放一下node
github.com/yisar/picop…webpack
欢迎 star 和 fork!git
最近其实写了几个 typescript 的库,可是打包一直困扰着我,一方面感受 tsc 比较好用,不想用 rollup,一边 ts 很难打包多文件github
typescript 是能够将多文件打包为一个文件的,使用 --outputFlie
web
"compilerOptions": {
"module": "amd",
"outFile": "./dist/doux.js"
}
复制代码
这样能够将全部的 ts 文件打包成一个 js 文件,但比较遗憾,只支持 adm 和 systemjstypescript
而咱们写库,一般是 umd 格式的,给 typescript 的人发 issue,回复基本上不会支持json
因此就萌生了本身写一个打包器的想法小程序
传统的 js 打包器都是分析 AST 而后进行各类的修改,替换,而后根据不一样的格式进行包裹,最终产生一个能用的 js 文件浏览器
ts 也不例外……和 babel 同样,ts 官方提供了一组 TS Compiler API
看上去很是不错,比 babel 好太多,主要是 babel 生态乱,想干啥就要用各类第三方库
首先,须要建立一个 ts 项目,顺便进行类型检查
let diagnostics = ts.getPreEmitDiagnostics(
ts.createProgram([entryFile], {
strict: true,
target: ts.ScriptTarget.Latest,
moduleResolution: ts.ModuleResolutionKind.NodeJs
})
)
if (diagnostics.length) {
diagnostics.forEach(d => console.log(d.messageText))
error('Type check Error.')
}
复制代码
首先,咱们大概是须要拿到一个文件的 AST,使用 createSource
const source = program.getSourceFile('fixtures/test.ts')
if (source) {
ts.forEachChild(source, node => {
if (ts.isFunctionDeclaration(node)) {
console.log(node.name && node.name.text)
}
})
}
复制代码
拿到 source,咱们能够根据 kind 进行判断是哪种代码
能够对应 AST viewer 来使用: TS AST viewer
而后通过一波操做后,须要从新生成 AST
const ast = ts.createVariableDeclarationList([
ts.createVariableDeclaration(
ts.createIdentifier('test'),
ts.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
ts.createLiteral('Hello!')
)
], ts.NodeFlags.Const)
const printer = ts.createPrinter()
const code = printer.printNode(ts.EmitHint.Unspecified, ast, source)
console.log(code)
复制代码
到此,整个思路就捋顺了,不过咱们既然是多文件打包,因此还须要根据 import 找到源文件,而后再去检查
case ImportDeclaration:
let moduleSpecifier = node.moduleSpecifier.getText(source)
let dep = JSON.parse(moduleSpecifier) as string
let depPath: string
if (dep.startsWith('.')) {
depPath = localModulePath(dep, path)
}
pathQueue.push(depPath)
break
复制代码
找到这个文件,须要再 compile 一次
很好,差很少就是这样啦
总的来讲,作 typescript compiler 远比 js 有前途的多,主要是 js 太乱了真的
其实 AST 也有两种,一种是借助 babel,webpack,ts compiler 生成的 AST,这种的缺点是比较乱,单词比较长
另外一种是本身作 AST 的生成,这种就至关于 jsx 插件了,最终能够生成和 vdom 同样干净的树
我我的比较倾向于第二种,但………工做量比较大
编译阶段能够说无所不能,前有各类打包器,作各类的代码打包和优化,后有国内各类小程序转译框架,如 taro,nanachi……
可是事实证实,什么东西适合作什么事情都是预约好了的
taro-next 使用了模拟浏览器 API 的方式,放弃编译思路,转投 runtime
svelte 使用编译思路,一直被 vue 等各类吐槽
因此看我的选择吧