Skip to content

Commit f4431cf

Browse files
committed
feat: add import error handler that ignores urls from themer.sanity.build
1 parent f7d62c6 commit f4431cf

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import Module from 'node:module'
2+
3+
export interface ImportErrorHandlerResult {
4+
cleanup: () => void
5+
}
6+
7+
// Module._load is an internal Node.js API not exposed in types
8+
interface ModuleConstructor {
9+
_load(request: string, parent: Module | undefined, isMain: boolean): any
10+
}
11+
12+
/**
13+
* Return safe empty module with Proxy for deep property access. This ensures any property
14+
* access or function call returns a safe value
15+
*/
16+
function getProxyHandler() {
17+
const handler: ProxyHandler<object> = {
18+
get: (_target, prop) => {
19+
if (prop === '__esModule') return true
20+
if (prop === 'default') return new Proxy({}, handler)
21+
return new Proxy({}, handler)
22+
},
23+
apply: () => new Proxy({}, handler),
24+
}
25+
return new Proxy({}, handler)
26+
}
27+
28+
/**
29+
* Sets up a Module._load wrapper to silently ignore imports from https://themer.sanity.build
30+
* This allows users to use themer URL imports in their config without breaking CLI commands.
31+
*
32+
* @returns Handler result with cleanup function
33+
* @internal
34+
*/
35+
export function setupImportErrorHandler(): ImportErrorHandlerResult {
36+
// Store original Module._load
37+
const ModuleConstructor = Module as unknown as ModuleConstructor
38+
const originalLoad = ModuleConstructor._load
39+
40+
// Override Module._load to catch and handle themer.sanity.build imports
41+
ModuleConstructor._load = function (
42+
request: string,
43+
parent: Module | undefined,
44+
isMain: boolean,
45+
) {
46+
try {
47+
return originalLoad.call(this, request, parent, isMain)
48+
} catch (error) {
49+
// Check if this is a themer.sanity.build URL import
50+
if (request.startsWith('https://themer.sanity.build/api/')) {
51+
// Return a safe proxy object that can be used in place of the theme
52+
return getProxyHandler()
53+
}
54+
55+
// Re-throw all other errors
56+
throw error
57+
}
58+
}
59+
60+
return {
61+
cleanup: () => {
62+
ModuleConstructor._load = originalLoad
63+
},
64+
}
65+
}

packages/sanity/src/_internal/cli/util/mockBrowserEnvironment.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {addHook} from 'pirates'
77
import resolveFrom from 'resolve-from'
88

99
import {getStudioEnvironmentVariables} from '../server/getStudioEnvironmentVariables'
10+
import {setupImportErrorHandler} from './importErrorHandler'
1011

1112
const require = createRequire(import.meta.url)
1213

@@ -24,6 +25,9 @@ export function mockBrowserEnvironment(basePath: string): () => void {
2425
}
2526
}
2627

28+
// Set up import error handler before esbuild-register to silently ignore themer.sanity.build URLs
29+
const importErrorHandler = setupImportErrorHandler()
30+
2731
const btoa = global.btoa
2832
const domCleanup = jsdomGlobal(jsdomDefaultHtml, {url: 'http://localhost:3333/'})
2933

@@ -60,6 +64,7 @@ export function mockBrowserEnvironment(basePath: string): () => void {
6064
globalCleanup()
6165
windowCleanup()
6266
domCleanup()
67+
importErrorHandler.cleanup()
6368
}
6469
}
6570

0 commit comments

Comments
 (0)