背景
在 GitHub 遇到一些好玩的 TS 代码想直接在浏览器运行,但是浏览器目前并不支持 TS,还处于提案阶段。
比如遇到一个好玩的在控制台播放视频的小工具 console.video.ts。 要是能直接复制即编译该多好。
如图,要是 GitHub 能有一个类似下图红框中的『Copy as JS』按钮该多好。
解决方案
在 node.js 中编译 ts 大家都知道用 tsc、esbuild 或 babel。这里相应也有几种解决方案。
tsc
1 浏览器安装 npm 包之安装 tsc 编译工具。
async function installTSCompiler() {
const typescriptServices = 'https://cdn.jsdelivr.net/npm/typescript@4.6.3/lib/typescriptServices.js'
return installNpmPackage(typescriptServices)
.then(() => {
const ts = window.ts;
if (!ts) { return null }
log(`ts@${ts.version} installed in your console.`);
return ts;
});
}
function installNpmPackage(packageSrcOrName) {
return isURL(packageSrcOrName) ? insertScript(packageSrcOrName) : insertScript(`https://cdn.jsdelivr.net/npm/${packageSrcOrName}`)
}
2 编译
const sourceCode = `function foo(str: string): number {
return str?.length ?? 0
}`;
const tsc = await installTSCompiler(id);
const { outputText: js } = tsc.transpileModule(sourceCode, {
compilerOptions: {
target: 'esnext'
}
});
console.log('编译结果:', js)
esbuild
1 同理浏览器安装 esbuild-wasm
await installNpmPackage('esbuild-wasm')
2 编译
const sourceCode = `const foo = (str: string): string => {
return 'bar';
}`
// 注意有且仅有一次初始化
await esbuild.initialize({
wasmURL: 'https://cdn.jsdelivr.net/npm/esbuild-wasm@0.14.38/esbuild.wasm',
})
const output = await esbuild.transform(sourceCode, { loader: 'ts' })
console.log('编译结果:', output)
Babel
1 同理浏览器安装 esbuild-wasm
await installNpmPackage('@babel/standalone')
2 编译
const sourceCode = `const foo = (str: string): string => {
return 'bar';
}`
var output = Babel.transform(sourceCode, { filename: 'file.ts', presets: ["typescript"] }).code;
console.log('编译结果:', output)
比较
可用性
esbuild 因为要初始化加载 wasmURL,而该链接的 host 不属于 github 的 content-security-policy host 之一,故没法在有 csp 的网站上运行比如 github 或 npm。
tsc 和 babel 方案没有类似问题 ,能在任意网站顺利编译。但是都是同步编译,存在阻塞主线程的可能性。
性能 WIP
预估 esbuild > babal > tsc
参考
- tsc – Script tag support for TypeScript
- esbuild – Running in the browser
- 完整代码