Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: add virtual:mercur/components module for dynamic component loading
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
  • Loading branch information
vholik and claude committed Feb 5, 2026
commit 1eab19c4f4739e272ecd01b0c9314957378eea5d
2 changes: 1 addition & 1 deletion apps/vendor/src/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export function Sidebar() {
return <div>Sidebar</div>
return <div>Sidebar 123123</div>
}
10 changes: 5 additions & 5 deletions packages/core-ui/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
// import customRoutes from "virtual:mercur/routes"
import config from "virtual:mercur/config"
import components from "virtual:mercur/components"
import { HelmetProvider } from "react-helmet-async"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { ThemeProvider } from "./providers"
import { Toaster, TooltipProvider } from "@medusajs/ui"

// cimport { createBrowserRouter, RouterProvider } from "react-router-dom"
// import { createBrowserRouter, RouterProvider } from "react-router-dom"

const queryClient = new QueryClient()

export default function App() {


return (
<TooltipProvider>
<HelmetProvider>
<QueryClientProvider client={queryClient}>
<ThemeProvider>
wassup
{JSON.stringify(config)}
{config.components?.Sidebar}
{components.Sidebar && <components.Sidebar />}
{/* <RouterProvider router={createBrowserRouter(customRoutes)} /> */}
<Toaster />
</ThemeProvider>
Expand Down
11 changes: 10 additions & 1 deletion packages/core-ui/src/module.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
declare module "virtual:mercur/config" {
import type { MercurConfig } from "./index"
const config: MercurConfig
const config: Omit<MercurConfig, 'components'>
export default config
}

declare module "virtual:mercur/routes" {
import type { RouteObject } from "react-router-dom"
const routes: RouteObject[]
export default routes
}

declare module "virtual:mercur/components" {
import type { ComponentType } from "react"
const components: {
Sidebar?: ComponentType
[key: string]: ComponentType | undefined
}
export default components
}
44 changes: 38 additions & 6 deletions packages/core-ui/src/vite-plugin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ const CONFIG_NAME = "mercur.config.ts"

const CONFIG_VIRTUAL_MODULE = "virtual:mercur/config"
const ROUTES_VIRTUAL_MODULE = "virtual:mercur/routes"
const COMPONENTS_VIRTUAL_MODULE = "virtual:mercur/components"

const RESOLVED_CONFIG_MODULE = "\0" + CONFIG_VIRTUAL_MODULE
const RESOLVED_ROUTES_MODULE = "\0" + ROUTES_VIRTUAL_MODULE
const RESOLVED_COMPONENTS_MODULE = "\0" + COMPONENTS_VIRTUAL_MODULE

const VIRTUAL_MODULES = [CONFIG_VIRTUAL_MODULE, ROUTES_VIRTUAL_MODULE]
const VIRTUAL_MODULES = [CONFIG_VIRTUAL_MODULE, ROUTES_VIRTUAL_MODULE, COMPONENTS_VIRTUAL_MODULE]

function isVirtualModule(id: string): boolean {
return VIRTUAL_MODULES.includes(id)
Expand All @@ -21,9 +23,39 @@ function resolveVirtualModule(id: string): string {
return "\0" + id
}

function loadVirtualModule(id: string, mercurConfig: MercurConfig) {
function loadVirtualModule({
cwd,
id,
mercurConfig,
}: {
id: string
mercurConfig: MercurConfig
cwd: string
}) {
if (id === RESOLVED_CONFIG_MODULE) {
return `export default ${JSON.stringify(mercurConfig)}`
// Export config without components (they go in separate module)
const { components, ...configWithoutComponents } = mercurConfig
return `export default ${JSON.stringify(configWithoutComponents)}`
}

if (id === RESOLVED_COMPONENTS_MODULE) {
const components = mercurConfig.components ?? {}
const imports: string[] = []
const exports: string[] = []

Object.entries(components).forEach(([name, componentPath]) => {
const resolvedPath = path.resolve(cwd, 'src', componentPath)
imports.push(`import { ${name} as _${name} } from "${resolvedPath}"`)
exports.push(`${name}: _${name}`)
})

return `
${imports.join('\n')}

export default {
${exports.join(',\n ')}
}
`
}

if (id === RESOLVED_ROUTES_MODULE) {
Expand Down Expand Up @@ -54,8 +86,8 @@ export function mercurVendorPlugin(): Vite.Plugin {

return {
name: "@mercurjs/core-ui/vite-plugin",
configResolved(config) {
root = config.root
configResolved(resolvedConfig) {
root = resolvedConfig.root
},
async buildStart() {
config = await loadMercurConfig(root)
Expand All @@ -67,7 +99,7 @@ export function mercurVendorPlugin(): Vite.Plugin {
return null
},
load(id) {
return loadVirtualModule(id, config)
return loadVirtualModule({ cwd: root, id, mercurConfig: config })
},
handleHotUpdate({ file, server }) {
if (file.endsWith(CONFIG_NAME)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/core-ui/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default defineConfig([
format: ["esm"],
dts: true,
clean: true,
external: ['virtual:mercur/routes', 'virtual:mercur/config'],
external: ['virtual:mercur/routes', 'virtual:mercur/config', 'virtual:mercur/components'],
},
{
entry: ["src/vite-plugin/index.ts"],
Expand Down