fix(esm): Vendor 支持子路径,不然 es-toolkit/compat 这种装不了
有些包把东西放在子路径下(es-toolkit 的 toString 只在 compat 里,主入口没有),
而摊平之后原包的 exports 映射就没了,import "es-toolkit/compat" 解析不到。
现在直接写子路径就行:
esm.Install(ctx, "es-toolkit/compat", "app/node_modules")
拉的是根包,摊平的是子路径,落到 node_modules/es-toolkit/compat/。根包和子路径
可以共存——子路径目录嵌在根包目录里,而最小 package.json 不写 exports,
所以解析器认得出来。
npm.SplitPath 负责拆名字,scoped 包名自带一个斜杠所以前两段才是包名。
This commit is contained in:
@@ -191,3 +191,71 @@ func TestVendor_写出最小的package_json(t *testing.T) {
|
||||
t.Error("不该写 exports 字段")
|
||||
}
|
||||
}
|
||||
|
||||
// 带子路径的名字要能摊平:有些包把东西放在子路径下(es-toolkit/compat),
|
||||
// 而摊平之后原包的 exports 映射就没了,子路径本来解析不到。
|
||||
func TestVendor_子路径当成独立的包摊平(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
// 摆一个带子目录的包:根入口和 sub 入口导出不同的东西
|
||||
writePkg(t, dir, "multi", "1.0.0", "index.js", `export const root = "根"`, nil)
|
||||
subDir := filepath.Join(dir, "node_modules", "multi", "sub")
|
||||
if err := os.MkdirAll(subDir, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(subDir, "index.js"),
|
||||
[]byte(`export const only = "只在子路径里"`), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
app := t.TempDir()
|
||||
out := filepath.Join(app, "node_modules")
|
||||
if _, err := esm.Vendor(dir, "multi/sub", out); err != nil {
|
||||
t.Fatalf("子路径摊不平: %v", err)
|
||||
}
|
||||
// 根包也摊一份,验证两者能共存(子路径目录嵌在根包目录里)
|
||||
if _, err := esm.Vendor(dir, "multi", out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Join(app, "Http"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(app, "Http", "C.ts"), []byte(`
|
||||
import { root } from "multi"
|
||||
import { only } from "multi/sub"
|
||||
export default class C {
|
||||
Run(): string { return root + "/" + only }
|
||||
}`), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
loader, err := esm.NewLoader(app)
|
||||
if err != nil {
|
||||
t.Fatalf("打包失败: %v", err)
|
||||
}
|
||||
e, err := jscriptx.New(jscriptx.WithLoader(loader), jscriptx.WithLogger(nil))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer e.Close()
|
||||
|
||||
s, err := e.Script("Http/C")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ctx := context.Background()
|
||||
obj, err := s.New(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer obj.Close()
|
||||
|
||||
got, err := obj.Call(ctx, "Run")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got != "根/只在子路径里" {
|
||||
t.Errorf("Run = %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user