复制即编译——如何在浏览器编译 TypeScript

复制即编译——如何在浏览器编译 TypeScript

背景

在 GitHub 遇到一些好玩的 TS 代码想直接在浏览器运行,但是浏览器目前并不支持 TS,还处于提案阶段。

比如遇到一个好玩的在控制台播放视频的小工具 console.video.ts。 要是能直接复制即编译该多好。

如图,要是 GitHub 能有一个类似下图红框中的『Copy as JS』按钮该多好。

复制即编译——如何在浏览器编译 TypeScript

解决方案

在 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
  • 完整代码

评论

发表回复