@decocms/blocks 7.0.2 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decocms/blocks",
|
|
3
|
-
"version": "7.0
|
|
3
|
+
"version": "7.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Deco framework-agnostic core: CMS block resolution, section registry, matchers, portable SDK utilities",
|
|
6
6
|
"repository": {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"exports": {
|
|
13
13
|
".": "./src/index.ts",
|
|
14
14
|
"./cms": "./src/cms/index.ts",
|
|
15
|
+
"./cms/client": "./src/cms/client.ts",
|
|
15
16
|
"./cms/loadDecofileDirectory": "./src/cms/loadDecofileDirectory.ts",
|
|
16
17
|
"./hooks": "./src/hooks/index.ts",
|
|
17
18
|
"./types": "./src/types/index.ts",
|
|
@@ -92,6 +93,7 @@
|
|
|
92
93
|
"devDependencies": {
|
|
93
94
|
"@types/react": "^19.0.0",
|
|
94
95
|
"@types/react-dom": "^19.0.0",
|
|
96
|
+
"esbuild": "^0.27.3",
|
|
95
97
|
"knip": "^5.86.0",
|
|
96
98
|
"typescript": "^5.9.0"
|
|
97
99
|
},
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
|
|
6
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
// esbuild's JS API relies on `new TextEncoder().encode("") instanceof
|
|
8
|
+
// Uint8Array` internally, which fails across Vitest's module-isolation VM
|
|
9
|
+
// boundary (a realm mismatch, not a real environment problem — `bun -e`
|
|
10
|
+
// confirms the invariant holds outside Vitest). Shelling out to the esbuild
|
|
11
|
+
// CLI binary sidesteps this: it's a separate OS process, no shared JS realm.
|
|
12
|
+
const esbuildBin = join(here, "../../../../node_modules/.bin/esbuild");
|
|
13
|
+
|
|
14
|
+
function bundleForBrowser(entry: string) {
|
|
15
|
+
return execFileSync(
|
|
16
|
+
esbuildBin,
|
|
17
|
+
[entry, "--bundle", "--platform=browser", "--format=esm", "--external:react"],
|
|
18
|
+
{ encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] },
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Regression test for the bug that motivated splitting `client.ts` out of
|
|
24
|
+
* `index.ts`: importing ANYTHING from the full `cms` barrel forces a
|
|
25
|
+
* bundler to evaluate `loader.ts` and `middleware/observability.ts`, which
|
|
26
|
+
* import `node:async_hooks` at the module level. Turbopack rejects that
|
|
27
|
+
* outright when bundling for a browser target; this test catches the same
|
|
28
|
+
* class of failure in CI, deterministically, without needing a real Next.js
|
|
29
|
+
* app to reproduce it.
|
|
30
|
+
*/
|
|
31
|
+
describe("cms/client browser bundle", () => {
|
|
32
|
+
it("bundles for a browser target with no Node built-ins", () => {
|
|
33
|
+
const output = bundleForBrowser(join(here, "client.ts"));
|
|
34
|
+
expect(output).not.toMatch(/node:async_hooks|node:fs|node:path/);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("sanity check: the full cms barrel does NOT bundle for a browser target", () => {
|
|
38
|
+
// Confirms the test above is actually discriminating — if this ever
|
|
39
|
+
// stops throwing, either the barrel no longer has the leak (great,
|
|
40
|
+
// update this test) or esbuild's Node-builtin detection changed
|
|
41
|
+
// (investigate before trusting the test above).
|
|
42
|
+
expect(() => bundleForBrowser(join(here, "index.ts"))).toThrow();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-safe subset of `@decocms/blocks/cms`.
|
|
3
|
+
*
|
|
4
|
+
* `@decocms/blocks/cms` (the full barrel in `./index.ts`) re-exports
|
|
5
|
+
* `loader.ts` and `resolve.ts`, which transitively import `node:async_hooks`
|
|
6
|
+
* and `node:fs/promises`. Bundling ANY export from that barrel for a browser
|
|
7
|
+
* target — even one that itself has zero Node dependencies, like
|
|
8
|
+
* `getResolvedComponent` — drags the whole module graph in, since ES module
|
|
9
|
+
* imports are evaluated at the file level, not per-export. Turbopack rejects
|
|
10
|
+
* this outright in production builds ("the chunking context does not
|
|
11
|
+
* support external modules"); webpack has historically let it through
|
|
12
|
+
* uncaught, which just defers the failure to whoever notices the bloated
|
|
13
|
+
* client bundle or a runtime error.
|
|
14
|
+
*
|
|
15
|
+
* This entry point exists so Client Components can import section-registry
|
|
16
|
+
* lookups (e.g. to resolve and render a section by name, given data already
|
|
17
|
+
* fetched server-side) without pulling in the resolver/loader machinery.
|
|
18
|
+
*
|
|
19
|
+
* Verified client-safe by import-graph inspection, transitively:
|
|
20
|
+
* - `registry.ts` imports only React types.
|
|
21
|
+
* - `sectionMixins.ts` imports `useDevice.ts`, which goes through
|
|
22
|
+
* `requestContext.ts` — that module's only `node:async_hooks` dependency
|
|
23
|
+
* (`requestContextStorage.ts`) is itself swapped for a no-op browser stub
|
|
24
|
+
* via this package's `"browser"` export condition (see
|
|
25
|
+
* `sdk/requestContextStorage.browser.ts`), so it's already safe for a
|
|
26
|
+
* browser bundle.
|
|
27
|
+
* - `schema.ts` has no imports at all.
|
|
28
|
+
*
|
|
29
|
+
* Deliberately NOT re-exported here: `loader.ts`, `resolve.ts`,
|
|
30
|
+
* `sectionLoaders.ts`, `loadDecofileDirectory.ts`, `blockSource.ts`, and
|
|
31
|
+
* `applySectionConventions.ts` (which itself pulls in `resolve.ts` and
|
|
32
|
+
* `sectionLoaders.ts` for section-registration setup). Those are resolver/
|
|
33
|
+
* storage concerns that only make sense server-side — import them from
|
|
34
|
+
* `@decocms/blocks/cms` instead.
|
|
35
|
+
*/
|
|
36
|
+
export type { OnBeforeResolveProps, SectionModule, SectionOptions } from "./registry";
|
|
37
|
+
export {
|
|
38
|
+
getResolvedComponent,
|
|
39
|
+
getSection,
|
|
40
|
+
getSectionOptions,
|
|
41
|
+
getSectionRegistry,
|
|
42
|
+
getSyncComponent,
|
|
43
|
+
listRegisteredSections,
|
|
44
|
+
preloadSectionComponents,
|
|
45
|
+
preloadSectionModule,
|
|
46
|
+
registerOnBeforeResolveProps,
|
|
47
|
+
registerSection,
|
|
48
|
+
registerSections,
|
|
49
|
+
registerSectionsSync,
|
|
50
|
+
setResolvedComponent,
|
|
51
|
+
} from "./registry";
|
|
52
|
+
export type { SectionLoaderFn } from "./sectionLoaders";
|
|
53
|
+
export { compose, withDevice, withMobile, withSearchParam, withSectionLoader } from "./sectionMixins";
|
|
54
|
+
export type { ActionConfig, LoaderConfig, MatcherConfig, MetaResponse } from "./schema";
|
|
55
|
+
export {
|
|
56
|
+
composeMeta,
|
|
57
|
+
getRegisteredLoaders,
|
|
58
|
+
getRegisteredMatchers,
|
|
59
|
+
registerActionSchema,
|
|
60
|
+
registerActionSchemas,
|
|
61
|
+
registerLoaderSchema,
|
|
62
|
+
registerLoaderSchemas,
|
|
63
|
+
registerMatcherSchema,
|
|
64
|
+
registerMatcherSchemas,
|
|
65
|
+
} from "./schema";
|