@solidjs/vite-plugin 3.0.0-next.37 → 3.0.0-next.39
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/README.md +47 -8
- package/dist/cjs/index.cjs +440 -87
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.mjs +442 -89
- package/dist/esm/index.mjs.map +1 -1
- package/dist/types/src/diagnostics/index.d.ts +14 -1
- package/dist/types/src/index.d.ts +17 -9
- package/dist/types/src/server-functions/compile.d.ts +2 -0
- package/dist/types/src/server-functions/index.d.ts +28 -10
- package/dist/types/src/ssr/index.d.ts +6 -5
- package/dist/types/src/tsrx.d.ts +11 -0
- package/package.json +3 -3
package/dist/cjs/index.cjs
CHANGED
|
@@ -170,6 +170,75 @@ function joinBase(base, pathname) {
|
|
|
170
170
|
return (base.endsWith('/') ? base.slice(0, -1) : base) + pathname;
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
const TSRX_CSS_QUERY = '?solid-tsrx-css&lang.css';
|
|
174
|
+
const NULL_BYTE_PLACEHOLDER$1 = '/@id/__x00__';
|
|
175
|
+
function cleanModuleId(id) {
|
|
176
|
+
const query = id.indexOf('?');
|
|
177
|
+
return query === -1 ? id : id.slice(0, query);
|
|
178
|
+
}
|
|
179
|
+
function isTsrxModule(id) {
|
|
180
|
+
return cleanModuleId(id).toLowerCase().endsWith('.tsrx');
|
|
181
|
+
}
|
|
182
|
+
function isTsrxCssModule(id) {
|
|
183
|
+
const unwrapped = id.startsWith('\0') ? id.slice(1) : id.startsWith(NULL_BYTE_PLACEHOLDER$1) ? id.slice(NULL_BYTE_PLACEHOLDER$1.length) : id;
|
|
184
|
+
const queryIndex = unwrapped.indexOf('?');
|
|
185
|
+
if (queryIndex === -1 || !unwrapped.slice(0, queryIndex).toLowerCase().endsWith('.tsrx')) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
const params = unwrapped.slice(queryIndex + 1).split('&');
|
|
189
|
+
return params.includes('solid-tsrx-css') && params.includes('lang.css');
|
|
190
|
+
}
|
|
191
|
+
function resolveTsrxCssModule(id) {
|
|
192
|
+
if (!isTsrxCssModule(id)) return null;
|
|
193
|
+
if (id.startsWith('\0')) return id;
|
|
194
|
+
if (id.startsWith(NULL_BYTE_PLACEHOLDER$1)) {
|
|
195
|
+
return '\0' + id.slice(NULL_BYTE_PLACEHOLDER$1.length);
|
|
196
|
+
}
|
|
197
|
+
return '\0' + id;
|
|
198
|
+
}
|
|
199
|
+
function tsrxCssModuleId(id) {
|
|
200
|
+
return cleanModuleId(id) + TSRX_CSS_QUERY;
|
|
201
|
+
}
|
|
202
|
+
function resolvedTsrxCssModuleId(id) {
|
|
203
|
+
return '\0' + tsrxCssModuleId(id);
|
|
204
|
+
}
|
|
205
|
+
function tsrxCssSourceId(id) {
|
|
206
|
+
if (!id.startsWith('\0') || !isTsrxCssModule(id)) return null;
|
|
207
|
+
return cleanModuleId(id.slice(1));
|
|
208
|
+
}
|
|
209
|
+
function updateTsrxCss(cache, id, css) {
|
|
210
|
+
const key = cleanModuleId(id);
|
|
211
|
+
if (css) {
|
|
212
|
+
cache.set(key, css);
|
|
213
|
+
} else {
|
|
214
|
+
cache.delete(key);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function prependTsrxCssImport(code, id) {
|
|
218
|
+
return `import ${JSON.stringify(tsrxCssModuleId(id))};\n${code}`;
|
|
219
|
+
}
|
|
220
|
+
function offsetSourceMapLine(map) {
|
|
221
|
+
if (map && typeof map === 'object' && 'mappings' in map && typeof map.mappings === 'string') {
|
|
222
|
+
return {
|
|
223
|
+
...map,
|
|
224
|
+
mappings: ';' + map.mappings
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
if (map && typeof map === 'object' && 'sections' in map && Array.isArray(map.sections)) {
|
|
228
|
+
return {
|
|
229
|
+
...map,
|
|
230
|
+
sections: map.sections.map(section => ({
|
|
231
|
+
...section,
|
|
232
|
+
offset: {
|
|
233
|
+
...section.offset,
|
|
234
|
+
line: section.offset.line + 1
|
|
235
|
+
}
|
|
236
|
+
}))
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
return map;
|
|
240
|
+
}
|
|
241
|
+
|
|
173
242
|
/**
|
|
174
243
|
* Dev-mode asset resolution: the `virtual:solid-manifest` module exports a
|
|
175
244
|
* resolver function in dev (instead of the static object a build produces),
|
|
@@ -279,6 +348,9 @@ const cssFileRegExp = /\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)$/;
|
|
|
279
348
|
// importer controls them — so they must not be SSR'd as style tags.
|
|
280
349
|
const nonAmbientQueryRegExp = /[?&](url|inline|raw)\b/;
|
|
281
350
|
const NULL_BYTE_PLACEHOLDER = '/@id/__x00__';
|
|
351
|
+
function isCssModuleUrl(url) {
|
|
352
|
+
return cssFileRegExp.test(url.split('?')[0]) || isTsrxCssModule(url);
|
|
353
|
+
}
|
|
282
354
|
|
|
283
355
|
// Per Vite's convention virtual module ids are prefixed with `\0`, which
|
|
284
356
|
// cannot appear in an HTML attribute (the parser replaces it). Serialize the
|
|
@@ -335,7 +407,7 @@ async function collectModuleDeps(env, file, deps, crawled, filter, onFile, impor
|
|
|
335
407
|
const node = await getModuleNode(env, file, importer);
|
|
336
408
|
if (!node?.id || deps.has(node)) return;
|
|
337
409
|
deps.add(node);
|
|
338
|
-
const isCss =
|
|
410
|
+
const isCss = isCssModuleUrl(node.url);
|
|
339
411
|
if (!isCss && node.file && !node.id.startsWith('\0') && !filter(node.file)) return;
|
|
340
412
|
if (node.file) onFile?.(node.file);
|
|
341
413
|
if (isCss) return;
|
|
@@ -367,8 +439,7 @@ async function collectDevStyleSources(env, files, onFile, filter = defaultStyleF
|
|
|
367
439
|
const seen = new Set();
|
|
368
440
|
for (const node of deps) {
|
|
369
441
|
if (!node.id) continue;
|
|
370
|
-
|
|
371
|
-
if (!cssFileRegExp.test(cleanUrl) || nonAmbientQueryRegExp.test(node.url)) continue;
|
|
442
|
+
if (!isCssModuleUrl(node.url) || nonAmbientQueryRegExp.test(node.url)) continue;
|
|
372
443
|
const id = wrapId(node.id);
|
|
373
444
|
if (seen.has(id)) continue;
|
|
374
445
|
seen.add(id);
|
|
@@ -582,7 +653,11 @@ function boundaryModules() {
|
|
|
582
653
|
}
|
|
583
654
|
|
|
584
655
|
/**
|
|
585
|
-
* Agent diagnostics surface (
|
|
656
|
+
* Agent diagnostics surface (dev serve only).
|
|
657
|
+
*
|
|
658
|
+
* Enabled automatically when the app declares `@solidjs/diagnostics` in
|
|
659
|
+
* its package.json (the `diagnostics` option overrides: `true` forces it
|
|
660
|
+
* on and errors if the package is missing, `false` opts out entirely).
|
|
586
661
|
*
|
|
587
662
|
* Three pieces:
|
|
588
663
|
* - an injected client module (virtual, imported by index.html or the
|
|
@@ -610,6 +685,36 @@ const METHODS = ['begin', 'end', 'active', 'whyDidRun', 'costs'];
|
|
|
610
685
|
|
|
611
686
|
/** How long the endpoint waits for a page to answer before failing the call. */
|
|
612
687
|
const RESPONSE_TIMEOUT_MS = 10_000;
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* Whether the app *declares* `@solidjs/diagnostics` — the auto-enable
|
|
691
|
+
* signal. Declaration in the nearest package.json (walking up from the
|
|
692
|
+
* Vite root, so a `client/` root still finds the app manifest) rather
|
|
693
|
+
* than node_modules presence: presence-based detection escapes the app
|
|
694
|
+
* into ancestor installs, which surprise-enables the surface for every
|
|
695
|
+
* fixture app inside a monorepo that happens to have the package
|
|
696
|
+
* somewhere above it (this broke the plugin's own example suites). A
|
|
697
|
+
* declared dependency is unambiguous intent, and resolution then works
|
|
698
|
+
* regardless of hoisting. `diagnostics: true` remains the override for
|
|
699
|
+
* setups the heuristic can't see.
|
|
700
|
+
*/
|
|
701
|
+
function detectDiagnosticsPackage(root) {
|
|
702
|
+
let dir = path.resolve(root);
|
|
703
|
+
while (true) {
|
|
704
|
+
const manifestPath = path.join(dir, 'package.json');
|
|
705
|
+
if (fs.existsSync(manifestPath)) {
|
|
706
|
+
try {
|
|
707
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
708
|
+
return !!(manifest.dependencies?.[DIAGNOSTICS_PACKAGE] ?? manifest.devDependencies?.[DIAGNOSTICS_PACKAGE] ?? manifest.optionalDependencies?.[DIAGNOSTICS_PACKAGE]);
|
|
709
|
+
} catch {
|
|
710
|
+
return false;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
const parent = path.dirname(dir);
|
|
714
|
+
if (parent === dir) return false;
|
|
715
|
+
dir = parent;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
613
718
|
function diagnosticsClientModuleCode() {
|
|
614
719
|
// Runtime imports resolve to the APP's diagnostics package (see the
|
|
615
720
|
// resolveId assist below) — the page speaks its own package's protocol.
|
|
@@ -636,18 +741,26 @@ function readJsonBody(req) {
|
|
|
636
741
|
req.on('error', reject);
|
|
637
742
|
});
|
|
638
743
|
}
|
|
639
|
-
function solidDiagnostics() {
|
|
744
|
+
function solidDiagnostics(mode = 'auto') {
|
|
640
745
|
let root = process.cwd();
|
|
641
746
|
let base = '/';
|
|
747
|
+
// Resolved at configResolved: explicit `true` is unconditional (missing
|
|
748
|
+
// package becomes a hard error at bridge resolution); `'auto'` enables
|
|
749
|
+
// only when the app has the package installed.
|
|
750
|
+
let enabled = mode === true;
|
|
642
751
|
return {
|
|
643
752
|
name: 'solid:diagnostics',
|
|
644
753
|
// Dev-serve only: the channels this fronts exist in dev builds only.
|
|
754
|
+
// Test mode excluded — vitest (including browser mode) runs a dev
|
|
755
|
+
// serve, and injecting the bridge into test pages perturbs suites
|
|
756
|
+
// that never asked for it.
|
|
645
757
|
apply(_config, env) {
|
|
646
|
-
return env.command === 'serve' && !env.isPreview;
|
|
758
|
+
return env.command === 'serve' && !env.isPreview && env.mode !== 'test';
|
|
647
759
|
},
|
|
648
760
|
configResolved(config) {
|
|
649
761
|
root = config.root;
|
|
650
762
|
base = config.base;
|
|
763
|
+
if (mode === 'auto') enabled = detectDiagnosticsPackage(root);
|
|
651
764
|
},
|
|
652
765
|
async resolveId(source, importer) {
|
|
653
766
|
if (source === DIAGNOSTICS_CLIENT_ID) {
|
|
@@ -663,7 +776,7 @@ function solidDiagnostics() {
|
|
|
663
776
|
skipSelf: true
|
|
664
777
|
});
|
|
665
778
|
if (!resolved || resolved.id.startsWith('__vite-optional-peer-dep:')) {
|
|
666
|
-
this.error(`[@solidjs/vite-plugin] the diagnostics
|
|
779
|
+
this.error(`[@solidjs/vite-plugin] the diagnostics surface requires ${DIAGNOSTICS_PACKAGE} ` + 'installed in the app (it provides the in-page bridge). Install it as a ' + 'development dependency, or set `diagnostics: false` to opt out.');
|
|
667
780
|
}
|
|
668
781
|
return resolved;
|
|
669
782
|
}
|
|
@@ -676,6 +789,7 @@ function solidDiagnostics() {
|
|
|
676
789
|
// Plain (index.html) apps get the client module injected here;
|
|
677
790
|
// start-mode apps import it from the generated client entry instead.
|
|
678
791
|
transformIndexHtml() {
|
|
792
|
+
if (!enabled) return undefined;
|
|
679
793
|
return [{
|
|
680
794
|
tag: 'script',
|
|
681
795
|
attrs: {
|
|
@@ -686,6 +800,11 @@ function solidDiagnostics() {
|
|
|
686
800
|
}];
|
|
687
801
|
},
|
|
688
802
|
configureServer(server) {
|
|
803
|
+
// The whole surface (announcement, middleware, bridge injection) only
|
|
804
|
+
// exists when enabled, so the discovery breadcrumb never lies about
|
|
805
|
+
// a dead endpoint.
|
|
806
|
+
if (!enabled) return;
|
|
807
|
+
|
|
689
808
|
// Announce the surface in the startup block. This is a discovery
|
|
690
809
|
// channel: agents watching dev-server output learn the endpoint and
|
|
691
810
|
// the skill documents without any project-level pointer (AGENTS.md).
|
|
@@ -694,7 +813,7 @@ function solidDiagnostics() {
|
|
|
694
813
|
originalPrintUrls();
|
|
695
814
|
const local = server.resolvedUrls?.local[0];
|
|
696
815
|
const endpoint = local ? new URL(DIAGNOSTICS_ENDPOINT, local).href : DIAGNOSTICS_ENDPOINT;
|
|
697
|
-
server.config.logger.info(` ➜ Solid diagnostics: ${endpoint} ` + `(GET status; POST {"method":"begin"|"end"|"whyDidRun"|"costs"})
|
|
816
|
+
server.config.logger.info(` ➜ Solid diagnostics: ${endpoint} ` + `(GET status; POST {"method":"begin"|"end"|"whyDidRun"|"costs"})` + (mode === 'auto' ? ' — auto-enabled; `diagnostics: false` opts out' : '') + `\n ➜ Agent skills: node_modules/${DIAGNOSTICS_PACKAGE}/skills/agent-loops/SKILL.md, ` + `node_modules/solid-js/skills/reactivity-diagnostics/SKILL.md`);
|
|
698
817
|
};
|
|
699
818
|
const pending = new Map();
|
|
700
819
|
let nextId = 1;
|
|
@@ -705,6 +824,11 @@ function solidDiagnostics() {
|
|
|
705
824
|
clearTimeout(entry.timer);
|
|
706
825
|
entry.resolve(data);
|
|
707
826
|
});
|
|
827
|
+
|
|
828
|
+
// No host/origin validation here: on all supported Vite versions
|
|
829
|
+
// (peer range ^8) Vite's own DNS-rebinding host check runs ahead of
|
|
830
|
+
// plugin middleware — verified: requests with a disallowed Host
|
|
831
|
+
// header get Vite's 403 before reaching this handler.
|
|
708
832
|
server.middlewares.use(DIAGNOSTICS_ENDPOINT, async (req, res) => {
|
|
709
833
|
// The middleware mounts on the exact path; anything deeper is 404.
|
|
710
834
|
if (req.url && req.url !== '/' && req.url !== '') {
|
|
@@ -827,7 +951,7 @@ async function compile(id, code, options) {
|
|
|
827
951
|
mode: options.mode,
|
|
828
952
|
env: options.env,
|
|
829
953
|
directive: options.directive,
|
|
830
|
-
sourceMap:
|
|
954
|
+
sourceMap: options.sourceMap !== false,
|
|
831
955
|
register: options.definitions.register,
|
|
832
956
|
create: options.definitions.create
|
|
833
957
|
});
|
|
@@ -953,11 +1077,11 @@ function xxHash32(buffer, seed = 0) {
|
|
|
953
1077
|
* root — not the invocation directory — so running `vite` from outside the
|
|
954
1078
|
* project keeps compiling the same files. Absolute patterns are used as-is.
|
|
955
1079
|
*
|
|
956
|
-
* @default include "src/**\/*.{jsx,tsx,ts,js,mjs,cjs}", exclude "node_modules/**\/*.{jsx,tsx,ts,js,mjs,cjs}"
|
|
1080
|
+
* @default include "src/**\/*.{jsx,tsx,tsrx,ts,js,mjs,cjs}", exclude "node_modules/**\/*.{jsx,tsx,tsrx,ts,js,mjs,cjs}"
|
|
957
1081
|
*/
|
|
958
1082
|
|
|
959
|
-
const DEFAULT_INCLUDE = 'src/**/*.{jsx,tsx,ts,js,mjs,cjs}';
|
|
960
|
-
const DEFAULT_EXCLUDE = 'node_modules/**/*.{jsx,tsx,ts,js,mjs,cjs}';
|
|
1083
|
+
const DEFAULT_INCLUDE = 'src/**/*.{jsx,tsx,tsrx,ts,js,mjs,cjs}';
|
|
1084
|
+
const DEFAULT_EXCLUDE = 'node_modules/**/*.{jsx,tsx,tsrx,ts,js,mjs,cjs}';
|
|
961
1085
|
const DEFAULT_MANIFEST = 'virtual:solid-server-function-manifest';
|
|
962
1086
|
const DEFAULT_DIRECTIVE = 'use server';
|
|
963
1087
|
const DEFAULT_RUNTIME = '@solidjs/web/server-functions';
|
|
@@ -978,29 +1102,50 @@ const HANDLER_ID$1 = 'virtual:solid-server-function-handler';
|
|
|
978
1102
|
// (`vite build` then `vite build --ssr`) does not, so the client build
|
|
979
1103
|
// persists its findings for the SSR build to merge (mirroring the plugin's
|
|
980
1104
|
// dist/client/.vite/manifest.json convention).
|
|
1105
|
+
//
|
|
1106
|
+
// The file doubles as the build's statement of which server functions the
|
|
1107
|
+
// CLIENT can reach — every reference the client compile emitted, by wire id
|
|
1108
|
+
// — for build tooling that needs that set without re-deriving it from
|
|
1109
|
+
// compiled output (a static-site prerenderer checking that each reachable
|
|
1110
|
+
// function was captured, for example). Paths are root-relative, posix.
|
|
981
1111
|
const PERSISTED_MANIFEST_PATH = '.vite/solid-server-functions.json';
|
|
1112
|
+
|
|
1113
|
+
/** The persisted manifest's on-disk shape (the array form is the pre-`functions` legacy). */
|
|
1114
|
+
|
|
982
1115
|
function readPersistedManifest(root) {
|
|
983
1116
|
const file = path.resolve(root, 'dist/client', PERSISTED_MANIFEST_PATH);
|
|
984
1117
|
if (!fs.existsSync(file)) return new Set();
|
|
985
1118
|
try {
|
|
986
|
-
const
|
|
1119
|
+
const parsed = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
1120
|
+
const entries = Array.isArray(parsed) ? parsed : parsed.modules;
|
|
987
1121
|
return new Set(entries.map(entry => path.resolve(root, entry)).filter(entry => fs.existsSync(entry)));
|
|
988
1122
|
} catch {
|
|
989
1123
|
return new Set();
|
|
990
1124
|
}
|
|
991
1125
|
}
|
|
992
|
-
function writePersistedManifest(root, outDir, entries) {
|
|
1126
|
+
function writePersistedManifest(root, outDir, entries, functions) {
|
|
993
1127
|
const file = path.resolve(root, outDir, PERSISTED_MANIFEST_PATH);
|
|
994
1128
|
fs.mkdirSync(path.dirname(file), {
|
|
995
1129
|
recursive: true
|
|
996
1130
|
});
|
|
997
|
-
const relative =
|
|
998
|
-
|
|
1131
|
+
const relative = entry => path.relative(root, entry).split(path.sep).join('/');
|
|
1132
|
+
const manifest = {
|
|
1133
|
+
modules: [...entries].map(relative),
|
|
1134
|
+
functions: [...functions].map(([id, record]) => ({
|
|
1135
|
+
id,
|
|
1136
|
+
name: record.name,
|
|
1137
|
+
module: relative(record.module)
|
|
1138
|
+
}))
|
|
1139
|
+
};
|
|
1140
|
+
fs.writeFileSync(file, JSON.stringify(manifest, null, 2));
|
|
999
1141
|
}
|
|
1000
1142
|
function createManifest() {
|
|
1001
1143
|
return {
|
|
1002
|
-
|
|
1003
|
-
|
|
1144
|
+
modules: {
|
|
1145
|
+
server: new Set(),
|
|
1146
|
+
client: new Set()
|
|
1147
|
+
},
|
|
1148
|
+
clientFunctions: new Map()
|
|
1004
1149
|
};
|
|
1005
1150
|
}
|
|
1006
1151
|
function createDeferredPromise() {
|
|
@@ -1208,13 +1353,13 @@ function serverFunctions(options = {}, internal = {}) {
|
|
|
1208
1353
|
const hashIndex = new Map();
|
|
1209
1354
|
let hashIndexSize = -1;
|
|
1210
1355
|
function moduleForFunctionId(functionId) {
|
|
1211
|
-
if (manifest.server.size !== hashIndexSize) {
|
|
1356
|
+
if (manifest.modules.server.size !== hashIndexSize) {
|
|
1212
1357
|
hashIndex.clear();
|
|
1213
|
-
for (const entry of manifest.server) {
|
|
1358
|
+
for (const entry of manifest.modules.server) {
|
|
1214
1359
|
const relative = path.relative(root, entry).split(path.sep).join('/');
|
|
1215
1360
|
hashIndex.set(xxHash32(relative).toString(16), entry);
|
|
1216
1361
|
}
|
|
1217
|
-
hashIndexSize = manifest.server.size;
|
|
1362
|
+
hashIndexSize = manifest.modules.server.size;
|
|
1218
1363
|
}
|
|
1219
1364
|
return hashIndex.get(functionId.split('-')[1]);
|
|
1220
1365
|
}
|
|
@@ -1322,6 +1467,62 @@ function serverFunctions(options = {}, internal = {}) {
|
|
|
1322
1467
|
}
|
|
1323
1468
|
});
|
|
1324
1469
|
}
|
|
1470
|
+
async function transformModule(ctx, code, fileId, opts, tsrx) {
|
|
1471
|
+
const mode = getEnvironmentConsumer(ctx.environment, opts);
|
|
1472
|
+
const [id] = fileId.split('?');
|
|
1473
|
+
if (!id || !filter(id) || isTsrxModule(id) !== tsrx) return null;
|
|
1474
|
+
|
|
1475
|
+
// The directive has to appear literally, so anything without the
|
|
1476
|
+
// substring can skip the native parse entirely.
|
|
1477
|
+
if (!code.includes(directive)) return null;
|
|
1478
|
+
const result = await compile(id, code, {
|
|
1479
|
+
...(mode === 'server' ? serverOptions : clientOptions),
|
|
1480
|
+
mode,
|
|
1481
|
+
env,
|
|
1482
|
+
root,
|
|
1483
|
+
sourceMap: !tsrx || !!internal.tsrxSourceMap
|
|
1484
|
+
});
|
|
1485
|
+
if (!result.valid) return null;
|
|
1486
|
+
|
|
1487
|
+
// The client compile is the authority on what the browser can dispatch:
|
|
1488
|
+
// record every reference it emitted, by wire id, for the persisted
|
|
1489
|
+
// manifest. A module is re-transformed on change, so its previous ids
|
|
1490
|
+
// are dropped first (a renamed function must not linger as reachable).
|
|
1491
|
+
if (mode === 'client') {
|
|
1492
|
+
for (const [functionId, record] of manifest.clientFunctions) {
|
|
1493
|
+
if (record.module === id) manifest.clientFunctions.delete(functionId);
|
|
1494
|
+
}
|
|
1495
|
+
for (const fn of result.functions) {
|
|
1496
|
+
manifest.clientFunctions.set(fn.id, {
|
|
1497
|
+
name: fn.name,
|
|
1498
|
+
module: id
|
|
1499
|
+
});
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
const preloader = preload[mode];
|
|
1503
|
+
if (preloader) preloader.defer();
|
|
1504
|
+
invalidateModules(currentServer, mergeManifestRecord(manifest.modules.server, new Set([id])), manifestId);
|
|
1505
|
+
return {
|
|
1506
|
+
// Appended (not prepended) so the source map for the compiled module
|
|
1507
|
+
// stays valid; imports hoist and the endpoint is only read at call time.
|
|
1508
|
+
code: (result.code || '') + endpointConfigureSnippet(mode),
|
|
1509
|
+
map: result.map
|
|
1510
|
+
};
|
|
1511
|
+
}
|
|
1512
|
+
const compilerPlugin = {
|
|
1513
|
+
name: 'solid:server-functions/compiler',
|
|
1514
|
+
enforce: 'pre',
|
|
1515
|
+
transform(code, fileId, opts) {
|
|
1516
|
+
return transformModule(this, code, fileId, opts, false);
|
|
1517
|
+
}
|
|
1518
|
+
};
|
|
1519
|
+
const tsrxCompilerPlugin = {
|
|
1520
|
+
name: 'solid:server-functions/tsrx-compiler',
|
|
1521
|
+
enforce: 'pre',
|
|
1522
|
+
transform(code, fileId, opts) {
|
|
1523
|
+
return transformModule(this, code, fileId, opts, true);
|
|
1524
|
+
}
|
|
1525
|
+
};
|
|
1325
1526
|
return [{
|
|
1326
1527
|
name: 'solid:server-functions/setup',
|
|
1327
1528
|
enforce: 'pre',
|
|
@@ -1348,7 +1549,7 @@ function serverFunctions(options = {}, internal = {}) {
|
|
|
1348
1549
|
// build discovered so the server manifest registers them even when
|
|
1349
1550
|
// the SSR module graph never imports them.
|
|
1350
1551
|
for (const entry of readPersistedManifest(root)) {
|
|
1351
|
-
manifest.server.add(entry);
|
|
1552
|
+
manifest.modules.server.add(entry);
|
|
1352
1553
|
}
|
|
1353
1554
|
}
|
|
1354
1555
|
},
|
|
@@ -1363,7 +1564,7 @@ function serverFunctions(options = {}, internal = {}) {
|
|
|
1363
1564
|
const consumer = ctx.environment?.config?.consumer;
|
|
1364
1565
|
const isClient = consumer ? consumer === 'client' : !isSsrBuild;
|
|
1365
1566
|
if (isBuild && isClient) {
|
|
1366
|
-
writePersistedManifest(root, outDir, manifest.server);
|
|
1567
|
+
writePersistedManifest(root, outDir, manifest.modules.server, manifest.clientFunctions);
|
|
1367
1568
|
}
|
|
1368
1569
|
}
|
|
1369
1570
|
}, {
|
|
@@ -1388,54 +1589,17 @@ function serverFunctions(options = {}, internal = {}) {
|
|
|
1388
1589
|
// configs resolve before the client build has written the file,
|
|
1389
1590
|
// but this load runs once the SSR environment builds — after it.
|
|
1390
1591
|
for (const entry of readPersistedManifest(root)) {
|
|
1391
|
-
manifest.server.add(entry);
|
|
1592
|
+
manifest.modules.server.add(entry);
|
|
1392
1593
|
}
|
|
1393
1594
|
}
|
|
1394
|
-
const current = new Debouncer(() => [...manifest[mode]].map(entry => `import ${JSON.stringify(entry)};`).join('\n'));
|
|
1595
|
+
const current = new Debouncer(() => [...manifest.modules[mode]].map(entry => `import ${JSON.stringify(entry)};`).join('\n'));
|
|
1395
1596
|
preload[mode] = current;
|
|
1396
1597
|
const result = await current.promise.reference;
|
|
1397
1598
|
return result;
|
|
1398
1599
|
}
|
|
1399
1600
|
return null;
|
|
1400
1601
|
}
|
|
1401
|
-
},
|
|
1402
|
-
name: 'solid:server-functions/compiler',
|
|
1403
|
-
enforce: 'pre',
|
|
1404
|
-
async transform(code, fileId, opts) {
|
|
1405
|
-
const mode = getEnvironmentConsumer(this.environment, opts);
|
|
1406
|
-
const [id] = fileId.split('?');
|
|
1407
|
-
if (!filter(id)) {
|
|
1408
|
-
return null;
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
// Fast path: the directive has to appear literally, so anything
|
|
1412
|
-
// without the substring can skip the native parse entirely.
|
|
1413
|
-
if (!code.includes(directive)) {
|
|
1414
|
-
return null;
|
|
1415
|
-
}
|
|
1416
|
-
const result = await compile(id, code, {
|
|
1417
|
-
...(mode === 'server' ? serverOptions : clientOptions),
|
|
1418
|
-
mode,
|
|
1419
|
-
env,
|
|
1420
|
-
root
|
|
1421
|
-
});
|
|
1422
|
-
if (result.valid) {
|
|
1423
|
-
const preloader = preload[mode];
|
|
1424
|
-
if (preloader) {
|
|
1425
|
-
preloader.defer();
|
|
1426
|
-
}
|
|
1427
|
-
invalidateModules(currentServer, mergeManifestRecord(manifest.server, new Set([id])), manifestId);
|
|
1428
|
-
return {
|
|
1429
|
-
// Appended (not prepended) so the source map for the compiled
|
|
1430
|
-
// module stays valid; imports hoist and the endpoint is only
|
|
1431
|
-
// read at call time, never during module evaluation.
|
|
1432
|
-
code: (result.code || '') + endpointConfigureSnippet(mode),
|
|
1433
|
-
map: result.map
|
|
1434
|
-
};
|
|
1435
|
-
}
|
|
1436
|
-
return null;
|
|
1437
|
-
}
|
|
1438
|
-
}, ...startPlugins];
|
|
1602
|
+
}, compilerPlugin, ...(internal.tsrxAfterSolid ? [tsrxCompilerPlugin] : []), ...startPlugins];
|
|
1439
1603
|
}
|
|
1440
1604
|
|
|
1441
1605
|
const DEVTOOLS_PACKAGE = '@solidjs/start-devtools';
|
|
@@ -1530,9 +1694,9 @@ const ERROR_BOUNDARY_ID = 'virtual:solid-ssr-error-boundary.tsx';
|
|
|
1530
1694
|
const MANIFEST_ID = 'virtual:solid-manifest';
|
|
1531
1695
|
const SERVER_FUNCTION_HANDLER_ID = 'virtual:solid-server-function-handler';
|
|
1532
1696
|
const STORAGE_SOURCE = '@solidjs/web/storage';
|
|
1533
|
-
const ENTRY_EXTENSIONS = ['.tsx', '.jsx', '.ts', '.js', '.mjs'];
|
|
1534
|
-
const APP_EXTENSIONS = ['.tsx', '.jsx', '.ts', '.js'];
|
|
1535
|
-
const DOCUMENT_EXTENSIONS = ['.tsx', '.jsx'];
|
|
1697
|
+
const ENTRY_EXTENSIONS = ['.tsx', '.jsx', '.ts', '.js', '.mjs', '.tsrx'];
|
|
1698
|
+
const APP_EXTENSIONS = ['.tsx', '.jsx', '.ts', '.js', '.tsrx'];
|
|
1699
|
+
const DOCUMENT_EXTENSIONS = ['.tsx', '.jsx', '.tsrx'];
|
|
1536
1700
|
function probe(root, stem, extensions) {
|
|
1537
1701
|
for (const ext of extensions) {
|
|
1538
1702
|
if (fs.existsSync(path.resolve(root, stem + ext))) return stem + ext;
|
|
@@ -1640,7 +1804,9 @@ function startServe(options, internal = {}) {
|
|
|
1640
1804
|
const serverComponents = !!internal.serverComponents;
|
|
1641
1805
|
const errorBoundary = options.errorBoundary !== false;
|
|
1642
1806
|
const styleFilter = internal.styleFilter;
|
|
1643
|
-
|
|
1807
|
+
// `'auto'` resolves against the project root in configResolved, before
|
|
1808
|
+
// any of the (lazy) uses in entry codegen and the entry transform.
|
|
1809
|
+
let diagnostics = internal.diagnostics === true;
|
|
1644
1810
|
let devtoolsEnabled = false;
|
|
1645
1811
|
let devtoolsResolutions = {};
|
|
1646
1812
|
let devtoolsIds = {};
|
|
@@ -2150,6 +2316,12 @@ function startServe(options, internal = {}) {
|
|
|
2150
2316
|
root = config.root;
|
|
2151
2317
|
base = config.base;
|
|
2152
2318
|
isBuild = config.command === 'build';
|
|
2319
|
+
// Test mode excluded for the same reason as the surface plugin's
|
|
2320
|
+
// `apply`: vitest runs a dev serve, and test pages should not get
|
|
2321
|
+
// the bridge import injected into their client entries.
|
|
2322
|
+
if (internal.diagnostics === 'auto' && !isBuild && config.mode !== 'test') {
|
|
2323
|
+
diagnostics = detectDiagnosticsPackage(root);
|
|
2324
|
+
}
|
|
2153
2325
|
},
|
|
2154
2326
|
resolveId(source, importer, opts) {
|
|
2155
2327
|
if (source === HANDLER_ID) {
|
|
@@ -3266,7 +3438,8 @@ function solidPlugin(options = {}) {
|
|
|
3266
3438
|
// resolve against the Vite root, not process.cwd() — running `vite` from
|
|
3267
3439
|
// outside the project would otherwise change what the filter matches.
|
|
3268
3440
|
let filter = vite.createFilter(options.include, options.exclude);
|
|
3269
|
-
const
|
|
3441
|
+
const serverComponentsOption = typeof options.serverFunctions === 'object' ? options.serverFunctions.components : undefined;
|
|
3442
|
+
const serverComponents = !!serverComponentsOption;
|
|
3270
3443
|
// `start: true` is sugar for the empty options bag — one start mode,
|
|
3271
3444
|
// two spellings — so normalize here and let everything downstream see a
|
|
3272
3445
|
// single shape (`false` behaves exactly like omission).
|
|
@@ -3316,6 +3489,7 @@ function solidPlugin(options = {}) {
|
|
|
3316
3489
|
let base = '/';
|
|
3317
3490
|
let clientOutDir = null;
|
|
3318
3491
|
let solidPkgsConfig;
|
|
3492
|
+
const tsrxCss = new Map();
|
|
3319
3493
|
|
|
3320
3494
|
// The client build's manifest, read back by SSR builds. In builder-mode
|
|
3321
3495
|
// (single process, e.g. SolidStart's nitro plugin) the client build runs
|
|
@@ -3410,6 +3584,44 @@ function solidPlugin(options = {}) {
|
|
|
3410
3584
|
const relativeId = path.relative(projectRoot, file).split(path.sep).join('/') + query;
|
|
3411
3585
|
return code + `\nexport const $$moduleUrl = ${JSON.stringify(relativeId)};\n`;
|
|
3412
3586
|
}
|
|
3587
|
+
function nativeTsrxCss(result) {
|
|
3588
|
+
const css = result.css;
|
|
3589
|
+
return typeof css === 'string' ? css : '';
|
|
3590
|
+
}
|
|
3591
|
+
function babelTsrxCss(result) {
|
|
3592
|
+
const css = result.metadata?.css;
|
|
3593
|
+
return typeof css === 'string' ? css : '';
|
|
3594
|
+
}
|
|
3595
|
+
async function compileTsrxCss(source, id) {
|
|
3596
|
+
const solidOptions = getSolidOptions(options, false, replaceDev, isTestMode);
|
|
3597
|
+
if (options.compiler === 'babel') {
|
|
3598
|
+
const babelUserOptions = await getBabelUserOptions(options, source, id, false);
|
|
3599
|
+
const babelOptions = mergeAnything.mergeAndConcat(babelUserOptions, {
|
|
3600
|
+
root: projectRoot,
|
|
3601
|
+
// Keep .tsrx: the Babel plugin uses it to select its TSRX parser.
|
|
3602
|
+
filename: id,
|
|
3603
|
+
sourceFileName: id,
|
|
3604
|
+
ast: false,
|
|
3605
|
+
code: false,
|
|
3606
|
+
sourceMaps: false,
|
|
3607
|
+
configFile: false,
|
|
3608
|
+
babelrc: false,
|
|
3609
|
+
parserOpts: {
|
|
3610
|
+
plugins: ['jsx', 'decorators', 'typescript']
|
|
3611
|
+
},
|
|
3612
|
+
plugins: [[solid, solidOptions]]
|
|
3613
|
+
});
|
|
3614
|
+
const result = await babel__namespace.transformAsync(source, babelOptions);
|
|
3615
|
+
return result ? babelTsrxCss(result) : '';
|
|
3616
|
+
}
|
|
3617
|
+
const compiler = await loadNativeCompiler();
|
|
3618
|
+
const result = await compiler.transformAsync(source, {
|
|
3619
|
+
...solidOptions,
|
|
3620
|
+
filename: id,
|
|
3621
|
+
sourceMap: false
|
|
3622
|
+
});
|
|
3623
|
+
return nativeTsrxCss(result);
|
|
3624
|
+
}
|
|
3413
3625
|
const mainPlugin = {
|
|
3414
3626
|
name: 'solid',
|
|
3415
3627
|
enforce: 'pre',
|
|
@@ -3500,6 +3712,7 @@ function solidPlugin(options = {}) {
|
|
|
3500
3712
|
dedupe: nestedDeps
|
|
3501
3713
|
},
|
|
3502
3714
|
optimizeDeps: {
|
|
3715
|
+
extensions: ['.tsrx'],
|
|
3503
3716
|
include: [...nestedDeps,
|
|
3504
3717
|
// Dev refresh wrappers import the solid-js/refresh runtime in
|
|
3505
3718
|
// every mode; pre-bundle it up front so its discovery doesn't
|
|
@@ -3520,7 +3733,28 @@ function solidPlugin(options = {}) {
|
|
|
3520
3733
|
jsx: {
|
|
3521
3734
|
runtime: 'classic'
|
|
3522
3735
|
}
|
|
3523
|
-
}
|
|
3736
|
+
},
|
|
3737
|
+
plugins: [{
|
|
3738
|
+
name: 'solid:tsrx-dep-scan',
|
|
3739
|
+
async transform(source, id) {
|
|
3740
|
+
if (!isTsrxModule(id) || isTsrxCssModule(id)) return null;
|
|
3741
|
+
const compiler = await loadNativeCompiler();
|
|
3742
|
+
const result = await compiler.transformAsync(source, {
|
|
3743
|
+
...getSolidOptions(options, false, replaceDev, isTestMode),
|
|
3744
|
+
filename: cleanModuleId(id),
|
|
3745
|
+
sourceMap: false
|
|
3746
|
+
});
|
|
3747
|
+
const stripped = await vite.transformWithOxc(result.code, cleanModuleId(id) + '.tsx', {
|
|
3748
|
+
lang: 'tsx',
|
|
3749
|
+
sourcemap: false,
|
|
3750
|
+
target: 'esnext'
|
|
3751
|
+
});
|
|
3752
|
+
return {
|
|
3753
|
+
code: stripped.code,
|
|
3754
|
+
map: null
|
|
3755
|
+
};
|
|
3756
|
+
}
|
|
3757
|
+
}]
|
|
3524
3758
|
}
|
|
3525
3759
|
},
|
|
3526
3760
|
...(Object.keys(test).length ? {
|
|
@@ -3579,8 +3813,13 @@ function solidPlugin(options = {}) {
|
|
|
3579
3813
|
resolve: projectRoot
|
|
3580
3814
|
});
|
|
3581
3815
|
styleFilter = createStyleFilter(projectRoot);
|
|
3582
|
-
|
|
3583
|
-
|
|
3816
|
+
// `components: 'external'` is the acknowledgement that a composing
|
|
3817
|
+
// host (e.g. the Astro adapter or TanStack Start's Solid integration)
|
|
3818
|
+
// owns the document wiring itself — behavior is identical to `true`,
|
|
3819
|
+
// only this warning is skipped. Under SSR start mode it's redundant
|
|
3820
|
+
// but harmless (treated exactly as `true`).
|
|
3821
|
+
if (serverComponents && serverComponentsOption !== 'external' && !(options.start && options.ssr)) {
|
|
3822
|
+
config.logger.warn('[@solidjs/vite-plugin] serverFunctions.components is set without SSR start mode (the `start` ' + 'option with `ssr: true`), so the plugin only installs the endpoint response transform ' + '(server functions returning components stream correctly). The document wiring — the ' + 'render plugin (with the direct-call transform) and the client-side ' + "installServerComponents() call — is emitted by SSR start mode's generated entries; " + 'without it, server components only mount from post-boot streams and your client code ' + 'must call installServerComponents() itself. If a composing host owns that wiring, set ' + "`components: 'external'` to acknowledge it and silence this warning.");
|
|
3584
3823
|
}
|
|
3585
3824
|
needHmr = config.command === 'serve' && config.mode !== 'production' && options.hot !== false && !options.refresh?.disabled;
|
|
3586
3825
|
},
|
|
@@ -3618,10 +3857,21 @@ function solidPlugin(options = {}) {
|
|
|
3618
3857
|
return origSend(...args);
|
|
3619
3858
|
};
|
|
3620
3859
|
},
|
|
3621
|
-
hotUpdate({
|
|
3860
|
+
async hotUpdate({
|
|
3861
|
+
file,
|
|
3622
3862
|
modules,
|
|
3623
|
-
|
|
3863
|
+
read
|
|
3624
3864
|
}) {
|
|
3865
|
+
if (isTsrxModule(file) && this.environment.name === 'client') {
|
|
3866
|
+
updateTsrxCss(tsrxCss, file, await compileTsrxCss(await read(), file));
|
|
3867
|
+
const cssModule = this.environment.moduleGraph.getModuleById(resolvedTsrxCssModuleId(file));
|
|
3868
|
+
if (cssModule) {
|
|
3869
|
+
this.environment.moduleGraph.invalidateModule(cssModule);
|
|
3870
|
+
if (!modules.includes(cssModule)) modules = [...modules, cssModule];
|
|
3871
|
+
return modules;
|
|
3872
|
+
}
|
|
3873
|
+
}
|
|
3874
|
+
|
|
3625
3875
|
// solid-refresh only injects HMR boundaries into client modules, so
|
|
3626
3876
|
// non-client environments have no accept handlers. Without this, Vite
|
|
3627
3877
|
// would see no boundaries and send full-reload messages that race with
|
|
@@ -3658,6 +3908,8 @@ function solidPlugin(options = {}) {
|
|
|
3658
3908
|
}
|
|
3659
3909
|
},
|
|
3660
3910
|
resolveId(id) {
|
|
3911
|
+
const tsrxCssId = resolveTsrxCssModule(id);
|
|
3912
|
+
if (tsrxCssId) return tsrxCssId;
|
|
3661
3913
|
if (id === VIRTUAL_MANIFEST_ID) return RESOLVED_VIRTUAL_MANIFEST_ID;
|
|
3662
3914
|
},
|
|
3663
3915
|
moduleParsed(info) {
|
|
@@ -3670,7 +3922,7 @@ function solidPlugin(options = {}) {
|
|
|
3670
3922
|
for (const depId of info.dynamicallyImportedIds || []) {
|
|
3671
3923
|
const cleanId = depId.split('?')[0];
|
|
3672
3924
|
if (/node_modules/.test(cleanId) || cleanId.startsWith('\0')) continue;
|
|
3673
|
-
if (
|
|
3925
|
+
if (!(/\.[mc]?[tj]sx?$/i.test(cleanId) || isTsrxModule(cleanId))) continue;
|
|
3674
3926
|
if (emittedLazyChunks.has(depId)) continue;
|
|
3675
3927
|
emittedLazyChunks.add(depId);
|
|
3676
3928
|
emittedLazyChunkRefs.push(this.emitFile({
|
|
@@ -3681,6 +3933,8 @@ function solidPlugin(options = {}) {
|
|
|
3681
3933
|
}
|
|
3682
3934
|
},
|
|
3683
3935
|
load(id) {
|
|
3936
|
+
const tsrxSource = tsrxCssSourceId(id);
|
|
3937
|
+
if (tsrxSource) return tsrxCss.get(tsrxSource) ?? '';
|
|
3684
3938
|
if (id === RESOLVED_VIRTUAL_MANIFEST_ID) {
|
|
3685
3939
|
if (!isBuild) {
|
|
3686
3940
|
return devManifestCode(projectRoot, base, devServer ? devManifestBridgeUrl(devServer) : null);
|
|
@@ -3722,6 +3976,7 @@ function solidPlugin(options = {}) {
|
|
|
3722
3976
|
}
|
|
3723
3977
|
},
|
|
3724
3978
|
async transform(source, id, transformOptions) {
|
|
3979
|
+
if (isTsrxCssModule(id)) return null;
|
|
3725
3980
|
const isSsr = getEnvironmentConsumer(this.environment, transformOptions) === 'server';
|
|
3726
3981
|
const currentFileExtension = getExtension(id);
|
|
3727
3982
|
const extensionsToWatch = options.extensions || [];
|
|
@@ -3737,14 +3992,15 @@ function solidPlugin(options = {}) {
|
|
|
3737
3992
|
// while the transform pipeline below works on the clean file path.
|
|
3738
3993
|
const moduleId = id;
|
|
3739
3994
|
id = id.replace(/\?.*$/, '');
|
|
3740
|
-
|
|
3995
|
+
const isTsrx = isTsrxModule(id);
|
|
3996
|
+
if (!(/\.[mc]?[tj]sx$/i.test(id) || isTsrx || allExtensions.includes(currentFileExtension))) {
|
|
3741
3997
|
return null;
|
|
3742
3998
|
}
|
|
3743
3999
|
const inNodeModules = /node_modules/.test(id);
|
|
3744
4000
|
const solidOptions = getSolidOptions(options, !!isSsr, replaceDev, isTestMode);
|
|
3745
4001
|
|
|
3746
4002
|
// We need to know if the current file extension has a typescript options tied to it
|
|
3747
|
-
const shouldBeProcessedWithTypescript = /\.[mc]?tsx$/i.test(id) || extensionsToWatch.some(extension => {
|
|
4003
|
+
const shouldBeProcessedWithTypescript = /\.[mc]?tsx$/i.test(id) || isTsrx || extensionsToWatch.some(extension => {
|
|
3748
4004
|
if (typeof extension === 'string') {
|
|
3749
4005
|
return extension.includes('tsx');
|
|
3750
4006
|
}
|
|
@@ -3768,7 +4024,7 @@ function solidPlugin(options = {}) {
|
|
|
3768
4024
|
// extension; custom extensions registered through `options.extensions`
|
|
3769
4025
|
// are unknown to it, so borrow a standard one matching the configured
|
|
3770
4026
|
// TypeScript-ness.
|
|
3771
|
-
const nativeFilename = /\.(?:[mc]?[jt]s|[jt]sx)$/i.test(id) ? id : id + (shouldBeProcessedWithTypescript ? '.tsx' : '.jsx');
|
|
4027
|
+
const nativeFilename = isTsrx || /\.(?:[mc]?[jt]s|[jt]sx)$/i.test(id) ? id : id + (shouldBeProcessedWithTypescript ? '.tsx' : '.jsx');
|
|
3772
4028
|
|
|
3773
4029
|
// Shared native prelude for every mode: the lazy() module-URL pass,
|
|
3774
4030
|
// then (dev/client/non-node_modules) the solid-refresh HMR pass, both
|
|
@@ -3778,6 +4034,97 @@ function solidPlugin(options = {}) {
|
|
|
3778
4034
|
const compiler = await loadNativeCompiler();
|
|
3779
4035
|
let code = source;
|
|
3780
4036
|
const maps = [];
|
|
4037
|
+
if (isTsrx) {
|
|
4038
|
+
// Solid lowering preserves authored TypeScript annotations; secondary
|
|
4039
|
+
// passes therefore parse the generated module as TSX even though no
|
|
4040
|
+
// template syntax remains.
|
|
4041
|
+
const generatedFilename = id + '.tsx';
|
|
4042
|
+
const babelBaseOptions = {
|
|
4043
|
+
root: projectRoot,
|
|
4044
|
+
filename: id,
|
|
4045
|
+
sourceFileName: id,
|
|
4046
|
+
ast: false,
|
|
4047
|
+
sourceMaps: true,
|
|
4048
|
+
configFile: false,
|
|
4049
|
+
babelrc: false,
|
|
4050
|
+
parserOpts: {
|
|
4051
|
+
plugins
|
|
4052
|
+
}
|
|
4053
|
+
};
|
|
4054
|
+
let css = '';
|
|
4055
|
+
if (options.compiler !== 'babel') {
|
|
4056
|
+
const result = await compiler.transformAsync(code, {
|
|
4057
|
+
...solidOptions,
|
|
4058
|
+
filename: id,
|
|
4059
|
+
sourceMap: true
|
|
4060
|
+
});
|
|
4061
|
+
code = result.code || '';
|
|
4062
|
+
css = nativeTsrxCss(result);
|
|
4063
|
+
maps.push(result.map);
|
|
4064
|
+
if (options.babel) {
|
|
4065
|
+
// The support pass cannot parse authored TSRX. On this route it
|
|
4066
|
+
// intentionally sees the lowered ordinary JavaScript instead.
|
|
4067
|
+
const supportOptions = mergeAnything.mergeAndConcat(babelUserOptions, babelBaseOptions);
|
|
4068
|
+
// This pass sees native-lowered ordinary JavaScript, so do not
|
|
4069
|
+
// route it back through Babel's TSRX parser.
|
|
4070
|
+
supportOptions.filename = generatedFilename;
|
|
4071
|
+
const supportResult = await babel__namespace.transformAsync(code, supportOptions);
|
|
4072
|
+
if (!supportResult) return undefined;
|
|
4073
|
+
code = supportResult.code || '';
|
|
4074
|
+
maps.push(supportResult.map);
|
|
4075
|
+
}
|
|
4076
|
+
} else {
|
|
4077
|
+
const babelOptions = mergeAnything.mergeAndConcat(babelUserOptions, {
|
|
4078
|
+
...babelBaseOptions,
|
|
4079
|
+
plugins: [[solid, solidOptions]]
|
|
4080
|
+
});
|
|
4081
|
+
const result = await babel__namespace.transformAsync(code, babelOptions);
|
|
4082
|
+
if (!result) return undefined;
|
|
4083
|
+
code = result.code || '';
|
|
4084
|
+
css = babelTsrxCss(result);
|
|
4085
|
+
maps.push(result.map);
|
|
4086
|
+
}
|
|
4087
|
+
const lazyResult = await compiler.transformLazyAsync(code, {
|
|
4088
|
+
filename: generatedFilename,
|
|
4089
|
+
sourceMap: true
|
|
4090
|
+
});
|
|
4091
|
+
code = lazyResult.code;
|
|
4092
|
+
maps.push(lazyResult.map);
|
|
4093
|
+
if (needRefresh) {
|
|
4094
|
+
const refreshResult = await compiler.transformRefreshAsync(code, {
|
|
4095
|
+
filename: generatedFilename,
|
|
4096
|
+
bundler: 'vite',
|
|
4097
|
+
fixRender: true,
|
|
4098
|
+
...(typeof options.refresh?.granular === 'boolean' ? {
|
|
4099
|
+
granular: options.refresh.granular
|
|
4100
|
+
} : {}),
|
|
4101
|
+
jsx: false,
|
|
4102
|
+
importSource: REFRESH_RUNTIME_SOURCE,
|
|
4103
|
+
sourceMap: true
|
|
4104
|
+
});
|
|
4105
|
+
code = refreshResult.code;
|
|
4106
|
+
maps.push(refreshResult.map);
|
|
4107
|
+
}
|
|
4108
|
+
code = injectSsrModuleId(await resolveLazyModuleUrls(this, code, id), moduleId, !!isSsr);
|
|
4109
|
+
let map = options.compiler === 'babel' ? combineSourcemaps(maps) : null;
|
|
4110
|
+
updateTsrxCss(tsrxCss, id, css);
|
|
4111
|
+
if (css) {
|
|
4112
|
+
code = prependTsrxCssImport(code, id);
|
|
4113
|
+
map = offsetSourceMapLine(map);
|
|
4114
|
+
}
|
|
4115
|
+
// Vite selects its TypeScript stripping by file extension. Since the
|
|
4116
|
+
// real module identity remains `.tsrx`, strip the annotations here
|
|
4117
|
+
// after Solid lowering instead of handing typed JavaScript to Rollup.
|
|
4118
|
+
const stripped = await vite.transformWithOxc(code, generatedFilename, {
|
|
4119
|
+
lang: 'tsx',
|
|
4120
|
+
sourcemap: map != null,
|
|
4121
|
+
target: 'esnext'
|
|
4122
|
+
}, map ?? undefined);
|
|
4123
|
+
return {
|
|
4124
|
+
code: stripped.code,
|
|
4125
|
+
map: map == null ? null : stripped.map
|
|
4126
|
+
};
|
|
4127
|
+
}
|
|
3781
4128
|
const lazyResult = await compiler.transformLazyAsync(code, {
|
|
3782
4129
|
filename: nativeFilename,
|
|
3783
4130
|
sourceMap: true
|
|
@@ -3860,20 +4207,24 @@ function solidPlugin(options = {}) {
|
|
|
3860
4207
|
}
|
|
3861
4208
|
};
|
|
3862
4209
|
|
|
3863
|
-
//
|
|
3864
|
-
//
|
|
3865
|
-
//
|
|
3866
|
-
//
|
|
3867
|
-
const
|
|
4210
|
+
// Ordinary modules need the directive transform before JSX. Authored TSRX
|
|
4211
|
+
// cannot be parsed by that standalone pass, so its companion compiler runs
|
|
4212
|
+
// after mainPlugin has lowered the file to ordinary JavaScript while keeping
|
|
4213
|
+
// the original .tsrx id for stable server-function hashes.
|
|
4214
|
+
const serverFunctionPlugins = options.serverFunctions ? serverFunctions(options.serverFunctions === true ? {} : options.serverFunctions, {
|
|
3868
4215
|
devMiddleware: true,
|
|
3869
4216
|
externalDevServer,
|
|
4217
|
+
tsrxAfterSolid: true,
|
|
4218
|
+
tsrxSourceMap: options.compiler === 'babel',
|
|
3870
4219
|
// With start mode on (either variant), the dev middleware dispatches
|
|
3871
4220
|
// the endpoint through the SSR handler so user middleware and the
|
|
3872
4221
|
// stub-backed request event front it exactly like page SSR.
|
|
3873
4222
|
...(startOptions ? {
|
|
3874
4223
|
ssrHandler: SSR_HANDLER_ID
|
|
3875
4224
|
} : {})
|
|
3876
|
-
})
|
|
4225
|
+
}) : [];
|
|
4226
|
+
const tsrxServerFunctionPlugin = serverFunctionPlugins.find(plugin => plugin.name === 'solid:server-functions/tsrx-compiler');
|
|
4227
|
+
const plugins = [boundaryModules(), ...serverFunctionPlugins.filter(plugin => plugin !== tsrxServerFunctionPlugin), mainPlugin, ...(tsrxServerFunctionPlugin ? [tsrxServerFunctionPlugin] : [])];
|
|
3877
4228
|
|
|
3878
4229
|
// The `start` option opts into start-mode serving on top of the transforms;
|
|
3879
4230
|
// the `ssr` boolean picks the mode (a bare `ssr: true` keeps the
|
|
@@ -3888,7 +4239,7 @@ function solidPlugin(options = {}) {
|
|
|
3888
4239
|
serverComponents,
|
|
3889
4240
|
ssr: !!options.ssr,
|
|
3890
4241
|
styleFilter: filterDevStyles,
|
|
3891
|
-
diagnostics:
|
|
4242
|
+
diagnostics: options.diagnostics ?? 'auto',
|
|
3892
4243
|
onDocumentResolved(documentPath) {
|
|
3893
4244
|
// Normalize to forward slashes to match Vite's transform ids.
|
|
3894
4245
|
documentModuleId = documentPath ? documentPath.split(path.sep).join('/') : null;
|
|
@@ -3897,9 +4248,11 @@ function solidPlugin(options = {}) {
|
|
|
3897
4248
|
}
|
|
3898
4249
|
|
|
3899
4250
|
// Agent diagnostics endpoint + injected bridge (dev serve only — the
|
|
3900
|
-
// plugin no-ops itself for builds and preview via `apply
|
|
3901
|
-
|
|
3902
|
-
|
|
4251
|
+
// plugin no-ops itself for builds and preview via `apply`, and in the
|
|
4252
|
+
// default auto mode additionally disables itself unless the app has
|
|
4253
|
+
// `@solidjs/diagnostics` installed).
|
|
4254
|
+
if (options.diagnostics !== false) {
|
|
4255
|
+
plugins.push(solidDiagnostics(options.diagnostics === true ? true : 'auto'));
|
|
3903
4256
|
}
|
|
3904
4257
|
|
|
3905
4258
|
// Builder-mode (environments API) client-before-server build ordering.
|