11import { defineConfig } from 'vite' ;
22import react from '@vitejs/plugin-react' ;
33import path from 'path' ;
4- import fs from 'fs' ;
54
65const hmrConfig = process . env . VITE_HMR_PORT
76 ? { port : parseInt ( process . env . VITE_HMR_PORT ) , clientPort : parseInt ( process . env . VITE_HMR_PORT ) }
87 : undefined ;
98
10- // Resolve @object -ui/* to the workspace `src/` folders in the sibling
11- // objectui checkout when present. This is required for local development
12- // because the published rolldown bundles inline their own private
13- // ComponentRegistry instance per plugin — breaking cross-plugin component
14- // lookup (e.g. plugin-list cannot find `object-grid` registered by
15- // plugin-grid). Pointing at source ensures a single shared
16- // @object -ui/core ComponentRegistry instance.
17- //
18- // In CI / fork-ready builds where the sibling checkout is not available,
19- // we fall back to the published @object -ui/* packages from node_modules
20- // (matches the official `examples/console-starter` template behaviour).
21- const OBJECTUI_ROOT = path . resolve ( __dirname , '../../../objectui' ) ;
22- const OBJECTUI_PACKAGES_DIR = path . resolve ( OBJECTUI_ROOT , 'packages' ) ;
23- const useObjectUiSource = fs . existsSync ( OBJECTUI_PACKAGES_DIR ) ;
24-
25- const objectUiPackages = [
26- 'app-shell' ,
27- 'auth' ,
28- 'collaboration' ,
29- 'components' ,
30- 'core' ,
31- 'data-objectstack' ,
32- 'fields' ,
33- 'i18n' ,
34- 'layout' ,
35- 'mobile' ,
36- 'permissions' ,
37- 'plugin-calendar' ,
38- 'plugin-charts' ,
39- 'plugin-chatbot' ,
40- 'plugin-dashboard' ,
41- 'plugin-detail' ,
42- 'plugin-form' ,
43- 'plugin-grid' ,
44- 'plugin-kanban' ,
45- 'plugin-list' ,
46- 'plugin-report' ,
47- 'plugin-view' ,
48- 'react' ,
49- 'types' ,
50- ] ;
51-
52- const workspaceAliases : Record < string , string > = useObjectUiSource
53- ? Object . fromEntries (
54- objectUiPackages . map ( ( name ) => [
55- `@object-ui/${ name } ` ,
56- path . resolve ( OBJECTUI_PACKAGES_DIR , name , 'src' ) ,
57- ] ) ,
58- )
59- : { } ;
9+ // Match any file under node_modules belonging to a given @object -ui/* package.
10+ // pnpm flattens packages into paths like:
11+ // node_modules/.pnpm/@object -ui+core@4.0.3_.../node_modules/@object-ui/core/dist/...
12+ // node_modules/@object -ui/core/dist/...
13+ const objectUiPkg = ( name : string ) => ( id : string ) =>
14+ id . includes ( `/@object-ui/${ name } /` ) ||
15+ id . includes ( `\\@object-ui\\${ name } \\` ) ||
16+ id . includes ( `/@object-ui+${ name } @` ) ||
17+ id . includes ( `\\@object-ui+${ name } @` ) ;
6018
6119export default defineConfig ( {
6220 base : process . env . VITE_BASE || '/_dashboard/' ,
6321 resolve : {
6422 dedupe : [ 'react' , 'react-dom' , 'lucide-react' , 'react-router-dom' , 'react-router' ] ,
6523 alias : {
66- ...workspaceAliases ,
6724 react : path . resolve ( __dirname , './node_modules/react' ) ,
6825 'react-dom' : path . resolve ( __dirname , './node_modules/react-dom' ) ,
69- // Force a single react-router copy. When @object-ui/* are aliased to
70- // sibling source, Node's resolver finds react-router-dom in
71- // ../objectui/node_modules — a different physical install than the one
72- // dashboard's App.tsx imports from. Two copies = two Router contexts =
73- // "<Navigate> may be used only in the context of a <Router>".
7426 'react-router-dom' : path . resolve ( __dirname , './node_modules/react-router-dom' ) ,
75- // Don't alias 'react-router' as a string (it would intercept the
76- // 'react-router/dom' subpath import inside react-router-dom). The
77- // dedupe entry above is enough to ensure a single copy.
78- // Force a single lucide-react copy. @object-ui/app-shell pulls 0.544.0
79- // while @object -ui/components and the plugins pull 1.14.0 — letting both
80- // through produces duplicate icon chunks where one references a stale
81- // `createLucideIcon` symbol from the main bundle and crashes at runtime.
82- 'lucide-react' : path . resolve (
83- __dirname ,
84- '../../node_modules/.pnpm/lucide-react@1.14.0_react@19.2.5/node_modules/lucide-react' ,
85- ) ,
27+ // Force a single lucide-react copy. @object-ui/app-shell pulls one
28+ // version while @object -ui/components and the plugins pull another —
29+ // letting both through produces duplicate icon chunks where one
30+ // references a stale `createLucideIcon` symbol from the main bundle
31+ // and crashes at runtime.
32+ 'lucide-react' : path . resolve ( __dirname , './node_modules/lucide-react' ) ,
8633 '@' : path . resolve ( __dirname , './src' ) ,
8734 } ,
8835 } ,
@@ -93,21 +40,19 @@ export default defineConfig({
9340 cssCodeSplit : true ,
9441 // Don't auto-emit `<link rel="modulepreload">` for every chunk; with
9542 // Vite-Rolldown's per-icon code splitting that would inject 1700+
96- // preload tags into the HTML, defeating lazy loading. Mirrors
97- // objectui/apps/console.
43+ // preload tags into the HTML, defeating lazy loading.
9844 modulePreload : false ,
9945 commonjsOptions : {
100- include : [ / n o d e _ m o d u l e s / , / p a c k a g e s / ] ,
46+ include : [ / n o d e _ m o d u l e s / ] ,
10147 transformMixedEsModules : true ,
10248 } ,
10349 rollupOptions : {
10450 output : {
105- // Manual chunking ported verbatim from objectui/apps/console — the
106- // proven shape that avoids the per-leaf TDZ ("X is not a function")
107- // crashes triggered by Vite-Rolldown's default dynamic-import
108- // splitting against @object -ui's static+dynamic widget imports.
51+ // Manual chunking ported from objectui/apps/console — the proven
52+ // shape that avoids per-leaf TDZ ("X is not a function") crashes
53+ // triggered by Vite-Rolldown's default dynamic-import splitting
54+ // against @object -ui's static+dynamic widget imports.
10955 manualChunks ( id : string ) {
110- // Vendor: React ecosystem
11156 if (
11257 id . includes ( 'node_modules/react/' ) ||
11358 id . includes ( 'node_modules/react-dom/' ) ||
@@ -116,20 +61,16 @@ export default defineConfig({
11661 ) {
11762 return 'vendor-react' ;
11863 }
119- // Vendor: Radix UI primitives
12064 if ( id . includes ( 'node_modules/@radix-ui/' ) ) {
12165 return 'vendor-radix' ;
12266 }
123- // Vendor: @objectstack /* SDK & spec
12467 if (
12568 id . includes ( 'node_modules/@objectstack/' ) ||
12669 id . includes ( '/@objectstack+' ) ||
12770 id . includes ( '\\@objectstack+' )
12871 ) {
12972 return 'vendor-objectstack' ;
13073 }
131- // Vendor: Lucide icons — only bundle the runtime helpers; per-icon
132- // chunks then import a fully-initialized factory.
13374 if (
13475 id . includes ( 'node_modules/lucide-react/dist/lucide-react' ) ||
13576 id . includes ( 'node_modules/lucide-react/dist/esm/Icon' ) ||
@@ -139,7 +80,6 @@ export default defineConfig({
13980 ) {
14081 return 'vendor-icons-core' ;
14182 }
142- // Vendor: UI utilities
14383 if (
14484 id . includes ( 'node_modules/class-variance-authority/' ) ||
14585 id . includes ( 'node_modules/clsx/' ) ||
@@ -148,85 +88,61 @@ export default defineConfig({
14888 ) {
14989 return 'vendor-ui-utils' ;
15090 }
151- if ( id . includes ( 'node_modules/zod/' ) ) {
152- return 'vendor-zod' ;
153- }
91+ if ( id . includes ( 'node_modules/zod/' ) ) return 'vendor-zod' ;
15492 if (
15593 id . includes ( 'node_modules/recharts/' ) ||
15694 id . includes ( 'node_modules/d3-' ) ||
15795 id . includes ( 'node_modules/victory-' )
15896 ) {
15997 return 'vendor-charts' ;
16098 }
161- if ( id . includes ( 'node_modules/@dnd-kit/' ) ) {
162- return 'vendor-dndkit' ;
163- }
99+ if ( id . includes ( 'node_modules/@dnd-kit/' ) ) return 'vendor-dndkit' ;
164100 if (
165101 id . includes ( 'node_modules/i18next' ) ||
166102 id . includes ( 'node_modules/react-i18next/' )
167103 ) {
168104 return 'vendor-i18n' ;
169105 }
170- // @object -ui/core + @object-ui/react (framework)
171- if (
172- id . includes ( '/packages/core/' ) ||
173- id . includes ( '/packages/react/' ) ||
174- id . includes ( '/packages/types/' )
175- ) {
106+ // @object -ui framework: core + react + types
107+ if ( objectUiPkg ( 'core' ) ( id ) || objectUiPkg ( 'react' ) ( id ) || objectUiPkg ( 'types' ) ( id ) ) {
176108 return 'framework' ;
177109 }
178- // @object -ui/components + @object-ui/fields
179- if (
180- id . includes ( '/packages/components/' ) ||
181- id . includes ( '/packages/fields/' ) ||
182- id . includes ( '/@object-ui/components/' ) ||
183- id . includes ( '/@object-ui/fields/' )
184- ) {
110+ if ( objectUiPkg ( 'components' ) ( id ) || objectUiPkg ( 'fields' ) ( id ) ) {
185111 return 'ui-components' ;
186112 }
187- if ( id . includes ( '/packages/layout/' ) ) {
188- return 'ui-layout' ;
189- }
190- if ( id . includes ( '/packages/data-objectstack/' ) ) {
191- return 'data-adapter' ;
192- }
113+ if ( objectUiPkg ( 'layout' ) ( id ) ) return 'ui-layout' ;
114+ if ( objectUiPkg ( 'data-objectstack' ) ( id ) ) return 'data-adapter' ;
193115 if (
194- id . includes ( '/packages/ auth/' ) ||
195- id . includes ( '/packages/ permissions/' ) ||
196- id . includes ( '/packages/ tenant/' ) ||
197- id . includes ( '/packages/ i18n/' )
116+ objectUiPkg ( ' auth' ) ( id ) ||
117+ objectUiPkg ( ' permissions' ) ( id ) ||
118+ objectUiPkg ( ' tenant' ) ( id ) ||
119+ objectUiPkg ( ' i18n' ) ( id )
198120 ) {
199121 return 'infrastructure' ;
200122 }
201- if ( id . includes ( '/packages/ plugin-grid/' ) ) return 'plugin-grid' ;
202- if ( id . includes ( '/packages/ plugin-form/' ) ) return 'plugin-form' ;
203- if ( id . includes ( '/packages/ plugin-view/' ) ) return 'plugin-view' ;
123+ if ( objectUiPkg ( ' plugin-grid' ) ( id ) ) return 'plugin-grid' ;
124+ if ( objectUiPkg ( ' plugin-form' ) ( id ) ) return 'plugin-form' ;
125+ if ( objectUiPkg ( ' plugin-view' ) ( id ) ) return 'plugin-view' ;
204126 if (
205- id . includes ( '/packages/ plugin-detail/' ) ||
206- id . includes ( '/packages/ plugin-list/' ) ||
207- id . includes ( '/packages/ plugin-dashboard/' ) ||
208- id . includes ( '/packages/ plugin-report/' )
127+ objectUiPkg ( ' plugin-detail' ) ( id ) ||
128+ objectUiPkg ( ' plugin-list' ) ( id ) ||
129+ objectUiPkg ( ' plugin-dashboard' ) ( id ) ||
130+ objectUiPkg ( ' plugin-report' ) ( id )
209131 ) {
210132 return 'plugins-views' ;
211133 }
212- if ( id . includes ( '/packages/ plugin-charts/' ) ) return 'plugin-charts' ;
213- if ( id . includes ( '/packages/ plugin-calendar/' ) ) return 'plugin-calendar' ;
214- if ( id . includes ( '/packages/ plugin-kanban/' ) ) return 'plugin-kanban' ;
215- if ( id . includes ( '/packages/ plugin-chatbot/' ) ) return 'plugin-chatbot' ;
216- if ( id . includes ( '/packages/ app-shell/' ) ) return 'app-shell' ;
134+ if ( objectUiPkg ( ' plugin-charts' ) ( id ) ) return 'plugin-charts' ;
135+ if ( objectUiPkg ( ' plugin-calendar' ) ( id ) ) return 'plugin-calendar' ;
136+ if ( objectUiPkg ( ' plugin-kanban' ) ( id ) ) return 'plugin-kanban' ;
137+ if ( objectUiPkg ( ' plugin-chatbot' ) ( id ) ) return 'plugin-chatbot' ;
138+ if ( objectUiPkg ( ' app-shell' ) ( id ) ) return 'app-shell' ;
217139 } ,
218140 } ,
219141 } ,
220142 } ,
221143 server : {
222144 port : parseInt ( process . env . VITE_PORT || '5175' ) ,
223145 hmr : hmrConfig ,
224- fs : {
225- // Allow vite to read sources outside the project root (sibling objectui).
226- allow : useObjectUiSource
227- ? [ path . resolve ( __dirname , '../..' ) , OBJECTUI_ROOT ]
228- : [ path . resolve ( __dirname , '../..' ) ] ,
229- } ,
230146 proxy : {
231147 '/api' : {
232148 target : process . env . VITE_PROXY_TARGET || 'http://localhost:3000' ,
0 commit comments