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 }) }, } }