package jscriptx_test import ( "context" "path/filepath" "testing" "git.fsdpf.net/go/jscriptx" "github.com/evanw/esbuild/pkg/api" ) // WithBundleDefine:编译期常量替换。 func TestBundleOption_Define(t *testing.T) { e := newEngine(t, jscriptx.WithBundleOptions( jscriptx.WithBundleDefine(map[string]string{"__MODE__": `"生产"`}), )) s := mustCompile(t, e, "def.ts", ` declare const __MODE__: string export function mode(): string { return __MODE__ } `) got, err := s.Call(context.Background(), "mode") if err != nil { t.Fatal(err) } if got != "生产" { t.Errorf("常量没被替换, got %#v", got) } } // WithBundleTarget:把语法降级到指定的 ECMAScript 版本。 // goja 对新语法的覆盖不是 100%,调低 target 是遇到问题时的出路。 func TestBundleOption_Target(t *testing.T) { // 用可选链和空值合并这类较新的语法,降级到 ES2015 后应该被改写掉 src := `export function pick(o) { return o?.a?.b ?? "兜底" }` for _, target := range []struct { name string t api.Target }{{"ES2015", api.ES2015}, {"ES2020", api.ES2020}} { t.Run(target.name, func(t *testing.T) { e := newEngine(t, jscriptx.WithBundleOptions(jscriptx.WithBundleTarget(target.t))) s := mustCompile(t, e, "t.ts", src) ctx := context.Background() got, err := s.Call(ctx, "pick", map[string]any{"a": map[string]any{"b": "命中"}}) if err != nil { t.Fatalf("调用失败: %v", err) } if got != "命中" { t.Errorf("got = %#v", got) } if got, err := s.Call(ctx, "pick", nil); err != nil || got != "兜底" { t.Errorf("空值合并没生效: got=%#v err=%v", got, err) } }) } } // WithNodePaths / WithAlias:给直接 Compile 的源码指定模块来源。 func TestBundleOption_NodePathsAndAlias(t *testing.T) { libs, err := filepath.Abs("esm/testdata/app/node_modules") if err != nil { t.Fatal(err) } src := `import { upper } from "tinylib" export function shout(s: string): string { return upper(s) }` // 不指定时找不到:这段源码没有文件系统上下文 e0 := newEngine(t) if _, err := e0.Compile("x.ts", src); err == nil { t.Error("没有解析基准时应该报错") } // NodePaths 指向 node_modules 所在目录 e1 := newEngine(t, jscriptx.WithBundleOptions(jscriptx.WithNodePaths(libs))) s1, err := e1.Compile("x.ts", src) if err != nil { t.Fatalf("WithNodePaths 没生效: %v", err) } if got, _ := s1.Call(context.Background(), "shout", "hi"); got != "HI" { t.Errorf("got = %#v", got) } // Alias 把模块名钉到具体文件 impl, err := filepath.Abs("esm/testdata/app/node_modules/tinylib/index.js") if err != nil { t.Fatal(err) } e2 := newEngine(t, jscriptx.WithBundleOptions( jscriptx.WithAlias(map[string]string{"tinylib": impl}), )) s2, err := e2.Compile("x.ts", src) if err != nil { t.Fatalf("WithAlias 没生效: %v", err) } if got, _ := s2.Call(context.Background(), "shout", "hi"); got != "HI" { t.Errorf("got = %#v", got) } }