@pracht/vite-plugin 0.7.0 → 0.7.2
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.mts +2 -1
- package/dist/index.mjs +235 -16
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
|
@@ -28,7 +28,8 @@ interface EnvLeakReference {
|
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* Scans JavaScript source for references to environment variables that are
|
|
31
|
-
* neither public-prefixed, Vite built-ins, nor explicitly allowed
|
|
31
|
+
* neither public-prefixed, Vite built-ins, nor explicitly allowed, plus reads
|
|
32
|
+
* that pull in the whole `import.meta.env` object.
|
|
32
33
|
*/
|
|
33
34
|
declare function scanCodeForEnvLeaks(code: string, allow?: ReadonlySet<string>): EnvLeakReference[];
|
|
34
35
|
interface EnvLeakProblem extends EnvLeakReference {
|
package/dist/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
import { preactSsrPrecompile } from "@pracht/preact-ssr-precompile";
|
|
4
4
|
import preact from "@preact/preset-vite";
|
|
5
5
|
import { dirname, extname, join, resolve } from "node:path";
|
|
6
|
-
import { parseAst } from "vite";
|
|
6
|
+
import { loadEnv, parseAst } from "vite";
|
|
7
7
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
8
8
|
import { CAPABILITY_SETTLED_EVENT, CAPABILITY_TRANSPORT_HEADER, CONFIRMATION_HEADER, capabilityHttpPath, isValidCapabilityHttpPath } from "@pracht/capabilities";
|
|
9
9
|
import { evaluateLiteral, extractCapabilityRegistrations, extractDefineCapabilityArgs, scanTopLevelProperties } from "@pracht/capabilities/static";
|
|
@@ -909,30 +909,51 @@ const VITE_BUILTIN_ENV_VARS = new Set([
|
|
|
909
909
|
const PUBLIC_ENV_PREFIX = "PRACHT_PUBLIC_";
|
|
910
910
|
/** Server-only core entry that must never resolve into client bundles. */
|
|
911
911
|
const SERVER_ENV_MODULE_ID = "@pracht/core/env/server";
|
|
912
|
-
const ENV_REFERENCE_RE = /\b(process\.env|import\.meta\.env)(
|
|
912
|
+
const ENV_REFERENCE_RE = /\b(process\.env|import\.meta\.env)(?:\??\.([A-Za-z_$][A-Za-z0-9_$]*)|(?:\?\.)?\[\s*(["'])([A-Za-z_$][A-Za-z0-9_$]*)\3\s*\])/g;
|
|
913
|
+
const WHOLE_ENV_READ_RE = /\bimport\.meta\.env\b(?!\s*\??\.\s*[A-Za-z_$])/g;
|
|
913
914
|
/**
|
|
914
915
|
* Scans JavaScript source for references to environment variables that are
|
|
915
|
-
* neither public-prefixed, Vite built-ins, nor explicitly allowed
|
|
916
|
+
* neither public-prefixed, Vite built-ins, nor explicitly allowed, plus reads
|
|
917
|
+
* that pull in the whole `import.meta.env` object.
|
|
916
918
|
*/
|
|
917
919
|
function scanCodeForEnvLeaks(code, allow = /* @__PURE__ */ new Set()) {
|
|
918
|
-
const findings = [];
|
|
919
|
-
const seen = /* @__PURE__ */ new Set();
|
|
920
920
|
const codePositions = getCodePositionMask(code);
|
|
921
|
+
const matches = [];
|
|
921
922
|
for (const match of code.matchAll(ENV_REFERENCE_RE)) {
|
|
922
|
-
|
|
923
|
+
const index = match.index ?? -1;
|
|
924
|
+
if (!codePositions[index]) continue;
|
|
923
925
|
const accessor = match[1];
|
|
924
926
|
const name = match[2] ?? match[4];
|
|
925
927
|
if (!name) continue;
|
|
926
928
|
if (name.startsWith("PRACHT_PUBLIC_")) continue;
|
|
927
929
|
if (VITE_BUILTIN_ENV_VARS.has(name)) continue;
|
|
928
930
|
if (allow.has(name)) continue;
|
|
929
|
-
|
|
931
|
+
matches.push({
|
|
932
|
+
index,
|
|
933
|
+
reference: {
|
|
934
|
+
accessor,
|
|
935
|
+
name
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
if (!allow.has("*")) for (const match of code.matchAll(WHOLE_ENV_READ_RE)) {
|
|
940
|
+
const index = match.index ?? -1;
|
|
941
|
+
if (!codePositions[index]) continue;
|
|
942
|
+
matches.push({
|
|
943
|
+
index,
|
|
944
|
+
reference: {
|
|
945
|
+
accessor: "import.meta.env",
|
|
946
|
+
name: "*"
|
|
947
|
+
}
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
const findings = [];
|
|
951
|
+
const seen = /* @__PURE__ */ new Set();
|
|
952
|
+
for (const { reference } of matches.sort((a, b) => a.index - b.index)) {
|
|
953
|
+
const key = `${reference.accessor}.${reference.name}`;
|
|
930
954
|
if (seen.has(key)) continue;
|
|
931
955
|
seen.add(key);
|
|
932
|
-
findings.push(
|
|
933
|
-
accessor,
|
|
934
|
-
name
|
|
935
|
-
});
|
|
956
|
+
findings.push(reference);
|
|
936
957
|
}
|
|
937
958
|
return findings;
|
|
938
959
|
}
|
|
@@ -1103,12 +1124,20 @@ function isIdentifierChar(char) {
|
|
|
1103
1124
|
return !!char && /[A-Za-z0-9_$]/.test(char);
|
|
1104
1125
|
}
|
|
1105
1126
|
function formatEnvLeakError(problems) {
|
|
1127
|
+
const lines = problems.map((problem) => {
|
|
1128
|
+
const source = problem.sources.length > 0 ? ` (likely from ${problem.sources.map((file) => JSON.stringify(file)).join(", ")})` : "";
|
|
1129
|
+
return ` - ${problem.name === "*" ? "import.meta.env read as a whole object" : `${problem.accessor}.${problem.name}`} in chunk "${problem.chunk}"${source}`;
|
|
1130
|
+
});
|
|
1131
|
+
const wholeEnvGuidance = problems.some((problem) => problem.name === "*") ? [
|
|
1132
|
+
"",
|
|
1133
|
+
"A whole-object `import.meta.env` read (bare reference, destructuring, spread, or bracket access)",
|
|
1134
|
+
"is replaced at build time by an object literal containing every exposed variable — including the",
|
|
1135
|
+
"`VITE_` values Pracht does not treat as public. Read one key at a time (`import.meta.env.KEY`)."
|
|
1136
|
+
] : [];
|
|
1106
1137
|
return [
|
|
1107
1138
|
"[pracht] Environment variable leak detected in the client bundle:",
|
|
1108
|
-
...
|
|
1109
|
-
|
|
1110
|
-
return ` - ${problem.accessor}.${problem.name} in chunk "${problem.chunk}"${source}`;
|
|
1111
|
-
}),
|
|
1139
|
+
...lines,
|
|
1140
|
+
...wholeEnvGuidance,
|
|
1112
1141
|
"",
|
|
1113
1142
|
`Only PRACHT_PUBLIC_-prefixed variables may be referenced in client code (prefer publicEnv from "@pracht/core" for typed public values).`,
|
|
1114
1143
|
`Move server-only reads into loaders/API routes and access them via serverEnv from "@pracht/core/env/server",`,
|
|
@@ -1193,6 +1222,7 @@ function createEnvSafetyPlugin(envSafety) {
|
|
|
1193
1222
|
//#region src/plugin-assets.ts
|
|
1194
1223
|
const PRACHT_CLIENT_MODULE_ID = "virtual:pracht/client";
|
|
1195
1224
|
const PRACHT_SERVER_MODULE_ID = "virtual:pracht/server";
|
|
1225
|
+
const PRACHT_DEV_MODULE_ID = "virtual:pracht/dev-metadata";
|
|
1196
1226
|
const PRACHT_ISLANDS_CLIENT_MODULE_ID = "virtual:pracht/islands-client";
|
|
1197
1227
|
const PRACHT_CAPABILITIES_MODULE_ID = "virtual:pracht/capabilities";
|
|
1198
1228
|
const PRACHT_WEBMCP_MODULE_ID = "virtual:pracht/webmcp";
|
|
@@ -1258,6 +1288,9 @@ function isClientModule(id) {
|
|
|
1258
1288
|
function isServerModule(id) {
|
|
1259
1289
|
return id === "virtual:pracht/server" || id.endsWith("virtual:pracht/server");
|
|
1260
1290
|
}
|
|
1291
|
+
function isDevModule(id) {
|
|
1292
|
+
return id === "virtual:pracht/dev-metadata" || id.endsWith("virtual:pracht/dev-metadata");
|
|
1293
|
+
}
|
|
1261
1294
|
function isIslandsClientModule(id) {
|
|
1262
1295
|
return id === "virtual:pracht/islands-client" || id === "/@pracht/islands.js" || id.endsWith("virtual:pracht/islands-client");
|
|
1263
1296
|
}
|
|
@@ -1891,6 +1924,23 @@ function createPrachtServerModuleSource(options = {}, buildOptions = {}) {
|
|
|
1891
1924
|
return source.join("\n");
|
|
1892
1925
|
}
|
|
1893
1926
|
/**
|
|
1927
|
+
* Adapter-neutral app metadata used by development tooling. Keeping this
|
|
1928
|
+
* separate from the server entry avoids evaluating worker-only imports (for
|
|
1929
|
+
* example `cloudflare:workers`) in Vite's Node SSR environment.
|
|
1930
|
+
*/
|
|
1931
|
+
function createPrachtDevModuleSource(options = {}, buildOptions = {}) {
|
|
1932
|
+
const resolved = resolveOptions(options);
|
|
1933
|
+
return [
|
|
1934
|
+
"import { resolveApp } from \"@pracht/core/server\";",
|
|
1935
|
+
resolved.pagesDir ? generatePagesAppInlineSource(resolved, buildOptions.root) : `import { app } from ${JSON.stringify(resolved.appFile)};`,
|
|
1936
|
+
"",
|
|
1937
|
+
createPrachtRegistryModuleSource(resolved),
|
|
1938
|
+
"",
|
|
1939
|
+
"export const resolvedApp = resolveApp(app);",
|
|
1940
|
+
""
|
|
1941
|
+
].join("\n");
|
|
1942
|
+
}
|
|
1943
|
+
/**
|
|
1894
1944
|
* Fill llms.txt title/description from the app's package.json when the user
|
|
1895
1945
|
* did not set them explicitly. Returns null when the feature is disabled so
|
|
1896
1946
|
* the server module codegen stays byte-for-byte unchanged.
|
|
@@ -1995,6 +2045,7 @@ function generatePagesAppInlineSource(options, root = process.cwd()) {
|
|
|
1995
2045
|
//#region src/plugin-dev-ssr.ts
|
|
1996
2046
|
const BODYLESS_METHODS = new Set(["GET", "HEAD"]);
|
|
1997
2047
|
const DEFAULT_MAX_BODY_SIZE = 1024 * 1024;
|
|
2048
|
+
const CSS_MODULE_URL_RE = /\.(?:css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/;
|
|
1998
2049
|
const DEVTOOLS_JSON_PATH = "/_pracht.json";
|
|
1999
2050
|
const LLMS_TXT_PATH = "/llms.txt";
|
|
2000
2051
|
function createDevSSRMiddleware(server, options = {}) {
|
|
@@ -2080,6 +2131,154 @@ function createDevSSRMiddleware(server, options = {}) {
|
|
|
2080
2131
|
};
|
|
2081
2132
|
}
|
|
2082
2133
|
/**
|
|
2134
|
+
* Build the development equivalent of the production CSS manifest for the
|
|
2135
|
+
* current route. Vite turns CSS imports into client-side style injection by
|
|
2136
|
+
* default; resolving the same imports through the active server environment
|
|
2137
|
+
* graphs lets pracht put real stylesheet links in the initial document and
|
|
2138
|
+
* avoid a first-paint FOUC.
|
|
2139
|
+
*/
|
|
2140
|
+
async function createDevCssManifest(server, options) {
|
|
2141
|
+
const route = options.matchAppRoute(options.app, options.pathname)?.route ?? options.app.notFound;
|
|
2142
|
+
if (!route) return {};
|
|
2143
|
+
const manifest = {};
|
|
2144
|
+
const modules = [...route.shellFile ? [{
|
|
2145
|
+
file: route.shellFile,
|
|
2146
|
+
registry: options.registry.shellModules
|
|
2147
|
+
}] : [], {
|
|
2148
|
+
file: route.file,
|
|
2149
|
+
registry: options.registry.routeModules
|
|
2150
|
+
}];
|
|
2151
|
+
const results = await Promise.all(modules.map(async ({ file, registry }) => {
|
|
2152
|
+
if (!registry) return {
|
|
2153
|
+
file,
|
|
2154
|
+
urls: []
|
|
2155
|
+
};
|
|
2156
|
+
const moduleKey = findRegistryModuleKey(registry, file);
|
|
2157
|
+
if (!moduleKey) return {
|
|
2158
|
+
file,
|
|
2159
|
+
urls: []
|
|
2160
|
+
};
|
|
2161
|
+
const entries = await Promise.all(Object.values(server.environments).map((environment) => environment.moduleGraph.getModuleByUrl(moduleKey)));
|
|
2162
|
+
return {
|
|
2163
|
+
file,
|
|
2164
|
+
urls: [...new Set(entries.flatMap((entry) => collectDevCssUrls(entry)))]
|
|
2165
|
+
};
|
|
2166
|
+
}));
|
|
2167
|
+
for (const { file, urls } of results) if (urls.length > 0) manifest[file] = urls;
|
|
2168
|
+
return manifest;
|
|
2169
|
+
}
|
|
2170
|
+
function findRegistryModuleKey(modules, file) {
|
|
2171
|
+
if (!modules) return void 0;
|
|
2172
|
+
if (file in modules) return file;
|
|
2173
|
+
const suffix = `/${file.split("?")[0].replace(/\\/g, "/").replace(/^\.?\//, "")}`;
|
|
2174
|
+
return Object.keys(modules).find((key) => key.split("?")[0].replace(/\\/g, "/").endsWith(suffix));
|
|
2175
|
+
}
|
|
2176
|
+
function collectDevCssUrls(entry) {
|
|
2177
|
+
if (!entry) return [];
|
|
2178
|
+
const urls = /* @__PURE__ */ new Set();
|
|
2179
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2180
|
+
const pending = [entry];
|
|
2181
|
+
while (pending.length > 0) {
|
|
2182
|
+
const module = pending.pop();
|
|
2183
|
+
if (visited.has(module)) continue;
|
|
2184
|
+
visited.add(module);
|
|
2185
|
+
if ((module.type === "css" || CSS_MODULE_URL_RE.test(module.url)) && !/[?&](?:inline|raw|url)(?:[=&]|$)/.test(module.url)) urls.add(module.url);
|
|
2186
|
+
pending.push(...[...module.importedModules].reverse());
|
|
2187
|
+
}
|
|
2188
|
+
return [...urls];
|
|
2189
|
+
}
|
|
2190
|
+
function injectDevCssLinks(html, manifest) {
|
|
2191
|
+
if (!html.includes("</head>")) return html;
|
|
2192
|
+
const tags = [...new Set(Object.values(manifest).flat())].map((url) => escapeHtmlAttribute(url)).filter((escapedUrl) => !html.includes(`href="${escapedUrl}"`)).map((escapedUrl) => `<link rel="stylesheet" href="${escapedUrl}">`);
|
|
2193
|
+
if (tags.length === 0) return html;
|
|
2194
|
+
return html.replace("</head>", ` ${tags.join("\n ")}\n </head>`);
|
|
2195
|
+
}
|
|
2196
|
+
async function injectDevCssForPath(server, path, html) {
|
|
2197
|
+
return injectDevCssLinks(html, await createDevCssManifest(server, await resolveDevCssContextForPath(server, path)));
|
|
2198
|
+
}
|
|
2199
|
+
async function resolveDevCssContextForPath(server, path) {
|
|
2200
|
+
const [framework, serverMod] = await Promise.all([server.ssrLoadModule("@pracht/core/server"), server.ssrLoadModule(PRACHT_DEV_MODULE_ID)]);
|
|
2201
|
+
const pathname = new URL(path, "http://localhost").pathname;
|
|
2202
|
+
return {
|
|
2203
|
+
app: serverMod.resolvedApp,
|
|
2204
|
+
matchAppRoute: framework.matchAppRoute,
|
|
2205
|
+
pathname,
|
|
2206
|
+
registry: serverMod.registry
|
|
2207
|
+
};
|
|
2208
|
+
}
|
|
2209
|
+
/**
|
|
2210
|
+
* Adapter-owned dev servers (for example Cloudflare's worker runtime) bypass
|
|
2211
|
+
* Vite's HTML transform hooks. Install this before the adapter middleware so
|
|
2212
|
+
* document responses still receive the same parser-blocking stylesheet links.
|
|
2213
|
+
*/
|
|
2214
|
+
function createDevCssInjectionMiddleware(server) {
|
|
2215
|
+
let warned = false;
|
|
2216
|
+
return (req, res, next) => {
|
|
2217
|
+
const method = (req.method ?? "GET").toUpperCase();
|
|
2218
|
+
const accept = readRequestHeader(req.headers.accept).toLowerCase();
|
|
2219
|
+
if (method !== "GET" || !accept.includes("text/html")) {
|
|
2220
|
+
next();
|
|
2221
|
+
return;
|
|
2222
|
+
}
|
|
2223
|
+
const contextPromise = resolveDevCssContextForPath(server, req.url ?? "/").catch((error) => {
|
|
2224
|
+
if (!warned) {
|
|
2225
|
+
warned = true;
|
|
2226
|
+
server.config.logger.warn(`[pracht] Could not discover development stylesheets: ${error instanceof Error ? error.message : String(error)}`);
|
|
2227
|
+
}
|
|
2228
|
+
return null;
|
|
2229
|
+
});
|
|
2230
|
+
const chunks = [];
|
|
2231
|
+
const originalEnd = res.end.bind(res);
|
|
2232
|
+
const originalWriteHead = res.writeHead.bind(res);
|
|
2233
|
+
res.writeHead = ((statusCode, ...args) => {
|
|
2234
|
+
res.removeHeader("content-length");
|
|
2235
|
+
return Reflect.apply(originalWriteHead, res, [statusCode, ...args.map(stripContentLengthHeader)]);
|
|
2236
|
+
});
|
|
2237
|
+
res.write = ((chunk, encodingOrCallback, callback) => {
|
|
2238
|
+
chunks.push(toBuffer(chunk, encodingOrCallback));
|
|
2239
|
+
(typeof encodingOrCallback === "function" ? encodingOrCallback : typeof callback === "function" ? callback : void 0)?.();
|
|
2240
|
+
return true;
|
|
2241
|
+
});
|
|
2242
|
+
res.end = ((chunk, encodingOrCallback, callback) => {
|
|
2243
|
+
if (chunk != null) chunks.push(toBuffer(chunk, encodingOrCallback));
|
|
2244
|
+
const done = typeof encodingOrCallback === "function" ? encodingOrCallback : typeof callback === "function" ? callback : void 0;
|
|
2245
|
+
(async () => {
|
|
2246
|
+
const body = Buffer.concat(chunks);
|
|
2247
|
+
if (!String(res.getHeader("content-type") ?? "").includes("text/html")) {
|
|
2248
|
+
originalEnd(body, done);
|
|
2249
|
+
return;
|
|
2250
|
+
}
|
|
2251
|
+
try {
|
|
2252
|
+
const context = await contextPromise;
|
|
2253
|
+
const manifest = context ? await createDevCssManifest(server, context) : null;
|
|
2254
|
+
originalEnd(manifest ? injectDevCssLinks(body.toString("utf-8"), manifest) : body.toString("utf-8"), done);
|
|
2255
|
+
} catch {
|
|
2256
|
+
originalEnd(body, done);
|
|
2257
|
+
}
|
|
2258
|
+
})();
|
|
2259
|
+
return res;
|
|
2260
|
+
});
|
|
2261
|
+
next();
|
|
2262
|
+
};
|
|
2263
|
+
}
|
|
2264
|
+
function toBuffer(chunk, encoding) {
|
|
2265
|
+
if (Buffer.isBuffer(chunk)) return chunk;
|
|
2266
|
+
if (chunk instanceof Uint8Array) return Buffer.from(chunk);
|
|
2267
|
+
return Buffer.from(String(chunk), typeof encoding === "string" ? encoding : void 0);
|
|
2268
|
+
}
|
|
2269
|
+
function stripContentLengthHeader(value) {
|
|
2270
|
+
if (Array.isArray(value)) {
|
|
2271
|
+
const headers = [];
|
|
2272
|
+
for (let index = 0; index < value.length; index += 2) if (String(value[index]).toLowerCase() !== "content-length") headers.push(value[index], value[index + 1]);
|
|
2273
|
+
return headers;
|
|
2274
|
+
}
|
|
2275
|
+
if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).filter(([name]) => name.toLowerCase() !== "content-length"));
|
|
2276
|
+
return value;
|
|
2277
|
+
}
|
|
2278
|
+
function escapeHtmlAttribute(value) {
|
|
2279
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
2280
|
+
}
|
|
2281
|
+
/**
|
|
2083
2282
|
* Serve the dev-only `/_pracht` devtools page (or `/_pracht.json`) built from
|
|
2084
2283
|
* the same resolved app graph that `pracht inspect` reports.
|
|
2085
2284
|
*/
|
|
@@ -2295,9 +2494,12 @@ function pracht(options = {}) {
|
|
|
2295
2494
|
const isSSRBuild = env.isSsrBuild;
|
|
2296
2495
|
const configRoot = _config.root ?? process.cwd();
|
|
2297
2496
|
const wantsIslandsEntry = env.command === "build" && !isSSRBuild && existsSync(resolveConfigPath(configRoot, resolved.islandsDir));
|
|
2497
|
+
const envDir = _config.envDir ? resolve(configRoot, _config.envDir) : configRoot;
|
|
2498
|
+
const publicEnvDefine = JSON.stringify(loadEnv(env.mode, envDir, PUBLIC_ENV_PREFIX));
|
|
2298
2499
|
return {
|
|
2299
2500
|
appType: "custom",
|
|
2300
2501
|
envPrefix: ["VITE_", PUBLIC_ENV_PREFIX],
|
|
2502
|
+
define: { __PRACHT_PUBLIC_ENV__: publicEnvDefine },
|
|
2301
2503
|
...isSSRBuild ? {} : { build: { rollupOptions: {
|
|
2302
2504
|
...wantsIslandsEntry ? { input: [PRACHT_ISLANDS_CLIENT_MODULE_ID] } : {},
|
|
2303
2505
|
output: { manualChunks(id) {
|
|
@@ -2321,6 +2523,7 @@ function pracht(options = {}) {
|
|
|
2321
2523
|
resolveId(id, importer, resolveIdOptions) {
|
|
2322
2524
|
if (isIslandsClientModule(id)) return PRACHT_ISLANDS_CLIENT_MODULE_ID;
|
|
2323
2525
|
if (isClientModule(id)) return PRACHT_CLIENT_MODULE_ID;
|
|
2526
|
+
if (isDevModule(id)) return PRACHT_DEV_MODULE_ID;
|
|
2324
2527
|
if (isServerModule(id)) return PRACHT_SERVER_MODULE_ID;
|
|
2325
2528
|
if (isCapabilitiesModule(id)) return PRACHT_CAPABILITIES_MODULE_ID;
|
|
2326
2529
|
if (isWebmcpModule(id)) return PRACHT_WEBMCP_MODULE_ID;
|
|
@@ -2330,6 +2533,7 @@ function pracht(options = {}) {
|
|
|
2330
2533
|
load(id) {
|
|
2331
2534
|
if (isIslandsClientModule(id)) return createPrachtIslandsClientModuleSource(resolved, { root });
|
|
2332
2535
|
if (isClientModule(id)) return createPrachtClientModuleSource(resolved, { root });
|
|
2536
|
+
if (isDevModule(id)) return createPrachtDevModuleSource(resolved, { root });
|
|
2333
2537
|
if (isServerModule(id)) return createPrachtServerModuleSource(resolved, {
|
|
2334
2538
|
root,
|
|
2335
2539
|
isBuild
|
|
@@ -2350,7 +2554,10 @@ function pracht(options = {}) {
|
|
|
2350
2554
|
},
|
|
2351
2555
|
configureServer(server) {
|
|
2352
2556
|
if (isPagesMode) watchPagesDirectory(server, resolved, root);
|
|
2353
|
-
if (resolved.adapter.ownsDevServer)
|
|
2557
|
+
if (resolved.adapter.ownsDevServer) {
|
|
2558
|
+
server.middlewares.use(createDevCssInjectionMiddleware(server));
|
|
2559
|
+
return;
|
|
2560
|
+
}
|
|
2354
2561
|
return () => {
|
|
2355
2562
|
server.middlewares.use(createDevSSRMiddleware(server, {
|
|
2356
2563
|
llmsTxt: !!resolved.llmsTxt,
|
|
@@ -2358,6 +2565,14 @@ function pracht(options = {}) {
|
|
|
2358
2565
|
}));
|
|
2359
2566
|
};
|
|
2360
2567
|
},
|
|
2568
|
+
async transformIndexHtml(html, context) {
|
|
2569
|
+
if (isBuild || !context.server || !html.includes("</head>")) return html;
|
|
2570
|
+
try {
|
|
2571
|
+
return await injectDevCssForPath(context.server, context.path, html);
|
|
2572
|
+
} catch {
|
|
2573
|
+
return html;
|
|
2574
|
+
}
|
|
2575
|
+
},
|
|
2361
2576
|
handleHotUpdate({ file, server }) {
|
|
2362
2577
|
const serverRoot = toPosixPath(server.config.root);
|
|
2363
2578
|
const normalizedFile = toPosixPath(file);
|
|
@@ -2382,6 +2597,8 @@ function pracht(options = {}) {
|
|
|
2382
2597
|
].some((dir) => relative.startsWith(dir))) {
|
|
2383
2598
|
const serverMod = server.moduleGraph.getModuleById(PRACHT_SERVER_MODULE_ID);
|
|
2384
2599
|
if (serverMod) server.moduleGraph.invalidateModule(serverMod);
|
|
2600
|
+
const devMod = server.moduleGraph.getModuleById(PRACHT_DEV_MODULE_ID);
|
|
2601
|
+
if (devMod) server.moduleGraph.invalidateModule(devMod);
|
|
2385
2602
|
if (relative.startsWith(resolved.routesDir)) {
|
|
2386
2603
|
const clientMod = server.moduleGraph.getModuleById(PRACHT_CLIENT_MODULE_ID);
|
|
2387
2604
|
if (clientMod) server.moduleGraph.invalidateModule(clientMod);
|
|
@@ -2520,8 +2737,10 @@ function watchPagesDirectory(server, resolved, root) {
|
|
|
2520
2737
|
function invalidateVirtualModules(server) {
|
|
2521
2738
|
const clientMod = server.moduleGraph.getModuleById(PRACHT_CLIENT_MODULE_ID);
|
|
2522
2739
|
const serverMod = server.moduleGraph.getModuleById(PRACHT_SERVER_MODULE_ID);
|
|
2740
|
+
const devMod = server.moduleGraph.getModuleById(PRACHT_DEV_MODULE_ID);
|
|
2523
2741
|
if (clientMod) server.moduleGraph.invalidateModule(clientMod);
|
|
2524
2742
|
if (serverMod) server.moduleGraph.invalidateModule(serverMod);
|
|
2743
|
+
if (devMod) server.moduleGraph.invalidateModule(devMod);
|
|
2525
2744
|
}
|
|
2526
2745
|
const ROUTE_FILE_EXTENSIONS = new Set([
|
|
2527
2746
|
".ts",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pracht/vite-plugin",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Vite plugin for Pracht apps with virtual modules, dev SSR, prerendering, route inspection, and multi-adapter builds.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pracht",
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@preact/preset-vite": "^2.10.5",
|
|
46
46
|
"@prefresh/vite": "^2.0.0",
|
|
47
|
-
"@pracht/adapter-node": "0.3.
|
|
48
|
-
"@pracht/
|
|
49
|
-
"@pracht/
|
|
50
|
-
"@pracht/
|
|
47
|
+
"@pracht/adapter-node": "0.3.5",
|
|
48
|
+
"@pracht/capabilities": "0.1.0",
|
|
49
|
+
"@pracht/core": "0.11.2",
|
|
50
|
+
"@pracht/preact-ssr-precompile": "0.1.2"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"vite": "^8.0.0"
|