vite-plugin-opal 0.3.5 → 0.3.6

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/index.d.ts CHANGED
@@ -135,115 +135,6 @@ interface OpalPluginOptions {
135
135
  * ```
136
136
  */
137
137
  includeConcerns?: boolean;
138
- /**
139
- * Enable disk-based caching for compiled files.
140
- * Persists cache across dev server restarts for faster rebuilds.
141
- * Cache is stored in node_modules/.cache/opal-vite/
142
- *
143
- * @default true
144
- * @example
145
- * ```ts
146
- * {
147
- * diskCache: true // Enable persistent caching
148
- * }
149
- * ```
150
- */
151
- diskCache?: boolean;
152
- /**
153
- * Custom directory for disk cache.
154
- * If not specified, uses node_modules/.cache/opal-vite/
155
- *
156
- * @default undefined (auto-detect)
157
- * @example
158
- * ```ts
159
- * {
160
- * cacheDir: '.cache/opal'
161
- * }
162
- * ```
163
- */
164
- cacheDir?: string;
165
- /**
166
- * Modules to stub (replace with empty implementations).
167
- * Useful for excluding server-side only gems or large unused libraries.
168
- * Reduces bundle size by replacing modules with empty exports.
169
- *
170
- * @default []
171
- * @example
172
- * ```ts
173
- * {
174
- * stubs: ['active_support', 'sprockets', 'listen']
175
- * }
176
- * ```
177
- */
178
- stubs?: string[];
179
- /**
180
- * Maximum number of concurrent Ruby processes for compilation.
181
- * Higher values can speed up initial builds with many files.
182
- * Set to 1 to disable parallel compilation.
183
- *
184
- * @default 4
185
- * @example
186
- * ```ts
187
- * {
188
- * parallelCompilation: 8 // Allow 8 concurrent compilations
189
- * }
190
- * ```
191
- */
192
- parallelCompilation?: number;
193
- /**
194
- * Enable compilation metrics logging.
195
- * Logs timing information for each compilation step.
196
- * Useful for identifying performance bottlenecks.
197
- *
198
- * @default false
199
- * @example
200
- * ```ts
201
- * {
202
- * metrics: true // Enable performance metrics
203
- * }
204
- * ```
205
- */
206
- metrics?: boolean;
207
- /**
208
- * Load Opal runtime from CDN instead of bundling it.
209
- * This reduces bundle size and improves caching across sites.
210
- *
211
- * Supported values:
212
- * - `false` or `undefined`: Bundle runtime locally (default)
213
- * - `'opalrb'`: Use official Opal CDN (https://cdn.opalrb.com) - Recommended
214
- * - `'jsdelivr'`: Use jsDelivr CDN with opal-cdn repository
215
- * - `'unpkg'`: Alias for opalrb CDN
216
- * - Custom URL string: Use a custom CDN URL
217
- *
218
- * @default false
219
- * @example
220
- * ```ts
221
- * // Use official Opal CDN (recommended)
222
- * {
223
- * cdn: 'opalrb'
224
- * }
225
- *
226
- * // Use custom CDN URL
227
- * {
228
- * cdn: 'https://my-cdn.example.com/opal/1.8.2/opal.min.js'
229
- * }
230
- * ```
231
- */
232
- cdn?: 'opalrb' | 'jsdelivr' | 'unpkg' | string | false;
233
- /**
234
- * Opal version to use when loading from CDN.
235
- * Only used when `cdn` is set to a CDN provider name.
236
- *
237
- * @default '1.8.2'
238
- * @example
239
- * ```ts
240
- * {
241
- * cdn: 'jsdelivr',
242
- * opalVersion: '1.8.2'
243
- * }
244
- * ```
245
- */
246
- opalVersion?: string;
247
138
  }
248
139
 
249
140
  /**
@@ -267,21 +158,6 @@ interface OpalPluginOptions {
267
158
  * })
268
159
  * ```
269
160
  *
270
- * @example CDN mode
271
- * ```ts
272
- * import { defineConfig } from 'vite'
273
- * import opal from 'vite-plugin-opal'
274
- *
275
- * export default defineConfig({
276
- * plugins: [
277
- * opal({
278
- * cdn: 'opalrb', // Recommended. Also: 'jsdelivr', 'unpkg', or custom URL
279
- * opalVersion: '1.8.2'
280
- * })
281
- * ]
282
- * })
283
- * ```
284
- *
285
161
  * @see {@link OpalPluginOptions} for all available options
286
162
  */
287
163
  declare function opalPlugin(options?: OpalPluginOptions): Plugin;
package/dist/index.js CHANGED
@@ -1,105 +1,14 @@
1
1
  import { spawn } from 'child_process';
2
2
  import * as fs from 'fs/promises';
3
- import { existsSync, mkdirSync, readFileSync, writeFileSync, accessSync } from 'fs';
4
- import * as path from 'path';
5
- import * as crypto from 'crypto';
3
+ import { accessSync } from 'fs';
4
+ import * as path2 from 'path';
6
5
  import * as chokidar from 'chokidar';
7
6
 
8
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
- }) : x)(function(x) {
11
- if (typeof require !== "undefined") return require.apply(this, arguments);
12
- throw Error('Dynamic require of "' + x + '" is not supported');
13
- });
14
- function parseRubyError(stderr, filePath) {
15
- const lines = stderr.trim().split("\n");
16
- const error = {
17
- message: stderr.trim(),
18
- file: filePath,
19
- rawOutput: stderr
20
- };
21
- for (const line of lines) {
22
- const lineMatch = line.match(/^(.+?):(\d+)(?::(\d+))?(?::in `[^']+')?\s*[:\-]?\s*(.*)/);
23
- if (lineMatch) {
24
- const [, matchedFile, lineNum, colNum, msg] = lineMatch;
25
- if (matchedFile.endsWith(".rb") || matchedFile.includes(filePath)) {
26
- error.file = matchedFile;
27
- error.line = parseInt(lineNum, 10);
28
- if (colNum) {
29
- error.column = parseInt(colNum, 10);
30
- }
31
- error.message = msg || line;
32
- break;
33
- }
34
- }
35
- }
36
- const typeMatch = stderr.match(/(\w+Error|\w+Exception):\s*(.+)/m);
37
- if (typeMatch) {
38
- error.errorType = typeMatch[1];
39
- if (!error.message || error.message === stderr.trim()) {
40
- error.message = typeMatch[2].trim();
41
- }
42
- }
43
- if (stderr.includes("SyntaxError")) {
44
- error.errorType = "SyntaxError";
45
- const syntaxMatch = stderr.match(/SyntaxError:\s*(.+?)(?:\n|$)/);
46
- if (syntaxMatch) {
47
- error.message = syntaxMatch[1];
48
- }
49
- } else if (stderr.includes("NameError")) {
50
- error.errorType = "NameError";
51
- const nameMatch = stderr.match(/NameError:\s*(.+?)(?:\n|$)/);
52
- if (nameMatch) {
53
- error.message = nameMatch[1];
54
- }
55
- } else if (stderr.includes("LoadError")) {
56
- error.errorType = "LoadError";
57
- const loadMatch = stderr.match(/LoadError:\s*(.+?)(?:\n|$)/);
58
- if (loadMatch) {
59
- error.message = loadMatch[1];
60
- }
61
- const requireMatch = stderr.match(/cannot load such file\s*--\s*(.+)/);
62
- if (requireMatch) {
63
- error.hint = `Check that '${requireMatch[1]}' exists and is in your load paths`;
64
- }
65
- }
66
- return error;
67
- }
68
- function formatCompilationError(error) {
69
- const parts = [];
70
- const errorType = error.errorType || "CompilationError";
71
- parts.push(`\x1B[31m\u2716 Opal ${errorType}\x1B[0m`);
72
- if (error.file) {
73
- let location = ` \x1B[36m\u2192 ${error.file}\x1B[0m`;
74
- if (error.line) {
75
- location += `\x1B[33m:${error.line}\x1B[0m`;
76
- if (error.column) {
77
- location += `\x1B[33m:${error.column}\x1B[0m`;
78
- }
79
- }
80
- parts.push(location);
81
- }
82
- parts.push(` \x1B[37m${error.message}\x1B[0m`);
83
- if (error.hint) {
84
- parts.push(` \x1B[33m\u{1F4A1} ${error.hint}\x1B[0m`);
85
- }
86
- return parts.join("\n");
87
- }
88
- var CACHE_VERSION = "1.0.0";
89
- var DEFAULT_OPAL_VERSION = "1.8.2";
90
- var CDN_URLS = {
91
- opalrb: "https://cdn.opalrb.com/opal/{version}/opal.min.js",
92
- jsdelivr: "https://cdn.jsdelivr.net/gh/opal/opal-cdn@{version}/opal/{version}/opal.min.js",
93
- unpkg: "https://cdn.opalrb.com/opal/{version}/opal.min.js"
94
- // Fallback to official CDN
95
- };
7
+ // src/compiler.ts
96
8
  var OpalCompiler = class {
97
9
  constructor(options = {}) {
98
10
  this.cache = /* @__PURE__ */ new Map();
99
11
  this.runtimeCache = null;
100
- this.metrics = [];
101
- this.compilationQueue = Promise.resolve();
102
- this.activeCompilations = 0;
103
12
  this.options = {
104
13
  gemPath: options.gemPath || "opal-vite",
105
14
  sourceMap: options.sourceMap !== false,
@@ -108,124 +17,18 @@ var OpalCompiler = class {
108
17
  freezing: options.freezing !== false,
109
18
  debug: options.debug || false,
110
19
  useBundler: options.useBundler !== void 0 ? options.useBundler : this.detectGemfile(),
111
- includeConcerns: options.includeConcerns !== false,
112
- // Performance options (v0.3.2+)
113
- diskCache: options.diskCache !== false,
114
- cacheDir: options.cacheDir || "",
115
- stubs: options.stubs || [],
116
- parallelCompilation: options.parallelCompilation || 4,
117
- metrics: options.metrics || false,
118
- // CDN options (v0.3.5+)
119
- cdn: options.cdn || false,
120
- opalVersion: options.opalVersion || DEFAULT_OPAL_VERSION
20
+ includeConcerns: options.includeConcerns !== false
121
21
  };
122
22
  this.useBundler = this.options.useBundler;
123
- this.cacheDir = this.resolveCacheDir();
124
- if (this.options.diskCache) {
125
- this.ensureCacheDir();
126
- }
127
23
  if (this.options.debug) {
128
24
  console.log(`[vite-plugin-opal] Using bundler: ${this.useBundler}`);
129
25
  console.log(`[vite-plugin-opal] Working directory: ${process.cwd()}`);
130
26
  console.log(`[vite-plugin-opal] Include concerns: ${this.options.includeConcerns}`);
131
- console.log(`[vite-plugin-opal] Disk cache: ${this.options.diskCache ? "enabled" : "disabled"}`);
132
- if (this.options.diskCache) {
133
- console.log(`[vite-plugin-opal] Cache directory: ${this.cacheDir}`);
134
- }
135
- if (this.options.stubs.length > 0) {
136
- console.log(`[vite-plugin-opal] Stubs: ${this.options.stubs.join(", ")}`);
137
- }
138
- console.log(`[vite-plugin-opal] Parallel compilation: ${this.options.parallelCompilation}`);
139
- if (this.options.cdn) {
140
- console.log(`[vite-plugin-opal] CDN mode: ${this.options.cdn}`);
141
- console.log(`[vite-plugin-opal] CDN URL: ${this.getCdnUrl()}`);
142
- }
143
- }
144
- }
145
- resolveCacheDir() {
146
- if (this.options.cacheDir) {
147
- return path.resolve(process.cwd(), this.options.cacheDir);
148
- }
149
- return path.resolve(process.cwd(), "node_modules", ".cache", "opal-vite");
150
- }
151
- ensureCacheDir() {
152
- try {
153
- if (!existsSync(this.cacheDir)) {
154
- mkdirSync(this.cacheDir, { recursive: true });
155
- this.log(`Created cache directory: ${this.cacheDir}`);
156
- }
157
- } catch (e) {
158
- this.log(`Warning: Could not create cache directory: ${e}`);
159
27
  }
160
28
  }
161
- getCacheKey(filePath) {
162
- const normalized = path.resolve(filePath);
163
- return crypto.createHash("md5").update(normalized).digest("hex");
164
- }
165
- getContentHash(content) {
166
- return crypto.createHash("md5").update(content).digest("hex");
167
- }
168
- getDiskCachePath(filePath) {
169
- return path.join(this.cacheDir, `${this.getCacheKey(filePath)}.json`);
170
- }
171
- async loadFromDiskCache(filePath, contentHash) {
172
- if (!this.options.diskCache) return null;
173
- const cachePath = this.getDiskCachePath(filePath);
174
- try {
175
- if (!existsSync(cachePath)) return null;
176
- const cacheContent = readFileSync(cachePath, "utf-8");
177
- const entry = JSON.parse(cacheContent);
178
- if (entry.version !== CACHE_VERSION) {
179
- this.log(`Disk cache version mismatch for ${filePath}`);
180
- return null;
181
- }
182
- if (entry.contentHash !== contentHash) {
183
- this.log(`Disk cache content hash mismatch for ${filePath}`);
184
- return null;
185
- }
186
- this.log(`Disk cache hit: ${filePath}`);
187
- return entry.result;
188
- } catch (e) {
189
- this.log(`Disk cache read error for ${filePath}: ${e}`);
190
- return null;
191
- }
192
- }
193
- saveToDiskCache(filePath, contentHash, mtime, result) {
194
- if (!this.options.diskCache) return;
195
- const cachePath = this.getDiskCachePath(filePath);
196
- try {
197
- const entry = {
198
- version: CACHE_VERSION,
199
- contentHash,
200
- mtime,
201
- result
202
- };
203
- writeFileSync(cachePath, JSON.stringify(entry), "utf-8");
204
- this.log(`Disk cache saved: ${filePath}`);
205
- } catch (e) {
206
- this.log(`Disk cache write error for ${filePath}: ${e}`);
207
- }
208
- }
209
- /**
210
- * Check if CDN mode is enabled
211
- */
212
- isCdnEnabled() {
213
- return !!this.options.cdn;
214
- }
215
- /**
216
- * Get the CDN URL for Opal runtime
217
- */
218
- getCdnUrl() {
219
- const cdn = this.options.cdn;
220
- if (!cdn) return null;
221
- if (cdn in CDN_URLS) {
222
- return CDN_URLS[cdn].replace(/\{version\}/g, this.options.opalVersion);
223
- }
224
- return cdn;
225
- }
226
29
  detectGemfile() {
227
30
  try {
228
- const gemfilePath = path.join(process.cwd(), "Gemfile");
31
+ const gemfilePath = path2.join(process.cwd(), "Gemfile");
229
32
  accessSync(gemfilePath);
230
33
  return true;
231
34
  } catch {
@@ -233,159 +36,34 @@ var OpalCompiler = class {
233
36
  }
234
37
  }
235
38
  async compile(filePath) {
236
- const startTime = this.options.metrics ? performance.now() : 0;
237
- const stubResult = this.checkStub(filePath);
238
- if (stubResult) {
239
- this.recordMetrics(filePath, startTime, true, "memory");
240
- return stubResult;
241
- }
242
- let fileContent;
243
- let stat3;
244
- try {
245
- fileContent = await fs.readFile(filePath, "utf-8");
246
- stat3 = await fs.stat(filePath);
247
- } catch (e) {
248
- throw new Error(`Failed to read file: ${filePath}`);
249
- }
250
- const contentHash = this.getContentHash(fileContent);
251
39
  const cached = this.cache.get(filePath);
252
40
  if (cached) {
253
- if (stat3.mtimeMs <= cached.mtime) {
254
- this.log(`Memory cache hit: ${filePath}`);
255
- this.recordMetrics(filePath, startTime, true, "memory");
256
- return {
257
- code: cached.code,
258
- map: cached.map,
259
- dependencies: cached.dependencies
260
- };
41
+ try {
42
+ const stat3 = await fs.stat(filePath);
43
+ if (stat3.mtimeMs <= cached.mtime) {
44
+ this.log(`Cache hit: ${filePath}`);
45
+ return {
46
+ code: cached.code,
47
+ map: cached.map,
48
+ dependencies: cached.dependencies
49
+ };
50
+ }
51
+ } catch (e) {
52
+ this.cache.delete(filePath);
261
53
  }
262
- this.cache.delete(filePath);
263
54
  }
264
- const diskCached = await this.loadFromDiskCache(filePath, contentHash);
265
- if (diskCached) {
55
+ this.log(`Compiling: ${filePath}`);
56
+ const result = await this.compileViaRuby(filePath);
57
+ try {
58
+ const stat3 = await fs.stat(filePath);
266
59
  this.cache.set(filePath, {
267
- ...diskCached,
60
+ ...result,
268
61
  mtime: stat3.mtimeMs
269
62
  });
270
- this.recordMetrics(filePath, startTime, true, "disk");
271
- return diskCached;
63
+ } catch (e) {
272
64
  }
273
- this.log(`Compiling: ${filePath}`);
274
- const result = await this.compileWithConcurrencyControl(filePath);
275
- this.cache.set(filePath, {
276
- ...result,
277
- mtime: stat3.mtimeMs
278
- });
279
- this.saveToDiskCache(filePath, contentHash, stat3.mtimeMs, result);
280
- this.recordMetrics(filePath, startTime, false, "compile");
281
65
  return result;
282
66
  }
283
- /**
284
- * Compile multiple files in parallel with concurrency control
285
- */
286
- async compileMany(filePaths) {
287
- const results = /* @__PURE__ */ new Map();
288
- const batchSize = this.options.parallelCompilation;
289
- for (let i = 0; i < filePaths.length; i += batchSize) {
290
- const batch = filePaths.slice(i, i + batchSize);
291
- const batchResults = await Promise.all(
292
- batch.map(async (filePath) => {
293
- try {
294
- const result = await this.compile(filePath);
295
- return { filePath, result, error: null };
296
- } catch (e) {
297
- return { filePath, result: null, error: e };
298
- }
299
- })
300
- );
301
- for (const { filePath, result, error } of batchResults) {
302
- if (result) {
303
- results.set(filePath, result);
304
- } else {
305
- this.log(`Compilation failed for ${filePath}: ${error}`);
306
- }
307
- }
308
- }
309
- return results;
310
- }
311
- async compileWithConcurrencyControl(filePath) {
312
- while (this.activeCompilations >= this.options.parallelCompilation) {
313
- await new Promise((resolve4) => setTimeout(resolve4, 10));
314
- }
315
- this.activeCompilations++;
316
- try {
317
- return await this.compileViaRuby(filePath);
318
- } finally {
319
- this.activeCompilations--;
320
- }
321
- }
322
- checkStub(filePath) {
323
- if (this.options.stubs.length === 0) return null;
324
- const fileName = path.basename(filePath, ".rb");
325
- const isStubbed = this.options.stubs.some((stub) => {
326
- if (stub === fileName) return true;
327
- if (filePath.includes(`/${stub}/`) || filePath.includes(`/${stub}.rb`)) return true;
328
- return false;
329
- });
330
- if (isStubbed) {
331
- this.log(`Stubbed module: ${filePath}`);
332
- return {
333
- code: '// Stubbed module\nOpal.loaded(["' + fileName + '"]);\n',
334
- map: void 0,
335
- dependencies: []
336
- };
337
- }
338
- return null;
339
- }
340
- recordMetrics(filePath, startTime, cacheHit, source) {
341
- if (!this.options.metrics) return;
342
- const duration = performance.now() - startTime;
343
- this.metrics.push({
344
- file: path.basename(filePath),
345
- duration,
346
- cacheHit,
347
- source
348
- });
349
- }
350
- /**
351
- * Get compilation metrics summary
352
- */
353
- getMetricsSummary() {
354
- const total = this.metrics.length;
355
- const cached = this.metrics.filter((m) => m.cacheHit).length;
356
- const compiled = total - cached;
357
- const avgDuration = total > 0 ? this.metrics.reduce((sum, m) => sum + m.duration, 0) / total : 0;
358
- return {
359
- total,
360
- cached,
361
- compiled,
362
- avgDuration: Math.round(avgDuration * 100) / 100,
363
- details: [...this.metrics]
364
- };
365
- }
366
- /**
367
- * Print metrics summary to console
368
- */
369
- printMetricsSummary() {
370
- const summary = this.getMetricsSummary();
371
- console.log("\n[vite-plugin-opal] Compilation Metrics:");
372
- console.log(` Total files: ${summary.total}`);
373
- console.log(` Cache hits: ${summary.cached} (${Math.round(summary.cached / summary.total * 100) || 0}%)`);
374
- console.log(` Compiled: ${summary.compiled}`);
375
- console.log(` Avg duration: ${summary.avgDuration}ms`);
376
- if (this.options.debug && summary.details.length > 0) {
377
- console.log("\n Details:");
378
- for (const m of summary.details) {
379
- console.log(` ${m.file}: ${Math.round(m.duration)}ms (${m.source})`);
380
- }
381
- }
382
- }
383
- /**
384
- * Clear metrics
385
- */
386
- clearMetrics() {
387
- this.metrics = [];
388
- }
389
67
  async getOpalRuntime() {
390
68
  if (this.runtimeCache) {
391
69
  return this.runtimeCache;
@@ -395,69 +73,15 @@ var OpalCompiler = class {
395
73
  this.runtimeCache = runtime;
396
74
  return runtime;
397
75
  }
398
- clearCache(filePath, clearDisk = false) {
76
+ clearCache(filePath) {
399
77
  if (filePath) {
400
78
  this.cache.delete(filePath);
401
- if (clearDisk && this.options.diskCache) {
402
- try {
403
- const cachePath = this.getDiskCachePath(filePath);
404
- if (existsSync(cachePath)) {
405
- const fsSync = __require("fs");
406
- fsSync.unlinkSync(cachePath);
407
- }
408
- } catch (e) {
409
- this.log(`Failed to clear disk cache for ${filePath}: ${e}`);
410
- }
411
- }
412
79
  this.log(`Cache cleared: ${filePath}`);
413
80
  } else {
414
81
  this.cache.clear();
415
- if (clearDisk && this.options.diskCache) {
416
- this.clearDiskCache();
417
- }
418
82
  this.log("Cache cleared (all)");
419
83
  }
420
84
  }
421
- /**
422
- * Clear all disk cache files
423
- */
424
- clearDiskCache() {
425
- if (!this.options.diskCache) return;
426
- try {
427
- const fsSync = __require("fs");
428
- if (existsSync(this.cacheDir)) {
429
- const files = fsSync.readdirSync(this.cacheDir);
430
- for (const file of files) {
431
- if (file.endsWith(".json")) {
432
- fsSync.unlinkSync(path.join(this.cacheDir, file));
433
- }
434
- }
435
- this.log(`Cleared ${files.length} disk cache files`);
436
- }
437
- } catch (e) {
438
- this.log(`Failed to clear disk cache: ${e}`);
439
- }
440
- }
441
- /**
442
- * Get disk cache statistics
443
- */
444
- getDiskCacheStats() {
445
- if (!this.options.diskCache || !existsSync(this.cacheDir)) {
446
- return { files: 0, size: 0 };
447
- }
448
- try {
449
- const fsSync = __require("fs");
450
- const files = fsSync.readdirSync(this.cacheDir).filter((f) => f.endsWith(".json"));
451
- let totalSize = 0;
452
- for (const file of files) {
453
- const stat3 = fsSync.statSync(path.join(this.cacheDir, file));
454
- totalSize += stat3.size;
455
- }
456
- return { files: files.length, size: totalSize };
457
- } catch (e) {
458
- return { files: 0, size: 0 };
459
- }
460
- }
461
85
  async compileViaRuby(filePath) {
462
86
  return new Promise((resolve4, reject) => {
463
87
  let command;
@@ -474,13 +98,14 @@ var OpalCompiler = class {
474
98
  filePath
475
99
  ];
476
100
  } else {
477
- const gemLibPath = this.resolveGemLibPath();
478
101
  command = "ruby";
479
102
  args = [
480
103
  "-I",
481
- gemLibPath,
104
+ this.resolveGemLibPath(),
105
+ "-r",
106
+ "opal-vite",
482
107
  "-e",
483
- `$LOAD_PATH.unshift('${gemLibPath}'); require 'opal-vite'; ${this.getCompilerScript()}`,
108
+ this.getCompilerScript(),
484
109
  filePath
485
110
  ];
486
111
  }
@@ -498,37 +123,21 @@ var OpalCompiler = class {
498
123
  });
499
124
  ruby.on("close", (code) => {
500
125
  if (code !== 0) {
501
- const parsedError = parseRubyError(stderr, filePath);
502
- const formattedMessage = formatCompilationError(parsedError);
503
- console.error(formattedMessage);
504
- const error = new Error(parsedError.message);
505
- error.file = parsedError.file;
506
- error.line = parsedError.line;
507
- error.column = parsedError.column;
508
- error.errorType = parsedError.errorType;
509
- error.hint = parsedError.hint;
510
- error.rawOutput = parsedError.rawOutput;
511
- reject(error);
126
+ reject(new Error(`Opal compilation failed:
127
+ ${stderr}`));
512
128
  return;
513
129
  }
514
130
  try {
515
131
  const result = JSON.parse(stdout);
516
132
  resolve4(result);
517
133
  } catch (e) {
518
- const parseError = new Error(`Failed to parse compiler output: ${e}`);
519
- console.error("\x1B[31m\u2716 Opal Compiler Output Parse Error\x1B[0m");
520
- console.error(` \x1B[36m\u2192 ${filePath}\x1B[0m`);
521
- console.error(` \x1B[37mUnexpected output from Ruby compiler\x1B[0m`);
522
- if (this.options.debug) {
523
- console.error(` \x1B[90mRaw output: ${stdout.substring(0, 500)}...\x1B[0m`);
524
- }
525
- reject(parseError);
134
+ reject(new Error(`Failed to parse compiler output:
135
+ ${stdout}
136
+
137
+ Error: ${e}`));
526
138
  }
527
139
  });
528
140
  ruby.on("error", (err) => {
529
- console.error("\x1B[31m\u2716 Ruby Process Error\x1B[0m");
530
- console.error(` \x1B[37m${err.message}\x1B[0m`);
531
- console.error(` \x1B[33m\u{1F4A1} Make sure Ruby and Opal are installed correctly\x1B[0m`);
532
141
  reject(new Error(`Failed to spawn Ruby process: ${err.message}`));
533
142
  });
534
143
  });
@@ -548,13 +157,14 @@ var OpalCompiler = class {
548
157
  "puts Opal::Vite::Compiler.runtime_code"
549
158
  ];
550
159
  } else {
551
- const gemLibPath = this.resolveGemLibPath();
552
160
  command = "ruby";
553
161
  args = [
554
162
  "-I",
555
- gemLibPath,
163
+ this.resolveGemLibPath(),
164
+ "-r",
165
+ "opal-vite",
556
166
  "-e",
557
- `$LOAD_PATH.unshift('${gemLibPath}'); require 'opal-vite'; puts Opal::Vite::Compiler.runtime_code`
167
+ "puts Opal::Vite::Compiler.runtime_code"
558
168
  ];
559
169
  }
560
170
  const ruby = spawn(command, args, {
@@ -584,16 +194,15 @@ ${stderr}`));
584
194
  getCompilerScript() {
585
195
  const includeConcerns = this.options.includeConcerns;
586
196
  const sourceMap = this.options.sourceMap;
587
- const stubs = JSON.stringify(this.options.stubs);
588
197
  return `
198
+ require 'opal-vite'
589
199
  file_path = ARGV[0]
590
- stubs = ${stubs}
591
- Opal::Vite.compile_for_vite(file_path, include_concerns: ${includeConcerns}, source_map: ${sourceMap}, stubs: stubs)
200
+ Opal::Vite.compile_for_vite(file_path, include_concerns: ${includeConcerns}, source_map: ${sourceMap})
592
201
  `.trim();
593
202
  }
594
203
  resolveGemLibPath() {
595
204
  if (this.options.gemPath.startsWith(".") || this.options.gemPath.startsWith("/")) {
596
- return path.resolve(this.options.gemPath, "lib");
205
+ return path2.resolve(this.options.gemPath, "lib");
597
206
  }
598
207
  return this.options.gemPath;
599
208
  }
@@ -668,7 +277,7 @@ var OpalResolver = class {
668
277
  }
669
278
  }
670
279
  async resolveAbsolute(id) {
671
- if (!path.isAbsolute(id)) {
280
+ if (!path2.isAbsolute(id)) {
672
281
  return null;
673
282
  }
674
283
  if (await this.fileExists(id)) {
@@ -686,8 +295,8 @@ var OpalResolver = class {
686
295
  if (!id.startsWith(".") || !importer) {
687
296
  return null;
688
297
  }
689
- const importerDir = path.dirname(importer);
690
- const resolved = path.resolve(importerDir, id);
298
+ const importerDir = path2.dirname(importer);
299
+ const resolved = path2.resolve(importerDir, id);
691
300
  if (await this.fileExists(resolved)) {
692
301
  return resolved;
693
302
  }
@@ -702,15 +311,15 @@ var OpalResolver = class {
702
311
  async resolveFromLoadPaths(id) {
703
312
  const baseId = id.endsWith(".rb") ? id.slice(0, -3) : id;
704
313
  for (const loadPath of this.loadPaths) {
705
- const fullPath = path.resolve(loadPath, id);
314
+ const fullPath = path2.resolve(loadPath, id);
706
315
  if (await this.fileExists(fullPath)) {
707
316
  return fullPath;
708
317
  }
709
- const withExt = path.resolve(loadPath, `${baseId}.rb`);
318
+ const withExt = path2.resolve(loadPath, `${baseId}.rb`);
710
319
  if (await this.fileExists(withExt)) {
711
320
  return withExt;
712
321
  }
713
- const indexPath = path.resolve(loadPath, baseId, "index.rb");
322
+ const indexPath = path2.resolve(loadPath, baseId, "index.rb");
714
323
  if (await this.fileExists(indexPath)) {
715
324
  return indexPath;
716
325
  }
@@ -726,7 +335,7 @@ var OpalResolver = class {
726
335
  }
727
336
  }
728
337
  hasExtension(filePath) {
729
- const ext = path.extname(filePath);
338
+ const ext = path2.extname(filePath);
730
339
  return ext !== "";
731
340
  }
732
341
  };
@@ -759,7 +368,7 @@ var OpalHMRManager = class {
759
368
  });
760
369
  this.watcher.on("unlink", (filePath) => {
761
370
  this.log(`File removed: ${filePath}`);
762
- const absolutePath = path.resolve(this.server.config.root, filePath);
371
+ const absolutePath = path2.resolve(this.server.config.root, filePath);
763
372
  this.compiler.clearCache(absolutePath);
764
373
  this.resolver.clearCache(absolutePath);
765
374
  this.dependencyGraph.delete(absolutePath);
@@ -783,7 +392,7 @@ var OpalHMRManager = class {
783
392
  * Handle file change and trigger HMR update
784
393
  */
785
394
  async handleFileChange(filePath) {
786
- const absolutePath = path.resolve(this.server.config.root, filePath);
395
+ const absolutePath = path2.resolve(this.server.config.root, filePath);
787
396
  this.log(`File changed: ${filePath}`);
788
397
  try {
789
398
  this.compiler.clearCache(absolutePath);
@@ -906,8 +515,6 @@ function opalPlugin(options = {}) {
906
515
  let server;
907
516
  let hmrManager;
908
517
  let isBuild = false;
909
- const useCdn = compiler.isCdnEnabled();
910
- const cdnUrl = compiler.getCdnUrl();
911
518
  return {
912
519
  name: "vite-plugin-opal",
913
520
  enforce: "pre",
@@ -936,20 +543,6 @@ function opalPlugin(options = {}) {
936
543
  // Load and compile .rb files
937
544
  async load(id) {
938
545
  if (id === VIRTUAL_RUNTIME_PREFIX) {
939
- if (useCdn) {
940
- if (options.debug) {
941
- console.log(`[vite-plugin-opal] Using CDN for Opal runtime: ${cdnUrl}`);
942
- }
943
- return {
944
- code: `// Opal runtime loaded from CDN: ${cdnUrl}
945
- // The runtime is loaded via script tag in index.html
946
- if (typeof Opal === 'undefined') {
947
- console.error('[vite-plugin-opal] Opal runtime not found. Make sure the CDN script is loaded before your application code.');
948
- }
949
- `,
950
- map: null
951
- };
952
- }
953
546
  if (options.debug) {
954
547
  console.log(`[vite-plugin-opal] Loading Opal runtime...`);
955
548
  }
@@ -987,20 +580,12 @@ if (typeof Opal === 'undefined') {
987
580
  }
988
581
  return null;
989
582
  },
990
- // Auto-inject Opal runtime into HTML
583
+ // Auto-inject Opal runtime into HTML (development only)
991
584
  transformIndexHtml(html) {
992
- let runtimeScript;
993
- if (useCdn && cdnUrl) {
994
- runtimeScript = `<script src="${cdnUrl}"></script>`;
995
- if (options.debug) {
996
- console.log(`[vite-plugin-opal] Injecting CDN script: ${cdnUrl}`);
997
- }
998
- } else {
999
- if (isBuild) {
1000
- return html;
1001
- }
1002
- runtimeScript = `<script type="module" src="${VIRTUAL_RUNTIME_ID}"></script>`;
585
+ if (isBuild) {
586
+ return html;
1003
587
  }
588
+ const runtimeScript = `<script type="module" src="${VIRTUAL_RUNTIME_ID}"></script>`;
1004
589
  if (html.includes("</head>")) {
1005
590
  return html.replace("</head>", ` ${runtimeScript}
1006
591
  </head>`);
@@ -1022,12 +607,6 @@ ${html}`;
1022
607
  hmrManager.cleanup();
1023
608
  }
1024
609
  };
1025
- },
1026
- // Print metrics after build completes
1027
- closeBundle() {
1028
- if (options.metrics) {
1029
- compiler.printMetricsSummary();
1030
- }
1031
610
  }
1032
611
  };
1033
612
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/compiler.ts","../src/resolver.ts","../src/hmr.ts","../src/index.ts"],"names":["stat","resolve","path2","fs2","path3"],"mappings":"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","file":"index.js","sourcesContent":["import { spawn } from 'child_process'\nimport * as fs from 'fs/promises'\nimport { accessSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'\nimport * as path from 'path'\nimport * as crypto from 'crypto'\nimport type { OpalPluginOptions, CompileResult, CacheEntry, OpalCompilationError } from './types'\n\n/**\n * Parse Opal/Ruby compilation error output into structured error information\n */\nfunction parseRubyError(stderr: string, filePath: string): OpalCompilationError {\n const lines = stderr.trim().split('\\n')\n const error: OpalCompilationError = {\n message: stderr.trim(),\n file: filePath,\n rawOutput: stderr\n }\n\n // Try to extract line number from Ruby error format: \"file.rb:123: error message\"\n // or \"file.rb:123:in `method': error message\"\n for (const line of lines) {\n const lineMatch = line.match(/^(.+?):(\\d+)(?::(\\d+))?(?::in `[^']+')?\\s*[:\\-]?\\s*(.*)/)\n if (lineMatch) {\n const [, matchedFile, lineNum, colNum, msg] = lineMatch\n if (matchedFile.endsWith('.rb') || matchedFile.includes(filePath)) {\n error.file = matchedFile\n error.line = parseInt(lineNum, 10)\n if (colNum) {\n error.column = parseInt(colNum, 10)\n }\n error.message = msg || line\n break\n }\n }\n }\n\n // Extract error type from Ruby exceptions\n const typeMatch = stderr.match(/(\\w+Error|\\w+Exception):\\s*(.+)/m)\n if (typeMatch) {\n error.errorType = typeMatch[1]\n if (!error.message || error.message === stderr.trim()) {\n error.message = typeMatch[2].trim()\n }\n }\n\n // Check for common Opal-specific errors\n if (stderr.includes('SyntaxError')) {\n error.errorType = 'SyntaxError'\n const syntaxMatch = stderr.match(/SyntaxError:\\s*(.+?)(?:\\n|$)/)\n if (syntaxMatch) {\n error.message = syntaxMatch[1]\n }\n } else if (stderr.includes('NameError')) {\n error.errorType = 'NameError'\n const nameMatch = stderr.match(/NameError:\\s*(.+?)(?:\\n|$)/)\n if (nameMatch) {\n error.message = nameMatch[1]\n }\n } else if (stderr.includes('LoadError')) {\n error.errorType = 'LoadError'\n const loadMatch = stderr.match(/LoadError:\\s*(.+?)(?:\\n|$)/)\n if (loadMatch) {\n error.message = loadMatch[1]\n }\n // Extract the file that couldn't be loaded\n const requireMatch = stderr.match(/cannot load such file\\s*--\\s*(.+)/)\n if (requireMatch) {\n error.hint = `Check that '${requireMatch[1]}' exists and is in your load paths`\n }\n }\n\n return error\n}\n\n/**\n * Format compilation error for display in terminal/browser\n */\nfunction formatCompilationError(error: OpalCompilationError): string {\n const parts: string[] = []\n\n // Header with error type\n const errorType = error.errorType || 'CompilationError'\n parts.push(`\\x1b[31m✖ Opal ${errorType}\\x1b[0m`)\n\n // Location info\n if (error.file) {\n let location = ` \\x1b[36m→ ${error.file}\\x1b[0m`\n if (error.line) {\n location += `\\x1b[33m:${error.line}\\x1b[0m`\n if (error.column) {\n location += `\\x1b[33m:${error.column}\\x1b[0m`\n }\n }\n parts.push(location)\n }\n\n // Error message\n parts.push(` \\x1b[37m${error.message}\\x1b[0m`)\n\n // Hint if available\n if (error.hint) {\n parts.push(` \\x1b[33m💡 ${error.hint}\\x1b[0m`)\n }\n\n return parts.join('\\n')\n}\n\n/**\n * Metrics for a single compilation\n */\ninterface CompileMetrics {\n file: string\n duration: number\n cacheHit: boolean\n source: 'memory' | 'disk' | 'compile'\n}\n\n/**\n * Disk cache entry format\n */\ninterface DiskCacheEntry {\n version: string\n contentHash: string\n mtime: number\n result: CompileResult\n}\n\nconst CACHE_VERSION = '1.0.0'\n\n// Default Opal version for CDN\nconst DEFAULT_OPAL_VERSION = '1.8.2'\n\n// CDN URL templates\n// Official Opal CDN: https://github.com/opal/opal-cdn\nconst CDN_URLS: Record<string, string> = {\n opalrb: 'https://cdn.opalrb.com/opal/{version}/opal.min.js',\n jsdelivr: 'https://cdn.jsdelivr.net/gh/opal/opal-cdn@{version}/opal/{version}/opal.min.js',\n unpkg: 'https://cdn.opalrb.com/opal/{version}/opal.min.js' // Fallback to official CDN\n}\n\nexport class OpalCompiler {\n private options: Required<OpalPluginOptions> & { cdn: string | false; opalVersion: string }\n private cache: Map<string, CacheEntry> = new Map()\n private runtimeCache: string | null = null\n private useBundler: boolean\n private cacheDir: string\n private metrics: CompileMetrics[] = []\n private compilationQueue: Promise<void> = Promise.resolve()\n private activeCompilations = 0\n\n constructor(options: OpalPluginOptions = {}) {\n this.options = {\n gemPath: options.gemPath || 'opal-vite',\n sourceMap: options.sourceMap !== false,\n loadPaths: options.loadPaths || ['./src'],\n arityCheck: options.arityCheck || false,\n freezing: options.freezing !== false,\n debug: options.debug || false,\n useBundler: options.useBundler !== undefined ? options.useBundler : this.detectGemfile(),\n includeConcerns: options.includeConcerns !== false,\n // Performance options (v0.3.2+)\n diskCache: options.diskCache !== false,\n cacheDir: options.cacheDir || '',\n stubs: options.stubs || [],\n parallelCompilation: options.parallelCompilation || 4,\n metrics: options.metrics || false,\n // CDN options (v0.3.5+)\n cdn: options.cdn || false,\n opalVersion: options.opalVersion || DEFAULT_OPAL_VERSION\n }\n this.useBundler = this.options.useBundler\n this.cacheDir = this.resolveCacheDir()\n\n // Ensure cache directory exists\n if (this.options.diskCache) {\n this.ensureCacheDir()\n }\n\n if (this.options.debug) {\n console.log(`[vite-plugin-opal] Using bundler: ${this.useBundler}`)\n console.log(`[vite-plugin-opal] Working directory: ${process.cwd()}`)\n console.log(`[vite-plugin-opal] Include concerns: ${this.options.includeConcerns}`)\n console.log(`[vite-plugin-opal] Disk cache: ${this.options.diskCache ? 'enabled' : 'disabled'}`)\n if (this.options.diskCache) {\n console.log(`[vite-plugin-opal] Cache directory: ${this.cacheDir}`)\n }\n if (this.options.stubs.length > 0) {\n console.log(`[vite-plugin-opal] Stubs: ${this.options.stubs.join(', ')}`)\n }\n console.log(`[vite-plugin-opal] Parallel compilation: ${this.options.parallelCompilation}`)\n if (this.options.cdn) {\n console.log(`[vite-plugin-opal] CDN mode: ${this.options.cdn}`)\n console.log(`[vite-plugin-opal] CDN URL: ${this.getCdnUrl()}`)\n }\n }\n }\n\n private resolveCacheDir(): string {\n if (this.options.cacheDir) {\n return path.resolve(process.cwd(), this.options.cacheDir)\n }\n // Default: node_modules/.cache/opal-vite\n return path.resolve(process.cwd(), 'node_modules', '.cache', 'opal-vite')\n }\n\n private ensureCacheDir(): void {\n try {\n if (!existsSync(this.cacheDir)) {\n mkdirSync(this.cacheDir, { recursive: true })\n this.log(`Created cache directory: ${this.cacheDir}`)\n }\n } catch (e) {\n this.log(`Warning: Could not create cache directory: ${e}`)\n }\n }\n\n private getCacheKey(filePath: string): string {\n // Create a safe filename from the file path\n const normalized = path.resolve(filePath)\n return crypto.createHash('md5').update(normalized).digest('hex')\n }\n\n private getContentHash(content: string): string {\n return crypto.createHash('md5').update(content).digest('hex')\n }\n\n private getDiskCachePath(filePath: string): string {\n return path.join(this.cacheDir, `${this.getCacheKey(filePath)}.json`)\n }\n\n private async loadFromDiskCache(filePath: string, contentHash: string): Promise<CompileResult | null> {\n if (!this.options.diskCache) return null\n\n const cachePath = this.getDiskCachePath(filePath)\n try {\n if (!existsSync(cachePath)) return null\n\n const cacheContent = readFileSync(cachePath, 'utf-8')\n const entry: DiskCacheEntry = JSON.parse(cacheContent)\n\n // Validate cache entry\n if (entry.version !== CACHE_VERSION) {\n this.log(`Disk cache version mismatch for ${filePath}`)\n return null\n }\n\n if (entry.contentHash !== contentHash) {\n this.log(`Disk cache content hash mismatch for ${filePath}`)\n return null\n }\n\n this.log(`Disk cache hit: ${filePath}`)\n return entry.result\n } catch (e) {\n // Cache file is invalid or corrupted\n this.log(`Disk cache read error for ${filePath}: ${e}`)\n return null\n }\n }\n\n private saveToDiskCache(filePath: string, contentHash: string, mtime: number, result: CompileResult): void {\n if (!this.options.diskCache) return\n\n const cachePath = this.getDiskCachePath(filePath)\n try {\n const entry: DiskCacheEntry = {\n version: CACHE_VERSION,\n contentHash,\n mtime,\n result\n }\n writeFileSync(cachePath, JSON.stringify(entry), 'utf-8')\n this.log(`Disk cache saved: ${filePath}`)\n } catch (e) {\n this.log(`Disk cache write error for ${filePath}: ${e}`)\n }\n }\n\n /**\n * Check if CDN mode is enabled\n */\n isCdnEnabled(): boolean {\n return !!this.options.cdn\n }\n\n /**\n * Get the CDN URL for Opal runtime\n */\n getCdnUrl(): string | null {\n const cdn = this.options.cdn\n if (!cdn) return null\n\n // Check if it's a known CDN provider\n if (cdn in CDN_URLS) {\n // Use global regex to replace all occurrences of {version}\n return CDN_URLS[cdn].replace(/\\{version\\}/g, this.options.opalVersion)\n }\n\n // Assume it's a custom URL\n return cdn\n }\n\n private detectGemfile(): boolean {\n try {\n const gemfilePath = path.join(process.cwd(), 'Gemfile')\n accessSync(gemfilePath)\n return true\n } catch {\n return false\n }\n }\n\n async compile(filePath: string): Promise<CompileResult> {\n const startTime = this.options.metrics ? performance.now() : 0\n\n // Check if this is a stubbed module\n const stubResult = this.checkStub(filePath)\n if (stubResult) {\n this.recordMetrics(filePath, startTime, true, 'memory')\n return stubResult\n }\n\n // Read file content for hash-based cache validation\n let fileContent: string\n let stat: { mtimeMs: number }\n try {\n fileContent = await fs.readFile(filePath, 'utf-8')\n stat = await fs.stat(filePath)\n } catch (e) {\n throw new Error(`Failed to read file: ${filePath}`)\n }\n\n const contentHash = this.getContentHash(fileContent)\n\n // Check memory cache first\n const cached = this.cache.get(filePath)\n if (cached) {\n if (stat.mtimeMs <= cached.mtime) {\n this.log(`Memory cache hit: ${filePath}`)\n this.recordMetrics(filePath, startTime, true, 'memory')\n return {\n code: cached.code,\n map: cached.map,\n dependencies: cached.dependencies\n }\n }\n // Cache is stale, remove it\n this.cache.delete(filePath)\n }\n\n // Check disk cache\n const diskCached = await this.loadFromDiskCache(filePath, contentHash)\n if (diskCached) {\n // Update memory cache\n this.cache.set(filePath, {\n ...diskCached,\n mtime: stat.mtimeMs\n })\n this.recordMetrics(filePath, startTime, true, 'disk')\n return diskCached\n }\n\n // Compile with concurrency control\n this.log(`Compiling: ${filePath}`)\n const result = await this.compileWithConcurrencyControl(filePath)\n\n // Cache the result in memory\n this.cache.set(filePath, {\n ...result,\n mtime: stat.mtimeMs\n })\n\n // Cache the result on disk\n this.saveToDiskCache(filePath, contentHash, stat.mtimeMs, result)\n\n this.recordMetrics(filePath, startTime, false, 'compile')\n return result\n }\n\n /**\n * Compile multiple files in parallel with concurrency control\n */\n async compileMany(filePaths: string[]): Promise<Map<string, CompileResult>> {\n const results = new Map<string, CompileResult>()\n\n // Process files in batches based on parallelCompilation setting\n const batchSize = this.options.parallelCompilation\n for (let i = 0; i < filePaths.length; i += batchSize) {\n const batch = filePaths.slice(i, i + batchSize)\n const batchResults = await Promise.all(\n batch.map(async (filePath) => {\n try {\n const result = await this.compile(filePath)\n return { filePath, result, error: null }\n } catch (e) {\n return { filePath, result: null, error: e }\n }\n })\n )\n\n for (const { filePath, result, error } of batchResults) {\n if (result) {\n results.set(filePath, result)\n } else {\n this.log(`Compilation failed for ${filePath}: ${error}`)\n }\n }\n }\n\n return results\n }\n\n private async compileWithConcurrencyControl(filePath: string): Promise<CompileResult> {\n // Wait if we're at the concurrency limit\n while (this.activeCompilations >= this.options.parallelCompilation) {\n await new Promise(resolve => setTimeout(resolve, 10))\n }\n\n this.activeCompilations++\n try {\n return await this.compileViaRuby(filePath)\n } finally {\n this.activeCompilations--\n }\n }\n\n private checkStub(filePath: string): CompileResult | null {\n if (this.options.stubs.length === 0) return null\n\n const fileName = path.basename(filePath, '.rb')\n const isStubbed = this.options.stubs.some(stub => {\n // Match exact name or pattern\n if (stub === fileName) return true\n // Match as a path component (e.g., 'active_support' matches any active_support/*.rb)\n if (filePath.includes(`/${stub}/`) || filePath.includes(`/${stub}.rb`)) return true\n return false\n })\n\n if (isStubbed) {\n this.log(`Stubbed module: ${filePath}`)\n return {\n code: '// Stubbed module\\nOpal.loaded([\"' + fileName + '\"]);\\n',\n map: undefined,\n dependencies: []\n }\n }\n\n return null\n }\n\n private recordMetrics(filePath: string, startTime: number, cacheHit: boolean, source: 'memory' | 'disk' | 'compile'): void {\n if (!this.options.metrics) return\n\n const duration = performance.now() - startTime\n this.metrics.push({\n file: path.basename(filePath),\n duration,\n cacheHit,\n source\n })\n }\n\n /**\n * Get compilation metrics summary\n */\n getMetricsSummary(): { total: number; cached: number; compiled: number; avgDuration: number; details: CompileMetrics[] } {\n const total = this.metrics.length\n const cached = this.metrics.filter(m => m.cacheHit).length\n const compiled = total - cached\n const avgDuration = total > 0\n ? this.metrics.reduce((sum, m) => sum + m.duration, 0) / total\n : 0\n\n return {\n total,\n cached,\n compiled,\n avgDuration: Math.round(avgDuration * 100) / 100,\n details: [...this.metrics]\n }\n }\n\n /**\n * Print metrics summary to console\n */\n printMetricsSummary(): void {\n const summary = this.getMetricsSummary()\n console.log('\\n[vite-plugin-opal] Compilation Metrics:')\n console.log(` Total files: ${summary.total}`)\n console.log(` Cache hits: ${summary.cached} (${Math.round(summary.cached / summary.total * 100) || 0}%)`)\n console.log(` Compiled: ${summary.compiled}`)\n console.log(` Avg duration: ${summary.avgDuration}ms`)\n\n if (this.options.debug && summary.details.length > 0) {\n console.log('\\n Details:')\n for (const m of summary.details) {\n console.log(` ${m.file}: ${Math.round(m.duration)}ms (${m.source})`)\n }\n }\n }\n\n /**\n * Clear metrics\n */\n clearMetrics(): void {\n this.metrics = []\n }\n\n async getOpalRuntime(): Promise<string> {\n if (this.runtimeCache) {\n return this.runtimeCache\n }\n\n this.log('Loading Opal runtime')\n const runtime = await this.getRuntimeViaRuby()\n this.runtimeCache = runtime\n return runtime\n }\n\n clearCache(filePath?: string, clearDisk = false): void {\n if (filePath) {\n this.cache.delete(filePath)\n if (clearDisk && this.options.diskCache) {\n try {\n const cachePath = this.getDiskCachePath(filePath)\n if (existsSync(cachePath)) {\n const fsSync = require('fs')\n fsSync.unlinkSync(cachePath)\n }\n } catch (e) {\n this.log(`Failed to clear disk cache for ${filePath}: ${e}`)\n }\n }\n this.log(`Cache cleared: ${filePath}`)\n } else {\n this.cache.clear()\n if (clearDisk && this.options.diskCache) {\n this.clearDiskCache()\n }\n this.log('Cache cleared (all)')\n }\n }\n\n /**\n * Clear all disk cache files\n */\n clearDiskCache(): void {\n if (!this.options.diskCache) return\n\n try {\n const fsSync = require('fs')\n if (existsSync(this.cacheDir)) {\n const files = fsSync.readdirSync(this.cacheDir)\n for (const file of files) {\n if (file.endsWith('.json')) {\n fsSync.unlinkSync(path.join(this.cacheDir, file))\n }\n }\n this.log(`Cleared ${files.length} disk cache files`)\n }\n } catch (e) {\n this.log(`Failed to clear disk cache: ${e}`)\n }\n }\n\n /**\n * Get disk cache statistics\n */\n getDiskCacheStats(): { files: number; size: number } {\n if (!this.options.diskCache || !existsSync(this.cacheDir)) {\n return { files: 0, size: 0 }\n }\n\n try {\n const fsSync = require('fs')\n const files = fsSync.readdirSync(this.cacheDir)\n .filter((f: string) => f.endsWith('.json'))\n let totalSize = 0\n for (const file of files) {\n const stat = fsSync.statSync(path.join(this.cacheDir, file))\n totalSize += stat.size\n }\n return { files: files.length, size: totalSize }\n } catch (e) {\n return { files: 0, size: 0 }\n }\n }\n\n private async compileViaRuby(filePath: string): Promise<CompileResult> {\n return new Promise((resolve, reject) => {\n let command: string\n let args: string[]\n\n if (this.useBundler) {\n command = 'bundle'\n args = [\n 'exec', 'ruby',\n '-r', 'opal-vite',\n '-e', this.getCompilerScript(),\n filePath\n ]\n } else {\n const gemLibPath = this.resolveGemLibPath()\n command = 'ruby'\n args = [\n '-I', gemLibPath,\n '-e', `$LOAD_PATH.unshift('${gemLibPath}'); require 'opal-vite'; ${this.getCompilerScript()}`,\n filePath\n ]\n }\n\n this.log(`Spawning Ruby: ${command} ${args.join(' ')}`)\n\n const ruby = spawn(command, args, {\n cwd: process.cwd()\n })\n\n let stdout = ''\n let stderr = ''\n\n ruby.stdout.on('data', (data) => {\n stdout += data.toString()\n })\n\n ruby.stderr.on('data', (data) => {\n stderr += data.toString()\n })\n\n ruby.on('close', (code) => {\n if (code !== 0) {\n const parsedError = parseRubyError(stderr, filePath)\n const formattedMessage = formatCompilationError(parsedError)\n console.error(formattedMessage)\n\n // Create an error with structured information for Vite\n const error = new Error(parsedError.message) as Error & OpalCompilationError\n error.file = parsedError.file\n error.line = parsedError.line\n error.column = parsedError.column\n error.errorType = parsedError.errorType\n error.hint = parsedError.hint\n error.rawOutput = parsedError.rawOutput\n\n reject(error)\n return\n }\n\n try {\n const result = JSON.parse(stdout)\n resolve(result)\n } catch (e) {\n const parseError = new Error(`Failed to parse compiler output: ${e}`)\n console.error('\\x1b[31m✖ Opal Compiler Output Parse Error\\x1b[0m')\n console.error(` \\x1b[36m→ ${filePath}\\x1b[0m`)\n console.error(` \\x1b[37mUnexpected output from Ruby compiler\\x1b[0m`)\n if (this.options.debug) {\n console.error(` \\x1b[90mRaw output: ${stdout.substring(0, 500)}...\\x1b[0m`)\n }\n reject(parseError)\n }\n })\n\n ruby.on('error', (err) => {\n console.error('\\x1b[31m✖ Ruby Process Error\\x1b[0m')\n console.error(` \\x1b[37m${err.message}\\x1b[0m`)\n console.error(` \\x1b[33m💡 Make sure Ruby and Opal are installed correctly\\x1b[0m`)\n reject(new Error(`Failed to spawn Ruby process: ${err.message}`))\n })\n })\n }\n\n private async getRuntimeViaRuby(): Promise<string> {\n return new Promise((resolve, reject) => {\n let command: string\n let args: string[]\n\n if (this.useBundler) {\n command = 'bundle'\n args = [\n 'exec', 'ruby',\n '-r', 'opal-vite',\n '-e', 'puts Opal::Vite::Compiler.runtime_code'\n ]\n } else {\n const gemLibPath = this.resolveGemLibPath()\n command = 'ruby'\n args = [\n '-I', gemLibPath,\n '-e', `$LOAD_PATH.unshift('${gemLibPath}'); require 'opal-vite'; puts Opal::Vite::Compiler.runtime_code`\n ]\n }\n\n const ruby = spawn(command, args, {\n cwd: process.cwd()\n })\n\n let stdout = ''\n let stderr = ''\n\n ruby.stdout.on('data', (data) => {\n stdout += data.toString()\n })\n\n ruby.stderr.on('data', (data) => {\n stderr += data.toString()\n })\n\n ruby.on('close', (code) => {\n if (code === 0) {\n resolve(stdout)\n } else {\n reject(new Error(`Failed to get Opal runtime:\\n${stderr}`))\n }\n })\n\n ruby.on('error', (err) => {\n reject(new Error(`Failed to spawn Ruby process: ${err.message}`))\n })\n })\n }\n\n private getCompilerScript(): string {\n const includeConcerns = this.options.includeConcerns\n const sourceMap = this.options.sourceMap\n const stubs = JSON.stringify(this.options.stubs)\n // Note: opal-vite is already required via -r flag or -I flag\n // The $LOAD_PATH is set up by -I option, so require 'opal-vite' will find it\n return `\n file_path = ARGV[0]\n stubs = ${stubs}\n Opal::Vite.compile_for_vite(file_path, include_concerns: ${includeConcerns}, source_map: ${sourceMap}, stubs: stubs)\n `.trim()\n }\n\n private resolveGemLibPath(): string {\n // Try to resolve the gem path\n // In development, this points to our local gem\n // In production, bundler will handle it\n if (this.options.gemPath.startsWith('.') || this.options.gemPath.startsWith('/')) {\n return path.resolve(this.options.gemPath, 'lib')\n }\n return this.options.gemPath\n }\n\n private log(message: string): void {\n if (this.options.debug) {\n console.log(`[vite-plugin-opal] ${message}`)\n }\n }\n}\n","import * as path from 'path'\nimport * as fs from 'fs/promises'\nimport type { OpalPluginOptions } from './types'\n\nexport class OpalResolver {\n private options: Required<OpalPluginOptions>\n private loadPaths: string[]\n private resolveCache: Map<string, string | null> = new Map()\n\n constructor(options: OpalPluginOptions = {}) {\n this.options = {\n gemPath: options.gemPath || 'opal-vite',\n sourceMap: options.sourceMap !== false,\n loadPaths: options.loadPaths || ['./src'],\n arityCheck: options.arityCheck || false,\n freezing: options.freezing !== false,\n debug: options.debug || false\n }\n this.loadPaths = this.options.loadPaths\n }\n\n /**\n * Resolve a Ruby file import\n * Supports:\n * - Absolute paths: /path/to/file.rb\n * - Relative paths: ./file.rb, ../file.rb\n * - Load path resolution: file (searches in loadPaths)\n */\n async resolve(id: string, importer?: string): Promise<string | null> {\n // Check cache first\n const cacheKey = `${id}|${importer || ''}`\n if (this.resolveCache.has(cacheKey)) {\n return this.resolveCache.get(cacheKey)!\n }\n\n let resolved: string | null = null\n\n // Only resolve .rb files or files without extension\n if (id.endsWith('.rb') || !this.hasExtension(id)) {\n // Try different resolution strategies\n resolved = await this.resolveAbsolute(id) ||\n await this.resolveRelative(id, importer) ||\n await this.resolveFromLoadPaths(id)\n }\n\n // Cache the result\n this.resolveCache.set(cacheKey, resolved)\n\n if (resolved && this.options.debug) {\n console.log(`[vite-plugin-opal] Resolved: ${id} -> ${resolved}`)\n }\n\n return resolved\n }\n\n /**\n * Clear the resolution cache\n */\n clearCache(filePath?: string): void {\n if (filePath) {\n // Clear cache entries related to this file\n for (const [key, value] of this.resolveCache.entries()) {\n if (value === filePath || key.startsWith(filePath)) {\n this.resolveCache.delete(key)\n }\n }\n } else {\n this.resolveCache.clear()\n }\n }\n\n /**\n * Get all load paths\n */\n getLoadPaths(): string[] {\n return [...this.loadPaths]\n }\n\n /**\n * Add a load path\n */\n addLoadPath(loadPath: string): void {\n if (!this.loadPaths.includes(loadPath)) {\n this.loadPaths.push(loadPath)\n this.clearCache() // Clear cache when load paths change\n }\n }\n\n private async resolveAbsolute(id: string): Promise<string | null> {\n if (!path.isAbsolute(id)) {\n return null\n }\n\n // Try as-is\n if (await this.fileExists(id)) {\n return id\n }\n\n // Try with .rb extension\n if (!id.endsWith('.rb')) {\n const withExt = `${id}.rb`\n if (await this.fileExists(withExt)) {\n return withExt\n }\n }\n\n return null\n }\n\n private async resolveRelative(id: string, importer?: string): Promise<string | null> {\n if (!id.startsWith('.') || !importer) {\n return null\n }\n\n const importerDir = path.dirname(importer)\n const resolved = path.resolve(importerDir, id)\n\n // Try as-is\n if (await this.fileExists(resolved)) {\n return resolved\n }\n\n // Try with .rb extension\n if (!id.endsWith('.rb')) {\n const withExt = `${resolved}.rb`\n if (await this.fileExists(withExt)) {\n return withExt\n }\n }\n\n return null\n }\n\n private async resolveFromLoadPaths(id: string): Promise<string | null> {\n // Remove .rb extension for load path search\n const baseId = id.endsWith('.rb') ? id.slice(0, -3) : id\n\n for (const loadPath of this.loadPaths) {\n // Try with original id\n const fullPath = path.resolve(loadPath, id)\n if (await this.fileExists(fullPath)) {\n return fullPath\n }\n\n // Try with .rb extension\n const withExt = path.resolve(loadPath, `${baseId}.rb`)\n if (await this.fileExists(withExt)) {\n return withExt\n }\n\n // Try as a directory with index.rb\n const indexPath = path.resolve(loadPath, baseId, 'index.rb')\n if (await this.fileExists(indexPath)) {\n return indexPath\n }\n }\n\n return null\n }\n\n private async fileExists(filePath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(filePath)\n return stat.isFile()\n } catch {\n return false\n }\n }\n\n private hasExtension(filePath: string): boolean {\n const ext = path.extname(filePath)\n return ext !== ''\n }\n}\n","import type { ViteDevServer, ModuleNode, Update } from 'vite'\nimport type { OpalCompiler } from './compiler'\nimport type { OpalResolver } from './resolver'\nimport type { OpalPluginOptions } from './types'\nimport * as path from 'path'\nimport * as chokidar from 'chokidar'\n\nexport interface HMRManager {\n setup(): void\n cleanup(): void\n handleFileChange(filePath: string): Promise<void>\n}\n\nexport class OpalHMRManager implements HMRManager {\n private server: ViteDevServer\n private compiler: OpalCompiler\n private resolver: OpalResolver\n private options: OpalPluginOptions\n private watcher?: chokidar.FSWatcher\n private dependencyGraph: Map<string, Set<string>> = new Map()\n\n constructor(\n server: ViteDevServer,\n compiler: OpalCompiler,\n resolver: OpalResolver,\n options: OpalPluginOptions\n ) {\n this.server = server\n this.compiler = compiler\n this.resolver = resolver\n this.options = options\n }\n\n /**\n * Setup HMR file watching\n */\n setup(): void {\n this.log('Setting up HMR for .rb files')\n\n // Watch .rb files for changes\n this.watcher = chokidar.watch('**/*.rb', {\n ignored: /node_modules/,\n persistent: true,\n cwd: this.server.config.root,\n ignoreInitial: true // Don't trigger on initial scan\n })\n\n this.watcher.on('change', async (filePath: string) => {\n await this.handleFileChange(filePath)\n })\n\n this.watcher.on('add', async (filePath: string) => {\n this.log(`New file detected: ${filePath}`)\n await this.handleFileChange(filePath)\n })\n\n this.watcher.on('unlink', (filePath: string) => {\n this.log(`File removed: ${filePath}`)\n const absolutePath = path.resolve(this.server.config.root, filePath)\n this.compiler.clearCache(absolutePath)\n this.resolver.clearCache(absolutePath)\n this.dependencyGraph.delete(absolutePath)\n })\n\n // Cleanup on server close\n this.server.httpServer?.on('close', () => {\n this.cleanup()\n })\n\n this.log('HMR setup complete')\n }\n\n /**\n * Cleanup resources\n */\n cleanup(): void {\n if (this.watcher) {\n this.log('Cleaning up HMR watcher')\n this.watcher.close()\n this.watcher = undefined\n }\n }\n\n /**\n * Handle file change and trigger HMR update\n */\n async handleFileChange(filePath: string): Promise<void> {\n const absolutePath = path.resolve(this.server.config.root, filePath)\n\n this.log(`File changed: ${filePath}`)\n\n try {\n // Clear caches for the changed file\n this.compiler.clearCache(absolutePath)\n this.resolver.clearCache(absolutePath)\n\n // Get the module from the module graph\n const module = this.server.moduleGraph.getModuleById(absolutePath)\n\n if (!module) {\n this.log(`Module not found in graph: ${filePath}`, 'warn')\n return\n }\n\n // Collect all modules that need to be updated\n const modulesToUpdate = new Set<ModuleNode>([module])\n\n // Find dependent modules (modules that import this one)\n await this.collectDependentModules(module, modulesToUpdate)\n\n // Invalidate all affected modules\n for (const mod of modulesToUpdate) {\n this.server.moduleGraph.invalidateModule(mod)\n this.log(`Invalidated: ${mod.url}`)\n }\n\n // Build HMR updates\n const updates: Update[] = Array.from(modulesToUpdate).map(mod => ({\n type: 'js-update' as const,\n path: mod.url,\n acceptedPath: mod.url,\n timestamp: Date.now()\n }))\n\n // Send HMR update to browser\n this.server.ws.send({\n type: 'update',\n updates\n })\n\n this.log(`✓ HMR update sent for ${updates.length} module(s)`, 'success')\n } catch (error) {\n this.handleError(filePath, error)\n }\n }\n\n /**\n * Collect all modules that depend on the given module\n */\n private async collectDependentModules(\n module: ModuleNode,\n result: Set<ModuleNode>\n ): Promise<void> {\n // Get modules that import this module\n for (const importer of module.importers) {\n if (!result.has(importer)) {\n result.add(importer)\n // Recursively collect their dependents\n await this.collectDependentModules(importer, result)\n }\n }\n }\n\n /**\n * Handle compilation or HMR errors\n */\n private handleError(filePath: string, error: unknown): void {\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n this.log(`Error processing ${filePath}: ${errorMessage}`, 'error')\n\n // Send error overlay to browser\n this.server.ws.send({\n type: 'error',\n err: {\n message: `Opal compilation failed for ${filePath}`,\n stack: error instanceof Error ? error.stack : undefined,\n id: filePath,\n frame: this.extractErrorFrame(errorMessage),\n plugin: 'vite-plugin-opal',\n loc: this.extractErrorLocation(errorMessage)\n }\n })\n }\n\n /**\n * Extract error frame from error message\n */\n private extractErrorFrame(errorMessage: string): string | undefined {\n // Try to extract relevant code frame from error\n const lines = errorMessage.split('\\n')\n const relevantLines = lines.slice(0, 10).join('\\n')\n return relevantLines || undefined\n }\n\n /**\n * Extract error location from error message\n */\n private extractErrorLocation(errorMessage: string): { file?: string; line?: number; column?: number } | undefined {\n // Try to parse location from Opal error messages\n // Example: \"file.rb:10:5: error message\"\n const match = errorMessage.match(/(.+):(\\d+):(\\d+)/)\n if (match) {\n return {\n file: match[1],\n line: parseInt(match[2], 10),\n column: parseInt(match[3], 10)\n }\n }\n return undefined\n }\n\n /**\n * Log HMR messages\n */\n private log(message: string, level: 'info' | 'warn' | 'error' | 'success' = 'info'): void {\n if (!this.options.debug && level === 'info') {\n return\n }\n\n const prefix = '[vite-plugin-opal:hmr]'\n const timestamp = new Date().toLocaleTimeString()\n\n const colors = {\n info: '\\x1b[36m', // Cyan\n warn: '\\x1b[33m', // Yellow\n error: '\\x1b[31m', // Red\n success: '\\x1b[32m' // Green\n }\n const reset = '\\x1b[0m'\n\n const color = colors[level]\n const levelText = level.toUpperCase().padEnd(7)\n\n console.log(`${color}${prefix} ${timestamp} [${levelText}]${reset} ${message}`)\n }\n\n /**\n * Get dependency graph information (for debugging)\n */\n getDependencyGraph(): Map<string, Set<string>> {\n return new Map(this.dependencyGraph)\n }\n}\n","import type { Plugin, ViteDevServer } from 'vite'\nimport { OpalCompiler } from './compiler'\nimport { OpalResolver } from './resolver'\nimport { OpalHMRManager } from './hmr'\nimport type { OpalPluginOptions } from './types'\nimport * as path from 'path'\n\nconst VIRTUAL_RUNTIME_ID = '/@opal-runtime'\nconst VIRTUAL_RUNTIME_PREFIX = '\\0' + VIRTUAL_RUNTIME_ID\n\n/**\n * Vite plugin for compiling Ruby files to JavaScript using Opal.\n *\n * @param options - Plugin configuration options\n * @returns Vite plugin instance\n *\n * @example\n * ```ts\n * import { defineConfig } from 'vite'\n * import opal from 'vite-plugin-opal'\n *\n * export default defineConfig({\n * plugins: [\n * opal({\n * loadPaths: ['./app/opal'],\n * sourceMap: true\n * })\n * ]\n * })\n * ```\n *\n * @example CDN mode\n * ```ts\n * import { defineConfig } from 'vite'\n * import opal from 'vite-plugin-opal'\n *\n * export default defineConfig({\n * plugins: [\n * opal({\n * cdn: 'opalrb', // Recommended. Also: 'jsdelivr', 'unpkg', or custom URL\n * opalVersion: '1.8.2'\n * })\n * ]\n * })\n * ```\n *\n * @see {@link OpalPluginOptions} for all available options\n */\nexport default function opalPlugin(options: OpalPluginOptions = {}): Plugin {\n const compiler = new OpalCompiler(options)\n const resolver = new OpalResolver(options)\n let server: ViteDevServer | undefined\n let hmrManager: OpalHMRManager | undefined\n let isBuild = false\n const useCdn = compiler.isCdnEnabled()\n const cdnUrl = compiler.getCdnUrl()\n\n return {\n name: 'vite-plugin-opal',\n enforce: 'pre', // Run before other plugins\n\n // Detect build vs serve mode\n config(_config, { command }) {\n isBuild = command === 'build'\n },\n\n // Mark .rb files as valid imports\n async resolveId(id: string, importer?: string) {\n // Handle virtual runtime module\n if (id === VIRTUAL_RUNTIME_ID) {\n if (options.debug) {\n console.log(`[vite-plugin-opal] Resolved virtual runtime: ${VIRTUAL_RUNTIME_PREFIX}`)\n }\n return VIRTUAL_RUNTIME_PREFIX\n }\n\n // Handle .rb files and files without extension (Opal style requires)\n if (id.endsWith('.rb') || (!id.includes('.') && !id.startsWith('/'))) {\n const resolved = await resolver.resolve(id, importer)\n if (options.debug) {\n console.log(`[vite-plugin-opal] resolveId: ${id} -> ${resolved}`)\n }\n return resolved\n }\n\n return null\n },\n\n // Load and compile .rb files\n async load(id: string) {\n // Handle virtual runtime module\n if (id === VIRTUAL_RUNTIME_PREFIX) {\n // In CDN mode, return a small stub that expects Opal to be globally available\n if (useCdn) {\n if (options.debug) {\n console.log(`[vite-plugin-opal] Using CDN for Opal runtime: ${cdnUrl}`)\n }\n return {\n code: `// Opal runtime loaded from CDN: ${cdnUrl}\\n// The runtime is loaded via script tag in index.html\\nif (typeof Opal === 'undefined') {\\n console.error('[vite-plugin-opal] Opal runtime not found. Make sure the CDN script is loaded before your application code.');\\n}\\n`,\n map: null\n }\n }\n\n if (options.debug) {\n console.log(`[vite-plugin-opal] Loading Opal runtime...`)\n }\n const runtime = await compiler.getOpalRuntime()\n if (options.debug) {\n console.log(`[vite-plugin-opal] Opal runtime loaded: ${runtime.length} bytes`)\n }\n return {\n code: runtime,\n map: null\n }\n }\n\n // Handle .rb files\n if (id.endsWith('.rb')) {\n if (options.debug) {\n console.log(`[vite-plugin-opal] load: Compiling ${id}`)\n }\n try {\n const result = await compiler.compile(id)\n if (options.debug) {\n console.log(`[vite-plugin-opal] load: Compiled ${id} -> ${result.code.length} bytes`)\n console.log(`[vite-plugin-opal] load: Source map: ${result.map ? 'yes' : 'no'}`)\n }\n const sourceMap = result.map ? JSON.parse(result.map) : null\n if (options.debug && sourceMap) {\n console.log(`[vite-plugin-opal] load: Source map version: ${sourceMap.version}, sections: ${sourceMap.sections?.length || 0}`)\n }\n return {\n code: result.code,\n map: sourceMap\n }\n } catch (error) {\n console.error(`[vite-plugin-opal] Compilation error for ${id}:`, error)\n this.error(error instanceof Error ? error.message : String(error))\n }\n }\n\n return null\n },\n\n // Auto-inject Opal runtime into HTML\n transformIndexHtml(html: string) {\n let runtimeScript: string\n\n if (useCdn && cdnUrl) {\n // CDN mode: inject script tag that loads Opal from CDN\n // This works for both development and production builds\n runtimeScript = `<script src=\"${cdnUrl}\"></script>`\n if (options.debug) {\n console.log(`[vite-plugin-opal] Injecting CDN script: ${cdnUrl}`)\n }\n } else {\n // Local mode: skip injection during build - runtime is bundled into JS\n if (isBuild) {\n return html\n }\n // Inject runtime module reference (development only)\n runtimeScript = `<script type=\"module\" src=\"${VIRTUAL_RUNTIME_ID}\"></script>`\n }\n\n if (html.includes('</head>')) {\n return html.replace('</head>', ` ${runtimeScript}\\n</head>`)\n } else if (html.includes('<head>')) {\n return html.replace('<head>', `<head>\\n ${runtimeScript}`)\n } else {\n // No head tag, inject at the beginning\n return `${runtimeScript}\\n${html}`\n }\n },\n\n // Setup HMR for .rb files\n configureServer(_server: ViteDevServer) {\n server = _server\n\n // Initialize HMR manager\n hmrManager = new OpalHMRManager(server, compiler, resolver, options)\n hmrManager.setup()\n\n return () => {\n // Cleanup function called when server closes\n if (hmrManager) {\n hmrManager.cleanup()\n }\n }\n },\n\n // Print metrics after build completes\n closeBundle() {\n if (options.metrics) {\n compiler.printMetricsSummary()\n }\n }\n }\n}\n\nexport type { OpalPluginOptions } from './types'\n"]}
1
+ {"version":3,"sources":["../src/compiler.ts","../src/resolver.ts","../src/hmr.ts","../src/index.ts"],"names":["path","stat","resolve","fs2","path3"],"mappings":"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","file":"index.js","sourcesContent":["import { spawn } from 'child_process'\nimport * as fs from 'fs/promises'\nimport { accessSync } from 'fs'\nimport * as path from 'path'\nimport type { OpalPluginOptions, CompileResult, CacheEntry } from './types'\n\nexport class OpalCompiler {\n private options: Required<OpalPluginOptions>\n private cache: Map<string, CacheEntry> = new Map()\n private runtimeCache: string | null = null\n private useBundler: boolean\n\n constructor(options: OpalPluginOptions = {}) {\n this.options = {\n gemPath: options.gemPath || 'opal-vite',\n sourceMap: options.sourceMap !== false,\n loadPaths: options.loadPaths || ['./src'],\n arityCheck: options.arityCheck || false,\n freezing: options.freezing !== false,\n debug: options.debug || false,\n useBundler: options.useBundler !== undefined ? options.useBundler : this.detectGemfile(),\n includeConcerns: options.includeConcerns !== false\n }\n this.useBundler = this.options.useBundler\n\n if (this.options.debug) {\n console.log(`[vite-plugin-opal] Using bundler: ${this.useBundler}`)\n console.log(`[vite-plugin-opal] Working directory: ${process.cwd()}`)\n console.log(`[vite-plugin-opal] Include concerns: ${this.options.includeConcerns}`)\n }\n }\n\n private detectGemfile(): boolean {\n try {\n const gemfilePath = path.join(process.cwd(), 'Gemfile')\n accessSync(gemfilePath)\n return true\n } catch {\n return false\n }\n }\n\n async compile(filePath: string): Promise<CompileResult> {\n // Check cache\n const cached = this.cache.get(filePath)\n if (cached) {\n try {\n const stat = await fs.stat(filePath)\n if (stat.mtimeMs <= cached.mtime) {\n this.log(`Cache hit: ${filePath}`)\n return {\n code: cached.code,\n map: cached.map,\n dependencies: cached.dependencies\n }\n }\n } catch (e) {\n // File might have been deleted, remove from cache\n this.cache.delete(filePath)\n }\n }\n\n // Compile\n this.log(`Compiling: ${filePath}`)\n const result = await this.compileViaRuby(filePath)\n\n // Cache the result\n try {\n const stat = await fs.stat(filePath)\n this.cache.set(filePath, {\n ...result,\n mtime: stat.mtimeMs\n })\n } catch (e) {\n // Ignore if we can't stat the file\n }\n\n return result\n }\n\n async getOpalRuntime(): Promise<string> {\n if (this.runtimeCache) {\n return this.runtimeCache\n }\n\n this.log('Loading Opal runtime')\n const runtime = await this.getRuntimeViaRuby()\n this.runtimeCache = runtime\n return runtime\n }\n\n clearCache(filePath?: string): void {\n if (filePath) {\n this.cache.delete(filePath)\n this.log(`Cache cleared: ${filePath}`)\n } else {\n this.cache.clear()\n this.log('Cache cleared (all)')\n }\n }\n\n private async compileViaRuby(filePath: string): Promise<CompileResult> {\n return new Promise((resolve, reject) => {\n let command: string\n let args: string[]\n\n if (this.useBundler) {\n command = 'bundle'\n args = [\n 'exec', 'ruby',\n '-r', 'opal-vite',\n '-e', this.getCompilerScript(),\n filePath\n ]\n } else {\n command = 'ruby'\n args = [\n '-I', this.resolveGemLibPath(),\n '-r', 'opal-vite',\n '-e', this.getCompilerScript(),\n filePath\n ]\n }\n\n this.log(`Spawning Ruby: ${command} ${args.join(' ')}`)\n\n const ruby = spawn(command, args, {\n cwd: process.cwd()\n })\n\n let stdout = ''\n let stderr = ''\n\n ruby.stdout.on('data', (data) => {\n stdout += data.toString()\n })\n\n ruby.stderr.on('data', (data) => {\n stderr += data.toString()\n })\n\n ruby.on('close', (code) => {\n if (code !== 0) {\n reject(new Error(`Opal compilation failed:\\n${stderr}`))\n return\n }\n\n try {\n const result = JSON.parse(stdout)\n resolve(result)\n } catch (e) {\n reject(new Error(`Failed to parse compiler output:\\n${stdout}\\n\\nError: ${e}`))\n }\n })\n\n ruby.on('error', (err) => {\n reject(new Error(`Failed to spawn Ruby process: ${err.message}`))\n })\n })\n }\n\n private async getRuntimeViaRuby(): Promise<string> {\n return new Promise((resolve, reject) => {\n let command: string\n let args: string[]\n\n if (this.useBundler) {\n command = 'bundle'\n args = [\n 'exec', 'ruby',\n '-r', 'opal-vite',\n '-e', 'puts Opal::Vite::Compiler.runtime_code'\n ]\n } else {\n command = 'ruby'\n args = [\n '-I', this.resolveGemLibPath(),\n '-r', 'opal-vite',\n '-e', 'puts Opal::Vite::Compiler.runtime_code'\n ]\n }\n\n const ruby = spawn(command, args, {\n cwd: process.cwd()\n })\n\n let stdout = ''\n let stderr = ''\n\n ruby.stdout.on('data', (data) => {\n stdout += data.toString()\n })\n\n ruby.stderr.on('data', (data) => {\n stderr += data.toString()\n })\n\n ruby.on('close', (code) => {\n if (code === 0) {\n resolve(stdout)\n } else {\n reject(new Error(`Failed to get Opal runtime:\\n${stderr}`))\n }\n })\n\n ruby.on('error', (err) => {\n reject(new Error(`Failed to spawn Ruby process: ${err.message}`))\n })\n })\n }\n\n private getCompilerScript(): string {\n const includeConcerns = this.options.includeConcerns\n const sourceMap = this.options.sourceMap\n return `\n require 'opal-vite'\n file_path = ARGV[0]\n Opal::Vite.compile_for_vite(file_path, include_concerns: ${includeConcerns}, source_map: ${sourceMap})\n `.trim()\n }\n\n private resolveGemLibPath(): string {\n // Try to resolve the gem path\n // In development, this points to our local gem\n // In production, bundler will handle it\n if (this.options.gemPath.startsWith('.') || this.options.gemPath.startsWith('/')) {\n return path.resolve(this.options.gemPath, 'lib')\n }\n return this.options.gemPath\n }\n\n private log(message: string): void {\n if (this.options.debug) {\n console.log(`[vite-plugin-opal] ${message}`)\n }\n }\n}\n","import * as path from 'path'\nimport * as fs from 'fs/promises'\nimport type { OpalPluginOptions } from './types'\n\nexport class OpalResolver {\n private options: Required<OpalPluginOptions>\n private loadPaths: string[]\n private resolveCache: Map<string, string | null> = new Map()\n\n constructor(options: OpalPluginOptions = {}) {\n this.options = {\n gemPath: options.gemPath || 'opal-vite',\n sourceMap: options.sourceMap !== false,\n loadPaths: options.loadPaths || ['./src'],\n arityCheck: options.arityCheck || false,\n freezing: options.freezing !== false,\n debug: options.debug || false\n }\n this.loadPaths = this.options.loadPaths\n }\n\n /**\n * Resolve a Ruby file import\n * Supports:\n * - Absolute paths: /path/to/file.rb\n * - Relative paths: ./file.rb, ../file.rb\n * - Load path resolution: file (searches in loadPaths)\n */\n async resolve(id: string, importer?: string): Promise<string | null> {\n // Check cache first\n const cacheKey = `${id}|${importer || ''}`\n if (this.resolveCache.has(cacheKey)) {\n return this.resolveCache.get(cacheKey)!\n }\n\n let resolved: string | null = null\n\n // Only resolve .rb files or files without extension\n if (id.endsWith('.rb') || !this.hasExtension(id)) {\n // Try different resolution strategies\n resolved = await this.resolveAbsolute(id) ||\n await this.resolveRelative(id, importer) ||\n await this.resolveFromLoadPaths(id)\n }\n\n // Cache the result\n this.resolveCache.set(cacheKey, resolved)\n\n if (resolved && this.options.debug) {\n console.log(`[vite-plugin-opal] Resolved: ${id} -> ${resolved}`)\n }\n\n return resolved\n }\n\n /**\n * Clear the resolution cache\n */\n clearCache(filePath?: string): void {\n if (filePath) {\n // Clear cache entries related to this file\n for (const [key, value] of this.resolveCache.entries()) {\n if (value === filePath || key.startsWith(filePath)) {\n this.resolveCache.delete(key)\n }\n }\n } else {\n this.resolveCache.clear()\n }\n }\n\n /**\n * Get all load paths\n */\n getLoadPaths(): string[] {\n return [...this.loadPaths]\n }\n\n /**\n * Add a load path\n */\n addLoadPath(loadPath: string): void {\n if (!this.loadPaths.includes(loadPath)) {\n this.loadPaths.push(loadPath)\n this.clearCache() // Clear cache when load paths change\n }\n }\n\n private async resolveAbsolute(id: string): Promise<string | null> {\n if (!path.isAbsolute(id)) {\n return null\n }\n\n // Try as-is\n if (await this.fileExists(id)) {\n return id\n }\n\n // Try with .rb extension\n if (!id.endsWith('.rb')) {\n const withExt = `${id}.rb`\n if (await this.fileExists(withExt)) {\n return withExt\n }\n }\n\n return null\n }\n\n private async resolveRelative(id: string, importer?: string): Promise<string | null> {\n if (!id.startsWith('.') || !importer) {\n return null\n }\n\n const importerDir = path.dirname(importer)\n const resolved = path.resolve(importerDir, id)\n\n // Try as-is\n if (await this.fileExists(resolved)) {\n return resolved\n }\n\n // Try with .rb extension\n if (!id.endsWith('.rb')) {\n const withExt = `${resolved}.rb`\n if (await this.fileExists(withExt)) {\n return withExt\n }\n }\n\n return null\n }\n\n private async resolveFromLoadPaths(id: string): Promise<string | null> {\n // Remove .rb extension for load path search\n const baseId = id.endsWith('.rb') ? id.slice(0, -3) : id\n\n for (const loadPath of this.loadPaths) {\n // Try with original id\n const fullPath = path.resolve(loadPath, id)\n if (await this.fileExists(fullPath)) {\n return fullPath\n }\n\n // Try with .rb extension\n const withExt = path.resolve(loadPath, `${baseId}.rb`)\n if (await this.fileExists(withExt)) {\n return withExt\n }\n\n // Try as a directory with index.rb\n const indexPath = path.resolve(loadPath, baseId, 'index.rb')\n if (await this.fileExists(indexPath)) {\n return indexPath\n }\n }\n\n return null\n }\n\n private async fileExists(filePath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(filePath)\n return stat.isFile()\n } catch {\n return false\n }\n }\n\n private hasExtension(filePath: string): boolean {\n const ext = path.extname(filePath)\n return ext !== ''\n }\n}\n","import type { ViteDevServer, ModuleNode, Update } from 'vite'\nimport type { OpalCompiler } from './compiler'\nimport type { OpalResolver } from './resolver'\nimport type { OpalPluginOptions } from './types'\nimport * as path from 'path'\nimport * as chokidar from 'chokidar'\n\nexport interface HMRManager {\n setup(): void\n cleanup(): void\n handleFileChange(filePath: string): Promise<void>\n}\n\nexport class OpalHMRManager implements HMRManager {\n private server: ViteDevServer\n private compiler: OpalCompiler\n private resolver: OpalResolver\n private options: OpalPluginOptions\n private watcher?: chokidar.FSWatcher\n private dependencyGraph: Map<string, Set<string>> = new Map()\n\n constructor(\n server: ViteDevServer,\n compiler: OpalCompiler,\n resolver: OpalResolver,\n options: OpalPluginOptions\n ) {\n this.server = server\n this.compiler = compiler\n this.resolver = resolver\n this.options = options\n }\n\n /**\n * Setup HMR file watching\n */\n setup(): void {\n this.log('Setting up HMR for .rb files')\n\n // Watch .rb files for changes\n this.watcher = chokidar.watch('**/*.rb', {\n ignored: /node_modules/,\n persistent: true,\n cwd: this.server.config.root,\n ignoreInitial: true // Don't trigger on initial scan\n })\n\n this.watcher.on('change', async (filePath: string) => {\n await this.handleFileChange(filePath)\n })\n\n this.watcher.on('add', async (filePath: string) => {\n this.log(`New file detected: ${filePath}`)\n await this.handleFileChange(filePath)\n })\n\n this.watcher.on('unlink', (filePath: string) => {\n this.log(`File removed: ${filePath}`)\n const absolutePath = path.resolve(this.server.config.root, filePath)\n this.compiler.clearCache(absolutePath)\n this.resolver.clearCache(absolutePath)\n this.dependencyGraph.delete(absolutePath)\n })\n\n // Cleanup on server close\n this.server.httpServer?.on('close', () => {\n this.cleanup()\n })\n\n this.log('HMR setup complete')\n }\n\n /**\n * Cleanup resources\n */\n cleanup(): void {\n if (this.watcher) {\n this.log('Cleaning up HMR watcher')\n this.watcher.close()\n this.watcher = undefined\n }\n }\n\n /**\n * Handle file change and trigger HMR update\n */\n async handleFileChange(filePath: string): Promise<void> {\n const absolutePath = path.resolve(this.server.config.root, filePath)\n\n this.log(`File changed: ${filePath}`)\n\n try {\n // Clear caches for the changed file\n this.compiler.clearCache(absolutePath)\n this.resolver.clearCache(absolutePath)\n\n // Get the module from the module graph\n const module = this.server.moduleGraph.getModuleById(absolutePath)\n\n if (!module) {\n this.log(`Module not found in graph: ${filePath}`, 'warn')\n return\n }\n\n // Collect all modules that need to be updated\n const modulesToUpdate = new Set<ModuleNode>([module])\n\n // Find dependent modules (modules that import this one)\n await this.collectDependentModules(module, modulesToUpdate)\n\n // Invalidate all affected modules\n for (const mod of modulesToUpdate) {\n this.server.moduleGraph.invalidateModule(mod)\n this.log(`Invalidated: ${mod.url}`)\n }\n\n // Build HMR updates\n const updates: Update[] = Array.from(modulesToUpdate).map(mod => ({\n type: 'js-update' as const,\n path: mod.url,\n acceptedPath: mod.url,\n timestamp: Date.now()\n }))\n\n // Send HMR update to browser\n this.server.ws.send({\n type: 'update',\n updates\n })\n\n this.log(`✓ HMR update sent for ${updates.length} module(s)`, 'success')\n } catch (error) {\n this.handleError(filePath, error)\n }\n }\n\n /**\n * Collect all modules that depend on the given module\n */\n private async collectDependentModules(\n module: ModuleNode,\n result: Set<ModuleNode>\n ): Promise<void> {\n // Get modules that import this module\n for (const importer of module.importers) {\n if (!result.has(importer)) {\n result.add(importer)\n // Recursively collect their dependents\n await this.collectDependentModules(importer, result)\n }\n }\n }\n\n /**\n * Handle compilation or HMR errors\n */\n private handleError(filePath: string, error: unknown): void {\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n this.log(`Error processing ${filePath}: ${errorMessage}`, 'error')\n\n // Send error overlay to browser\n this.server.ws.send({\n type: 'error',\n err: {\n message: `Opal compilation failed for ${filePath}`,\n stack: error instanceof Error ? error.stack : undefined,\n id: filePath,\n frame: this.extractErrorFrame(errorMessage),\n plugin: 'vite-plugin-opal',\n loc: this.extractErrorLocation(errorMessage)\n }\n })\n }\n\n /**\n * Extract error frame from error message\n */\n private extractErrorFrame(errorMessage: string): string | undefined {\n // Try to extract relevant code frame from error\n const lines = errorMessage.split('\\n')\n const relevantLines = lines.slice(0, 10).join('\\n')\n return relevantLines || undefined\n }\n\n /**\n * Extract error location from error message\n */\n private extractErrorLocation(errorMessage: string): { file?: string; line?: number; column?: number } | undefined {\n // Try to parse location from Opal error messages\n // Example: \"file.rb:10:5: error message\"\n const match = errorMessage.match(/(.+):(\\d+):(\\d+)/)\n if (match) {\n return {\n file: match[1],\n line: parseInt(match[2], 10),\n column: parseInt(match[3], 10)\n }\n }\n return undefined\n }\n\n /**\n * Log HMR messages\n */\n private log(message: string, level: 'info' | 'warn' | 'error' | 'success' = 'info'): void {\n if (!this.options.debug && level === 'info') {\n return\n }\n\n const prefix = '[vite-plugin-opal:hmr]'\n const timestamp = new Date().toLocaleTimeString()\n\n const colors = {\n info: '\\x1b[36m', // Cyan\n warn: '\\x1b[33m', // Yellow\n error: '\\x1b[31m', // Red\n success: '\\x1b[32m' // Green\n }\n const reset = '\\x1b[0m'\n\n const color = colors[level]\n const levelText = level.toUpperCase().padEnd(7)\n\n console.log(`${color}${prefix} ${timestamp} [${levelText}]${reset} ${message}`)\n }\n\n /**\n * Get dependency graph information (for debugging)\n */\n getDependencyGraph(): Map<string, Set<string>> {\n return new Map(this.dependencyGraph)\n }\n}\n","import type { Plugin, ViteDevServer } from 'vite'\nimport { OpalCompiler } from './compiler'\nimport { OpalResolver } from './resolver'\nimport { OpalHMRManager } from './hmr'\nimport type { OpalPluginOptions } from './types'\nimport * as path from 'path'\n\nconst VIRTUAL_RUNTIME_ID = '/@opal-runtime'\nconst VIRTUAL_RUNTIME_PREFIX = '\\0' + VIRTUAL_RUNTIME_ID\n\n/**\n * Vite plugin for compiling Ruby files to JavaScript using Opal.\n *\n * @param options - Plugin configuration options\n * @returns Vite plugin instance\n *\n * @example\n * ```ts\n * import { defineConfig } from 'vite'\n * import opal from 'vite-plugin-opal'\n *\n * export default defineConfig({\n * plugins: [\n * opal({\n * loadPaths: ['./app/opal'],\n * sourceMap: true\n * })\n * ]\n * })\n * ```\n *\n * @see {@link OpalPluginOptions} for all available options\n */\nexport default function opalPlugin(options: OpalPluginOptions = {}): Plugin {\n const compiler = new OpalCompiler(options)\n const resolver = new OpalResolver(options)\n let server: ViteDevServer | undefined\n let hmrManager: OpalHMRManager | undefined\n let isBuild = false\n\n return {\n name: 'vite-plugin-opal',\n enforce: 'pre', // Run before other plugins\n\n // Detect build vs serve mode\n config(_config, { command }) {\n isBuild = command === 'build'\n },\n\n // Mark .rb files as valid imports\n async resolveId(id: string, importer?: string) {\n // Handle virtual runtime module\n if (id === VIRTUAL_RUNTIME_ID) {\n if (options.debug) {\n console.log(`[vite-plugin-opal] Resolved virtual runtime: ${VIRTUAL_RUNTIME_PREFIX}`)\n }\n return VIRTUAL_RUNTIME_PREFIX\n }\n\n // Handle .rb files and files without extension (Opal style requires)\n if (id.endsWith('.rb') || (!id.includes('.') && !id.startsWith('/'))) {\n const resolved = await resolver.resolve(id, importer)\n if (options.debug) {\n console.log(`[vite-plugin-opal] resolveId: ${id} -> ${resolved}`)\n }\n return resolved\n }\n\n return null\n },\n\n // Load and compile .rb files\n async load(id: string) {\n // Handle virtual runtime module\n if (id === VIRTUAL_RUNTIME_PREFIX) {\n if (options.debug) {\n console.log(`[vite-plugin-opal] Loading Opal runtime...`)\n }\n const runtime = await compiler.getOpalRuntime()\n if (options.debug) {\n console.log(`[vite-plugin-opal] Opal runtime loaded: ${runtime.length} bytes`)\n }\n return {\n code: runtime,\n map: null\n }\n }\n\n // Handle .rb files\n if (id.endsWith('.rb')) {\n if (options.debug) {\n console.log(`[vite-plugin-opal] load: Compiling ${id}`)\n }\n try {\n const result = await compiler.compile(id)\n if (options.debug) {\n console.log(`[vite-plugin-opal] load: Compiled ${id} -> ${result.code.length} bytes`)\n console.log(`[vite-plugin-opal] load: Source map: ${result.map ? 'yes' : 'no'}`)\n }\n const sourceMap = result.map ? JSON.parse(result.map) : null\n if (options.debug && sourceMap) {\n console.log(`[vite-plugin-opal] load: Source map version: ${sourceMap.version}, sections: ${sourceMap.sections?.length || 0}`)\n }\n return {\n code: result.code,\n map: sourceMap\n }\n } catch (error) {\n console.error(`[vite-plugin-opal] Compilation error for ${id}:`, error)\n this.error(error instanceof Error ? error.message : String(error))\n }\n }\n\n return null\n },\n\n // Auto-inject Opal runtime into HTML (development only)\n transformIndexHtml(html: string) {\n // Skip injection during build - runtime is bundled into JS\n if (isBuild) {\n return html\n }\n\n // Inject runtime before closing </head> tag (development only)\n const runtimeScript = `<script type=\"module\" src=\"${VIRTUAL_RUNTIME_ID}\"></script>`\n\n if (html.includes('</head>')) {\n return html.replace('</head>', ` ${runtimeScript}\\n</head>`)\n } else if (html.includes('<head>')) {\n return html.replace('<head>', `<head>\\n ${runtimeScript}`)\n } else {\n // No head tag, inject at the beginning\n return `${runtimeScript}\\n${html}`\n }\n },\n\n // Setup HMR for .rb files\n configureServer(_server: ViteDevServer) {\n server = _server\n\n // Initialize HMR manager\n hmrManager = new OpalHMRManager(server, compiler, resolver, options)\n hmrManager.setup()\n\n return () => {\n // Cleanup function called when server closes\n if (hmrManager) {\n hmrManager.cleanup()\n }\n }\n }\n }\n}\n\nexport type { OpalPluginOptions } from './types'\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-opal",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "description": "Vite plugin for Opal - Compile Ruby to JavaScript",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",