把一个目录当脚本仓库:按路径寻址、esbuild 打包、内容变了自动重编。
- Loader 扫目录建索引,Load(name) 给出打好包的源码和版本号
- bundler esbuild 的封装。ESM 格式而不是 IIFE——IIFE 会附带一整套
CommonJS interop helper,每建一个 VM 都要重跑一遍
- plugin 把扩展的 TS 模块变成可以 import 的虚拟模块,磁盘上没有文件
- typings 把这些虚拟模块的类型按 node_modules 布局落盘,编辑器才认识
esbuild 原生实现了 Node 的模块解析,所以脚本能直接 import node_modules
里的第三方库。写出来的类型文件是 index.ts 而不是 index.d.ts:扩展给的是
真正的模块源码,里面可能带实现,声明文件里不允许有实现。
node_modules 不参与热更新的版本计算——依赖包是装出来的,改动总伴随显式的
安装动作,而真实的 npm 包动辄上千个文件,每次取脚本 stat 一遍太贵。
51 lines
1.9 KiB
Go
51 lines
1.9 KiB
Go
package esm
|
|
|
|
import (
|
|
"git.fsdpf.net/go/jscriptx"
|
|
"github.com/evanw/esbuild/pkg/api"
|
|
)
|
|
|
|
// extNamespace 是扩展模块在 esbuild 里的命名空间。这些模块不在磁盘上,
|
|
// 靠插件在解析阶段临时提供,所以要跟真实文件区分开。
|
|
const extNamespace = "jscriptx-ext"
|
|
|
|
// extensionPlugin 把扩展的 TS 模块变成可以 import 的虚拟模块:
|
|
//
|
|
// import store from "@jscriptx/store"
|
|
//
|
|
// 磁盘上没有这个文件,路径由扩展自己的 Module() 给出,源码也是它提供的。
|
|
// 模块本身只是个门面——把全局对象转发出来并附上类型声明,真正的实现在 Go 侧,
|
|
// 由 jscriptx 在建 VM 时注入。
|
|
//
|
|
// 拿不到扩展实例时(比如脚本 import 了但 ctx 里没带这个扩展),打包阶段不会报错,
|
|
// 因为模块只声明全局;真正缺东西要到运行时才暴露——这跟直接用全局变量的行为一致。
|
|
func extensionPlugin(exts []jscriptx.Extension) api.Plugin {
|
|
modules := make(map[string]string, len(exts))
|
|
for _, ext := range exts {
|
|
path, source := ext.Module()
|
|
if path == "" || source == "" {
|
|
continue
|
|
}
|
|
modules[path] = source
|
|
}
|
|
|
|
return api.Plugin{
|
|
Name: "jscriptx-extensions",
|
|
Setup: func(build api.PluginBuild) {
|
|
// 认领扩展的模块路径,交给下面的 OnLoad 提供内容
|
|
build.OnResolve(api.OnResolveOptions{Filter: `.*`}, func(args api.OnResolveArgs) (api.OnResolveResult, error) {
|
|
if _, ok := modules[args.Path]; !ok {
|
|
return api.OnResolveResult{}, nil // 不是扩展模块,让 esbuild 照常解析
|
|
}
|
|
return api.OnResolveResult{Path: args.Path, Namespace: extNamespace}, nil
|
|
})
|
|
|
|
build.OnLoad(api.OnLoadOptions{Filter: `.*`, Namespace: extNamespace},
|
|
func(args api.OnLoadArgs) (api.OnLoadResult, error) {
|
|
source := modules[args.Path]
|
|
return api.OnLoadResult{Contents: &source, Loader: api.LoaderTS}, nil
|
|
})
|
|
},
|
|
}
|
|
}
|