@energy8platform/game-engine 0.10.2 → 0.10.3

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/dist/vite.esm.js CHANGED
@@ -64,31 +64,84 @@ await import('${entrySrc}');
64
64
  }
65
65
  // ─── Lua Plugin ─────────────────────────────────────────
66
66
  /**
67
- * Vite plugin that enables importing `.lua` files as raw strings
68
- * and triggers a full page reload on `.lua` file changes.
67
+ * Vite plugin that:
68
+ * 1. Enables importing `.lua` files as raw strings with HMR
69
+ * 2. Runs a LuaEngine on the Vite dev server (Node.js) via `POST /__lua-play`
69
70
  *
70
- * Also shims Node.js built-in modules (`os`, `child_process`, etc.) that
71
- * `fengari` references at the top level so the library can be pre-bundled
72
- * by esbuild and run in the browser without errors.
71
+ * fengari runs server-side only no browser shims needed.
73
72
  */
74
- const FENGARI_NODE_SHIMS = {
75
- os: 'export function platform() { return "browser"; } export default { platform };',
76
- child_process: 'export default {};',
77
- fs: 'export default {};',
78
- };
79
- function luaPlugin() {
73
+ function luaPlugin(configPath) {
74
+ let luaEngine = null;
75
+ let viteServer = null;
76
+ async function initEngine() {
77
+ if (!viteServer)
78
+ return;
79
+ try {
80
+ // Use Vite's SSR module loader to handle .ts config files
81
+ const resolvedPath = configPath.startsWith('.')
82
+ ? '/' + configPath.replace(/^\.\//, '')
83
+ : configPath;
84
+ // ssrLoadModule transpiles TS and resolves imports (including ?raw)
85
+ const mod = await viteServer.ssrLoadModule(resolvedPath);
86
+ const config = mod.default ?? mod.config ?? mod;
87
+ if (!config.luaScript || !config.gameDefinition) {
88
+ console.log('[LuaPlugin] No luaScript/gameDefinition in config — Lua server disabled');
89
+ luaEngine = null;
90
+ return;
91
+ }
92
+ // Load LuaEngine via SSR too (handles the fengari CJS import in Node.js)
93
+ const luaMod = await viteServer.ssrLoadModule('@energy8platform/game-engine/lua');
94
+ const { LuaEngine } = luaMod;
95
+ if (luaEngine)
96
+ luaEngine.destroy();
97
+ luaEngine = new LuaEngine({
98
+ script: config.luaScript,
99
+ gameDefinition: config.gameDefinition,
100
+ seed: config.luaSeed,
101
+ });
102
+ console.log('[LuaPlugin] LuaEngine initialized (server-side)');
103
+ }
104
+ catch (e) {
105
+ console.warn('[LuaPlugin] Failed to initialize LuaEngine:', e.message);
106
+ luaEngine = null;
107
+ }
108
+ }
80
109
  return {
81
110
  name: 'game-engine:lua',
82
111
  apply: 'serve',
83
- resolveId(id) {
84
- if (id in FENGARI_NODE_SHIMS)
85
- return `\0fengari-shim:${id}`;
86
- },
87
- load(id) {
88
- if (id.startsWith('\0fengari-shim:')) {
89
- const mod = id.slice('\0fengari-shim:'.length);
90
- return FENGARI_NODE_SHIMS[mod];
91
- }
112
+ async configureServer(server) {
113
+ viteServer = server;
114
+ await initEngine();
115
+ // POST /__lua-play — execute Lua on the server
116
+ server.middlewares.use('/__lua-play', (req, res) => {
117
+ if (req.method !== 'POST') {
118
+ res.statusCode = 405;
119
+ res.end('Method Not Allowed');
120
+ return;
121
+ }
122
+ let body = '';
123
+ req.on('data', (chunk) => { body += chunk; });
124
+ req.on('end', () => {
125
+ try {
126
+ if (!luaEngine) {
127
+ res.statusCode = 503;
128
+ res.setHeader('Content-Type', 'application/json');
129
+ res.end(JSON.stringify({ error: 'LuaEngine not initialized' }));
130
+ return;
131
+ }
132
+ const params = JSON.parse(body);
133
+ const result = luaEngine.execute(params);
134
+ res.statusCode = 200;
135
+ res.setHeader('Content-Type', 'application/json');
136
+ res.end(JSON.stringify(result));
137
+ }
138
+ catch (e) {
139
+ res.statusCode = 500;
140
+ res.setHeader('Content-Type', 'application/json');
141
+ res.end(JSON.stringify({ error: e.message }));
142
+ }
143
+ });
144
+ });
92
145
  },
93
146
  transform(code, id) {
94
147
  if (id.endsWith('.lua')) {
@@ -98,8 +151,10 @@ function luaPlugin() {
98
151
  };
99
152
  }
100
153
  },
101
- handleHotUpdate({ file, server }) {
102
- if (file.endsWith('.lua')) {
154
+ async handleHotUpdate({ file, server }) {
155
+ if (file.endsWith('.lua') || file.includes('dev.config')) {
156
+ console.log('[LuaPlugin] Reloading LuaEngine...');
157
+ await initEngine();
103
158
  server.ws.send({ type: 'full-reload' });
104
159
  return [];
105
160
  }
@@ -132,26 +187,15 @@ function defineGameConfig(config = {}) {
132
187
  if (config.devBridge) {
133
188
  const configPath = config.devBridgeConfig ?? './dev.config';
134
189
  plugins.push(devBridgePlugin(configPath));
135
- plugins.push(luaPlugin());
190
+ plugins.push(luaPlugin(configPath));
136
191
  }
137
192
  const userVite = config.vite ?? {};
138
- // fengari (Lua 5.3 in JS) is a CJS Node.js package that references `process`
139
- // and `require('os')` at module level. Provide shims so it works in the browser.
140
- const fengariShims = config.devBridge ? {
141
- 'process.versions.node': 'undefined',
142
- 'process.env': '({})',
143
- 'process.platform': '"browser"',
144
- } : {};
145
193
  return {
146
194
  base: config.base ?? '/',
147
195
  plugins: [
148
196
  ...plugins,
149
197
  ...(userVite.plugins ?? []),
150
198
  ],
151
- define: {
152
- ...fengariShims,
153
- ...userVite.define,
154
- },
155
199
  build: {
156
200
  target: 'esnext',
157
201
  assetsInlineLimit: 8192,
@@ -193,10 +237,10 @@ function defineGameConfig(config = {}) {
193
237
  'yoga-layout/load',
194
238
  'react',
195
239
  'react-dom',
196
- ...(config.devBridge ? ['fengari'] : []),
197
240
  ],
198
241
  exclude: [
199
242
  'yoga-layout',
243
+ 'fengari',
200
244
  ],
201
245
  esbuildOptions: {
202
246
  target: 'esnext',
@@ -1 +1 @@
1
- {"version":3,"file":"vite.esm.js","sources":["../src/vite/index.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"vite.esm.js","sources":["../src/vite/index.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@energy8platform/game-engine",
3
- "version": "0.10.2",
3
+ "version": "0.10.3",
4
4
  "description": "Universal casino game engine built on PixiJS v8 and @energy8platform/game-sdk",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs.js",
@@ -9,7 +9,6 @@ import {
9
9
  type PlayParams,
10
10
  } from '@energy8platform/game-sdk';
11
11
  import type { GameDefinition } from '../lua/types';
12
- import { LuaEngine } from '../lua/LuaEngine';
13
12
 
14
13
  export interface DevBridgeConfig {
15
14
  /** Mock initial balance */
@@ -28,7 +27,7 @@ export interface DevBridgeConfig {
28
27
  networkDelay?: number;
29
28
  /** Enable debug logging */
30
29
  debug?: boolean;
31
- /** Lua script source code. When set, overrides onPlay with LuaEngine. */
30
+ /** Lua script source code. When set, play requests are routed to the Vite dev server's LuaEngine. */
32
31
  luaScript?: string;
33
32
  /** Game definition for Lua engine (actions, transitions, etc.) */
34
33
  gameDefinition?: GameDefinition;
@@ -60,11 +59,11 @@ const DEFAULT_CONFIG: Omit<Required<DevBridgeConfig>, 'luaScript' | 'gameDefinit
60
59
  * `CasinoGameSDK` via a shared in-memory `MemoryChannel`, removing
61
60
  * the need for postMessage and iframes.
62
61
  *
63
- * This allows games to be developed and tested without a real backend.
62
+ * When `luaScript` is set, play requests are sent to the Vite dev server
63
+ * which runs LuaEngine in Node.js — no fengari in the browser.
64
64
  *
65
65
  * @example
66
66
  * ```ts
67
- * // In your dev entry point or vite plugin
68
67
  * import { DevBridge } from '@energy8platform/game-engine/debug';
69
68
  *
70
69
  * const devBridge = new DevBridge({
@@ -73,10 +72,7 @@ const DEFAULT_CONFIG: Omit<Required<DevBridgeConfig>, 'luaScript' | 'gameDefinit
73
72
  * gameConfig: { id: 'my-slot', type: 'slot', betLevels: [0.2, 0.5, 1, 2] },
74
73
  * onPlay: ({ action, bet }) => ({
75
74
  * totalWin: Math.random() > 0.5 ? bet * (Math.random() * 20) : 0,
76
- * data: {
77
- * matrix: generateRandomMatrix(5, 3, 10),
78
- * win_lines: [],
79
- * },
75
+ * data: { matrix: [[1,2,3],[4,5,6],[7,8,9]] },
80
76
  * }),
81
77
  * });
82
78
  * devBridge.start();
@@ -87,12 +83,12 @@ export class DevBridge {
87
83
  private _balance: number;
88
84
  private _roundCounter = 0;
89
85
  private _bridge: Bridge | null = null;
90
- private _luaEngine: LuaEngine | null = null;
86
+ private _useLuaServer: boolean;
91
87
 
92
88
  constructor(config: DevBridgeConfig = {}) {
93
89
  this._config = { ...DEFAULT_CONFIG, ...config };
94
90
  this._balance = this._config.balance;
95
- this.initLuaEngine();
91
+ this._useLuaServer = !!(this._config.luaScript && this._config.gameDefinition);
96
92
  }
97
93
 
98
94
  /** Current mock balance */
@@ -133,7 +129,8 @@ export class DevBridge {
133
129
  });
134
130
 
135
131
  if (this._config.debug) {
136
- console.log('[DevBridge] Started listening via Bridge (devMode)');
132
+ const mode = this._useLuaServer ? 'Lua (server-side)' : 'onPlay callback';
133
+ console.log(`[DevBridge] Started — mode: ${mode}`);
137
134
  }
138
135
  }
139
136
 
@@ -158,24 +155,6 @@ export class DevBridge {
158
155
  /** Destroy the dev bridge */
159
156
  destroy(): void {
160
157
  this.stop();
161
- if (this._luaEngine) {
162
- this._luaEngine.destroy();
163
- this._luaEngine = null;
164
- }
165
- }
166
-
167
- private initLuaEngine(): void {
168
- if (!this._config.luaScript || !this._config.gameDefinition) return;
169
-
170
- this._luaEngine = new LuaEngine({
171
- script: this._config.luaScript,
172
- gameDefinition: this._config.gameDefinition,
173
- seed: this._config.luaSeed,
174
- });
175
-
176
- if (this._config.debug) {
177
- console.log('[DevBridge] LuaEngine initialized');
178
- }
179
158
  }
180
159
 
181
160
  // ─── Message Handling ──────────────────────────────────
@@ -202,28 +181,18 @@ export class DevBridge {
202
181
  this._balance -= bet;
203
182
  this._roundCounter++;
204
183
 
205
- let result: PlayResultData;
206
-
207
- if (this._luaEngine) {
208
- // Use LuaEngine for real Lua execution
209
- const luaResult = this._luaEngine.execute({ action, bet, roundId, params });
210
- const totalWin = luaResult.creditDeferred ? 0 : luaResult.totalWin;
211
-
212
- this._balance += totalWin;
213
-
214
- result = {
215
- roundId: roundId ?? `dev-round-${this._roundCounter}`,
216
- action,
217
- balanceAfter: this._balance,
218
- totalWin: Math.round(luaResult.totalWin * 100) / 100,
219
- data: luaResult.data,
220
- nextActions: luaResult.nextActions,
221
- session: luaResult.session,
222
- creditPending: luaResult.creditDeferred,
223
- bonusFreeSpin: null,
224
- currency: this._config.currency,
225
- gameId: this._config.gameConfig?.id ?? 'dev-game',
226
- };
184
+ if (this._useLuaServer) {
185
+ // Send to Vite dev server for Lua execution
186
+ this.executeLuaOnServer({ action, bet, roundId, params })
187
+ .then((result) => {
188
+ this._bridge?.send('PLAY_RESULT', result, id);
189
+ })
190
+ .catch((err) => {
191
+ console.error('[DevBridge] Lua server error:', err);
192
+ // Refund bet on error
193
+ this._balance += bet;
194
+ this._bridge?.send('PLAY_RESULT', this.buildFallbackResult(action, bet, roundId), id);
195
+ });
227
196
  } else {
228
197
  // Fallback to onPlay callback
229
198
  const customResult = this._config.onPlay({ action, bet, roundId, params });
@@ -231,7 +200,7 @@ export class DevBridge {
231
200
 
232
201
  this._balance += totalWin;
233
202
 
234
- result = {
203
+ const result: PlayResultData = {
235
204
  roundId: roundId ?? `dev-round-${this._roundCounter}`,
236
205
  action,
237
206
  balanceAfter: this._balance,
@@ -244,9 +213,57 @@ export class DevBridge {
244
213
  currency: this._config.currency,
245
214
  gameId: this._config.gameConfig?.id ?? 'dev-game',
246
215
  };
216
+
217
+ this.delayedSend('PLAY_RESULT', result, id);
247
218
  }
219
+ }
220
+
221
+ private async executeLuaOnServer(params: PlayParams): Promise<PlayResultData> {
222
+ const response = await fetch('/__lua-play', {
223
+ method: 'POST',
224
+ headers: { 'Content-Type': 'application/json' },
225
+ body: JSON.stringify(params),
226
+ });
248
227
 
249
- this.delayedSend('PLAY_RESULT', result, id);
228
+ if (!response.ok) {
229
+ const err = await response.json().catch(() => ({ error: 'Unknown error' }));
230
+ throw new Error(err.error ?? `HTTP ${response.status}`);
231
+ }
232
+
233
+ const luaResult = await response.json();
234
+
235
+ const totalWin = luaResult.creditDeferred ? 0 : luaResult.totalWin;
236
+ this._balance += totalWin;
237
+
238
+ return {
239
+ roundId: params.roundId ?? `dev-round-${this._roundCounter}`,
240
+ action: params.action,
241
+ balanceAfter: this._balance,
242
+ totalWin: Math.round(luaResult.totalWin * 100) / 100,
243
+ data: luaResult.data,
244
+ nextActions: luaResult.nextActions,
245
+ session: luaResult.session,
246
+ creditPending: luaResult.creditDeferred,
247
+ bonusFreeSpin: null,
248
+ currency: this._config.currency,
249
+ gameId: this._config.gameConfig?.id ?? 'dev-game',
250
+ };
251
+ }
252
+
253
+ private buildFallbackResult(action: string, bet: number, roundId?: string): PlayResultData {
254
+ return {
255
+ roundId: roundId ?? `dev-round-${this._roundCounter}`,
256
+ action,
257
+ balanceAfter: this._balance,
258
+ totalWin: 0,
259
+ data: { error: 'Lua execution failed' },
260
+ nextActions: ['spin'],
261
+ session: null,
262
+ creditPending: false,
263
+ bonusFreeSpin: null,
264
+ currency: this._config.currency,
265
+ gameId: this._config.gameConfig?.id ?? 'dev-game',
266
+ };
250
267
  }
251
268
 
252
269
  private handlePlayAck(_payload: PlayResultAckPayload): void {
@@ -265,7 +282,7 @@ export class DevBridge {
265
282
 
266
283
  private handleOpenDeposit(): void {
267
284
  if (this._config.debug) {
268
- console.log('[DevBridge] 💰 Open deposit requested (mock: adding 1000)');
285
+ console.log('[DevBridge] Open deposit requested (mock: adding 1000)');
269
286
  }
270
287
  this._balance += 1000;
271
288
  this._bridge?.send('BALANCE_UPDATE', { balance: this._balance });
package/src/index.ts CHANGED
@@ -101,14 +101,9 @@ export type { DevBridgeConfig } from './debug/DevBridge';
101
101
  export { FPSOverlay } from './debug/FPSOverlay';
102
102
 
103
103
  // ─── Lua ────────────────────────────────────────────────
104
- // NOTE: fengari is an optional peer dependency.
105
- // Import Lua components from '@energy8platform/game-engine/lua' sub-path
106
- // to avoid pulling in fengari when it isn't installed.
107
- export { LuaEngine } from './lua/LuaEngine';
108
- export { LuaEngineAPI, createSeededRng } from './lua/LuaEngineAPI';
109
- export { ActionRouter, evaluateCondition } from './lua/ActionRouter';
110
- export { SessionManager } from './lua/SessionManager';
111
- export { PersistentState } from './lua/PersistentState';
104
+ // Lua module is Node.js only (fengari). Use the sub-path import:
105
+ // import { LuaEngine } from '@energy8platform/game-engine/lua'
106
+ // Re-export only types (zero runtime cost, no fengari in browser bundle).
112
107
  export type {
113
108
  GameDefinition,
114
109
  ActionDefinition,
@@ -6,9 +6,8 @@ import { SessionManager } from './SessionManager';
6
6
  import { PersistentState } from './PersistentState';
7
7
 
8
8
  // fengari — Lua 5.3 in pure JavaScript
9
- // eslint-disable-next-line @typescript-eslint/no-var-requires
10
- declare const require: (module: string) => any;
11
- const fengari = require('fengari');
9
+ import fengari from 'fengari';
10
+
12
11
  const { lua, lauxlib, lualib } = fengari;
13
12
  const { to_luastring, to_jsstring } = fengari;
14
13
 
@@ -1,9 +1,6 @@
1
1
  import type { GameDefinition } from './types';
2
+ import fengari from 'fengari';
2
3
 
3
- // fengari is a CJS module — use dynamic import workaround for ESM compatibility
4
- // eslint-disable-next-line @typescript-eslint/no-var-requires
5
- declare const require: (module: string) => any;
6
- const fengari = require('fengari');
7
4
  const { lua, lauxlib } = fengari;
8
5
  const { to_luastring, to_jsstring } = fengari;
9
6
 
@@ -0,0 +1,10 @@
1
+ declare module 'fengari' {
2
+ const fengari: {
3
+ lua: any;
4
+ lauxlib: any;
5
+ lualib: any;
6
+ to_luastring: (str: string) => Uint8Array;
7
+ to_jsstring: (str: Uint8Array) => string;
8
+ };
9
+ export default fengari;
10
+ }
package/src/vite/index.ts CHANGED
@@ -91,33 +91,92 @@ await import('${entrySrc}');
91
91
  // ─── Lua Plugin ─────────────────────────────────────────
92
92
 
93
93
  /**
94
- * Vite plugin that enables importing `.lua` files as raw strings
95
- * and triggers a full page reload on `.lua` file changes.
94
+ * Vite plugin that:
95
+ * 1. Enables importing `.lua` files as raw strings with HMR
96
+ * 2. Runs a LuaEngine on the Vite dev server (Node.js) via `POST /__lua-play`
96
97
  *
97
- * Also shims Node.js built-in modules (`os`, `child_process`, etc.) that
98
- * `fengari` references at the top level so the library can be pre-bundled
99
- * by esbuild and run in the browser without errors.
98
+ * fengari runs server-side only no browser shims needed.
100
99
  */
101
- const FENGARI_NODE_SHIMS: Record<string, string> = {
102
- os: 'export function platform() { return "browser"; } export default { platform };',
103
- child_process: 'export default {};',
104
- fs: 'export default {};',
105
- };
100
+ function luaPlugin(configPath: string): Plugin {
101
+ let luaEngine: any = null;
102
+ let viteServer: any = null;
103
+
104
+ async function initEngine() {
105
+ if (!viteServer) return;
106
+
107
+ try {
108
+ // Use Vite's SSR module loader to handle .ts config files
109
+ const resolvedPath = configPath.startsWith('.')
110
+ ? '/' + configPath.replace(/^\.\//, '')
111
+ : configPath;
112
+
113
+ // ssrLoadModule transpiles TS and resolves imports (including ?raw)
114
+ const mod = await viteServer.ssrLoadModule(resolvedPath);
115
+ const config = mod.default ?? mod.config ?? mod;
116
+
117
+ if (!config.luaScript || !config.gameDefinition) {
118
+ console.log('[LuaPlugin] No luaScript/gameDefinition in config — Lua server disabled');
119
+ luaEngine = null;
120
+ return;
121
+ }
122
+
123
+ // Load LuaEngine via SSR too (handles the fengari CJS import in Node.js)
124
+ const luaMod = await viteServer.ssrLoadModule('@energy8platform/game-engine/lua');
125
+ const { LuaEngine } = luaMod;
126
+
127
+ if (luaEngine) luaEngine.destroy();
128
+ luaEngine = new LuaEngine({
129
+ script: config.luaScript,
130
+ gameDefinition: config.gameDefinition,
131
+ seed: config.luaSeed,
132
+ });
133
+ console.log('[LuaPlugin] LuaEngine initialized (server-side)');
134
+ } catch (e: any) {
135
+ console.warn('[LuaPlugin] Failed to initialize LuaEngine:', e.message);
136
+ luaEngine = null;
137
+ }
138
+ }
106
139
 
107
- function luaPlugin(): Plugin {
108
140
  return {
109
141
  name: 'game-engine:lua',
110
142
  apply: 'serve',
111
143
 
112
- resolveId(id: string) {
113
- if (id in FENGARI_NODE_SHIMS) return `\0fengari-shim:${id}`;
114
- },
115
-
116
- load(id: string) {
117
- if (id.startsWith('\0fengari-shim:')) {
118
- const mod = id.slice('\0fengari-shim:'.length);
119
- return FENGARI_NODE_SHIMS[mod];
120
- }
144
+ async configureServer(server) {
145
+ viteServer = server;
146
+ await initEngine();
147
+
148
+ // POST /__lua-play — execute Lua on the server
149
+ server.middlewares.use('/__lua-play', (req: any, res: any) => {
150
+ if (req.method !== 'POST') {
151
+ res.statusCode = 405;
152
+ res.end('Method Not Allowed');
153
+ return;
154
+ }
155
+
156
+ let body = '';
157
+ req.on('data', (chunk: string) => { body += chunk; });
158
+ req.on('end', () => {
159
+ try {
160
+ if (!luaEngine) {
161
+ res.statusCode = 503;
162
+ res.setHeader('Content-Type', 'application/json');
163
+ res.end(JSON.stringify({ error: 'LuaEngine not initialized' }));
164
+ return;
165
+ }
166
+
167
+ const params = JSON.parse(body);
168
+ const result = luaEngine.execute(params);
169
+
170
+ res.statusCode = 200;
171
+ res.setHeader('Content-Type', 'application/json');
172
+ res.end(JSON.stringify(result));
173
+ } catch (e: any) {
174
+ res.statusCode = 500;
175
+ res.setHeader('Content-Type', 'application/json');
176
+ res.end(JSON.stringify({ error: e.message }));
177
+ }
178
+ });
179
+ });
121
180
  },
122
181
 
123
182
  transform(code: string, id: string) {
@@ -129,8 +188,10 @@ function luaPlugin(): Plugin {
129
188
  }
130
189
  },
131
190
 
132
- handleHotUpdate({ file, server }: { file: string; server: any }) {
133
- if (file.endsWith('.lua')) {
191
+ async handleHotUpdate({ file, server }: { file: string; server: any }) {
192
+ if (file.endsWith('.lua') || file.includes('dev.config')) {
193
+ console.log('[LuaPlugin] Reloading LuaEngine...');
194
+ await initEngine();
134
195
  server.ws.send({ type: 'full-reload' });
135
196
  return [];
136
197
  }
@@ -166,19 +227,11 @@ export function defineGameConfig(config: GameConfig = {}): UserConfig {
166
227
  if (config.devBridge) {
167
228
  const configPath = config.devBridgeConfig ?? './dev.config';
168
229
  plugins.push(devBridgePlugin(configPath));
169
- plugins.push(luaPlugin());
230
+ plugins.push(luaPlugin(configPath));
170
231
  }
171
232
 
172
233
  const userVite = config.vite ?? {};
173
234
 
174
- // fengari (Lua 5.3 in JS) is a CJS Node.js package that references `process`
175
- // and `require('os')` at module level. Provide shims so it works in the browser.
176
- const fengariShims: Record<string, string> = config.devBridge ? {
177
- 'process.versions.node': 'undefined',
178
- 'process.env': '({})',
179
- 'process.platform': '"browser"',
180
- } : {};
181
-
182
235
  return {
183
236
  base: config.base ?? '/',
184
237
 
@@ -187,11 +240,6 @@ export function defineGameConfig(config: GameConfig = {}): UserConfig {
187
240
  ...((userVite.plugins as Plugin[]) ?? []),
188
241
  ],
189
242
 
190
- define: {
191
- ...fengariShims,
192
- ...(userVite as Record<string, any>).define,
193
- },
194
-
195
243
  build: {
196
244
  target: 'esnext',
197
245
  assetsInlineLimit: 8192,
@@ -236,10 +284,10 @@ export function defineGameConfig(config: GameConfig = {}): UserConfig {
236
284
  'yoga-layout/load',
237
285
  'react',
238
286
  'react-dom',
239
- ...(config.devBridge ? ['fengari'] : []),
240
287
  ],
241
288
  exclude: [
242
289
  'yoga-layout',
290
+ 'fengari',
243
291
  ],
244
292
  esbuildOptions: {
245
293
  target: 'esnext',