vite-plugin-opal 0.3.1 → 0.3.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/index.d.ts +69 -0
- package/dist/index.js +415 -50
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -135,6 +135,75 @@ 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;
|
|
138
207
|
}
|
|
139
208
|
|
|
140
209
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,98 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
2
|
import * as fs from 'fs/promises';
|
|
3
|
-
import { accessSync } from 'fs';
|
|
4
|
-
import * as
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, accessSync } from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import * as crypto from 'crypto';
|
|
5
6
|
import * as chokidar from 'chokidar';
|
|
6
7
|
|
|
7
|
-
|
|
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";
|
|
8
89
|
var OpalCompiler = class {
|
|
9
90
|
constructor(options = {}) {
|
|
10
91
|
this.cache = /* @__PURE__ */ new Map();
|
|
11
92
|
this.runtimeCache = null;
|
|
93
|
+
this.metrics = [];
|
|
94
|
+
this.compilationQueue = Promise.resolve();
|
|
95
|
+
this.activeCompilations = 0;
|
|
12
96
|
this.options = {
|
|
13
97
|
gemPath: options.gemPath || "opal-vite",
|
|
14
98
|
sourceMap: options.sourceMap !== false,
|
|
@@ -17,18 +101,99 @@ var OpalCompiler = class {
|
|
|
17
101
|
freezing: options.freezing !== false,
|
|
18
102
|
debug: options.debug || false,
|
|
19
103
|
useBundler: options.useBundler !== void 0 ? options.useBundler : this.detectGemfile(),
|
|
20
|
-
includeConcerns: options.includeConcerns !== false
|
|
104
|
+
includeConcerns: options.includeConcerns !== false,
|
|
105
|
+
diskCache: options.diskCache !== false,
|
|
106
|
+
cacheDir: options.cacheDir || "",
|
|
107
|
+
stubs: options.stubs || [],
|
|
108
|
+
parallelCompilation: options.parallelCompilation || 4,
|
|
109
|
+
metrics: options.metrics || false
|
|
21
110
|
};
|
|
22
111
|
this.useBundler = this.options.useBundler;
|
|
112
|
+
this.cacheDir = this.resolveCacheDir();
|
|
113
|
+
if (this.options.diskCache) {
|
|
114
|
+
this.ensureCacheDir();
|
|
115
|
+
}
|
|
23
116
|
if (this.options.debug) {
|
|
24
117
|
console.log(`[vite-plugin-opal] Using bundler: ${this.useBundler}`);
|
|
25
118
|
console.log(`[vite-plugin-opal] Working directory: ${process.cwd()}`);
|
|
26
119
|
console.log(`[vite-plugin-opal] Include concerns: ${this.options.includeConcerns}`);
|
|
120
|
+
console.log(`[vite-plugin-opal] Disk cache: ${this.options.diskCache ? "enabled" : "disabled"}`);
|
|
121
|
+
if (this.options.diskCache) {
|
|
122
|
+
console.log(`[vite-plugin-opal] Cache directory: ${this.cacheDir}`);
|
|
123
|
+
}
|
|
124
|
+
if (this.options.stubs.length > 0) {
|
|
125
|
+
console.log(`[vite-plugin-opal] Stubs: ${this.options.stubs.join(", ")}`);
|
|
126
|
+
}
|
|
127
|
+
console.log(`[vite-plugin-opal] Parallel compilation: ${this.options.parallelCompilation}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
resolveCacheDir() {
|
|
131
|
+
if (this.options.cacheDir) {
|
|
132
|
+
return path.resolve(process.cwd(), this.options.cacheDir);
|
|
133
|
+
}
|
|
134
|
+
return path.resolve(process.cwd(), "node_modules", ".cache", "opal-vite");
|
|
135
|
+
}
|
|
136
|
+
ensureCacheDir() {
|
|
137
|
+
try {
|
|
138
|
+
if (!existsSync(this.cacheDir)) {
|
|
139
|
+
mkdirSync(this.cacheDir, { recursive: true });
|
|
140
|
+
this.log(`Created cache directory: ${this.cacheDir}`);
|
|
141
|
+
}
|
|
142
|
+
} catch (e) {
|
|
143
|
+
this.log(`Warning: Could not create cache directory: ${e}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
getCacheKey(filePath) {
|
|
147
|
+
const normalized = path.resolve(filePath);
|
|
148
|
+
return crypto.createHash("md5").update(normalized).digest("hex");
|
|
149
|
+
}
|
|
150
|
+
getContentHash(content) {
|
|
151
|
+
return crypto.createHash("md5").update(content).digest("hex");
|
|
152
|
+
}
|
|
153
|
+
getDiskCachePath(filePath) {
|
|
154
|
+
return path.join(this.cacheDir, `${this.getCacheKey(filePath)}.json`);
|
|
155
|
+
}
|
|
156
|
+
async loadFromDiskCache(filePath, contentHash) {
|
|
157
|
+
if (!this.options.diskCache) return null;
|
|
158
|
+
const cachePath = this.getDiskCachePath(filePath);
|
|
159
|
+
try {
|
|
160
|
+
if (!existsSync(cachePath)) return null;
|
|
161
|
+
const cacheContent = readFileSync(cachePath, "utf-8");
|
|
162
|
+
const entry = JSON.parse(cacheContent);
|
|
163
|
+
if (entry.version !== CACHE_VERSION) {
|
|
164
|
+
this.log(`Disk cache version mismatch for ${filePath}`);
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
if (entry.contentHash !== contentHash) {
|
|
168
|
+
this.log(`Disk cache content hash mismatch for ${filePath}`);
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
this.log(`Disk cache hit: ${filePath}`);
|
|
172
|
+
return entry.result;
|
|
173
|
+
} catch (e) {
|
|
174
|
+
this.log(`Disk cache read error for ${filePath}: ${e}`);
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
saveToDiskCache(filePath, contentHash, mtime, result) {
|
|
179
|
+
if (!this.options.diskCache) return;
|
|
180
|
+
const cachePath = this.getDiskCachePath(filePath);
|
|
181
|
+
try {
|
|
182
|
+
const entry = {
|
|
183
|
+
version: CACHE_VERSION,
|
|
184
|
+
contentHash,
|
|
185
|
+
mtime,
|
|
186
|
+
result
|
|
187
|
+
};
|
|
188
|
+
writeFileSync(cachePath, JSON.stringify(entry), "utf-8");
|
|
189
|
+
this.log(`Disk cache saved: ${filePath}`);
|
|
190
|
+
} catch (e) {
|
|
191
|
+
this.log(`Disk cache write error for ${filePath}: ${e}`);
|
|
27
192
|
}
|
|
28
193
|
}
|
|
29
194
|
detectGemfile() {
|
|
30
195
|
try {
|
|
31
|
-
const gemfilePath =
|
|
196
|
+
const gemfilePath = path.join(process.cwd(), "Gemfile");
|
|
32
197
|
accessSync(gemfilePath);
|
|
33
198
|
return true;
|
|
34
199
|
} catch {
|
|
@@ -36,34 +201,159 @@ var OpalCompiler = class {
|
|
|
36
201
|
}
|
|
37
202
|
}
|
|
38
203
|
async compile(filePath) {
|
|
204
|
+
const startTime = this.options.metrics ? performance.now() : 0;
|
|
205
|
+
const stubResult = this.checkStub(filePath);
|
|
206
|
+
if (stubResult) {
|
|
207
|
+
this.recordMetrics(filePath, startTime, true, "memory");
|
|
208
|
+
return stubResult;
|
|
209
|
+
}
|
|
210
|
+
let fileContent;
|
|
211
|
+
let stat3;
|
|
212
|
+
try {
|
|
213
|
+
fileContent = await fs.readFile(filePath, "utf-8");
|
|
214
|
+
stat3 = await fs.stat(filePath);
|
|
215
|
+
} catch (e) {
|
|
216
|
+
throw new Error(`Failed to read file: ${filePath}`);
|
|
217
|
+
}
|
|
218
|
+
const contentHash = this.getContentHash(fileContent);
|
|
39
219
|
const cached = this.cache.get(filePath);
|
|
40
220
|
if (cached) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
} catch (e) {
|
|
52
|
-
this.cache.delete(filePath);
|
|
221
|
+
if (stat3.mtimeMs <= cached.mtime) {
|
|
222
|
+
this.log(`Memory cache hit: ${filePath}`);
|
|
223
|
+
this.recordMetrics(filePath, startTime, true, "memory");
|
|
224
|
+
return {
|
|
225
|
+
code: cached.code,
|
|
226
|
+
map: cached.map,
|
|
227
|
+
dependencies: cached.dependencies
|
|
228
|
+
};
|
|
53
229
|
}
|
|
230
|
+
this.cache.delete(filePath);
|
|
54
231
|
}
|
|
55
|
-
this.
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
const stat3 = await fs.stat(filePath);
|
|
232
|
+
const diskCached = await this.loadFromDiskCache(filePath, contentHash);
|
|
233
|
+
if (diskCached) {
|
|
59
234
|
this.cache.set(filePath, {
|
|
60
|
-
...
|
|
235
|
+
...diskCached,
|
|
61
236
|
mtime: stat3.mtimeMs
|
|
62
237
|
});
|
|
63
|
-
|
|
238
|
+
this.recordMetrics(filePath, startTime, true, "disk");
|
|
239
|
+
return diskCached;
|
|
64
240
|
}
|
|
241
|
+
this.log(`Compiling: ${filePath}`);
|
|
242
|
+
const result = await this.compileWithConcurrencyControl(filePath);
|
|
243
|
+
this.cache.set(filePath, {
|
|
244
|
+
...result,
|
|
245
|
+
mtime: stat3.mtimeMs
|
|
246
|
+
});
|
|
247
|
+
this.saveToDiskCache(filePath, contentHash, stat3.mtimeMs, result);
|
|
248
|
+
this.recordMetrics(filePath, startTime, false, "compile");
|
|
65
249
|
return result;
|
|
66
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* Compile multiple files in parallel with concurrency control
|
|
253
|
+
*/
|
|
254
|
+
async compileMany(filePaths) {
|
|
255
|
+
const results = /* @__PURE__ */ new Map();
|
|
256
|
+
const batchSize = this.options.parallelCompilation;
|
|
257
|
+
for (let i = 0; i < filePaths.length; i += batchSize) {
|
|
258
|
+
const batch = filePaths.slice(i, i + batchSize);
|
|
259
|
+
const batchResults = await Promise.all(
|
|
260
|
+
batch.map(async (filePath) => {
|
|
261
|
+
try {
|
|
262
|
+
const result = await this.compile(filePath);
|
|
263
|
+
return { filePath, result, error: null };
|
|
264
|
+
} catch (e) {
|
|
265
|
+
return { filePath, result: null, error: e };
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
);
|
|
269
|
+
for (const { filePath, result, error } of batchResults) {
|
|
270
|
+
if (result) {
|
|
271
|
+
results.set(filePath, result);
|
|
272
|
+
} else {
|
|
273
|
+
this.log(`Compilation failed for ${filePath}: ${error}`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return results;
|
|
278
|
+
}
|
|
279
|
+
async compileWithConcurrencyControl(filePath) {
|
|
280
|
+
while (this.activeCompilations >= this.options.parallelCompilation) {
|
|
281
|
+
await new Promise((resolve4) => setTimeout(resolve4, 10));
|
|
282
|
+
}
|
|
283
|
+
this.activeCompilations++;
|
|
284
|
+
try {
|
|
285
|
+
return await this.compileViaRuby(filePath);
|
|
286
|
+
} finally {
|
|
287
|
+
this.activeCompilations--;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
checkStub(filePath) {
|
|
291
|
+
if (this.options.stubs.length === 0) return null;
|
|
292
|
+
const fileName = path.basename(filePath, ".rb");
|
|
293
|
+
const isStubbed = this.options.stubs.some((stub) => {
|
|
294
|
+
if (stub === fileName) return true;
|
|
295
|
+
if (filePath.includes(`/${stub}/`) || filePath.includes(`/${stub}.rb`)) return true;
|
|
296
|
+
return false;
|
|
297
|
+
});
|
|
298
|
+
if (isStubbed) {
|
|
299
|
+
this.log(`Stubbed module: ${filePath}`);
|
|
300
|
+
return {
|
|
301
|
+
code: '// Stubbed module\nOpal.loaded(["' + fileName + '"]);\n',
|
|
302
|
+
map: void 0,
|
|
303
|
+
dependencies: []
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
recordMetrics(filePath, startTime, cacheHit, source) {
|
|
309
|
+
if (!this.options.metrics) return;
|
|
310
|
+
const duration = performance.now() - startTime;
|
|
311
|
+
this.metrics.push({
|
|
312
|
+
file: path.basename(filePath),
|
|
313
|
+
duration,
|
|
314
|
+
cacheHit,
|
|
315
|
+
source
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Get compilation metrics summary
|
|
320
|
+
*/
|
|
321
|
+
getMetricsSummary() {
|
|
322
|
+
const total = this.metrics.length;
|
|
323
|
+
const cached = this.metrics.filter((m) => m.cacheHit).length;
|
|
324
|
+
const compiled = total - cached;
|
|
325
|
+
const avgDuration = total > 0 ? this.metrics.reduce((sum, m) => sum + m.duration, 0) / total : 0;
|
|
326
|
+
return {
|
|
327
|
+
total,
|
|
328
|
+
cached,
|
|
329
|
+
compiled,
|
|
330
|
+
avgDuration: Math.round(avgDuration * 100) / 100,
|
|
331
|
+
details: [...this.metrics]
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Print metrics summary to console
|
|
336
|
+
*/
|
|
337
|
+
printMetricsSummary() {
|
|
338
|
+
const summary = this.getMetricsSummary();
|
|
339
|
+
console.log("\n[vite-plugin-opal] Compilation Metrics:");
|
|
340
|
+
console.log(` Total files: ${summary.total}`);
|
|
341
|
+
console.log(` Cache hits: ${summary.cached} (${Math.round(summary.cached / summary.total * 100) || 0}%)`);
|
|
342
|
+
console.log(` Compiled: ${summary.compiled}`);
|
|
343
|
+
console.log(` Avg duration: ${summary.avgDuration}ms`);
|
|
344
|
+
if (this.options.debug && summary.details.length > 0) {
|
|
345
|
+
console.log("\n Details:");
|
|
346
|
+
for (const m of summary.details) {
|
|
347
|
+
console.log(` ${m.file}: ${Math.round(m.duration)}ms (${m.source})`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Clear metrics
|
|
353
|
+
*/
|
|
354
|
+
clearMetrics() {
|
|
355
|
+
this.metrics = [];
|
|
356
|
+
}
|
|
67
357
|
async getOpalRuntime() {
|
|
68
358
|
if (this.runtimeCache) {
|
|
69
359
|
return this.runtimeCache;
|
|
@@ -73,15 +363,69 @@ var OpalCompiler = class {
|
|
|
73
363
|
this.runtimeCache = runtime;
|
|
74
364
|
return runtime;
|
|
75
365
|
}
|
|
76
|
-
clearCache(filePath) {
|
|
366
|
+
clearCache(filePath, clearDisk = false) {
|
|
77
367
|
if (filePath) {
|
|
78
368
|
this.cache.delete(filePath);
|
|
369
|
+
if (clearDisk && this.options.diskCache) {
|
|
370
|
+
try {
|
|
371
|
+
const cachePath = this.getDiskCachePath(filePath);
|
|
372
|
+
if (existsSync(cachePath)) {
|
|
373
|
+
const fsSync = __require("fs");
|
|
374
|
+
fsSync.unlinkSync(cachePath);
|
|
375
|
+
}
|
|
376
|
+
} catch (e) {
|
|
377
|
+
this.log(`Failed to clear disk cache for ${filePath}: ${e}`);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
79
380
|
this.log(`Cache cleared: ${filePath}`);
|
|
80
381
|
} else {
|
|
81
382
|
this.cache.clear();
|
|
383
|
+
if (clearDisk && this.options.diskCache) {
|
|
384
|
+
this.clearDiskCache();
|
|
385
|
+
}
|
|
82
386
|
this.log("Cache cleared (all)");
|
|
83
387
|
}
|
|
84
388
|
}
|
|
389
|
+
/**
|
|
390
|
+
* Clear all disk cache files
|
|
391
|
+
*/
|
|
392
|
+
clearDiskCache() {
|
|
393
|
+
if (!this.options.diskCache) return;
|
|
394
|
+
try {
|
|
395
|
+
const fsSync = __require("fs");
|
|
396
|
+
if (existsSync(this.cacheDir)) {
|
|
397
|
+
const files = fsSync.readdirSync(this.cacheDir);
|
|
398
|
+
for (const file of files) {
|
|
399
|
+
if (file.endsWith(".json")) {
|
|
400
|
+
fsSync.unlinkSync(path.join(this.cacheDir, file));
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
this.log(`Cleared ${files.length} disk cache files`);
|
|
404
|
+
}
|
|
405
|
+
} catch (e) {
|
|
406
|
+
this.log(`Failed to clear disk cache: ${e}`);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Get disk cache statistics
|
|
411
|
+
*/
|
|
412
|
+
getDiskCacheStats() {
|
|
413
|
+
if (!this.options.diskCache || !existsSync(this.cacheDir)) {
|
|
414
|
+
return { files: 0, size: 0 };
|
|
415
|
+
}
|
|
416
|
+
try {
|
|
417
|
+
const fsSync = __require("fs");
|
|
418
|
+
const files = fsSync.readdirSync(this.cacheDir).filter((f) => f.endsWith(".json"));
|
|
419
|
+
let totalSize = 0;
|
|
420
|
+
for (const file of files) {
|
|
421
|
+
const stat3 = fsSync.statSync(path.join(this.cacheDir, file));
|
|
422
|
+
totalSize += stat3.size;
|
|
423
|
+
}
|
|
424
|
+
return { files: files.length, size: totalSize };
|
|
425
|
+
} catch (e) {
|
|
426
|
+
return { files: 0, size: 0 };
|
|
427
|
+
}
|
|
428
|
+
}
|
|
85
429
|
async compileViaRuby(filePath) {
|
|
86
430
|
return new Promise((resolve4, reject) => {
|
|
87
431
|
let command;
|
|
@@ -98,14 +442,13 @@ var OpalCompiler = class {
|
|
|
98
442
|
filePath
|
|
99
443
|
];
|
|
100
444
|
} else {
|
|
445
|
+
const gemLibPath = this.resolveGemLibPath();
|
|
101
446
|
command = "ruby";
|
|
102
447
|
args = [
|
|
103
448
|
"-I",
|
|
104
|
-
|
|
105
|
-
"-r",
|
|
106
|
-
"opal-vite",
|
|
449
|
+
gemLibPath,
|
|
107
450
|
"-e",
|
|
108
|
-
this.getCompilerScript()
|
|
451
|
+
`$LOAD_PATH.unshift('${gemLibPath}'); require 'opal-vite'; ${this.getCompilerScript()}`,
|
|
109
452
|
filePath
|
|
110
453
|
];
|
|
111
454
|
}
|
|
@@ -123,21 +466,37 @@ var OpalCompiler = class {
|
|
|
123
466
|
});
|
|
124
467
|
ruby.on("close", (code) => {
|
|
125
468
|
if (code !== 0) {
|
|
126
|
-
|
|
127
|
-
|
|
469
|
+
const parsedError = parseRubyError(stderr, filePath);
|
|
470
|
+
const formattedMessage = formatCompilationError(parsedError);
|
|
471
|
+
console.error(formattedMessage);
|
|
472
|
+
const error = new Error(parsedError.message);
|
|
473
|
+
error.file = parsedError.file;
|
|
474
|
+
error.line = parsedError.line;
|
|
475
|
+
error.column = parsedError.column;
|
|
476
|
+
error.errorType = parsedError.errorType;
|
|
477
|
+
error.hint = parsedError.hint;
|
|
478
|
+
error.rawOutput = parsedError.rawOutput;
|
|
479
|
+
reject(error);
|
|
128
480
|
return;
|
|
129
481
|
}
|
|
130
482
|
try {
|
|
131
483
|
const result = JSON.parse(stdout);
|
|
132
484
|
resolve4(result);
|
|
133
485
|
} catch (e) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
486
|
+
const parseError = new Error(`Failed to parse compiler output: ${e}`);
|
|
487
|
+
console.error("\x1B[31m\u2716 Opal Compiler Output Parse Error\x1B[0m");
|
|
488
|
+
console.error(` \x1B[36m\u2192 ${filePath}\x1B[0m`);
|
|
489
|
+
console.error(` \x1B[37mUnexpected output from Ruby compiler\x1B[0m`);
|
|
490
|
+
if (this.options.debug) {
|
|
491
|
+
console.error(` \x1B[90mRaw output: ${stdout.substring(0, 500)}...\x1B[0m`);
|
|
492
|
+
}
|
|
493
|
+
reject(parseError);
|
|
138
494
|
}
|
|
139
495
|
});
|
|
140
496
|
ruby.on("error", (err) => {
|
|
497
|
+
console.error("\x1B[31m\u2716 Ruby Process Error\x1B[0m");
|
|
498
|
+
console.error(` \x1B[37m${err.message}\x1B[0m`);
|
|
499
|
+
console.error(` \x1B[33m\u{1F4A1} Make sure Ruby and Opal are installed correctly\x1B[0m`);
|
|
141
500
|
reject(new Error(`Failed to spawn Ruby process: ${err.message}`));
|
|
142
501
|
});
|
|
143
502
|
});
|
|
@@ -157,14 +516,13 @@ Error: ${e}`));
|
|
|
157
516
|
"puts Opal::Vite::Compiler.runtime_code"
|
|
158
517
|
];
|
|
159
518
|
} else {
|
|
519
|
+
const gemLibPath = this.resolveGemLibPath();
|
|
160
520
|
command = "ruby";
|
|
161
521
|
args = [
|
|
162
522
|
"-I",
|
|
163
|
-
|
|
164
|
-
"-r",
|
|
165
|
-
"opal-vite",
|
|
523
|
+
gemLibPath,
|
|
166
524
|
"-e",
|
|
167
|
-
|
|
525
|
+
`$LOAD_PATH.unshift('${gemLibPath}'); require 'opal-vite'; puts Opal::Vite::Compiler.runtime_code`
|
|
168
526
|
];
|
|
169
527
|
}
|
|
170
528
|
const ruby = spawn(command, args, {
|
|
@@ -194,15 +552,16 @@ ${stderr}`));
|
|
|
194
552
|
getCompilerScript() {
|
|
195
553
|
const includeConcerns = this.options.includeConcerns;
|
|
196
554
|
const sourceMap = this.options.sourceMap;
|
|
555
|
+
const stubs = JSON.stringify(this.options.stubs);
|
|
197
556
|
return `
|
|
198
|
-
require 'opal-vite'
|
|
199
557
|
file_path = ARGV[0]
|
|
200
|
-
|
|
558
|
+
stubs = ${stubs}
|
|
559
|
+
Opal::Vite.compile_for_vite(file_path, include_concerns: ${includeConcerns}, source_map: ${sourceMap}, stubs: stubs)
|
|
201
560
|
`.trim();
|
|
202
561
|
}
|
|
203
562
|
resolveGemLibPath() {
|
|
204
563
|
if (this.options.gemPath.startsWith(".") || this.options.gemPath.startsWith("/")) {
|
|
205
|
-
return
|
|
564
|
+
return path.resolve(this.options.gemPath, "lib");
|
|
206
565
|
}
|
|
207
566
|
return this.options.gemPath;
|
|
208
567
|
}
|
|
@@ -277,7 +636,7 @@ var OpalResolver = class {
|
|
|
277
636
|
}
|
|
278
637
|
}
|
|
279
638
|
async resolveAbsolute(id) {
|
|
280
|
-
if (!
|
|
639
|
+
if (!path.isAbsolute(id)) {
|
|
281
640
|
return null;
|
|
282
641
|
}
|
|
283
642
|
if (await this.fileExists(id)) {
|
|
@@ -295,8 +654,8 @@ var OpalResolver = class {
|
|
|
295
654
|
if (!id.startsWith(".") || !importer) {
|
|
296
655
|
return null;
|
|
297
656
|
}
|
|
298
|
-
const importerDir =
|
|
299
|
-
const resolved =
|
|
657
|
+
const importerDir = path.dirname(importer);
|
|
658
|
+
const resolved = path.resolve(importerDir, id);
|
|
300
659
|
if (await this.fileExists(resolved)) {
|
|
301
660
|
return resolved;
|
|
302
661
|
}
|
|
@@ -311,15 +670,15 @@ var OpalResolver = class {
|
|
|
311
670
|
async resolveFromLoadPaths(id) {
|
|
312
671
|
const baseId = id.endsWith(".rb") ? id.slice(0, -3) : id;
|
|
313
672
|
for (const loadPath of this.loadPaths) {
|
|
314
|
-
const fullPath =
|
|
673
|
+
const fullPath = path.resolve(loadPath, id);
|
|
315
674
|
if (await this.fileExists(fullPath)) {
|
|
316
675
|
return fullPath;
|
|
317
676
|
}
|
|
318
|
-
const withExt =
|
|
677
|
+
const withExt = path.resolve(loadPath, `${baseId}.rb`);
|
|
319
678
|
if (await this.fileExists(withExt)) {
|
|
320
679
|
return withExt;
|
|
321
680
|
}
|
|
322
|
-
const indexPath =
|
|
681
|
+
const indexPath = path.resolve(loadPath, baseId, "index.rb");
|
|
323
682
|
if (await this.fileExists(indexPath)) {
|
|
324
683
|
return indexPath;
|
|
325
684
|
}
|
|
@@ -335,7 +694,7 @@ var OpalResolver = class {
|
|
|
335
694
|
}
|
|
336
695
|
}
|
|
337
696
|
hasExtension(filePath) {
|
|
338
|
-
const ext =
|
|
697
|
+
const ext = path.extname(filePath);
|
|
339
698
|
return ext !== "";
|
|
340
699
|
}
|
|
341
700
|
};
|
|
@@ -368,7 +727,7 @@ var OpalHMRManager = class {
|
|
|
368
727
|
});
|
|
369
728
|
this.watcher.on("unlink", (filePath) => {
|
|
370
729
|
this.log(`File removed: ${filePath}`);
|
|
371
|
-
const absolutePath =
|
|
730
|
+
const absolutePath = path.resolve(this.server.config.root, filePath);
|
|
372
731
|
this.compiler.clearCache(absolutePath);
|
|
373
732
|
this.resolver.clearCache(absolutePath);
|
|
374
733
|
this.dependencyGraph.delete(absolutePath);
|
|
@@ -392,7 +751,7 @@ var OpalHMRManager = class {
|
|
|
392
751
|
* Handle file change and trigger HMR update
|
|
393
752
|
*/
|
|
394
753
|
async handleFileChange(filePath) {
|
|
395
|
-
const absolutePath =
|
|
754
|
+
const absolutePath = path.resolve(this.server.config.root, filePath);
|
|
396
755
|
this.log(`File changed: ${filePath}`);
|
|
397
756
|
try {
|
|
398
757
|
this.compiler.clearCache(absolutePath);
|
|
@@ -607,6 +966,12 @@ ${html}`;
|
|
|
607
966
|
hmrManager.cleanup();
|
|
608
967
|
}
|
|
609
968
|
};
|
|
969
|
+
},
|
|
970
|
+
// Print metrics after build completes
|
|
971
|
+
closeBundle() {
|
|
972
|
+
if (options.metrics) {
|
|
973
|
+
compiler.printMetricsSummary();
|
|
974
|
+
}
|
|
610
975
|
}
|
|
611
976
|
};
|
|
612
977
|
}
|
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":["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"]}
|
|
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\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 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 diskCache: options.diskCache !== false,\n cacheDir: options.cacheDir || '',\n stubs: options.stubs || [],\n parallelCompilation: options.parallelCompilation || 4,\n metrics: options.metrics || false\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 }\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 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 * @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 // 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"]}
|