Commit Graph
4 Commits
Author SHA1 Message Date
what 7e1893b246 refactor: 文件按主类型划分,一个 struct 一个功能
约定:文件名 = 主类型名;同一个类型要拆多个文件时用 类型_子项.go。

  engine.go          355 → 231 行。原来混了三件不相干的事
  engine_globals.go  ← bind / lazyGlobal / freeze / defineReadOnly(96 行)
                       它是「Go 值 → 只读 JS 全局」的转换层,跟脚本缓存毫无关系
  engine_console.go  ← console.go,跟上面是同一主题
  script.go          325 → 100 行,只留公开方法
  script_vm.go       ← VM 的取、还、装载。上个 commit 合一的三条路径现在住一起
  script_static.go   ← static.go
  errors.go          364 → 150 行
  errors_goja.go     ← goja 错误的翻译层
  errors_hints.go    ← missingGlobalHint,一份 JS 运行时知识库,跟错误分类是
                       两回事;拆出来之后 missing_global_test.go 才有对应源文件
  bundle_finalize.go ← esmwrap.go
  bundle.go          收下 validIdent / hashVersion(原来住在 engine.go)

Engine.New 原来排在所有私有函数之后,挪到导出方法那一段。

classify 83 → 54 行:四个 errors.As 分支各手搓一个 8 字段的 &Error{},脚本上下文
那三行重复了 4 遍,抽出 gojaError 构造器。

顺带修四处注释漂移:

  Session/会话   代码里叫 Instance,注释里大面积残留。engine_globals.go 那条
                 「注入会话全局对象失败」还是用户可见文案,而公开 API 里根本
                 没有「会话」这个概念
  Extension      文档示例写 Module() string,接口是 Module() (path, source string)。
                 这是唯一一段教人写扩展的文档,照抄编译不过
  doc.go 的 freeze  说白名单「逐层拷贝成只读对象,不会跨 VM 共享可变的 Go map」,
                 但那只对 map[string]any 成立。结构体指针和 slice 是**共享同一个
                 对象**的——扩展走的正是这条路,不该被当成隔离保证
2026-09-10 15:28:59 +08:00
what 1f25425762 refactor: 取 VM 的三条路径合一,newVM 成为唯一入口
borrow(池化)、ensure(实例)、borrowStatic(静态)各自写了一遍「取作用域 →
拼 extra → 建 Runtime → load」。borrowStatic 甚至把 newVM 逐行抄了一遍,只为把
noInstance 传成 true。

结果就是规则会漏:上一个 commit 修的「borrowStatic 没标 scoped」正是这么来的。
现在三条都走 newVM,作用域注入和 scoped 标记只有一份。

顺带删掉两处无意义的间接:

  loadInto     s.load(ctx, rt, ctorArgs, false) 的单行包装,只被 newVM 调一次
  newRuntime   它的 scope 参数两个调用点都传 s.name,而注释描述的「会话 VM 用
               会话 key」这条路径根本没实现(作用域 key 走的是 vmGlobals)。
               参数名还跟同包的 type scope struct 撞名

**scope 是显式参数,不是从 ctx 嗅的**——这一点差点被我改坏:Instance 重建 VM
时要回到它**创建时**那个作用域,而不是当次调用 ctx 里的。对一个作用域实例调
Call(context.Background()) 不该把它的扩展弄丢。加了
TestScope_实例重建VM后仍在原作用域 守这条,用超时逼出 VM 重建(第一版用抛异常,
那不会丢 VM,两种写法都通过,等于没测)。
2026-09-10 15:25:12 +08:00
what 9b3509ae29 refactor: 清掉指向不存在的 Dispatch 的文档,删掉为它留的死导出
Dispatch 在仓库里出现 7 次,全是注释和错误文案,没有任何实现。三处错误文案
写着「需要回调语义请用 Dispatch」——使用者按这句去查会找不到东西,真正该指的
是 WithCall。caller.go 那句还指向不存在的子包 jscriptx/dispatch。

连带删掉四个为它留的导出(全仓库零调用):

  Target                   统一 Script/Instance 的接口。有未导出方法 owner(),
                           外部实现不了;也没有任何函数以它为参数或返回值
  ErrUnsupportedSignature  哨兵错误,库自己从不产生它
  KindSignature            错误分类,全仓库唯一一次出现就是它自己的声明。
                           留着会让写 switch 的人为一个永不出现的分支写代码
  OverlayLoader.Loaders    零调用的 getter,连测试都没有

另外删掉 Instance.IdleFor 和 lastUsed 字段:它是给「空闲回收」用的,而
doc.go 明确写着本库不代管实例生命周期、没有空闲回收——字段注释和包文档直接
对立。代价是每次 Call 白付两次 time.Now() + atomic store。业务侧真要自己回收,
记一个时间戳是一行的事。

caller 的示例原来拿 ErrUnsupportedSignature 当哨兵,改成自己声明一个——
回调签名的约定本来就是调用方定的,哨兵该归调用方。

验证:framework-v2 和 lx-bid 都仍能编译。
2026-09-10 15:15:10 +08:00
what 0627d49425 feat: 嵌入式 JS 脚本引擎核心
用 goja 承载业务回调,让业务逻辑变更不必重新编译发布 Go 程序。脚本用
ESM + TypeScript 写,Go 侧按名字把它们当普通对象实例化并调用方法。

主要组成:

  - Engine    编译脚本、管配置,公开 API 不暴露任何 goja 类型
  - Script    一份编译好的脚本 + 它的 VM 池,热更新时整体顶替
  - Instance  独占一个 VM 的实例,状态留在 JS 侧
  - Caller    自定义调用约定,把脚本函数适配成 Go 侧要的签名
  - Scope     让同一个 ctx 下的多个脚本共享 Go 侧对象
  - Extension 扩展接口:给脚本添全局对象,配套 TS 类型
  - Overlay   多层 Loader 叠加,后面的盖前面的

几个关键取舍:

  - 源码一律先过 esbuild 打包成 ESM,再改写成立即执行函数。goja 不认
    import/export,而业务脚本要能拆文件、用 TypeScript。
  - VM 池化复用,但每个 VM 单线程。goja 的 Runtime 不是 goroutine 安全的。
  - Go 侧函数返回的 error 在脚本里表现为抛异常,不占返回值位置。
  - 脚本能看见的全局只有白名单放行的那些,且注入是惰性的——没读到的
    全局根本不会被转换。
2026-09-05 22:11:55 +08:00