TypeBox: Modules incorrectly caching by path
Failing module
There appears to be a module "cache by path" issue on esm.sh which is causing runtime functionality to fail in TypeBox. The functionality relates specifically to registering custom types in TypeBox (where a shared stateful registry (TypeRegistry) is defined in one module) which is then shared across multiple other modules.
The expectation is that absolute path "https://esm.sh/@sinclair/typebox" (which contains the TypeRegistry) is cached once and reused, however multiple instances of this module seem to be created when importing sub module paths.
- GitHub: https://github.com/sinclairzx81/typebox
- npm: https://www.npmjs.com/package/@sinclair/typebox
The following is repro of the issue.
// using deno npm specifier works ok
import { Kind, TypeRegistry } from "npm:@sinclair/typebox"
import { Value } from "npm:@sinclair/typebox/value"
// esm.sh import seems to generate two instances of TypeRegistry
// import { Kind, TypeRegistry } from "https://esm.sh/@sinclair/typebox"
// import { Value } from "https://esm.sh/@sinclair/typebox/value"
// This line registers the `Foo` type on the TypeRegistry (defined in https://esm.sh/@sinclair/typebox)
TypeRegistry.Set('Foo', (_, value) => value === 'foo')
// This line will internally check the TypeRegistry (via relative path to https://esm.sh/@sinclair/typebox)
const R = Value.Check({ [Kind]: 'Foo' }, 'foo')
console.log(R)
Error message
After running deno run I got this:
# This error message is generated by TypeBox as it cannot find the registered type as
# the Value import is using it's own instance of the TypeRegistry. This only occurs when
# using esm.sh.
error: Uncaught Error: Unknown type
Additional info
I think the issue here is that the path to ./typebox.ts (which is referenced by the Value modules) are being loaded in as distinct modules. Because they are distinct, two versions of the TypeRegistry are being created, one for user level import, and another which is internally imported via the Value (as well as TypeCompiler) modules, but not sure.
- esm.sh version: n/a (loading via import)
- Deno version: deno 1.37.1
Happy to provide more detail if needed
Related https://github.com/esm-dev/esm.sh/issues/16
@ije Any update on this? I just ran into this issue, esm.sh appears to instance the same module multiple times.
i am looking into it...seems typebox and typebox/value do not share the typebox/type module
just found the no-bundle mode works:
import { Kind, type TSchema, TypeRegistry } from "https://esm.sh/@sinclair/[email protected]?no-bundle";
import { Value } from "https://esm.sh/@sinclair/[email protected]/value?no-bundle";
const Foo = { [Kind]: "Foo" } as TSchema;
TypeRegistry.Set("Foo", (_, value) => value === "foo");
assertEquals(Value.Check(Foo, "foo"), true);
assertEquals(Value.Check(Foo, "bar"), false);
@sinclairzx81 can you please add a esm.sh specific field in the pakcage.json?
{
"name": "@sinclair/typebox",
"esm.sh": {
"bundle": false // disables the default bundling behavior
}
}
check https://github.com/esm-dev/esm.sh#bundling-strategy
@ije Hi, thanks for the follow up on this!
can you please add a esm.sh specific field in the pakcage.json?
Thanks, I'll give this some consideration, but may recommend the ?no-bundle option in the short term as I think I prefer the explicit opt-out on the import path vs package.json configurations, but will give it some thought.
Happy to close off this issue! Cheers S
@sinclairzx81 thanks!