@rusveltejs/compiler 0.1.0 → 0.1.1
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/compiler.js +80 -27
- package/native.js +7 -1
- package/package.json +9 -8
- package/register.js +10 -19
package/compiler.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
// built by Svelte's own code. Anything rusvelte doesn't handle falls back to the real compiler:
|
|
5
5
|
// other Svelte versions, unsupported options, compile errors (so their messages and frames
|
|
6
6
|
// are Svelte's own) and internal failures.
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
8
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
7
9
|
import * as native from './native.js';
|
|
8
10
|
|
|
9
11
|
const debug = !!process.env.RUSVELTE_DEBUG;
|
|
@@ -132,17 +134,54 @@ class JsSourceMap {
|
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
/**
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* merge_with_preprocessor_map: Function,
|
|
140
|
-
* get_source_name: Function,
|
|
141
|
-
* MagicSourceMap: any
|
|
142
|
-
* }} svelte
|
|
137
|
+
* The internals of the installed compiler that results are built with (its `state`,
|
|
138
|
+
* `CompileDiagnostic`, source map helpers and magic-string's `SourceMap`), loaded only once the
|
|
139
|
+
* versions match: another version may lay its files out differently
|
|
140
|
+
* @param {string} real_url the URL of the installed `svelte/compiler` entry
|
|
143
141
|
*/
|
|
144
|
-
|
|
145
|
-
const
|
|
142
|
+
async function load_internals(real_url) {
|
|
143
|
+
const at = (path) => new URL(path, real_url).href;
|
|
144
|
+
const [state, { CompileDiagnostic }, { merge_with_preprocessor_map, get_source_name }, { validate_component_options }] = await Promise.all([
|
|
145
|
+
import(at('./state.js')),
|
|
146
|
+
import(at('./utils/compile_diagnostic.js')),
|
|
147
|
+
import(at('./utils/mapped_code.js')),
|
|
148
|
+
import(at('./validate-options.js'))
|
|
149
|
+
]);
|
|
150
|
+
const magic_string = createRequire(fileURLToPath(real_url)).resolve('magic-string');
|
|
151
|
+
// `require` resolves its CommonJS build, where `SourceMap` hangs off the default export
|
|
152
|
+
const magic = await import(pathToFileURL(magic_string).href);
|
|
153
|
+
const MagicSourceMap = magic.SourceMap ?? magic.default?.SourceMap;
|
|
154
|
+
for (const [name, value] of Object.entries({ CompileDiagnostic, merge_with_preprocessor_map, get_source_name, MagicSourceMap, validate_component_options })) {
|
|
155
|
+
if (typeof value !== 'function') throw new Error(`${name} is not available`);
|
|
156
|
+
}
|
|
157
|
+
if (typeof state.reset !== 'function' || typeof state.set_source !== 'function' || typeof state.adjust !== 'function') {
|
|
158
|
+
throw new Error('svelte/compiler state has an unexpected shape');
|
|
159
|
+
}
|
|
160
|
+
return { state, CompileDiagnostic, merge_with_preprocessor_map, get_source_name, MagicSourceMap, validate_component_options };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* `compile` and `compileModule` for the installed compiler: rusvelte's where it can run, the
|
|
165
|
+
* installed compiler's otherwise
|
|
166
|
+
* @param {typeof import('svelte/compiler')} real
|
|
167
|
+
* @param {string} real_url
|
|
168
|
+
*/
|
|
169
|
+
export async function create(real, real_url) {
|
|
170
|
+
const use_real = (reason) => {
|
|
171
|
+
console.warn(`[rusvelte] ${reason}; using svelte/compiler`);
|
|
172
|
+
return { compile: real.compile, compileModule: real.compileModule };
|
|
173
|
+
};
|
|
174
|
+
if (!native.native) return use_real(native.load_error);
|
|
175
|
+
if (real.VERSION !== native.svelteVersion && !process.env.RUSVELTE_ALLOW_VERSION_MISMATCH) {
|
|
176
|
+
return use_real(`svelte ${real.VERSION} is installed, but this rusvelte build reproduces svelte ${native.svelteVersion}`);
|
|
177
|
+
}
|
|
178
|
+
let internals;
|
|
179
|
+
try {
|
|
180
|
+
internals = await load_internals(real_url);
|
|
181
|
+
} catch (e) {
|
|
182
|
+
return use_real(`can't use the internals of the installed svelte/compiler (${e.message})`);
|
|
183
|
+
}
|
|
184
|
+
const { state, CompileDiagnostic, merge_with_preprocessor_map, get_source_name, MagicSourceMap, validate_component_options } = internals;
|
|
146
185
|
|
|
147
186
|
/** results rusvelte produced (not the real compiler) */
|
|
148
187
|
const native_results = new WeakSet();
|
|
@@ -151,18 +190,6 @@ export function create(svelte) {
|
|
|
151
190
|
name = 'CompileWarning';
|
|
152
191
|
}
|
|
153
192
|
|
|
154
|
-
if (!native.native) {
|
|
155
|
-
console.warn(`[rusvelte] ${native.load_error}; using svelte/compiler`);
|
|
156
|
-
return { compile: real.compile, compileModule: real.compileModule };
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const version_ok = real.VERSION === native.svelteVersion || !!process.env.RUSVELTE_ALLOW_VERSION_MISMATCH;
|
|
160
|
-
if (!version_ok) {
|
|
161
|
-
console.warn(
|
|
162
|
-
`[rusvelte] svelte ${real.VERSION} is installed, but this rusvelte build reproduces svelte ${native.svelteVersion}; using svelte/compiler`
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
193
|
/**
|
|
167
194
|
* Runs the native compiler; null means "use the real one"
|
|
168
195
|
* @param {boolean} module
|
|
@@ -170,10 +197,17 @@ export function create(svelte) {
|
|
|
170
197
|
function run(source, options, module) {
|
|
171
198
|
// `validate-options.js` defaults `rootDir` to the working directory
|
|
172
199
|
if (options.rootDir === undefined && typeof process !== 'undefined') options = { ...options, rootDir: process.cwd() };
|
|
173
|
-
|
|
200
|
+
// a lone surrogate doesn't survive the trip into Rust (its strings are valid UTF-8)
|
|
201
|
+
if (!source.isWellFormed()) return fell_back('the source has a lone surrogate'), null;
|
|
174
202
|
const bad = unsupported_option(options, module ? MODULE_OPTIONS : COMPONENT_OPTIONS);
|
|
175
203
|
if (bad) return fell_back(`option ${bad}`), null;
|
|
176
|
-
|
|
204
|
+
let result;
|
|
205
|
+
try {
|
|
206
|
+
result = JSON.parse((module ? native.compileModule : native.compile)(source, native_options(options)));
|
|
207
|
+
} catch (e) {
|
|
208
|
+
// a broken or mismatched native build: the real compiler takes over
|
|
209
|
+
return fell_back(`native error: ${e.message}`), null;
|
|
210
|
+
}
|
|
177
211
|
if (result.unsupported) return fell_back(result.unsupported), null;
|
|
178
212
|
// let the real compiler throw, so the error is exactly Svelte's
|
|
179
213
|
if (result.error) return fell_back(`compile error ${result.error.code}`), null;
|
|
@@ -192,6 +226,7 @@ export function create(svelte) {
|
|
|
192
226
|
const filter = options.warningFilter ?? (() => true);
|
|
193
227
|
const out = [];
|
|
194
228
|
for (const w of result.warnings) {
|
|
229
|
+
if (w.code.startsWith('options_deprecated_')) continue;
|
|
195
230
|
const warning = new CompileWarning(w.code, w.message, w.position ?? undefined);
|
|
196
231
|
if (filter(warning)) out.push(warning);
|
|
197
232
|
}
|
|
@@ -234,6 +269,14 @@ export function create(svelte) {
|
|
|
234
269
|
const result = run(source, options, false);
|
|
235
270
|
if (!result) return real.compile(source, options);
|
|
236
271
|
set_state(source, options, result.runes);
|
|
272
|
+
// the option warnings (deprecated options) come from the installed compiler's own
|
|
273
|
+
// validation, so its once-per-instance memory and the warning filter apply as in compile
|
|
274
|
+
try {
|
|
275
|
+
validate_component_options(options, '');
|
|
276
|
+
} catch {
|
|
277
|
+
return real.compile(source, options);
|
|
278
|
+
}
|
|
279
|
+
const option_warnings = [...state.warnings];
|
|
237
280
|
// `validate_component_options` defaults the filename
|
|
238
281
|
options = { ...options, filename: options.filename ?? '(unknown)' };
|
|
239
282
|
|
|
@@ -256,7 +299,7 @@ export function create(svelte) {
|
|
|
256
299
|
merge_with_preprocessor_map(css, options, css.map.sources[0]);
|
|
257
300
|
}
|
|
258
301
|
|
|
259
|
-
const warnings = warnings_of(result, options);
|
|
302
|
+
const warnings = [...option_warnings, ...warnings_of(result, options)];
|
|
260
303
|
let ast;
|
|
261
304
|
const compiled = {
|
|
262
305
|
js,
|
|
@@ -265,7 +308,8 @@ export function create(svelte) {
|
|
|
265
308
|
metadata: { runes: result.runes },
|
|
266
309
|
// parsed on demand: vite-plugin-svelte doesn't read it
|
|
267
310
|
get ast() {
|
|
268
|
-
|
|
311
|
+
// compile's AST (TypeScript removed etc.); warnings are dropped so the filter isn't called twice
|
|
312
|
+
return (ast ??= real.compile(source, { ...options, generate: false, warningFilter: () => false }).ast);
|
|
269
313
|
},
|
|
270
314
|
set ast(value) {
|
|
271
315
|
ast = value;
|
|
@@ -277,19 +321,28 @@ export function create(svelte) {
|
|
|
277
321
|
|
|
278
322
|
/** @type {typeof real.compileModule} */
|
|
279
323
|
function compileModule(source, options) {
|
|
324
|
+
const result = compile_module_native(source, options);
|
|
325
|
+
if (verify && native_results.has(result)) check('module', remove_bom(source), options, result);
|
|
326
|
+
return result;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/** @type {typeof real.compileModule} */
|
|
330
|
+
function compile_module_native(source, options) {
|
|
280
331
|
source = remove_bom(source);
|
|
281
332
|
const result = run(source, options, true);
|
|
282
333
|
if (!result) return real.compileModule(source, options);
|
|
283
334
|
set_state(source, options, true);
|
|
284
335
|
options = { ...options, filename: options.filename ?? '(unknown)' };
|
|
285
336
|
const js_source_name = get_source_name(options.filename, undefined, 'input.svelte.js');
|
|
286
|
-
|
|
337
|
+
const compiled = {
|
|
287
338
|
js: { code: result.js.code, map: new JsSourceMap(result.js.mappings, js_source_name, source) },
|
|
288
339
|
css: null,
|
|
289
340
|
warnings: warnings_of(result, options),
|
|
290
341
|
metadata: { runes: true },
|
|
291
342
|
ast: null
|
|
292
343
|
};
|
|
344
|
+
native_results.add(compiled);
|
|
345
|
+
return compiled;
|
|
293
346
|
}
|
|
294
347
|
|
|
295
348
|
return { compile, compileModule };
|
package/native.js
CHANGED
|
@@ -32,7 +32,13 @@ export let native = null;
|
|
|
32
32
|
export let load_error = null;
|
|
33
33
|
try {
|
|
34
34
|
native = load();
|
|
35
|
+
// a build from another rusvelte version may not have this API
|
|
36
|
+
if (typeof native.compile !== 'function' || typeof native.compileModule !== 'function' || typeof native.svelteVersion !== 'function') {
|
|
37
|
+
throw new Error('it lacks compile, compileModule or svelteVersion');
|
|
38
|
+
}
|
|
39
|
+
native.version = native.svelteVersion();
|
|
35
40
|
} catch (e) {
|
|
41
|
+
native = null;
|
|
36
42
|
const where = process.env.RUSVELTE_NATIVE ?? platform_package();
|
|
37
43
|
load_error = `no native module for ${process.platform}-${process.arch} (${where}): ${e.message.split('\n')[0]}`;
|
|
38
44
|
}
|
|
@@ -40,4 +46,4 @@ try {
|
|
|
40
46
|
export const compile = native?.compile;
|
|
41
47
|
export const compileModule = native?.compileModule;
|
|
42
48
|
/** The Svelte version whose output this build reproduces */
|
|
43
|
-
export const svelteVersion = native?.
|
|
49
|
+
export const svelteVersion = native?.version ?? null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rusveltejs/compiler",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "The Svelte 5 compiler ported to Rust, as a drop-in for svelte/compiler in Vite builds",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"svelte",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"exports": {
|
|
22
22
|
".": "./native.js",
|
|
23
23
|
"./register": "./register.js",
|
|
24
|
-
"./vite": "./vite.js"
|
|
24
|
+
"./vite": "./vite.js",
|
|
25
|
+
"./package.json": "./package.json"
|
|
25
26
|
},
|
|
26
27
|
"files": [
|
|
27
28
|
"native.js",
|
|
@@ -39,11 +40,11 @@
|
|
|
39
40
|
"svelte": "^5.0.0"
|
|
40
41
|
},
|
|
41
42
|
"optionalDependencies": {
|
|
42
|
-
"@rusveltejs/darwin-arm64": "0.1.
|
|
43
|
-
"@rusveltejs/darwin-x64": "0.1.
|
|
44
|
-
"@rusveltejs/linux-x64-gnu": "0.1.
|
|
45
|
-
"@rusveltejs/linux-arm64-gnu": "0.1.
|
|
46
|
-
"@rusveltejs/linux-x64-musl": "0.1.
|
|
47
|
-
"@rusveltejs/win32-x64-msvc": "0.1.
|
|
43
|
+
"@rusveltejs/darwin-arm64": "0.1.1",
|
|
44
|
+
"@rusveltejs/darwin-x64": "0.1.1",
|
|
45
|
+
"@rusveltejs/linux-x64-gnu": "0.1.1",
|
|
46
|
+
"@rusveltejs/linux-arm64-gnu": "0.1.1",
|
|
47
|
+
"@rusveltejs/linux-x64-musl": "0.1.1",
|
|
48
|
+
"@rusveltejs/win32-x64-msvc": "0.1.1"
|
|
48
49
|
}
|
|
49
50
|
}
|
package/register.js
CHANGED
|
@@ -7,24 +7,20 @@
|
|
|
7
7
|
// or call `register()` before importing them dynamically (vite.js does).
|
|
8
8
|
import { registerHooks } from 'node:module';
|
|
9
9
|
|
|
10
|
-
const PACKAGE = new URL('./', import.meta.url).href;
|
|
11
10
|
const SHIM = new URL('./svelte-compiler.js', import.meta.url).href;
|
|
12
11
|
const COMPILER = new URL('./compiler.js', import.meta.url).href;
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
// one hook per process, even with several copies of this package installed: a second hook
|
|
14
|
+
// would wrap the first one's module instead of the real compiler
|
|
15
|
+
const REGISTERED = Symbol.for('@rusveltejs/compiler/register');
|
|
15
16
|
|
|
16
17
|
export function register() {
|
|
17
|
-
if (
|
|
18
|
-
|
|
18
|
+
if (globalThis[REGISTERED]) return;
|
|
19
|
+
globalThis[REGISTERED] = true;
|
|
19
20
|
registerHooks({
|
|
20
21
|
resolve(specifier, context, next) {
|
|
21
22
|
const parent = context.parentURL ?? '';
|
|
22
|
-
|
|
23
|
-
if (parent.startsWith(SHIM + '?')) {
|
|
24
|
-
const real = new URL(parent).searchParams.get('real');
|
|
25
|
-
return next(specifier, { ...context, parentURL: real });
|
|
26
|
-
}
|
|
27
|
-
if (specifier === 'svelte/compiler' && !parent.startsWith(PACKAGE) && context.conditions?.includes('import')) {
|
|
23
|
+
if (specifier === 'svelte/compiler' && !parent.startsWith(SHIM) && context.conditions?.includes('import')) {
|
|
28
24
|
const real = next(specifier, context);
|
|
29
25
|
return { url: `${SHIM}?real=${encodeURIComponent(real.url)}`, format: 'module', shortCircuit: true };
|
|
30
26
|
}
|
|
@@ -32,17 +28,12 @@ export function register() {
|
|
|
32
28
|
},
|
|
33
29
|
load(url, context, next) {
|
|
34
30
|
if (!url.startsWith(SHIM + '?')) return next(url, context);
|
|
35
|
-
const real = new URL(url).searchParams.get('real');
|
|
36
|
-
const at = (path) => JSON.stringify(new URL(path, real).href);
|
|
31
|
+
const real = JSON.stringify(new URL(url).searchParams.get('real'));
|
|
37
32
|
const source = `
|
|
38
|
-
export * from ${
|
|
39
|
-
import * as real from ${
|
|
40
|
-
import * as state from ${at('./state.js')};
|
|
41
|
-
import { CompileDiagnostic } from ${at('./utils/compile_diagnostic.js')};
|
|
42
|
-
import { merge_with_preprocessor_map, get_source_name } from ${at('./utils/mapped_code.js')};
|
|
43
|
-
import { SourceMap as MagicSourceMap } from 'magic-string';
|
|
33
|
+
export * from ${real};
|
|
34
|
+
import * as real from ${real};
|
|
44
35
|
import { create } from ${JSON.stringify(COMPILER)};
|
|
45
|
-
export const { compile, compileModule } = create(
|
|
36
|
+
export const { compile, compileModule } = await create(real, ${real});
|
|
46
37
|
`;
|
|
47
38
|
return { format: 'module', source, shortCircuit: true };
|
|
48
39
|
}
|