@askrjs/vite 0.0.12 → 0.0.14
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 +7 -0
- package/dist/image-node.d.ts +1 -1
- package/dist/{image-types-BQpLyBLt.d.ts → image-types-BnNQOZXL.d.ts} +8 -0
- package/dist/image.d.ts +1 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +85 -19
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +40 -0
- package/dist/server.js +39 -2
- package/dist/server.js.map +1 -1
- package/package.json +15 -13
package/README.md
CHANGED
|
@@ -29,6 +29,13 @@ export default defineConfig({
|
|
|
29
29
|
});
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
`askr({ optimizeTemplates: true })` optionally hoists repeated static
|
|
33
|
+
`class`, `className`, and `style` literals from parsed JSX-runtime property
|
|
34
|
+
nodes. The optimizer never scans or rewrites unrelated strings, template
|
|
35
|
+
literals, or ordinary objects. JSX/TSX transform failures are reported through
|
|
36
|
+
Vite with the source filename and parser detail instead of falling through to a
|
|
37
|
+
later build stage.
|
|
38
|
+
|
|
32
39
|
## Responsive images
|
|
33
40
|
|
|
34
41
|
Responsive image processing is opt in and requires the optional `sharp` peer:
|
package/dist/image-node.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { a as ImageProps, c as ResponsiveImageSource, i as ImagePipelineOptions, n as ImageOptions, o as ImageQualityOptions, r as ImageOutputFormat, s as ResponsiveImage, t as ImageFit } from "./image-types-
|
|
2
|
+
import { a as ImageProps, c as ResponsiveImageSource, i as ImagePipelineOptions, n as ImageOptions, o as ImageQualityOptions, r as ImageOutputFormat, s as ResponsiveImage, t as ImageFit } from "./image-types-BnNQOZXL.js";
|
|
3
3
|
import { Image } from "./image.js";
|
|
4
4
|
//#region src/image-node.d.ts
|
|
5
5
|
/** Resolve the exact responsive metadata produced by the preceding client build. */
|
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
|
|
2
2
|
//#region src/image-types.d.ts
|
|
3
|
+
/** Output image formats the pipeline can emit; `"source"` keeps the original format. */
|
|
3
4
|
type ImageOutputFormat = "avif" | "webp" | "source";
|
|
5
|
+
/** Resize strategy: `"inside"` fits within bounds, `"cover"` crops to fill. */
|
|
4
6
|
type ImageFit = "inside" | "cover";
|
|
7
|
+
/** Per-format quality settings (0-100) used when encoding output images. */
|
|
5
8
|
interface ImageQualityOptions {
|
|
6
9
|
avif?: number;
|
|
7
10
|
webp?: number;
|
|
8
11
|
jpeg?: number;
|
|
9
12
|
png?: number;
|
|
10
13
|
}
|
|
14
|
+
/** Plugin-level defaults applied to every `image()` declaration. */
|
|
11
15
|
interface ImagePipelineOptions {
|
|
12
16
|
widths?: readonly number[];
|
|
13
17
|
formats?: readonly ImageOutputFormat[];
|
|
14
18
|
quality?: ImageQualityOptions;
|
|
15
19
|
}
|
|
20
|
+
/** Per-declaration overrides for a single `image()` call. */
|
|
16
21
|
interface ImageOptions {
|
|
17
22
|
widths?: readonly number[];
|
|
18
23
|
formats?: readonly ImageOutputFormat[];
|
|
@@ -26,10 +31,12 @@ interface ImageOptions {
|
|
|
26
31
|
/** Sharp-compatible crop position. Defaults to centre. */
|
|
27
32
|
position?: string;
|
|
28
33
|
}
|
|
34
|
+
/** A single `<source>` candidate within a {@link ResponsiveImage}. */
|
|
29
35
|
interface ResponsiveImageSource {
|
|
30
36
|
type: string;
|
|
31
37
|
srcset: string;
|
|
32
38
|
}
|
|
39
|
+
/** Build-time-resolved metadata for a declared image, ready to render. */
|
|
33
40
|
interface ResponsiveImage {
|
|
34
41
|
readonly __askrImage: true;
|
|
35
42
|
readonly src: string;
|
|
@@ -38,6 +45,7 @@ interface ResponsiveImage {
|
|
|
38
45
|
readonly height: number;
|
|
39
46
|
readonly sources: readonly ResponsiveImageSource[];
|
|
40
47
|
}
|
|
48
|
+
/** Props accepted by the {@link Image} component. */
|
|
41
49
|
interface ImageProps {
|
|
42
50
|
image: ResponsiveImage;
|
|
43
51
|
alt: string;
|
package/dist/image.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { a as ImageProps, c as ResponsiveImageSource, i as ImagePipelineOptions, n as ImageOptions, o as ImageQualityOptions, r as ImageOutputFormat, s as ResponsiveImage, t as ImageFit } from "./image-types-
|
|
2
|
+
import { a as ImageProps, c as ResponsiveImageSource, i as ImagePipelineOptions, n as ImageOptions, o as ImageQualityOptions, r as ImageOutputFormat, s as ResponsiveImage, t as ImageFit } from "./image-types-BnNQOZXL.js";
|
|
3
3
|
import { jsxs } from "@askrjs/askr/jsx-runtime";
|
|
4
4
|
//#region src/image.d.ts
|
|
5
5
|
/** Declare a source-controlled image for the opt-in Vite image pipeline. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
|
|
2
|
-
import { i as ImagePipelineOptions } from "./image-types-
|
|
2
|
+
import { i as ImagePipelineOptions } from "./image-types-BnNQOZXL.js";
|
|
3
3
|
//#region src/jsx-plugin.d.ts
|
|
4
|
+
/** Options accepted by {@link askrVitePlugin}. */
|
|
4
5
|
interface AskrVitePluginOptions {
|
|
6
|
+
/** Transform `.jsx`/`.tsx` files with the Askr JSX runtime. Defaults to `true`. */
|
|
5
7
|
transformJsx?: boolean;
|
|
8
|
+
/** Hoist repeated JSX class/style literals using parsed compiled output. Defaults to `false`. */
|
|
6
9
|
optimizeTemplates?: boolean;
|
|
7
10
|
ssrPrecompile?: boolean;
|
|
8
11
|
/** Opt into declared responsive image transforms. */
|
|
@@ -18,6 +21,16 @@ interface AskrVitePluginOptions {
|
|
|
18
21
|
interface AskrVitePlugin {
|
|
19
22
|
readonly name: "askr:vite";
|
|
20
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Create the Askr Vite plugin, which transforms Askr JSX/TSX with oxc, wires
|
|
26
|
+
* up dependency pre-bundling and aliasing for `@askrjs/askr`, and optionally
|
|
27
|
+
* runs the responsive image pipeline and template optimizer.
|
|
28
|
+
* JSX transform failures are reported through the active Vite/Rollup plugin
|
|
29
|
+
* context with the source file and original transform detail.
|
|
30
|
+
*
|
|
31
|
+
* @param options Plugin configuration; all fields are optional.
|
|
32
|
+
* @returns A Vite-compatible plugin object exposing the `askr:vite` name.
|
|
33
|
+
*/
|
|
21
34
|
declare function askrVitePlugin(options?: AskrVitePluginOptions): AskrVitePlugin;
|
|
22
35
|
//#endregion
|
|
23
36
|
export { type AskrVitePlugin, type AskrVitePluginOptions, type ImagePipelineOptions, askrVitePlugin as askr, askrVitePlugin, askrVitePlugin as default };
|
package/dist/index.js
CHANGED
|
@@ -1,27 +1,85 @@
|
|
|
1
1
|
|
|
2
2
|
import { n as normalizeImageOptions, r as IMAGE_METADATA_PATH, t as normalizeDeclarationOptions } from "./image-options-B-QnEqPc.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
|
+
import { Visitor, parseSync } from "oxc-parser";
|
|
4
5
|
import fs from "node:fs/promises";
|
|
5
6
|
import path from "node:path";
|
|
6
7
|
import { createHash } from "node:crypto";
|
|
7
8
|
//#region src/template-optimizer.ts
|
|
9
|
+
const OPTIMIZED_PROPS = /* @__PURE__ */ new Set([
|
|
10
|
+
"class",
|
|
11
|
+
"className",
|
|
12
|
+
"style"
|
|
13
|
+
]);
|
|
14
|
+
const JSX_RUNTIME_SOURCE = "@askrjs/askr/jsx-runtime";
|
|
15
|
+
const JSX_FACTORIES = /* @__PURE__ */ new Set([
|
|
16
|
+
"jsx",
|
|
17
|
+
"jsxs",
|
|
18
|
+
"jsxDEV"
|
|
19
|
+
]);
|
|
20
|
+
function importedName(specifier) {
|
|
21
|
+
return specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value;
|
|
22
|
+
}
|
|
23
|
+
function collectRuntimeFactories(program) {
|
|
24
|
+
const factories = /* @__PURE__ */ new Set();
|
|
25
|
+
for (const statement of program.body) {
|
|
26
|
+
if (statement.type !== "ImportDeclaration" || statement.source.value !== JSX_RUNTIME_SOURCE) continue;
|
|
27
|
+
for (const specifier of statement.specifiers) if (specifier.type === "ImportSpecifier" && JSX_FACTORIES.has(String(importedName(specifier)))) factories.add(specifier.local.name);
|
|
28
|
+
}
|
|
29
|
+
return factories;
|
|
30
|
+
}
|
|
31
|
+
function collectCandidate(property, code, candidates) {
|
|
32
|
+
if (property.kind !== "init" || property.computed || property.method || property.key.type !== "Identifier" || !OPTIMIZED_PROPS.has(property.key.name) || property.value.type !== "Literal" || typeof property.value.value !== "string") return;
|
|
33
|
+
const literal = code.slice(property.value.start, property.value.end);
|
|
34
|
+
const cacheKey = `${property.key.name}:${literal}`;
|
|
35
|
+
const group = candidates.get(cacheKey) ?? [];
|
|
36
|
+
group.push({
|
|
37
|
+
literal,
|
|
38
|
+
start: property.value.start,
|
|
39
|
+
end: property.value.end
|
|
40
|
+
});
|
|
41
|
+
candidates.set(cacheKey, group);
|
|
42
|
+
}
|
|
8
43
|
function optimizeTemplateOutput(code) {
|
|
9
|
-
const
|
|
44
|
+
const parsed = parseSync("askr-compiled.js", code, {
|
|
45
|
+
lang: "js",
|
|
46
|
+
sourceType: "module"
|
|
47
|
+
});
|
|
48
|
+
if (parsed.errors.length > 0) return code;
|
|
49
|
+
const runtimeFactories = collectRuntimeFactories(parsed.program);
|
|
50
|
+
if (runtimeFactories.size === 0) return code;
|
|
51
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
52
|
+
const identifiers = /* @__PURE__ */ new Set();
|
|
53
|
+
new Visitor({
|
|
54
|
+
Identifier(identifier) {
|
|
55
|
+
identifiers.add(identifier.name);
|
|
56
|
+
},
|
|
57
|
+
CallExpression(call) {
|
|
58
|
+
if (call.callee.type !== "Identifier" || !runtimeFactories.has(call.callee.name) || call.arguments[1]?.type !== "ObjectExpression") return;
|
|
59
|
+
for (const property of call.arguments[1].properties) if (property.type === "Property") collectCandidate(property, code, candidates);
|
|
60
|
+
}
|
|
61
|
+
}).visit(parsed.program);
|
|
62
|
+
const declarations = [];
|
|
63
|
+
const replacements = [];
|
|
10
64
|
let hoistIndex = 0;
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
let identifier
|
|
14
|
-
|
|
15
|
-
if (code.split(fullMatch).length - 1 < 2) return fullMatch;
|
|
65
|
+
for (const group of candidates.values()) {
|
|
66
|
+
if (group.length < 2) continue;
|
|
67
|
+
let identifier;
|
|
68
|
+
do
|
|
16
69
|
identifier = `__askrStaticLiteral${hoistIndex++}`;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
70
|
+
while (identifiers.has(identifier));
|
|
71
|
+
identifiers.add(identifier);
|
|
72
|
+
declarations.push(`const ${identifier} = ${group[0].literal};`);
|
|
73
|
+
for (const candidate of group) replacements.push({
|
|
74
|
+
start: candidate.start,
|
|
75
|
+
end: candidate.end,
|
|
76
|
+
identifier
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (declarations.length === 0) return code;
|
|
80
|
+
let optimized = code;
|
|
81
|
+
for (const replacement of replacements.sort((left, right) => right.start - left.start)) optimized = optimized.slice(0, replacement.start) + replacement.identifier + optimized.slice(replacement.end);
|
|
82
|
+
return `${declarations.join("\n")}\n${optimized}`;
|
|
25
83
|
}
|
|
26
84
|
//#endregion
|
|
27
85
|
//#region src/image-lexical.ts
|
|
@@ -582,6 +640,16 @@ async function loadTransformWithOxc() {
|
|
|
582
640
|
})();
|
|
583
641
|
return transformWithOxcPromise;
|
|
584
642
|
}
|
|
643
|
+
/**
|
|
644
|
+
* Create the Askr Vite plugin, which transforms Askr JSX/TSX with oxc, wires
|
|
645
|
+
* up dependency pre-bundling and aliasing for `@askrjs/askr`, and optionally
|
|
646
|
+
* runs the responsive image pipeline and template optimizer.
|
|
647
|
+
* JSX transform failures are reported through the active Vite/Rollup plugin
|
|
648
|
+
* context with the source file and original transform detail.
|
|
649
|
+
*
|
|
650
|
+
* @param options Plugin configuration; all fields are optional.
|
|
651
|
+
* @returns A Vite-compatible plugin object exposing the `askr:vite` name.
|
|
652
|
+
*/
|
|
585
653
|
function askrVitePlugin(options = {}) {
|
|
586
654
|
const shouldTransform = options.transformJsx ?? true;
|
|
587
655
|
const shouldOptimizeTemplates = options.optimizeTemplates ?? false;
|
|
@@ -656,11 +724,9 @@ function askrVitePlugin(options = {}) {
|
|
|
656
724
|
code: shouldOptimizeTemplates ? optimizeTemplateOutput(result.code) : result.code,
|
|
657
725
|
map: result.map
|
|
658
726
|
};
|
|
659
|
-
} catch {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
map: null
|
|
663
|
-
} : null;
|
|
727
|
+
} catch (error) {
|
|
728
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
729
|
+
this.error(`@askrjs/vite failed to transform ${id}: ${detail}`);
|
|
664
730
|
}
|
|
665
731
|
},
|
|
666
732
|
async writeBundle() {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["mime","#options","#processed","#sharpLoader","#config"],"sources":["../src/template-optimizer.ts","../src/image-lexical.ts","../src/image-inspection.ts","../src/image-transform.ts","../src/image-pipeline.ts","../src/jsx-plugin.ts"],"sourcesContent":["export function optimizeTemplateOutput(code: string): string {\n const hoists = new Map<string, string>();\n let hoistIndex = 0;\n const optimized = code.replace(\n /\\b(class|className|style):\\s*(\"([^\"\\\\]|\\\\.)*\")/g,\n (fullMatch: string, key: string, literal: string) => {\n const cacheKey = `${key}:${literal}`;\n let identifier = hoists.get(cacheKey);\n if (!identifier) {\n if (code.split(fullMatch).length - 1 < 2) return fullMatch;\n identifier = `__askrStaticLiteral${hoistIndex++}`;\n hoists.set(cacheKey, identifier);\n }\n return `${key}: ${identifier}`;\n },\n );\n if (hoists.size === 0) return code;\n const declarations = Array.from(hoists.entries()).map(([cacheKey, name]) => {\n const literal = cacheKey.slice(cacheKey.indexOf(\":\") + 1);\n return `const ${name} = ${literal};`;\n });\n return `${declarations.join(\"\\n\")}\\n${optimized}`;\n}\n","const IMAGE_IMPORT = /from\\s+[\"']@askrjs\\/vite\\/image[\"']/g;\n\nfunction lexicalCodeMask(source: string): Uint8Array {\n const mask = new Uint8Array(source.length);\n let state: \"code\" | \"single\" | \"double\" | \"template\" | \"line-comment\" | \"block-comment\" = \"code\";\n let escaped = false;\n for (let index = 0; index < source.length; index += 1) {\n const character = source[index]!;\n const next = source[index + 1];\n if (state === \"code\") {\n if (character === \"/\" && next === \"/\") {\n state = \"line-comment\";\n index += 1;\n } else if (character === \"/\" && next === \"*\") {\n state = \"block-comment\";\n index += 1;\n } else if (character === \"'\") state = \"single\";\n else if (character === '\"') state = \"double\";\n else if (character === \"`\") state = \"template\";\n else mask[index] = 1;\n continue;\n }\n if (state === \"line-comment\") {\n if (character === \"\\n\" || character === \"\\r\") {\n state = \"code\";\n mask[index] = 1;\n }\n continue;\n }\n if (state === \"block-comment\") {\n if (character === \"*\" && next === \"/\") {\n state = \"code\";\n index += 1;\n }\n continue;\n }\n if (escaped) escaped = false;\n else if (character === \"\\\\\") escaped = true;\n else if (\n (state === \"single\" && character === \"'\") ||\n (state === \"double\" && character === '\"') ||\n (state === \"template\" && character === \"`\")\n ) {\n state = \"code\";\n }\n }\n return mask;\n}\n\nexport function imageDeclarationMask(code: string): Uint8Array | undefined {\n const mask = lexicalCodeMask(code);\n IMAGE_IMPORT.lastIndex = 0;\n for (let match = IMAGE_IMPORT.exec(code); match; match = IMAGE_IMPORT.exec(code)) {\n if (mask[match.index]) return mask;\n }\n return undefined;\n}\n","export type AssetFormat = \"avif\" | \"webp\" | \"jpeg\" | \"png\" | \"gif\" | \"svg\";\n\nexport interface SourceInspection {\n width: number;\n height: number;\n format: AssetFormat;\n transformable: boolean;\n animated: boolean;\n}\n\nfunction positiveDimensions(\n width: number,\n height: number,\n format: AssetFormat,\n transformable: boolean,\n animated = false,\n): SourceInspection | undefined {\n return width > 0 && height > 0 ? { width, height, format, transformable, animated } : undefined;\n}\n\nfunction inspectPng(source: Buffer): SourceInspection | undefined {\n if (\n source.length < 24 ||\n !source.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))\n ) {\n return undefined;\n }\n return positiveDimensions(\n source.readUInt32BE(16),\n source.readUInt32BE(20),\n \"png\",\n true,\n source.includes(Buffer.from(\"acTL\")),\n );\n}\n\nfunction inspectGif(source: Buffer): SourceInspection | undefined {\n if (source.length < 10 || !/^GIF8[79]a$/.test(source.subarray(0, 6).toString(\"ascii\"))) {\n return undefined;\n }\n return positiveDimensions(source.readUInt16LE(6), source.readUInt16LE(8), \"gif\", false, true);\n}\n\nfunction exifOrientation(segment: Buffer): number | undefined {\n if (segment.length < 14 || segment.subarray(0, 6).toString(\"binary\") !== \"Exif\\0\\0\") {\n return undefined;\n }\n const tiff = 6;\n const byteOrder = segment.subarray(tiff, tiff + 2).toString(\"ascii\");\n const littleEndian = byteOrder === \"II\";\n if (!littleEndian && byteOrder !== \"MM\") return undefined;\n const read16 = (offset: number): number | undefined => {\n const absolute = tiff + offset;\n if (absolute < tiff || absolute + 2 > segment.length) return undefined;\n return littleEndian ? segment.readUInt16LE(absolute) : segment.readUInt16BE(absolute);\n };\n const read32 = (offset: number): number | undefined => {\n const absolute = tiff + offset;\n if (absolute < tiff || absolute + 4 > segment.length) return undefined;\n return littleEndian ? segment.readUInt32LE(absolute) : segment.readUInt32BE(absolute);\n };\n if (read16(2) !== 42) return undefined;\n const directoryOffset = read32(4);\n if (directoryOffset === undefined) return undefined;\n const entries = read16(directoryOffset);\n if (entries === undefined) return undefined;\n for (let index = 0; index < entries; index += 1) {\n const entry = directoryOffset + 2 + index * 12;\n if (read16(entry) !== 0x0112 || read16(entry + 2) !== 3 || read32(entry + 4) !== 1) {\n continue;\n }\n const orientation = read16(entry + 8);\n return orientation && orientation >= 1 && orientation <= 8 ? orientation : undefined;\n }\n return undefined;\n}\n\nfunction inspectJpeg(source: Buffer): SourceInspection | undefined {\n if (source.length < 4 || source[0] !== 0xff || source[1] !== 0xd8) return undefined;\n const startOfFrame = new Set([\n 0xc0, 0xc1, 0xc2, 0xc3, 0xc5, 0xc6, 0xc7, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf,\n ]);\n let orientation: number | undefined;\n let offset = 2;\n while (offset + 8 < source.length) {\n if (source[offset] !== 0xff) {\n offset += 1;\n continue;\n }\n while (source[offset] === 0xff) offset += 1;\n const marker = source[offset++]!;\n if (marker === 0xd8 || marker === 0xd9 || marker === 0x01) continue;\n if (marker >= 0xd0 && marker <= 0xd7) continue;\n if (offset + 2 > source.length) break;\n const length = source.readUInt16BE(offset);\n if (length < 2 || offset + length > source.length) break;\n if (marker === 0xe1) {\n orientation = exifOrientation(source.subarray(offset + 2, offset + length)) ?? orientation;\n }\n if (startOfFrame.has(marker) && length >= 7) {\n const width = source.readUInt16BE(offset + 5);\n const height = source.readUInt16BE(offset + 3);\n return positiveDimensions(\n orientation !== undefined && orientation >= 5 ? height : width,\n orientation !== undefined && orientation >= 5 ? width : height,\n \"jpeg\",\n true,\n );\n }\n offset += length;\n }\n return undefined;\n}\n\nfunction inspectSvg(source: Buffer): SourceInspection | undefined {\n const openingTag = source\n .subarray(0, 16_384)\n .toString(\"utf8\")\n .match(/<svg\\b[^>]*>/i)?.[0];\n if (!openingTag) return undefined;\n const numberAttribute = (name: string): number | undefined => {\n const value = openingTag.match(new RegExp(`\\\\b${name}\\\\s*=\\\\s*[\"']\\\\s*([0-9.]+)`, \"i\"))?.[1];\n const parsed = value ? Number(value) : Number.NaN;\n return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;\n };\n let width = numberAttribute(\"width\");\n let height = numberAttribute(\"height\");\n const viewBox = openingTag\n .match(/\\bviewBox\\s*=\\s*[\"']\\s*[-+0-9.e]+[ ,]+[-+0-9.e]+[ ,]+([-+0-9.e]+)[ ,]+([-+0-9.e]+)/i)\n ?.slice(1)\n .map(Number);\n if (!width && viewBox?.[0] && viewBox[0] > 0) width = viewBox[0];\n if (!height && viewBox?.[1] && viewBox[1] > 0) height = viewBox[1];\n if (!width && height && viewBox?.[0] && viewBox?.[1]) width = height * (viewBox[0] / viewBox[1]);\n if (!height && width && viewBox?.[0] && viewBox?.[1]) height = width / (viewBox[0] / viewBox[1]);\n return width && height ? positiveDimensions(width, height, \"svg\", false) : undefined;\n}\n\nfunction inspectWebp(source: Buffer): SourceInspection | undefined {\n if (\n source.length < 30 ||\n source.subarray(0, 4).toString(\"ascii\") !== \"RIFF\" ||\n source.subarray(8, 12).toString(\"ascii\") !== \"WEBP\"\n ) {\n return undefined;\n }\n const chunk = source.subarray(12, 16).toString(\"ascii\");\n if (chunk === \"VP8X\") {\n const width = 1 + source.readUIntLE(24, 3);\n const height = 1 + source.readUIntLE(27, 3);\n return positiveDimensions(width, height, \"webp\", false, Boolean(source[20]! & 0x02));\n }\n if (chunk === \"VP8 \") {\n return positiveDimensions(\n source.readUInt16LE(26) & 0x3fff,\n source.readUInt16LE(28) & 0x3fff,\n \"webp\",\n false,\n );\n }\n if (chunk === \"VP8L\" && source[20] === 0x2f) {\n const bits = source.readUInt32LE(21);\n return positiveDimensions(1 + (bits & 0x3fff), 1 + ((bits >>> 14) & 0x3fff), \"webp\", false);\n }\n return undefined;\n}\n\nfunction inspectAvif(source: Buffer): SourceInspection | undefined {\n if (source.length < 24 || source.subarray(4, 8).toString(\"ascii\") !== \"ftyp\") return undefined;\n const typeOffset = source.indexOf(Buffer.from(\"ispe\"));\n if (typeOffset < 0 || typeOffset + 16 > source.length) return undefined;\n return positiveDimensions(\n source.readUInt32BE(typeOffset + 8),\n source.readUInt32BE(typeOffset + 12),\n \"avif\",\n false,\n );\n}\n\nexport function inspectSource(sourcePath: string, source: Buffer): SourceInspection {\n const inspection =\n inspectPng(source) ??\n inspectGif(source) ??\n inspectJpeg(source) ??\n inspectSvg(source) ??\n inspectWebp(source) ??\n inspectAvif(source);\n if (!inspection) {\n throw new Error(\n `@askrjs/vite could not determine intrinsic dimensions for pass-through image ${sourcePath}.`,\n );\n }\n return inspection;\n}\n","import { createHash } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { inspectSource, type AssetFormat } from \"./image-inspection\";\nimport { normalizeDeclarationOptions, normalizeImageOptions } from \"./image-options\";\nimport type { ImageOptions, ImageOutputFormat, ImagePipelineOptions } from \"./image-types\";\n\ntype SharpFactory = (typeof import(\"sharp\"))[\"default\"];\nexport type SharpLoader = () => Promise<SharpFactory>;\ntype TransformFormat = \"avif\" | \"webp\" | \"jpeg\" | \"png\";\n\nexport interface EmittedVariant {\n referenceId: string;\n width: number;\n height: number;\n format: AssetFormat;\n mime: string;\n}\n\nexport interface AssetPluginContext {\n emitFile(file: { type: \"asset\"; name: string; source: string | Uint8Array }): string;\n getFileName(referenceId: string): string;\n}\n\nexport interface ProcessedImage {\n declarationKey: string;\n sourcePath: string;\n sourceHash: string;\n declarationOptions: ImageOptions;\n transformKey: string;\n encoder: string;\n fallback: EmittedVariant;\n variants: EmittedVariant[];\n passThrough: boolean;\n}\n\nfunction hash(value: string | Buffer): string {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nexport function declarationKey(sourcePath: string, options: ImageOptions): string {\n return hash(`${sourcePath}\\0${JSON.stringify(normalizeDeclarationOptions(options))}`);\n}\n\nexport const defaultSharpLoader: SharpLoader = async () => (await import(\"sharp\")).default;\n\nasync function loadSharp(loader: SharpLoader): Promise<SharpFactory> {\n try {\n return await loader();\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ERR_MODULE_NOT_FOUND\") {\n throw new Error(\n '@askrjs/vite responsive images require the optional peer \"sharp\". Install sharp@^0.35.3 and rebuild.',\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nfunction sourceFormat(format: string | undefined): \"jpeg\" | \"png\" | undefined {\n if (format === \"jpeg\" || format === \"jpg\") return \"jpeg\";\n return format === \"png\" ? \"png\" : undefined;\n}\n\nfunction extension(format: AssetFormat): string {\n return format === \"jpeg\" ? \"jpg\" : format;\n}\n\nfunction mime(format: AssetFormat): string {\n return format === \"jpeg\" ? \"image/jpeg\" : `image/${format}`;\n}\n\nfunction outputName(sourcePath: string, width: number, format: EmittedVariant[\"format\"]): string {\n const basename = path.basename(sourcePath, path.extname(sourcePath));\n return `${basename}-${width}.${extension(format)}`;\n}\n\nfunction outputHeight(\n width: number,\n sourceWidth: number,\n sourceHeight: number,\n aspectRatio: number | undefined,\n): number {\n return Math.max(1, Math.round(width / (aspectRatio ?? sourceWidth / sourceHeight)));\n}\n\nasync function encodedVariant(\n sharp: SharpFactory,\n source: Buffer,\n cacheDir: string,\n transformKey: string,\n width: number,\n height: number,\n format: TransformFormat,\n options: ReturnType<typeof normalizeImageOptions>,\n): Promise<Buffer> {\n const cachePath = path.join(cacheDir, `${transformKey}-${width}.${extension(format)}`);\n const cached = await fs.readFile(cachePath).catch(() => undefined);\n if (cached) return cached;\n\n let pipeline = sharp(source, { animated: false }).autoOrient();\n pipeline =\n options.fit === \"cover\"\n ? pipeline.resize({ width, height, fit: \"cover\", position: options.position })\n : pipeline.resize({ width, fit: \"inside\", withoutEnlargement: true });\n if (format === \"avif\") pipeline = pipeline.avif({ quality: options.quality.avif });\n else if (format === \"webp\") pipeline = pipeline.webp({ quality: options.quality.webp });\n else if (format === \"jpeg\") pipeline = pipeline.jpeg({ quality: options.quality.jpeg });\n else {\n pipeline = pipeline.png(\n options.quality.png === 100\n ? { compressionLevel: 9 }\n : { compressionLevel: 9, quality: options.quality.png },\n );\n }\n const encoded = await pipeline.toBuffer();\n await fs.mkdir(cacheDir, { recursive: true });\n await fs.writeFile(cachePath, encoded);\n return encoded;\n}\n\nfunction variantFormats(\n formats: readonly ImageOutputFormat[],\n fallback: \"jpeg\" | \"png\",\n): Array<\"avif\" | \"webp\" | \"jpeg\" | \"png\"> {\n const output: Array<\"avif\" | \"webp\" | \"jpeg\" | \"png\"> = [];\n for (const format of formats) {\n const resolved = format === \"source\" ? fallback : format;\n if (!output.includes(resolved)) output.push(resolved);\n }\n if (!output.includes(fallback)) output.push(fallback);\n return output;\n}\n\nfunction passThroughImage(\n context: AssetPluginContext,\n sourcePath: string,\n source: Buffer,\n width: number,\n height: number,\n format: AssetFormat,\n): { fallback: EmittedVariant; variants: EmittedVariant[] } {\n const referenceId = context.emitFile({ type: \"asset\", name: path.basename(sourcePath), source });\n const fallback = { referenceId, width, height, format, mime: mime(format) };\n return { fallback, variants: [fallback] };\n}\n\nexport async function processImage(\n context: AssetPluginContext,\n sourcePath: string,\n declarationOptions: ImageOptions,\n globalOptions: ImagePipelineOptions,\n cacheDir: string,\n sharpLoader: SharpLoader,\n): Promise<ProcessedImage> {\n const source = await fs.readFile(sourcePath);\n const sourceHash = hash(source);\n const normalized = normalizeImageOptions(globalOptions, declarationOptions);\n const inspection = inspectSource(sourcePath, source);\n const key = declarationKey(sourcePath, declarationOptions);\n const shouldPassThroughWithoutSharp =\n !inspection.transformable ||\n inspection.animated ||\n (normalized.fit === \"inside\" && inspection.width <= normalized.widths[0]!);\n if (shouldPassThroughWithoutSharp) {\n const encoder = \"passthrough\";\n return {\n declarationKey: key,\n sourcePath,\n sourceHash,\n declarationOptions: normalizeDeclarationOptions(declarationOptions),\n transformKey: hash(`${sourceHash}\\0${JSON.stringify(normalized)}\\0${encoder}`),\n encoder,\n ...passThroughImage(\n context,\n sourcePath,\n source,\n inspection.width,\n inspection.height,\n inspection.format,\n ),\n passThrough: true,\n };\n }\n const sharp = await loadSharp(sharpLoader);\n const metadata = await sharp(source, { animated: true }).metadata();\n const sourceWidth = metadata.autoOrient.width ?? metadata.width;\n const sourceHeight =\n (metadata.pages ?? 1) > 1\n ? (metadata.pageHeight ?? metadata.height)\n : (metadata.autoOrient.height ?? metadata.height);\n if (!sourceWidth || !sourceHeight) {\n throw new Error(`@askrjs/vite could not determine intrinsic dimensions for ${sourcePath}.`);\n }\n const encoder = `sharp@${sharp.versions.sharp}`;\n const transformKey = hash(`${sourceHash}\\0${JSON.stringify(normalized)}\\0${encoder}`);\n const fallbackFormat = sourceFormat(metadata.format);\n\n const shouldPassThrough = (metadata.pages ?? 1) > 1 || !fallbackFormat;\n if (shouldPassThrough) {\n return {\n declarationKey: key,\n sourcePath,\n sourceHash,\n declarationOptions: normalizeDeclarationOptions(declarationOptions),\n transformKey,\n encoder,\n ...passThroughImage(\n context,\n sourcePath,\n source,\n sourceWidth,\n sourceHeight,\n fallbackFormat ?? inspection.format,\n ),\n passThrough: true,\n };\n }\n\n const maximumWidth =\n normalized.fit === \"cover\"\n ? Math.min(sourceWidth, Math.floor(sourceHeight * normalized.aspectRatio!))\n : sourceWidth;\n if (maximumWidth < 1) {\n throw new Error(\n `@askrjs/vite cannot crop ${sourcePath} to aspect ratio ${normalized.aspectRatio} without upscaling.`,\n );\n }\n const widths = normalized.widths.filter((width) => width <= maximumWidth);\n if (!widths.includes(maximumWidth)) widths.push(maximumWidth);\n widths.sort((left, right) => left - right);\n const variants: EmittedVariant[] = [];\n for (const format of variantFormats(normalized.formats, fallbackFormat)) {\n for (const width of widths) {\n const height = outputHeight(\n width,\n sourceWidth,\n sourceHeight,\n normalized.fit === \"cover\" ? normalized.aspectRatio : undefined,\n );\n const buffer = await encodedVariant(\n sharp,\n source,\n cacheDir,\n transformKey,\n width,\n height,\n format,\n normalized,\n );\n variants.push({\n referenceId: context.emitFile({\n type: \"asset\",\n name: outputName(sourcePath, width, format),\n source: buffer,\n }),\n width,\n height,\n format,\n mime: mime(format),\n });\n }\n }\n return {\n declarationKey: key,\n sourcePath,\n sourceHash,\n declarationOptions: normalizeDeclarationOptions(declarationOptions),\n transformKey,\n encoder,\n fallback: variants.filter((variant) => variant.format === fallbackFormat).at(-1)!,\n variants,\n passThrough: false,\n };\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { ResolvedConfig } from \"vite\";\nimport { imageDeclarationMask } from \"./image-lexical\";\nimport {\n IMAGE_METADATA_PATH,\n IMAGE_METADATA_VERSION,\n type ImageMetadataEntry,\n type ImageMetadataRecord,\n} from \"./image-metadata\";\nimport type { ImageOptions, ImagePipelineOptions, ResponsiveImage } from \"./image-types\";\nimport {\n declarationKey,\n defaultSharpLoader,\n processImage,\n type AssetPluginContext,\n type EmittedVariant,\n type ProcessedImage,\n type SharpLoader,\n} from \"./image-transform\";\n\ninterface Declaration {\n start: number;\n end: number;\n source: string;\n options: ImageOptions;\n}\n\nconst IMAGE_CALL = /\\bimage\\s*\\(\\s*new\\s+URL\\s*\\(\\s*([\"'])([^\"']+)\\1\\s*,\\s*import\\.meta\\.url\\s*\\)/g;\n\nfunction staticJson(source: string, id: string): string {\n let output = \"\";\n for (let index = 0; index < source.length;) {\n const character = source[index]!;\n if (/\\s/.test(character) || \"{}[]:\".includes(character)) {\n output += character;\n index += 1;\n continue;\n }\n if (character === \",\") {\n let next = index + 1;\n while (/\\s/.test(source[next] ?? \"\")) next += 1;\n if (source[next] !== \"}\" && source[next] !== \"]\") output += character;\n index += 1;\n continue;\n }\n if (character === '\"' || character === \"'\") {\n let end = index + 1;\n while (end < source.length && source[end] !== character) {\n if (source[end] === \"\\\\\") {\n throw new Error(\n `@askrjs/vite image() option strings in ${id} cannot contain escape sequences.`,\n );\n }\n end += 1;\n }\n if (end >= source.length) {\n throw new Error(`@askrjs/vite found an unterminated image option in ${id}.`);\n }\n output += JSON.stringify(source.slice(index + 1, end));\n index = end + 1;\n continue;\n }\n const number = /^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:e[+-]?\\d+)?/i.exec(source.slice(index));\n if (number) {\n output += number[0];\n index += number[0].length;\n continue;\n }\n const identifier = /^[A-Za-z_]\\w*/.exec(source.slice(index));\n if (identifier) {\n let next = index + identifier[0].length;\n while (/\\s/.test(source[next] ?? \"\")) next += 1;\n if (source[next] === \":\") output += JSON.stringify(identifier[0]);\n else if ([\"true\", \"false\", \"null\"].includes(identifier[0])) output += identifier[0];\n else {\n throw new Error(\n `@askrjs/vite image() options in ${id} must not reference ${identifier[0]}; use a static object literal.`,\n );\n }\n index += identifier[0].length;\n continue;\n }\n throw new Error(\n `@askrjs/vite image() options in ${id} must be a static object literal so builds and direct SSG imports agree.`,\n );\n }\n return output;\n}\n\nfunction staticOptions(source: string, id: string): ImageOptions {\n const trimmed = source.trim();\n if (!trimmed) return {};\n let value: unknown;\n try {\n value = JSON.parse(staticJson(trimmed, id));\n } catch (error) {\n if (error instanceof Error && error.message.startsWith(\"@askrjs/vite\")) throw error;\n throw new Error(`@askrjs/vite could not parse image() options in ${id}.`, { cause: error });\n }\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(`@askrjs/vite image() options in ${id} must be an object literal.`);\n }\n return value as ImageOptions;\n}\n\nfunction findCallEnd(code: string, start: number): number {\n let depth = 1;\n let quote = \"\";\n let escaped = false;\n for (let index = start; index < code.length; index += 1) {\n const character = code[index]!;\n if (quote) {\n if (escaped) escaped = false;\n else if (character === \"\\\\\") escaped = true;\n else if (character === quote) quote = \"\";\n continue;\n }\n if (character === '\"' || character === \"'\") {\n quote = character;\n continue;\n }\n if (character === \"(\") depth += 1;\n if (character === \")\") {\n depth -= 1;\n if (depth === 0) return index;\n }\n }\n return -1;\n}\n\nfunction declarations(code: string, id: string): Declaration[] {\n const mask = imageDeclarationMask(code);\n if (!mask) return [];\n const output: Declaration[] = [];\n IMAGE_CALL.lastIndex = 0;\n for (let match = IMAGE_CALL.exec(code); match; match = IMAGE_CALL.exec(code)) {\n if (!mask[match.index]) continue;\n const afterUrl = IMAGE_CALL.lastIndex;\n const end = findCallEnd(code, afterUrl);\n if (end < 0) throw new Error(`@askrjs/vite found an unterminated image() call in ${id}.`);\n const remainder = code.slice(afterUrl, end).trim();\n if (remainder && !remainder.startsWith(\",\")) {\n throw new Error(`@askrjs/vite could not parse image() declaration in ${id}.`);\n }\n output.push({\n start: match.index,\n end: end + 1,\n source: match[2]!,\n options: staticOptions(remainder.replace(/^,/, \"\"), id),\n });\n IMAGE_CALL.lastIndex = end + 1;\n }\n return output;\n}\n\nfunction urlExpression(referenceId: string): string {\n return `import.meta.ROLLUP_FILE_URL_${referenceId}`;\n}\n\nfunction mime(format: EmittedVariant[\"format\"]): string {\n return format === \"jpeg\" ? \"image/jpeg\" : `image/${format}`;\n}\n\nfunction srcsetExpression(variants: readonly EmittedVariant[]): string {\n return `[${variants.map((variant) => `${urlExpression(variant.referenceId)} + ${JSON.stringify(` ${variant.width}w`)}`).join(\",\")}].join(\", \")`;\n}\n\nfunction imageExpression(processed: ProcessedImage): string {\n const fallbackVariants = processed.variants.filter(\n (variant) => variant.format === processed.fallback.format,\n );\n const modernFormats = [\"avif\", \"webp\"] as const;\n const sources = processed.passThrough\n ? []\n : modernFormats.flatMap((format) => {\n const variants = processed.variants.filter((variant) => variant.format === format);\n return variants.length === 0\n ? []\n : [`{type:${JSON.stringify(mime(format))},srcset:${srcsetExpression(variants)}}`];\n });\n return `image({__askrImage:true,src:${urlExpression(processed.fallback.referenceId)},${\n processed.passThrough ? \"\" : `srcset:${srcsetExpression(fallbackVariants)},`\n }width:${processed.fallback.width},height:${processed.fallback.height},sources:[${sources.join(\",\")}]})`;\n}\n\nfunction builtUrl(base: string, fileName: string): string {\n if (/^https?:\\/\\//.test(base))\n return new URL(fileName, base.endsWith(\"/\") ? base : `${base}/`).href;\n if (base === \"\" || base === \"./\" || base === \".\")\n return `${base === \".\" ? \"./\" : base}${fileName}`;\n return `${base.endsWith(\"/\") ? base : `${base}/`}${fileName}`;\n}\n\nfunction responsiveMetadata(\n processed: ProcessedImage,\n fileName: (referenceId: string) => string,\n base: string,\n): ResponsiveImage {\n const url = (variant: EmittedVariant) => builtUrl(base, fileName(variant.referenceId));\n const srcset = (variants: readonly EmittedVariant[]) =>\n variants.map((variant) => `${url(variant)} ${variant.width}w`).join(\", \");\n const fallbackVariants = processed.variants.filter(\n (variant) => variant.format === processed.fallback.format,\n );\n return {\n __askrImage: true,\n src: url(processed.fallback),\n ...(processed.passThrough ? {} : { srcset: srcset(fallbackVariants) }),\n width: processed.fallback.width,\n height: processed.fallback.height,\n sources: processed.passThrough\n ? []\n : ([\"avif\", \"webp\"] as const).flatMap((format) => {\n const variants = processed.variants.filter((variant) => variant.format === format);\n return variants.length === 0 ? [] : [{ type: mime(format), srcset: srcset(variants) }];\n }),\n };\n}\n\nexport class ImagePipeline {\n readonly #options: ImagePipelineOptions;\n readonly #processed = new Map<string, ProcessedImage>();\n readonly #sharpLoader: SharpLoader;\n #config: ResolvedConfig | undefined;\n\n constructor(options: ImagePipelineOptions, sharpLoader: SharpLoader = defaultSharpLoader) {\n this.#options = options;\n this.#sharpLoader = sharpLoader;\n }\n\n configure(config: ResolvedConfig): void {\n this.#config = config;\n }\n\n async transform(\n context: AssetPluginContext,\n code: string,\n id: string,\n ): Promise<string | undefined> {\n const found = declarations(code, id);\n if (found.length === 0) return undefined;\n if (!this.#config) throw new Error(\"@askrjs/vite image pipeline was not configured.\");\n if (this.#config.command !== \"build\") {\n throw new Error(\"@askrjs/vite responsive image declarations currently require a Vite build.\");\n }\n const cacheDir = path.join(this.#config.root, \"node_modules/.cache/@askrjs/vite/images\");\n let transformed = code;\n for (const declaration of [...found].reverse()) {\n const sourcePath = path.resolve(path.dirname(id.split(\"?\", 1)[0]!), declaration.source);\n const key = declarationKey(sourcePath, declaration.options);\n let processed = this.#processed.get(key);\n if (!processed) {\n processed = await processImage(\n context,\n sourcePath,\n declaration.options,\n this.#options,\n cacheDir,\n this.#sharpLoader,\n );\n this.#processed.set(key, processed);\n }\n transformed = `${transformed.slice(0, declaration.start)}${imageExpression(processed)}${transformed.slice(declaration.end)}`;\n }\n return transformed;\n }\n\n async writeMetadata(context: AssetPluginContext): Promise<void> {\n if (!this.#config || this.#processed.size === 0) return;\n const entries: Record<string, ImageMetadataEntry> = {};\n for (const processed of [...this.#processed.values()].sort((left, right) =>\n left.declarationKey.localeCompare(right.declarationKey),\n )) {\n entries[processed.declarationKey] = {\n sourcePath: processed.sourcePath,\n sourceHash: processed.sourceHash,\n declarationOptions: processed.declarationOptions,\n transformKey: processed.transformKey,\n encoder: processed.encoder,\n image: responsiveMetadata(\n processed,\n (referenceId) => context.getFileName(referenceId),\n this.#config.base,\n ),\n };\n }\n const record: ImageMetadataRecord = {\n version: IMAGE_METADATA_VERSION,\n entries,\n };\n const metadataPath = path.join(this.#config.root, IMAGE_METADATA_PATH);\n await fs.mkdir(path.dirname(metadataPath), { recursive: true });\n await fs.writeFile(metadataPath, `${JSON.stringify(record, null, 2)}\\n`, \"utf8\");\n }\n}\n","import { createRequire } from \"node:module\";\nimport type { Plugin } from \"vite\";\nimport { optimizeTemplateOutput } from \"./template-optimizer\";\nimport { ImagePipeline } from \"./image-pipeline\";\nimport type { ImagePipelineOptions } from \"./image-types\";\n\nconst require = createRequire(import.meta.url);\ntype TransformWithOxc = (typeof import(\"vite\"))[\"transformWithOxc\"];\nlet transformWithOxcPromise: Promise<TransformWithOxc> | undefined;\n\nasync function loadTransformWithOxc(): Promise<TransformWithOxc> {\n transformWithOxcPromise ??= (async () => {\n for (const packageName of [\"vite-plus\", \"vite\"] as const) {\n try {\n const buildTool = await import(packageName);\n if (typeof buildTool.transformWithOxc === \"function\") {\n return buildTool.transformWithOxc as TransformWithOxc;\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ERR_MODULE_NOT_FOUND\") throw error;\n }\n }\n throw new Error(\"@askrjs/vite requires either vite or vite-plus to transform JSX.\");\n })();\n return transformWithOxcPromise;\n}\n\nexport interface AskrVitePluginOptions {\n transformJsx?: boolean;\n optimizeTemplates?: boolean;\n ssrPrecompile?: boolean;\n /** Opt into declared responsive image transforms. */\n images?: boolean | ImagePipelineOptions;\n}\n\n/**\n * Portable public plugin identity.\n *\n * Vite-compatible runners only require the plugin name. Keeping versioned Vite\n * hook types out of the installed declaration prevents consumers such as\n * vite-plus from comparing two distinct copies of Vite's recursive Plugin type.\n */\nexport interface AskrVitePlugin {\n readonly name: \"askr:vite\";\n}\n\nexport function askrVitePlugin(options: AskrVitePluginOptions = {}): AskrVitePlugin {\n const shouldTransform = options.transformJsx ?? true;\n const shouldOptimizeTemplates = options.optimizeTemplates ?? false;\n const imagePipeline = options.images\n ? new ImagePipeline(options.images === true ? {} : options.images)\n : undefined;\n const plugin = {\n name: \"askr:vite\" as const,\n enforce: \"pre\",\n config() {\n let askrEntry: string | null = null;\n try {\n askrEntry = require.resolve(\"@askrjs/askr\");\n } catch {\n askrEntry = null;\n }\n return {\n define: {\n __ASKR_OPTIMIZE_TEMPLATES__: JSON.stringify(shouldOptimizeTemplates),\n },\n resolve: {\n alias: askrEntry ? [{ find: \"@askrjs/askr\", replacement: askrEntry }] : [],\n dedupe: [\"@askrjs/askr\"],\n },\n optimizeDeps: {\n include: [\n \"@askrjs/askr\",\n \"@askrjs/askr/router\",\n \"@askrjs/askr/boot\",\n \"@askrjs/askr/control\",\n \"@askrjs/askr/fx\",\n \"@askrjs/askr/resources\",\n \"@askrjs/askr/data\",\n \"@askrjs/askr/foundations\",\n \"@askrjs/askr/foundations/icon\",\n \"@askrjs/askr/foundations/interactions\",\n \"@askrjs/askr/foundations/state\",\n \"@askrjs/askr/foundations/structures\",\n \"@askrjs/askr/foundations/utilities\",\n \"@askrjs/askr/jsx-runtime\",\n \"@askrjs/askr/jsx-dev-runtime\",\n ],\n },\n oxc: {\n jsx: { runtime: \"automatic\", importSource: \"@askrjs/askr\" },\n jsxInject: \"import { jsx, jsxs, Fragment } from '@askrjs/askr/jsx-runtime';\",\n },\n };\n },\n configResolved(config) {\n imagePipeline?.configure(config);\n },\n async transform(code, id) {\n if (id.includes(\"node_modules\")) return null;\n const imageTransformed = imagePipeline\n ? await imagePipeline.transform(this, code, id)\n : undefined;\n const input = imageTransformed ?? code;\n if (!shouldTransform || !/\\.(jsx|tsx)$/.test(id)) {\n return imageTransformed ? { code: imageTransformed, map: null } : null;\n }\n try {\n const transformWithOxc = await loadTransformWithOxc();\n const result = await transformWithOxc(input, id, {\n lang: id.endsWith(\".tsx\") ? \"tsx\" : \"jsx\",\n jsx: { runtime: \"automatic\", importSource: \"@askrjs/askr\" },\n sourcemap: true,\n });\n if (!result?.code) return null;\n return {\n code: shouldOptimizeTemplates ? optimizeTemplateOutput(result.code) : result.code,\n map: result.map,\n };\n } catch {\n return imageTransformed ? { code: imageTransformed, map: null } : null;\n }\n },\n async writeBundle() {\n await imagePipeline?.writeMetadata(this);\n },\n } satisfies Plugin;\n return plugin;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["mime","#options","#processed","#sharpLoader","#config"],"sources":["../src/template-optimizer.ts","../src/image-lexical.ts","../src/image-inspection.ts","../src/image-transform.ts","../src/image-pipeline.ts","../src/jsx-plugin.ts"],"sourcesContent":["import { parseSync, Visitor, type ObjectProperty } from \"oxc-parser\";\n\nconst OPTIMIZED_PROPS = new Set([\"class\", \"className\", \"style\"]);\nconst JSX_RUNTIME_SOURCE = \"@askrjs/askr/jsx-runtime\";\nconst JSX_FACTORIES = new Set([\"jsx\", \"jsxs\", \"jsxDEV\"]);\n\ntype Candidate = {\n literal: string;\n start: number;\n end: number;\n};\n\nfunction importedName(specifier: { imported: { type: string; name?: string; value?: unknown } }) {\n return specifier.imported.type === \"Identifier\"\n ? specifier.imported.name\n : specifier.imported.value;\n}\n\nfunction collectRuntimeFactories(program: ReturnType<typeof parseSync>[\"program\"]): Set<string> {\n const factories = new Set<string>();\n\n for (const statement of program.body) {\n if (statement.type !== \"ImportDeclaration\" || statement.source.value !== JSX_RUNTIME_SOURCE) {\n continue;\n }\n\n for (const specifier of statement.specifiers) {\n if (\n specifier.type === \"ImportSpecifier\" &&\n JSX_FACTORIES.has(String(importedName(specifier)))\n ) {\n factories.add(specifier.local.name);\n }\n }\n }\n\n return factories;\n}\n\nfunction collectCandidate(\n property: ObjectProperty,\n code: string,\n candidates: Map<string, Candidate[]>,\n) {\n if (\n property.kind !== \"init\" ||\n property.computed ||\n property.method ||\n property.key.type !== \"Identifier\" ||\n !OPTIMIZED_PROPS.has(property.key.name) ||\n property.value.type !== \"Literal\" ||\n typeof property.value.value !== \"string\"\n ) {\n return;\n }\n\n const literal = code.slice(property.value.start, property.value.end);\n const cacheKey = `${property.key.name}:${literal}`;\n const group = candidates.get(cacheKey) ?? [];\n group.push({\n literal,\n start: property.value.start,\n end: property.value.end,\n });\n candidates.set(cacheKey, group);\n}\n\nexport function optimizeTemplateOutput(code: string): string {\n const parsed = parseSync(\"askr-compiled.js\", code, {\n lang: \"js\",\n sourceType: \"module\",\n });\n if (parsed.errors.length > 0) return code;\n\n const runtimeFactories = collectRuntimeFactories(parsed.program);\n if (runtimeFactories.size === 0) return code;\n\n const candidates = new Map<string, Candidate[]>();\n const identifiers = new Set<string>();\n new Visitor({\n Identifier(identifier) {\n identifiers.add(identifier.name);\n },\n CallExpression(call) {\n if (\n call.callee.type !== \"Identifier\" ||\n !runtimeFactories.has(call.callee.name) ||\n call.arguments[1]?.type !== \"ObjectExpression\"\n ) {\n return;\n }\n\n for (const property of call.arguments[1].properties) {\n if (property.type === \"Property\") {\n collectCandidate(property, code, candidates);\n }\n }\n },\n }).visit(parsed.program);\n\n const declarations: string[] = [];\n const replacements: Array<{ start: number; end: number; identifier: string }> = [];\n let hoistIndex = 0;\n for (const group of candidates.values()) {\n if (group.length < 2) continue;\n\n let identifier: string;\n do {\n identifier = `__askrStaticLiteral${hoistIndex++}`;\n } while (identifiers.has(identifier));\n identifiers.add(identifier);\n declarations.push(`const ${identifier} = ${group[0].literal};`);\n for (const candidate of group) {\n replacements.push({ start: candidate.start, end: candidate.end, identifier });\n }\n }\n\n if (declarations.length === 0) return code;\n\n let optimized = code;\n for (const replacement of replacements.sort((left, right) => right.start - left.start)) {\n optimized =\n optimized.slice(0, replacement.start) +\n replacement.identifier +\n optimized.slice(replacement.end);\n }\n return `${declarations.join(\"\\n\")}\\n${optimized}`;\n}\n","const IMAGE_IMPORT = /from\\s+[\"']@askrjs\\/vite\\/image[\"']/g;\n\nfunction lexicalCodeMask(source: string): Uint8Array {\n const mask = new Uint8Array(source.length);\n let state: \"code\" | \"single\" | \"double\" | \"template\" | \"line-comment\" | \"block-comment\" = \"code\";\n let escaped = false;\n for (let index = 0; index < source.length; index += 1) {\n const character = source[index]!;\n const next = source[index + 1];\n if (state === \"code\") {\n if (character === \"/\" && next === \"/\") {\n state = \"line-comment\";\n index += 1;\n } else if (character === \"/\" && next === \"*\") {\n state = \"block-comment\";\n index += 1;\n } else if (character === \"'\") state = \"single\";\n else if (character === '\"') state = \"double\";\n else if (character === \"`\") state = \"template\";\n else mask[index] = 1;\n continue;\n }\n if (state === \"line-comment\") {\n if (character === \"\\n\" || character === \"\\r\") {\n state = \"code\";\n mask[index] = 1;\n }\n continue;\n }\n if (state === \"block-comment\") {\n if (character === \"*\" && next === \"/\") {\n state = \"code\";\n index += 1;\n }\n continue;\n }\n if (escaped) escaped = false;\n else if (character === \"\\\\\") escaped = true;\n else if (\n (state === \"single\" && character === \"'\") ||\n (state === \"double\" && character === '\"') ||\n (state === \"template\" && character === \"`\")\n ) {\n state = \"code\";\n }\n }\n return mask;\n}\n\nexport function imageDeclarationMask(code: string): Uint8Array | undefined {\n const mask = lexicalCodeMask(code);\n IMAGE_IMPORT.lastIndex = 0;\n for (let match = IMAGE_IMPORT.exec(code); match; match = IMAGE_IMPORT.exec(code)) {\n if (mask[match.index]) return mask;\n }\n return undefined;\n}\n","export type AssetFormat = \"avif\" | \"webp\" | \"jpeg\" | \"png\" | \"gif\" | \"svg\";\n\nexport interface SourceInspection {\n width: number;\n height: number;\n format: AssetFormat;\n transformable: boolean;\n animated: boolean;\n}\n\nfunction positiveDimensions(\n width: number,\n height: number,\n format: AssetFormat,\n transformable: boolean,\n animated = false,\n): SourceInspection | undefined {\n return width > 0 && height > 0 ? { width, height, format, transformable, animated } : undefined;\n}\n\nfunction inspectPng(source: Buffer): SourceInspection | undefined {\n if (\n source.length < 24 ||\n !source.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))\n ) {\n return undefined;\n }\n return positiveDimensions(\n source.readUInt32BE(16),\n source.readUInt32BE(20),\n \"png\",\n true,\n source.includes(Buffer.from(\"acTL\")),\n );\n}\n\nfunction inspectGif(source: Buffer): SourceInspection | undefined {\n if (source.length < 10 || !/^GIF8[79]a$/.test(source.subarray(0, 6).toString(\"ascii\"))) {\n return undefined;\n }\n return positiveDimensions(source.readUInt16LE(6), source.readUInt16LE(8), \"gif\", false, true);\n}\n\nfunction exifOrientation(segment: Buffer): number | undefined {\n if (segment.length < 14 || segment.subarray(0, 6).toString(\"binary\") !== \"Exif\\0\\0\") {\n return undefined;\n }\n const tiff = 6;\n const byteOrder = segment.subarray(tiff, tiff + 2).toString(\"ascii\");\n const littleEndian = byteOrder === \"II\";\n if (!littleEndian && byteOrder !== \"MM\") return undefined;\n const read16 = (offset: number): number | undefined => {\n const absolute = tiff + offset;\n if (absolute < tiff || absolute + 2 > segment.length) return undefined;\n return littleEndian ? segment.readUInt16LE(absolute) : segment.readUInt16BE(absolute);\n };\n const read32 = (offset: number): number | undefined => {\n const absolute = tiff + offset;\n if (absolute < tiff || absolute + 4 > segment.length) return undefined;\n return littleEndian ? segment.readUInt32LE(absolute) : segment.readUInt32BE(absolute);\n };\n if (read16(2) !== 42) return undefined;\n const directoryOffset = read32(4);\n if (directoryOffset === undefined) return undefined;\n const entries = read16(directoryOffset);\n if (entries === undefined) return undefined;\n for (let index = 0; index < entries; index += 1) {\n const entry = directoryOffset + 2 + index * 12;\n if (read16(entry) !== 0x0112 || read16(entry + 2) !== 3 || read32(entry + 4) !== 1) {\n continue;\n }\n const orientation = read16(entry + 8);\n return orientation && orientation >= 1 && orientation <= 8 ? orientation : undefined;\n }\n return undefined;\n}\n\nfunction inspectJpeg(source: Buffer): SourceInspection | undefined {\n if (source.length < 4 || source[0] !== 0xff || source[1] !== 0xd8) return undefined;\n const startOfFrame = new Set([\n 0xc0, 0xc1, 0xc2, 0xc3, 0xc5, 0xc6, 0xc7, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf,\n ]);\n let orientation: number | undefined;\n let offset = 2;\n while (offset + 8 < source.length) {\n if (source[offset] !== 0xff) {\n offset += 1;\n continue;\n }\n while (source[offset] === 0xff) offset += 1;\n const marker = source[offset++]!;\n if (marker === 0xd8 || marker === 0xd9 || marker === 0x01) continue;\n if (marker >= 0xd0 && marker <= 0xd7) continue;\n if (offset + 2 > source.length) break;\n const length = source.readUInt16BE(offset);\n if (length < 2 || offset + length > source.length) break;\n if (marker === 0xe1) {\n orientation = exifOrientation(source.subarray(offset + 2, offset + length)) ?? orientation;\n }\n if (startOfFrame.has(marker) && length >= 7) {\n const width = source.readUInt16BE(offset + 5);\n const height = source.readUInt16BE(offset + 3);\n return positiveDimensions(\n orientation !== undefined && orientation >= 5 ? height : width,\n orientation !== undefined && orientation >= 5 ? width : height,\n \"jpeg\",\n true,\n );\n }\n offset += length;\n }\n return undefined;\n}\n\nfunction inspectSvg(source: Buffer): SourceInspection | undefined {\n const openingTag = source\n .subarray(0, 16_384)\n .toString(\"utf8\")\n .match(/<svg\\b[^>]*>/i)?.[0];\n if (!openingTag) return undefined;\n const numberAttribute = (name: string): number | undefined => {\n const value = openingTag.match(new RegExp(`\\\\b${name}\\\\s*=\\\\s*[\"']\\\\s*([0-9.]+)`, \"i\"))?.[1];\n const parsed = value ? Number(value) : Number.NaN;\n return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;\n };\n let width = numberAttribute(\"width\");\n let height = numberAttribute(\"height\");\n const viewBox = openingTag\n .match(/\\bviewBox\\s*=\\s*[\"']\\s*[-+0-9.e]+[ ,]+[-+0-9.e]+[ ,]+([-+0-9.e]+)[ ,]+([-+0-9.e]+)/i)\n ?.slice(1)\n .map(Number);\n if (!width && viewBox?.[0] && viewBox[0] > 0) width = viewBox[0];\n if (!height && viewBox?.[1] && viewBox[1] > 0) height = viewBox[1];\n if (!width && height && viewBox?.[0] && viewBox?.[1]) width = height * (viewBox[0] / viewBox[1]);\n if (!height && width && viewBox?.[0] && viewBox?.[1]) height = width / (viewBox[0] / viewBox[1]);\n return width && height ? positiveDimensions(width, height, \"svg\", false) : undefined;\n}\n\nfunction inspectWebp(source: Buffer): SourceInspection | undefined {\n if (\n source.length < 30 ||\n source.subarray(0, 4).toString(\"ascii\") !== \"RIFF\" ||\n source.subarray(8, 12).toString(\"ascii\") !== \"WEBP\"\n ) {\n return undefined;\n }\n const chunk = source.subarray(12, 16).toString(\"ascii\");\n if (chunk === \"VP8X\") {\n const width = 1 + source.readUIntLE(24, 3);\n const height = 1 + source.readUIntLE(27, 3);\n return positiveDimensions(width, height, \"webp\", false, Boolean(source[20]! & 0x02));\n }\n if (chunk === \"VP8 \") {\n return positiveDimensions(\n source.readUInt16LE(26) & 0x3fff,\n source.readUInt16LE(28) & 0x3fff,\n \"webp\",\n false,\n );\n }\n if (chunk === \"VP8L\" && source[20] === 0x2f) {\n const bits = source.readUInt32LE(21);\n return positiveDimensions(1 + (bits & 0x3fff), 1 + ((bits >>> 14) & 0x3fff), \"webp\", false);\n }\n return undefined;\n}\n\nfunction inspectAvif(source: Buffer): SourceInspection | undefined {\n if (source.length < 24 || source.subarray(4, 8).toString(\"ascii\") !== \"ftyp\") return undefined;\n const typeOffset = source.indexOf(Buffer.from(\"ispe\"));\n if (typeOffset < 0 || typeOffset + 16 > source.length) return undefined;\n return positiveDimensions(\n source.readUInt32BE(typeOffset + 8),\n source.readUInt32BE(typeOffset + 12),\n \"avif\",\n false,\n );\n}\n\nexport function inspectSource(sourcePath: string, source: Buffer): SourceInspection {\n const inspection =\n inspectPng(source) ??\n inspectGif(source) ??\n inspectJpeg(source) ??\n inspectSvg(source) ??\n inspectWebp(source) ??\n inspectAvif(source);\n if (!inspection) {\n throw new Error(\n `@askrjs/vite could not determine intrinsic dimensions for pass-through image ${sourcePath}.`,\n );\n }\n return inspection;\n}\n","import { createHash } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { inspectSource, type AssetFormat } from \"./image-inspection\";\nimport { normalizeDeclarationOptions, normalizeImageOptions } from \"./image-options\";\nimport type { ImageOptions, ImageOutputFormat, ImagePipelineOptions } from \"./image-types\";\n\ntype SharpFactory = (typeof import(\"sharp\"))[\"default\"];\nexport type SharpLoader = () => Promise<SharpFactory>;\ntype TransformFormat = \"avif\" | \"webp\" | \"jpeg\" | \"png\";\n\nexport interface EmittedVariant {\n referenceId: string;\n width: number;\n height: number;\n format: AssetFormat;\n mime: string;\n}\n\nexport interface AssetPluginContext {\n emitFile(file: { type: \"asset\"; name: string; source: string | Uint8Array }): string;\n getFileName(referenceId: string): string;\n}\n\nexport interface ProcessedImage {\n declarationKey: string;\n sourcePath: string;\n sourceHash: string;\n declarationOptions: ImageOptions;\n transformKey: string;\n encoder: string;\n fallback: EmittedVariant;\n variants: EmittedVariant[];\n passThrough: boolean;\n}\n\nfunction hash(value: string | Buffer): string {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nexport function declarationKey(sourcePath: string, options: ImageOptions): string {\n return hash(`${sourcePath}\\0${JSON.stringify(normalizeDeclarationOptions(options))}`);\n}\n\nexport const defaultSharpLoader: SharpLoader = async () => (await import(\"sharp\")).default;\n\nasync function loadSharp(loader: SharpLoader): Promise<SharpFactory> {\n try {\n return await loader();\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ERR_MODULE_NOT_FOUND\") {\n throw new Error(\n '@askrjs/vite responsive images require the optional peer \"sharp\". Install sharp@^0.35.3 and rebuild.',\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nfunction sourceFormat(format: string | undefined): \"jpeg\" | \"png\" | undefined {\n if (format === \"jpeg\" || format === \"jpg\") return \"jpeg\";\n return format === \"png\" ? \"png\" : undefined;\n}\n\nfunction extension(format: AssetFormat): string {\n return format === \"jpeg\" ? \"jpg\" : format;\n}\n\nfunction mime(format: AssetFormat): string {\n return format === \"jpeg\" ? \"image/jpeg\" : `image/${format}`;\n}\n\nfunction outputName(sourcePath: string, width: number, format: EmittedVariant[\"format\"]): string {\n const basename = path.basename(sourcePath, path.extname(sourcePath));\n return `${basename}-${width}.${extension(format)}`;\n}\n\nfunction outputHeight(\n width: number,\n sourceWidth: number,\n sourceHeight: number,\n aspectRatio: number | undefined,\n): number {\n return Math.max(1, Math.round(width / (aspectRatio ?? sourceWidth / sourceHeight)));\n}\n\nasync function encodedVariant(\n sharp: SharpFactory,\n source: Buffer,\n cacheDir: string,\n transformKey: string,\n width: number,\n height: number,\n format: TransformFormat,\n options: ReturnType<typeof normalizeImageOptions>,\n): Promise<Buffer> {\n const cachePath = path.join(cacheDir, `${transformKey}-${width}.${extension(format)}`);\n const cached = await fs.readFile(cachePath).catch(() => undefined);\n if (cached) return cached;\n\n let pipeline = sharp(source, { animated: false }).autoOrient();\n pipeline =\n options.fit === \"cover\"\n ? pipeline.resize({ width, height, fit: \"cover\", position: options.position })\n : pipeline.resize({ width, fit: \"inside\", withoutEnlargement: true });\n if (format === \"avif\") pipeline = pipeline.avif({ quality: options.quality.avif });\n else if (format === \"webp\") pipeline = pipeline.webp({ quality: options.quality.webp });\n else if (format === \"jpeg\") pipeline = pipeline.jpeg({ quality: options.quality.jpeg });\n else {\n pipeline = pipeline.png(\n options.quality.png === 100\n ? { compressionLevel: 9 }\n : { compressionLevel: 9, quality: options.quality.png },\n );\n }\n const encoded = await pipeline.toBuffer();\n await fs.mkdir(cacheDir, { recursive: true });\n await fs.writeFile(cachePath, encoded);\n return encoded;\n}\n\nfunction variantFormats(\n formats: readonly ImageOutputFormat[],\n fallback: \"jpeg\" | \"png\",\n): Array<\"avif\" | \"webp\" | \"jpeg\" | \"png\"> {\n const output: Array<\"avif\" | \"webp\" | \"jpeg\" | \"png\"> = [];\n for (const format of formats) {\n const resolved = format === \"source\" ? fallback : format;\n if (!output.includes(resolved)) output.push(resolved);\n }\n if (!output.includes(fallback)) output.push(fallback);\n return output;\n}\n\nfunction passThroughImage(\n context: AssetPluginContext,\n sourcePath: string,\n source: Buffer,\n width: number,\n height: number,\n format: AssetFormat,\n): { fallback: EmittedVariant; variants: EmittedVariant[] } {\n const referenceId = context.emitFile({ type: \"asset\", name: path.basename(sourcePath), source });\n const fallback = { referenceId, width, height, format, mime: mime(format) };\n return { fallback, variants: [fallback] };\n}\n\nexport async function processImage(\n context: AssetPluginContext,\n sourcePath: string,\n declarationOptions: ImageOptions,\n globalOptions: ImagePipelineOptions,\n cacheDir: string,\n sharpLoader: SharpLoader,\n): Promise<ProcessedImage> {\n const source = await fs.readFile(sourcePath);\n const sourceHash = hash(source);\n const normalized = normalizeImageOptions(globalOptions, declarationOptions);\n const inspection = inspectSource(sourcePath, source);\n const key = declarationKey(sourcePath, declarationOptions);\n const shouldPassThroughWithoutSharp =\n !inspection.transformable ||\n inspection.animated ||\n (normalized.fit === \"inside\" && inspection.width <= normalized.widths[0]!);\n if (shouldPassThroughWithoutSharp) {\n const encoder = \"passthrough\";\n return {\n declarationKey: key,\n sourcePath,\n sourceHash,\n declarationOptions: normalizeDeclarationOptions(declarationOptions),\n transformKey: hash(`${sourceHash}\\0${JSON.stringify(normalized)}\\0${encoder}`),\n encoder,\n ...passThroughImage(\n context,\n sourcePath,\n source,\n inspection.width,\n inspection.height,\n inspection.format,\n ),\n passThrough: true,\n };\n }\n const sharp = await loadSharp(sharpLoader);\n const metadata = await sharp(source, { animated: true }).metadata();\n const sourceWidth = metadata.autoOrient.width ?? metadata.width;\n const sourceHeight =\n (metadata.pages ?? 1) > 1\n ? (metadata.pageHeight ?? metadata.height)\n : (metadata.autoOrient.height ?? metadata.height);\n if (!sourceWidth || !sourceHeight) {\n throw new Error(`@askrjs/vite could not determine intrinsic dimensions for ${sourcePath}.`);\n }\n const encoder = `sharp@${sharp.versions.sharp}`;\n const transformKey = hash(`${sourceHash}\\0${JSON.stringify(normalized)}\\0${encoder}`);\n const fallbackFormat = sourceFormat(metadata.format);\n\n const shouldPassThrough = (metadata.pages ?? 1) > 1 || !fallbackFormat;\n if (shouldPassThrough) {\n return {\n declarationKey: key,\n sourcePath,\n sourceHash,\n declarationOptions: normalizeDeclarationOptions(declarationOptions),\n transformKey,\n encoder,\n ...passThroughImage(\n context,\n sourcePath,\n source,\n sourceWidth,\n sourceHeight,\n fallbackFormat ?? inspection.format,\n ),\n passThrough: true,\n };\n }\n\n const maximumWidth =\n normalized.fit === \"cover\"\n ? Math.min(sourceWidth, Math.floor(sourceHeight * normalized.aspectRatio!))\n : sourceWidth;\n if (maximumWidth < 1) {\n throw new Error(\n `@askrjs/vite cannot crop ${sourcePath} to aspect ratio ${normalized.aspectRatio} without upscaling.`,\n );\n }\n const widths = normalized.widths.filter((width) => width <= maximumWidth);\n if (!widths.includes(maximumWidth)) widths.push(maximumWidth);\n widths.sort((left, right) => left - right);\n const variants: EmittedVariant[] = [];\n for (const format of variantFormats(normalized.formats, fallbackFormat)) {\n for (const width of widths) {\n const height = outputHeight(\n width,\n sourceWidth,\n sourceHeight,\n normalized.fit === \"cover\" ? normalized.aspectRatio : undefined,\n );\n const buffer = await encodedVariant(\n sharp,\n source,\n cacheDir,\n transformKey,\n width,\n height,\n format,\n normalized,\n );\n variants.push({\n referenceId: context.emitFile({\n type: \"asset\",\n name: outputName(sourcePath, width, format),\n source: buffer,\n }),\n width,\n height,\n format,\n mime: mime(format),\n });\n }\n }\n return {\n declarationKey: key,\n sourcePath,\n sourceHash,\n declarationOptions: normalizeDeclarationOptions(declarationOptions),\n transformKey,\n encoder,\n fallback: variants.filter((variant) => variant.format === fallbackFormat).at(-1)!,\n variants,\n passThrough: false,\n };\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { ResolvedConfig } from \"vite\";\nimport { imageDeclarationMask } from \"./image-lexical\";\nimport {\n IMAGE_METADATA_PATH,\n IMAGE_METADATA_VERSION,\n type ImageMetadataEntry,\n type ImageMetadataRecord,\n} from \"./image-metadata\";\nimport type { ImageOptions, ImagePipelineOptions, ResponsiveImage } from \"./image-types\";\nimport {\n declarationKey,\n defaultSharpLoader,\n processImage,\n type AssetPluginContext,\n type EmittedVariant,\n type ProcessedImage,\n type SharpLoader,\n} from \"./image-transform\";\n\ninterface Declaration {\n start: number;\n end: number;\n source: string;\n options: ImageOptions;\n}\n\nconst IMAGE_CALL = /\\bimage\\s*\\(\\s*new\\s+URL\\s*\\(\\s*([\"'])([^\"']+)\\1\\s*,\\s*import\\.meta\\.url\\s*\\)/g;\n\nfunction staticJson(source: string, id: string): string {\n let output = \"\";\n for (let index = 0; index < source.length;) {\n const character = source[index]!;\n if (/\\s/.test(character) || \"{}[]:\".includes(character)) {\n output += character;\n index += 1;\n continue;\n }\n if (character === \",\") {\n let next = index + 1;\n while (/\\s/.test(source[next] ?? \"\")) next += 1;\n if (source[next] !== \"}\" && source[next] !== \"]\") output += character;\n index += 1;\n continue;\n }\n if (character === '\"' || character === \"'\") {\n let end = index + 1;\n while (end < source.length && source[end] !== character) {\n if (source[end] === \"\\\\\") {\n throw new Error(\n `@askrjs/vite image() option strings in ${id} cannot contain escape sequences.`,\n );\n }\n end += 1;\n }\n if (end >= source.length) {\n throw new Error(`@askrjs/vite found an unterminated image option in ${id}.`);\n }\n output += JSON.stringify(source.slice(index + 1, end));\n index = end + 1;\n continue;\n }\n const number = /^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:e[+-]?\\d+)?/i.exec(source.slice(index));\n if (number) {\n output += number[0];\n index += number[0].length;\n continue;\n }\n const identifier = /^[A-Za-z_]\\w*/.exec(source.slice(index));\n if (identifier) {\n let next = index + identifier[0].length;\n while (/\\s/.test(source[next] ?? \"\")) next += 1;\n if (source[next] === \":\") output += JSON.stringify(identifier[0]);\n else if ([\"true\", \"false\", \"null\"].includes(identifier[0])) output += identifier[0];\n else {\n throw new Error(\n `@askrjs/vite image() options in ${id} must not reference ${identifier[0]}; use a static object literal.`,\n );\n }\n index += identifier[0].length;\n continue;\n }\n throw new Error(\n `@askrjs/vite image() options in ${id} must be a static object literal so builds and direct SSG imports agree.`,\n );\n }\n return output;\n}\n\nfunction staticOptions(source: string, id: string): ImageOptions {\n const trimmed = source.trim();\n if (!trimmed) return {};\n let value: unknown;\n try {\n value = JSON.parse(staticJson(trimmed, id));\n } catch (error) {\n if (error instanceof Error && error.message.startsWith(\"@askrjs/vite\")) throw error;\n throw new Error(`@askrjs/vite could not parse image() options in ${id}.`, { cause: error });\n }\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(`@askrjs/vite image() options in ${id} must be an object literal.`);\n }\n return value as ImageOptions;\n}\n\nfunction findCallEnd(code: string, start: number): number {\n let depth = 1;\n let quote = \"\";\n let escaped = false;\n for (let index = start; index < code.length; index += 1) {\n const character = code[index]!;\n if (quote) {\n if (escaped) escaped = false;\n else if (character === \"\\\\\") escaped = true;\n else if (character === quote) quote = \"\";\n continue;\n }\n if (character === '\"' || character === \"'\") {\n quote = character;\n continue;\n }\n if (character === \"(\") depth += 1;\n if (character === \")\") {\n depth -= 1;\n if (depth === 0) return index;\n }\n }\n return -1;\n}\n\nfunction declarations(code: string, id: string): Declaration[] {\n const mask = imageDeclarationMask(code);\n if (!mask) return [];\n const output: Declaration[] = [];\n IMAGE_CALL.lastIndex = 0;\n for (let match = IMAGE_CALL.exec(code); match; match = IMAGE_CALL.exec(code)) {\n if (!mask[match.index]) continue;\n const afterUrl = IMAGE_CALL.lastIndex;\n const end = findCallEnd(code, afterUrl);\n if (end < 0) throw new Error(`@askrjs/vite found an unterminated image() call in ${id}.`);\n const remainder = code.slice(afterUrl, end).trim();\n if (remainder && !remainder.startsWith(\",\")) {\n throw new Error(`@askrjs/vite could not parse image() declaration in ${id}.`);\n }\n output.push({\n start: match.index,\n end: end + 1,\n source: match[2]!,\n options: staticOptions(remainder.replace(/^,/, \"\"), id),\n });\n IMAGE_CALL.lastIndex = end + 1;\n }\n return output;\n}\n\nfunction urlExpression(referenceId: string): string {\n return `import.meta.ROLLUP_FILE_URL_${referenceId}`;\n}\n\nfunction mime(format: EmittedVariant[\"format\"]): string {\n return format === \"jpeg\" ? \"image/jpeg\" : `image/${format}`;\n}\n\nfunction srcsetExpression(variants: readonly EmittedVariant[]): string {\n return `[${variants.map((variant) => `${urlExpression(variant.referenceId)} + ${JSON.stringify(` ${variant.width}w`)}`).join(\",\")}].join(\", \")`;\n}\n\nfunction imageExpression(processed: ProcessedImage): string {\n const fallbackVariants = processed.variants.filter(\n (variant) => variant.format === processed.fallback.format,\n );\n const modernFormats = [\"avif\", \"webp\"] as const;\n const sources = processed.passThrough\n ? []\n : modernFormats.flatMap((format) => {\n const variants = processed.variants.filter((variant) => variant.format === format);\n return variants.length === 0\n ? []\n : [`{type:${JSON.stringify(mime(format))},srcset:${srcsetExpression(variants)}}`];\n });\n return `image({__askrImage:true,src:${urlExpression(processed.fallback.referenceId)},${\n processed.passThrough ? \"\" : `srcset:${srcsetExpression(fallbackVariants)},`\n }width:${processed.fallback.width},height:${processed.fallback.height},sources:[${sources.join(\",\")}]})`;\n}\n\nfunction builtUrl(base: string, fileName: string): string {\n if (/^https?:\\/\\//.test(base))\n return new URL(fileName, base.endsWith(\"/\") ? base : `${base}/`).href;\n if (base === \"\" || base === \"./\" || base === \".\")\n return `${base === \".\" ? \"./\" : base}${fileName}`;\n return `${base.endsWith(\"/\") ? base : `${base}/`}${fileName}`;\n}\n\nfunction responsiveMetadata(\n processed: ProcessedImage,\n fileName: (referenceId: string) => string,\n base: string,\n): ResponsiveImage {\n const url = (variant: EmittedVariant) => builtUrl(base, fileName(variant.referenceId));\n const srcset = (variants: readonly EmittedVariant[]) =>\n variants.map((variant) => `${url(variant)} ${variant.width}w`).join(\", \");\n const fallbackVariants = processed.variants.filter(\n (variant) => variant.format === processed.fallback.format,\n );\n return {\n __askrImage: true,\n src: url(processed.fallback),\n ...(processed.passThrough ? {} : { srcset: srcset(fallbackVariants) }),\n width: processed.fallback.width,\n height: processed.fallback.height,\n sources: processed.passThrough\n ? []\n : ([\"avif\", \"webp\"] as const).flatMap((format) => {\n const variants = processed.variants.filter((variant) => variant.format === format);\n return variants.length === 0 ? [] : [{ type: mime(format), srcset: srcset(variants) }];\n }),\n };\n}\n\nexport class ImagePipeline {\n readonly #options: ImagePipelineOptions;\n readonly #processed = new Map<string, ProcessedImage>();\n readonly #sharpLoader: SharpLoader;\n #config: ResolvedConfig | undefined;\n\n constructor(options: ImagePipelineOptions, sharpLoader: SharpLoader = defaultSharpLoader) {\n this.#options = options;\n this.#sharpLoader = sharpLoader;\n }\n\n configure(config: ResolvedConfig): void {\n this.#config = config;\n }\n\n async transform(\n context: AssetPluginContext,\n code: string,\n id: string,\n ): Promise<string | undefined> {\n const found = declarations(code, id);\n if (found.length === 0) return undefined;\n if (!this.#config) throw new Error(\"@askrjs/vite image pipeline was not configured.\");\n if (this.#config.command !== \"build\") {\n throw new Error(\"@askrjs/vite responsive image declarations currently require a Vite build.\");\n }\n const cacheDir = path.join(this.#config.root, \"node_modules/.cache/@askrjs/vite/images\");\n let transformed = code;\n for (const declaration of [...found].reverse()) {\n const sourcePath = path.resolve(path.dirname(id.split(\"?\", 1)[0]!), declaration.source);\n const key = declarationKey(sourcePath, declaration.options);\n let processed = this.#processed.get(key);\n if (!processed) {\n processed = await processImage(\n context,\n sourcePath,\n declaration.options,\n this.#options,\n cacheDir,\n this.#sharpLoader,\n );\n this.#processed.set(key, processed);\n }\n transformed = `${transformed.slice(0, declaration.start)}${imageExpression(processed)}${transformed.slice(declaration.end)}`;\n }\n return transformed;\n }\n\n async writeMetadata(context: AssetPluginContext): Promise<void> {\n if (!this.#config || this.#processed.size === 0) return;\n const entries: Record<string, ImageMetadataEntry> = {};\n for (const processed of [...this.#processed.values()].sort((left, right) =>\n left.declarationKey.localeCompare(right.declarationKey),\n )) {\n entries[processed.declarationKey] = {\n sourcePath: processed.sourcePath,\n sourceHash: processed.sourceHash,\n declarationOptions: processed.declarationOptions,\n transformKey: processed.transformKey,\n encoder: processed.encoder,\n image: responsiveMetadata(\n processed,\n (referenceId) => context.getFileName(referenceId),\n this.#config.base,\n ),\n };\n }\n const record: ImageMetadataRecord = {\n version: IMAGE_METADATA_VERSION,\n entries,\n };\n const metadataPath = path.join(this.#config.root, IMAGE_METADATA_PATH);\n await fs.mkdir(path.dirname(metadataPath), { recursive: true });\n await fs.writeFile(metadataPath, `${JSON.stringify(record, null, 2)}\\n`, \"utf8\");\n }\n}\n","import { createRequire } from \"node:module\";\nimport type { Plugin } from \"vite\";\nimport { optimizeTemplateOutput } from \"./template-optimizer\";\nimport { ImagePipeline } from \"./image-pipeline\";\nimport type { ImagePipelineOptions } from \"./image-types\";\n\nconst require = createRequire(import.meta.url);\ntype TransformWithOxc = (typeof import(\"vite\"))[\"transformWithOxc\"];\nlet transformWithOxcPromise: Promise<TransformWithOxc> | undefined;\n\nasync function loadTransformWithOxc(): Promise<TransformWithOxc> {\n transformWithOxcPromise ??= (async () => {\n for (const packageName of [\"vite-plus\", \"vite\"] as const) {\n try {\n const buildTool = await import(packageName);\n if (typeof buildTool.transformWithOxc === \"function\") {\n return buildTool.transformWithOxc as TransformWithOxc;\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ERR_MODULE_NOT_FOUND\") throw error;\n }\n }\n throw new Error(\"@askrjs/vite requires either vite or vite-plus to transform JSX.\");\n })();\n return transformWithOxcPromise;\n}\n\n/** Options accepted by {@link askrVitePlugin}. */\nexport interface AskrVitePluginOptions {\n /** Transform `.jsx`/`.tsx` files with the Askr JSX runtime. Defaults to `true`. */\n transformJsx?: boolean;\n /** Hoist repeated JSX class/style literals using parsed compiled output. Defaults to `false`. */\n optimizeTemplates?: boolean;\n ssrPrecompile?: boolean;\n /** Opt into declared responsive image transforms. */\n images?: boolean | ImagePipelineOptions;\n}\n\n/**\n * Portable public plugin identity.\n *\n * Vite-compatible runners only require the plugin name. Keeping versioned Vite\n * hook types out of the installed declaration prevents consumers such as\n * vite-plus from comparing two distinct copies of Vite's recursive Plugin type.\n */\nexport interface AskrVitePlugin {\n readonly name: \"askr:vite\";\n}\n\n/**\n * Create the Askr Vite plugin, which transforms Askr JSX/TSX with oxc, wires\n * up dependency pre-bundling and aliasing for `@askrjs/askr`, and optionally\n * runs the responsive image pipeline and template optimizer.\n * JSX transform failures are reported through the active Vite/Rollup plugin\n * context with the source file and original transform detail.\n *\n * @param options Plugin configuration; all fields are optional.\n * @returns A Vite-compatible plugin object exposing the `askr:vite` name.\n */\nexport function askrVitePlugin(options: AskrVitePluginOptions = {}): AskrVitePlugin {\n const shouldTransform = options.transformJsx ?? true;\n const shouldOptimizeTemplates = options.optimizeTemplates ?? false;\n const imagePipeline = options.images\n ? new ImagePipeline(options.images === true ? {} : options.images)\n : undefined;\n const plugin = {\n name: \"askr:vite\" as const,\n enforce: \"pre\",\n config() {\n let askrEntry: string | null = null;\n try {\n askrEntry = require.resolve(\"@askrjs/askr\");\n } catch {\n askrEntry = null;\n }\n return {\n define: {\n __ASKR_OPTIMIZE_TEMPLATES__: JSON.stringify(shouldOptimizeTemplates),\n },\n resolve: {\n alias: askrEntry ? [{ find: \"@askrjs/askr\", replacement: askrEntry }] : [],\n dedupe: [\"@askrjs/askr\"],\n },\n optimizeDeps: {\n include: [\n \"@askrjs/askr\",\n \"@askrjs/askr/router\",\n \"@askrjs/askr/boot\",\n \"@askrjs/askr/control\",\n \"@askrjs/askr/fx\",\n \"@askrjs/askr/resources\",\n \"@askrjs/askr/data\",\n \"@askrjs/askr/foundations\",\n \"@askrjs/askr/foundations/icon\",\n \"@askrjs/askr/foundations/interactions\",\n \"@askrjs/askr/foundations/state\",\n \"@askrjs/askr/foundations/structures\",\n \"@askrjs/askr/foundations/utilities\",\n \"@askrjs/askr/jsx-runtime\",\n \"@askrjs/askr/jsx-dev-runtime\",\n ],\n },\n oxc: {\n jsx: { runtime: \"automatic\", importSource: \"@askrjs/askr\" },\n jsxInject: \"import { jsx, jsxs, Fragment } from '@askrjs/askr/jsx-runtime';\",\n },\n };\n },\n configResolved(config) {\n imagePipeline?.configure(config);\n },\n async transform(code, id) {\n if (id.includes(\"node_modules\")) return null;\n const imageTransformed = imagePipeline\n ? await imagePipeline.transform(this, code, id)\n : undefined;\n const input = imageTransformed ?? code;\n if (!shouldTransform || !/\\.(jsx|tsx)$/.test(id)) {\n return imageTransformed ? { code: imageTransformed, map: null } : null;\n }\n try {\n const transformWithOxc = await loadTransformWithOxc();\n const result = await transformWithOxc(input, id, {\n lang: id.endsWith(\".tsx\") ? \"tsx\" : \"jsx\",\n jsx: { runtime: \"automatic\", importSource: \"@askrjs/askr\" },\n sourcemap: true,\n });\n if (!result?.code) return null;\n return {\n code: shouldOptimizeTemplates ? optimizeTemplateOutput(result.code) : result.code,\n map: result.map,\n };\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n this.error(`@askrjs/vite failed to transform ${id}: ${detail}`);\n }\n },\n async writeBundle() {\n await imagePipeline?.writeMetadata(this);\n },\n } satisfies Plugin;\n return plugin;\n}\n"],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -7,30 +7,70 @@ interface ViteTelemetryFields {
|
|
|
7
7
|
interface ViteTelemetry {
|
|
8
8
|
viteDocument?<T>(fields: ViteTelemetryFields, work: () => T): T;
|
|
9
9
|
}
|
|
10
|
+
/** Options for composing a rendered Askr fragment into the HTML document. */
|
|
10
11
|
interface AskrDocumentOptions {
|
|
11
12
|
telemetry?: ViteTelemetry;
|
|
12
13
|
}
|
|
14
|
+
/** Placeholder marker in `index.html` replaced with the rendered app fragment. */
|
|
13
15
|
declare const ASKR_APP_MARKER = "<!--askr-app-->";
|
|
16
|
+
/** Placeholder marker in `index.html` replaced with rendered `<head>` content. */
|
|
14
17
|
declare const ASKR_HEAD_MARKER = "<!--askr-head-->";
|
|
18
|
+
/**
|
|
19
|
+
* Replace the single {@link ASKR_APP_MARKER} in `document` with `fragment`.
|
|
20
|
+
*
|
|
21
|
+
* @throws If `document` does not contain exactly one app marker.
|
|
22
|
+
*/
|
|
15
23
|
declare function insertAskrFragment(document: string, fragment: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Replace the {@link ASKR_HEAD_MARKER} in `document` with normalized `head`
|
|
26
|
+
* markup, and patch the `<html>` tag's `lang`/`dir` attributes when given.
|
|
27
|
+
*/
|
|
16
28
|
declare function composeAskrHead(document: string, head: string, lang?: string, dir?: string): string;
|
|
29
|
+
/** Whether `response` carries the `askr-fragment=1` content-type marker. */
|
|
17
30
|
declare function isAskrFragment(response: Response): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Compose an Askr fragment response into the full `transformedDocument` HTML,
|
|
33
|
+
* streaming the fragment's body between the document prefix and suffix.
|
|
34
|
+
* Non-fragment responses are returned unchanged.
|
|
35
|
+
*
|
|
36
|
+
* @param response The upstream response, expected to be an Askr fragment.
|
|
37
|
+
* @param transformedDocument The `index.html` document with app/head markers.
|
|
38
|
+
* @param options Optional telemetry hook wrapping the compose work.
|
|
39
|
+
* @returns The composed full-document `Response`, or `response` unchanged.
|
|
40
|
+
*/
|
|
18
41
|
declare function composeAskrDocumentResponse(response: Response, transformedDocument: string, options?: AskrDocumentOptions): Promise<Response>;
|
|
42
|
+
/**
|
|
43
|
+
* Wrap `app` so every response is composed into `transformedDocument` via
|
|
44
|
+
* {@link composeAskrDocumentResponse}.
|
|
45
|
+
*/
|
|
19
46
|
declare function createDocumentApp(app: ServerApp, transformedDocument: string, options?: AskrDocumentOptions): ServerApp;
|
|
20
47
|
//#endregion
|
|
21
48
|
//#region src/server/types.d.ts
|
|
49
|
+
/** Options for {@link askrServer}. */
|
|
22
50
|
interface AskrServerOptions {
|
|
51
|
+
/** Path to the server entry module, resolved relative to the Vite root. */
|
|
23
52
|
entry: string;
|
|
53
|
+
/** Named export on `entry` providing the `ServerApp`. Defaults to `"app"`, falling back to the default export. */
|
|
24
54
|
exportName?: string;
|
|
55
|
+
/** Path to the HTML document template, resolved relative to the Vite root. Defaults to `"index.html"`. */
|
|
25
56
|
indexHtml?: string;
|
|
26
57
|
}
|
|
27
58
|
//#endregion
|
|
28
59
|
//#region src/server/plugin.d.ts
|
|
60
|
+
/** Virtual module id that resolves to the generated server document app. */
|
|
29
61
|
declare const ASKR_SERVER_MODULE_ID = "virtual:askr-server";
|
|
30
62
|
/** Portable public identity for the server integration plugin. */
|
|
31
63
|
interface AskrServerPlugin {
|
|
32
64
|
readonly name: "askr:server";
|
|
33
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Create the Vite plugin that serves Askr's server-rendered document during
|
|
68
|
+
* development and generates the {@link ASKR_SERVER_MODULE_ID} virtual module
|
|
69
|
+
* that composes the built server app with the HTML document.
|
|
70
|
+
*
|
|
71
|
+
* @param options Server entry and document configuration.
|
|
72
|
+
* @returns A Vite-compatible plugin object exposing the `askr:server` name.
|
|
73
|
+
*/
|
|
34
74
|
declare function askrServer(options: AskrServerOptions): AskrServerPlugin;
|
|
35
75
|
//#endregion
|
|
36
76
|
export { ASKR_APP_MARKER, ASKR_HEAD_MARKER, ASKR_SERVER_MODULE_ID, AskrDocumentOptions, type AskrServerOptions, AskrServerPlugin, askrServer, composeAskrDocumentResponse, composeAskrHead, createDocumentApp, insertAskrFragment, isAskrFragment };
|
package/dist/server.js
CHANGED
|
@@ -99,7 +99,9 @@ function normalizeAskrHead(head) {
|
|
|
99
99
|
}
|
|
100
100
|
//#endregion
|
|
101
101
|
//#region src/server/document.ts
|
|
102
|
+
/** Placeholder marker in `index.html` replaced with the rendered app fragment. */
|
|
102
103
|
const ASKR_APP_MARKER = "<!--askr-app-->";
|
|
104
|
+
/** Placeholder marker in `index.html` replaced with rendered `<head>` content. */
|
|
103
105
|
const ASKR_HEAD_MARKER = "<!--askr-head-->";
|
|
104
106
|
function markerCount(document) {
|
|
105
107
|
return document.split(ASKR_APP_MARKER).length - 1;
|
|
@@ -116,17 +118,27 @@ function patchHtmlAttribute(document, name, value) {
|
|
|
116
118
|
return `<html${attributes.replace(matcher, "")} ${name}="${escapeAttribute(value)}">`;
|
|
117
119
|
});
|
|
118
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Replace the single {@link ASKR_APP_MARKER} in `document` with `fragment`.
|
|
123
|
+
*
|
|
124
|
+
* @throws If `document` does not contain exactly one app marker.
|
|
125
|
+
*/
|
|
119
126
|
function insertAskrFragment(document, fragment) {
|
|
120
127
|
const count = markerCount(document);
|
|
121
128
|
if (count !== 1) throw new Error(`index.html must contain exactly one ${ASKR_APP_MARKER} marker; found ${count}.`);
|
|
122
129
|
return document.replace(ASKR_APP_MARKER, fragment);
|
|
123
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Replace the {@link ASKR_HEAD_MARKER} in `document` with normalized `head`
|
|
133
|
+
* markup, and patch the `<html>` tag's `lang`/`dir` attributes when given.
|
|
134
|
+
*/
|
|
124
135
|
function composeAskrHead(document, head, lang, dir) {
|
|
125
136
|
let output = document.replace(ASKR_HEAD_MARKER, normalizeAskrHead(head));
|
|
126
137
|
if (lang) output = patchHtmlAttribute(output, "lang", lang);
|
|
127
138
|
if (dir) output = patchHtmlAttribute(output, "dir", dir);
|
|
128
139
|
return output;
|
|
129
140
|
}
|
|
141
|
+
/** Whether `response` carries the `askr-fragment=1` content-type marker. */
|
|
130
142
|
function isAskrFragment(response) {
|
|
131
143
|
return response.headers.get("content-type")?.split(";").some((part) => part.trim().toLowerCase() === "askr-fragment=1") ?? false;
|
|
132
144
|
}
|
|
@@ -194,6 +206,16 @@ function composeDocumentBody(fragment, prefix, suffix) {
|
|
|
194
206
|
}
|
|
195
207
|
});
|
|
196
208
|
}
|
|
209
|
+
/**
|
|
210
|
+
* Compose an Askr fragment response into the full `transformedDocument` HTML,
|
|
211
|
+
* streaming the fragment's body between the document prefix and suffix.
|
|
212
|
+
* Non-fragment responses are returned unchanged.
|
|
213
|
+
*
|
|
214
|
+
* @param response The upstream response, expected to be an Askr fragment.
|
|
215
|
+
* @param transformedDocument The `index.html` document with app/head markers.
|
|
216
|
+
* @param options Optional telemetry hook wrapping the compose work.
|
|
217
|
+
* @returns The composed full-document `Response`, or `response` unchanged.
|
|
218
|
+
*/
|
|
197
219
|
async function composeAskrDocumentResponse(response, transformedDocument, options = {}) {
|
|
198
220
|
if (!isAskrFragment(response)) return response;
|
|
199
221
|
const compose = () => {
|
|
@@ -212,6 +234,10 @@ async function composeAskrDocumentResponse(response, transformedDocument, option
|
|
|
212
234
|
};
|
|
213
235
|
return options.telemetry?.viteDocument ? options.telemetry.viteDocument({ status: response.status }, compose) : compose();
|
|
214
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Wrap `app` so every response is composed into `transformedDocument` via
|
|
239
|
+
* {@link composeAskrDocumentResponse}.
|
|
240
|
+
*/
|
|
215
241
|
function createDocumentApp(app, transformedDocument, options = {}) {
|
|
216
242
|
return { async fetch(request) {
|
|
217
243
|
return composeAskrDocumentResponse(await app.fetch(request), transformedDocument, options);
|
|
@@ -233,12 +259,14 @@ function createDevelopmentApp(server, options) {
|
|
|
233
259
|
const module = await server.ssrLoadModule(options.entry);
|
|
234
260
|
const response = await serverApp(module, options).fetch(request);
|
|
235
261
|
if (!isAskrFragment(response)) return response;
|
|
236
|
-
const
|
|
262
|
+
const file = resolve(server.config.root, options.indexHtml ?? "index.html");
|
|
263
|
+
const document = await readFile(file, "utf8");
|
|
237
264
|
return composeAskrDocumentResponse(response, await server.transformIndexHtml(new URL(request.url).pathname, document), moduleTelemetry(module));
|
|
238
265
|
} };
|
|
239
266
|
}
|
|
240
267
|
//#endregion
|
|
241
268
|
//#region src/server/plugin.ts
|
|
269
|
+
/** Virtual module id that resolves to the generated server document app. */
|
|
242
270
|
const ASKR_SERVER_MODULE_ID = "virtual:askr-server";
|
|
243
271
|
const RESOLVED_SERVER_MODULE_ID = "\0askr:server";
|
|
244
272
|
function createNodeHandlerOptions(server) {
|
|
@@ -258,6 +286,14 @@ function createNodeHandlerOptions(server) {
|
|
|
258
286
|
]);
|
|
259
287
|
return { allowedHosts: Array.from(allowedHosts) };
|
|
260
288
|
}
|
|
289
|
+
/**
|
|
290
|
+
* Create the Vite plugin that serves Askr's server-rendered document during
|
|
291
|
+
* development and generates the {@link ASKR_SERVER_MODULE_ID} virtual module
|
|
292
|
+
* that composes the built server app with the HTML document.
|
|
293
|
+
*
|
|
294
|
+
* @param options Server entry and document configuration.
|
|
295
|
+
* @returns A Vite-compatible plugin object exposing the `askr:server` name.
|
|
296
|
+
*/
|
|
261
297
|
function askrServer(options) {
|
|
262
298
|
let config;
|
|
263
299
|
return {
|
|
@@ -278,7 +314,8 @@ function askrServer(options) {
|
|
|
278
314
|
if (id !== RESOLVED_SERVER_MODULE_ID) return null;
|
|
279
315
|
if (!config) throw new Error("@askrjs/vite: server plugin was not configured.");
|
|
280
316
|
const sourceDocument = resolve(config.root, options.indexHtml ?? "index.html");
|
|
281
|
-
const
|
|
317
|
+
const builtDocument = [resolve(config.root, config.build.outDir, "index.html"), resolve(config.root, config.build.outDir, "..", "index.html")].find(existsSync);
|
|
318
|
+
const document = await readFile(builtDocument ?? sourceDocument, "utf8");
|
|
282
319
|
const entry = resolve(config.root, options.entry);
|
|
283
320
|
const exportName = options.exportName ?? "app";
|
|
284
321
|
return [
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","names":[],"sources":["../src/server/head.ts","../src/server/document.ts","../src/server/development.ts","../src/server/plugin.ts"],"sourcesContent":["import { parseFragment, serialize, type DefaultTreeAdapterMap } from \"parse5\";\n\nconst htmlNamespace = \"http://www.w3.org/1999/xhtml\";\nconst linkAttributes = new Set([\n \"as\",\n \"crossorigin\",\n \"data-askr-head\",\n \"fetchpriority\",\n \"href\",\n \"hreflang\",\n \"imagesizes\",\n \"imagesrcset\",\n \"media\",\n \"referrerpolicy\",\n \"rel\",\n \"sizes\",\n \"type\",\n]);\n\nfunction headMarkupError(message: string): never {\n throw new TypeError(`Invalid x-askr-head metadata: ${message}`);\n}\n\nfunction attributesOf(node: DefaultTreeAdapterMap[\"element\"]): Map<string, string> {\n const attributes = new Map<string, string>();\n for (const attribute of node.attrs) {\n if (attribute.namespace || attribute.prefix)\n headMarkupError(\"namespaced attributes are not allowed.\");\n attributes.set(attribute.name.toLowerCase(), attribute.value);\n }\n return attributes;\n}\n\nfunction requireAllowedAttributes(\n attributes: Map<string, string>,\n allowed: ReadonlySet<string>,\n): void {\n for (const name of attributes.keys()) {\n if (!allowed.has(name)) headMarkupError(`attribute ${name} is not allowed.`);\n }\n if (attributes.get(\"data-askr-head\") !== \"\")\n headMarkupError(\"every metadata node must be Askr-owned.\");\n}\n\nfunction isTextNode(\n node: DefaultTreeAdapterMap[\"childNode\"],\n): node is DefaultTreeAdapterMap[\"textNode\"] {\n return \"value\" in node;\n}\n\nfunction textContent(node: DefaultTreeAdapterMap[\"element\"]): string {\n let value = \"\";\n for (const child of node.childNodes) {\n if (!isTextNode(child)) headMarkupError(`${node.tagName} must contain only text.`);\n value += child.value;\n }\n return value;\n}\n\nfunction validateHeadElement(node: DefaultTreeAdapterMap[\"element\"]): void {\n if (node.namespaceURI !== htmlNamespace) headMarkupError(\"foreign elements are not allowed.\");\n const attributes = attributesOf(node);\n if (node.tagName === \"title\") {\n requireAllowedAttributes(attributes, new Set([\"data-askr-head\"]));\n textContent(node);\n return;\n }\n if (node.tagName === \"meta\") {\n requireAllowedAttributes(\n attributes,\n new Set([\"content\", \"data-askr-head\", \"name\", \"property\"]),\n );\n const hasName = attributes.has(\"name\");\n const hasProperty = attributes.has(\"property\");\n if (hasName === hasProperty || !attributes.has(\"content\"))\n headMarkupError(\"meta requires content and exactly one of name or property.\");\n if (node.childNodes.length) headMarkupError(\"meta cannot contain child nodes.\");\n return;\n }\n if (node.tagName === \"link\") {\n requireAllowedAttributes(attributes, linkAttributes);\n if (!attributes.has(\"rel\") || !attributes.has(\"href\"))\n headMarkupError(\"link requires rel and href.\");\n if (node.childNodes.length) headMarkupError(\"link cannot contain child nodes.\");\n return;\n }\n if (node.tagName === \"script\") {\n requireAllowedAttributes(attributes, new Set([\"data-askr-head\", \"type\"]));\n if (attributes.get(\"type\") !== \"application/ld+json\")\n headMarkupError(\"only application/ld+json script nodes are allowed.\");\n const json = textContent(node);\n try {\n JSON.parse(json);\n } catch {\n headMarkupError(\"JSON-LD content must be valid JSON.\");\n }\n return;\n }\n headMarkupError(`element ${node.tagName} is not allowed.`);\n}\n\nexport function normalizeAskrHead(head: string): string {\n const fragment = parseFragment(head);\n for (const node of fragment.childNodes) {\n if (isTextNode(node)) {\n if (node.value.trim()) headMarkupError(\"top-level text is not allowed.\");\n continue;\n }\n if (!(\"tagName\" in node)) headMarkupError(\"non-element nodes are not allowed.\");\n validateHeadElement(node);\n }\n return serialize(fragment);\n}\n","import type { ServerApp } from \"@askrjs/server\";\nimport { normalizeAskrHead } from \"./head\";\n\ninterface ViteTelemetryFields {\n status?: number;\n}\n\ninterface ViteTelemetry {\n viteDocument?<T>(fields: ViteTelemetryFields, work: () => T): T;\n}\n\nexport interface AskrDocumentOptions {\n telemetry?: ViteTelemetry;\n}\n\nexport const ASKR_APP_MARKER = \"<!--askr-app-->\";\nexport const ASKR_HEAD_MARKER = \"<!--askr-head-->\";\n\nfunction markerCount(document: string): number {\n return document.split(ASKR_APP_MARKER).length - 1;\n}\n\nfunction headMarkerCount(document: string): number {\n return document.split(ASKR_HEAD_MARKER).length - 1;\n}\n\nfunction escapeAttribute(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nfunction patchHtmlAttribute(document: string, name: \"lang\" | \"dir\", value: string): string {\n return document.replace(/<html\\b([^>]*)>/i, (_match, attributes: string) => {\n const matcher = new RegExp(\n `\\\\s+${name}(?:\\\\s*=\\\\s*(?:\"[^\"]*\"|'[^']*'|[^\\\\s\"'=<>\\u0060]+))?`,\n \"gi\",\n );\n const withoutExisting = attributes.replace(matcher, \"\");\n return `<html${withoutExisting} ${name}=\"${escapeAttribute(value)}\">`;\n });\n}\n\nexport function insertAskrFragment(document: string, fragment: string): string {\n const count = markerCount(document);\n if (count !== 1) {\n throw new Error(\n `index.html must contain exactly one ${ASKR_APP_MARKER} marker; found ${count}.`,\n );\n }\n return document.replace(ASKR_APP_MARKER, fragment);\n}\n\nexport function composeAskrHead(\n document: string,\n head: string,\n lang?: string,\n dir?: string,\n): string {\n let output = document.replace(ASKR_HEAD_MARKER, normalizeAskrHead(head));\n if (lang) output = patchHtmlAttribute(output, \"lang\", lang);\n if (dir) output = patchHtmlAttribute(output, \"dir\", dir);\n return output;\n}\n\nexport function isAskrFragment(response: Response): boolean {\n return (\n response.headers\n .get(\"content-type\")\n ?.split(\";\")\n .some((part) => part.trim().toLowerCase() === \"askr-fragment=1\") ?? false\n );\n}\n\nfunction documentHeaders(response: Response): Headers {\n const headers = new Headers(response.headers);\n const type = response.headers\n .get(\"content-type\")\n ?.split(\";\")\n .map((part) => part.trim())\n .filter((part) => part.toLowerCase() !== \"askr-fragment=1\")\n .join(\"; \");\n if (type) headers.set(\"content-type\", type);\n for (const name of [\n \"accept-ranges\",\n \"content-digest\",\n \"content-encoding\",\n \"content-length\",\n \"content-md5\",\n \"content-range\",\n \"digest\",\n \"etag\",\n \"last-modified\",\n \"repr-digest\",\n \"trailer\",\n ]) {\n headers.delete(name);\n }\n const internalHeaders: string[] = [];\n headers.forEach((_value, key) => {\n if (key.toLowerCase().startsWith(\"x-askr-\")) internalHeaders.push(key);\n });\n for (const key of internalHeaders) headers.delete(key);\n return headers;\n}\n\nfunction composeDocumentBody(\n fragment: ReadableStream<Uint8Array> | null,\n prefix: string,\n suffix: string,\n): BodyInit {\n if (!fragment) return `${prefix}${suffix}`;\n const encoder = new TextEncoder();\n const reader = fragment.getReader();\n let prefixPending = true;\n let suffixPending = true;\n let reading = false;\n let cancelled = false;\n\n return new ReadableStream<Uint8Array>({\n pull(controller) {\n if (prefixPending) {\n prefixPending = false;\n if (prefix) controller.enqueue(encoder.encode(prefix));\n return;\n }\n if (reading) return;\n reading = true;\n void reader.read().then(\n (part) => {\n reading = false;\n if (cancelled) return;\n if (!part.done) {\n controller.enqueue(part.value);\n return;\n }\n if (suffixPending && suffix) controller.enqueue(encoder.encode(suffix));\n suffixPending = false;\n controller.close();\n },\n (error) => {\n reading = false;\n if (cancelled) return;\n controller.error(error);\n void reader.cancel(error).catch(() => undefined);\n },\n );\n },\n async cancel(reason) {\n cancelled = true;\n await reader.cancel(reason).catch(() => undefined);\n },\n });\n}\n\nexport async function composeAskrDocumentResponse(\n response: Response,\n transformedDocument: string,\n options: AskrDocumentOptions = {},\n): Promise<Response> {\n if (!isAskrFragment(response)) return response;\n const compose = () => {\n if (headMarkerCount(transformedDocument) !== 1) {\n throw new Error(\n `index.html must contain exactly one ${ASKR_HEAD_MARKER} marker; found ${headMarkerCount(transformedDocument)}.`,\n );\n }\n const withHead = composeAskrHead(\n transformedDocument,\n response.headers.get(\"x-askr-head\") ?? \"\",\n response.headers.get(\"x-askr-html-lang\") ?? undefined,\n response.headers.get(\"x-askr-html-dir\") ?? undefined,\n );\n const appCount = markerCount(withHead);\n if (appCount !== 1) {\n throw new Error(\n `index.html must contain exactly one ${ASKR_APP_MARKER} marker; found ${appCount}.`,\n );\n }\n const markerIndex = withHead.indexOf(ASKR_APP_MARKER);\n const prefix = withHead.slice(0, markerIndex);\n const suffix = withHead.slice(markerIndex + ASKR_APP_MARKER.length);\n return new Response(composeDocumentBody(response.body, prefix, suffix), {\n status: response.status,\n statusText: response.statusText,\n headers: documentHeaders(response),\n });\n };\n return options.telemetry?.viteDocument\n ? options.telemetry.viteDocument({ status: response.status }, compose)\n : compose();\n}\n\nexport function createDocumentApp(\n app: ServerApp,\n transformedDocument: string,\n options: AskrDocumentOptions = {},\n): ServerApp {\n return {\n async fetch(request) {\n return composeAskrDocumentResponse(await app.fetch(request), transformedDocument, options);\n },\n };\n}\n","import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport type { ServerApp } from \"@askrjs/server\";\nimport type { ViteDevServer } from \"vite\";\nimport { composeAskrDocumentResponse, isAskrFragment } from \"./document\";\nimport type { AskrServerOptions } from \"./types\";\n\nfunction serverApp(module: Record<string, unknown>, options: AskrServerOptions): ServerApp {\n const value = module[options.exportName ?? \"app\"] ?? module.default;\n if (!value || typeof (value as ServerApp).fetch !== \"function\") {\n throw new Error(\n `@askrjs/vite: ${options.entry} must export a ServerApp as ${options.exportName ?? \"app\"} or default`,\n );\n }\n return value as ServerApp;\n}\n\nfunction moduleTelemetry(module: Record<string, unknown>) {\n const telemetry = module[\"telemetry\"];\n return telemetry && typeof telemetry === \"object\"\n ? {\n telemetry: telemetry as NonNullable<\n Parameters<typeof composeAskrDocumentResponse>[2]\n >[\"telemetry\"],\n }\n : undefined;\n}\n\nexport function createDevelopmentApp(server: ViteDevServer, options: AskrServerOptions): ServerApp {\n return {\n async fetch(request) {\n const module = await server.ssrLoadModule(options.entry);\n const response = await serverApp(module, options).fetch(request);\n if (!isAskrFragment(response)) return response;\n const file = resolve(server.config.root, options.indexHtml ?? \"index.html\");\n const document = await readFile(file, \"utf8\");\n const transformed = await server.transformIndexHtml(new URL(request.url).pathname, document);\n return composeAskrDocumentResponse(response, transformed, moduleTelemetry(module));\n },\n };\n}\n","import { createNodeHandler } from \"@askrjs/node\";\nimport { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Plugin, ResolvedConfig, ViteDevServer } from \"vite\";\nimport { createDevelopmentApp } from \"./development\";\nimport type { AskrServerOptions } from \"./types\";\n\nexport const ASKR_SERVER_MODULE_ID = \"virtual:askr-server\";\nconst RESOLVED_SERVER_MODULE_ID = \"\\0askr:server\";\n\n/** Portable public identity for the server integration plugin. */\nexport interface AskrServerPlugin {\n readonly name: \"askr:server\";\n}\n\nfunction createNodeHandlerOptions(server: ViteDevServer): {\n baseUrl?: string;\n allowedHosts?: readonly string[];\n} {\n const serverConfig = server.config?.server;\n const baseUrl = serverConfig?.origin;\n\n if (\n serverConfig?.allowedHosts &&\n serverConfig.allowedHosts !== true &&\n serverConfig.allowedHosts.length > 0\n ) {\n return { baseUrl, allowedHosts: serverConfig.allowedHosts };\n }\n\n if (baseUrl) {\n return { baseUrl };\n }\n\n const host = typeof serverConfig?.host === \"string\" ? serverConfig.host : \"localhost\";\n const allowedHosts = new Set([host, \"localhost\", \"127.0.0.1\", \"[::1]\"]);\n return { allowedHosts: Array.from(allowedHosts) };\n}\n\nexport function askrServer(options: AskrServerOptions): AskrServerPlugin {\n let config: ResolvedConfig | undefined;\n const plugin = {\n name: \"askr:server\" as const,\n config() {\n // Askr owns document routing. Vite should serve modules and assets, but\n // must not rewrite page URLs to /index.html before the Askr fallback.\n // Keep the Askr package family inside Vite's module graph so file-linked\n // peers cannot load a second runtime with a different component context.\n // Vitest derives its dependency inlining from resolve.noExternal, which\n // is also Vite 8's replacement for the deprecated ssr.noExternal option.\n return {\n appType: \"custom\",\n resolve: { noExternal: [\"@askrjs/*\"] },\n };\n },\n configResolved(resolved) {\n config = resolved;\n },\n resolveId(id) {\n return id === ASKR_SERVER_MODULE_ID ? RESOLVED_SERVER_MODULE_ID : null;\n },\n async load(id) {\n if (id !== RESOLVED_SERVER_MODULE_ID) return null;\n if (!config) throw new Error(\"@askrjs/vite: server plugin was not configured.\");\n const sourceDocument = resolve(config.root, options.indexHtml ?? \"index.html\");\n const serverOutDocument = resolve(config.root, config.build.outDir, \"index.html\");\n const clientOutDocument = resolve(config.root, config.build.outDir, \"..\", \"index.html\");\n const builtDocument = [serverOutDocument, clientOutDocument].find(existsSync);\n const document = await readFile(builtDocument ?? sourceDocument, \"utf8\");\n const entry = resolve(config.root, options.entry);\n const exportName = options.exportName ?? \"app\";\n return [\n `import * as source from ${JSON.stringify(entry)};`,\n `import { createDocumentApp } from '@askrjs/vite/server';`,\n `const sourceApp = source[${JSON.stringify(exportName)}] ?? source.default;`,\n `const sourceTelemetry = Reflect.get(source, 'telemetry');`,\n `if (!sourceApp?.fetch) throw new Error(${JSON.stringify(`@askrjs/vite: ${options.entry} must export a ServerApp`)});`,\n `export const app = createDocumentApp(sourceApp, ${JSON.stringify(document)}, sourceTelemetry ? { telemetry: sourceTelemetry } : undefined);`,\n `export default app;`,\n ].join(\"\\n\");\n },\n configureServer(server) {\n const handler = createNodeHandler(\n createDevelopmentApp(server, options),\n createNodeHandlerOptions(server),\n );\n // Page rendering is the development fallback. Register it after Vite's\n // module, asset, and HTML middleware so client entries and imported CSS\n // are served by Vite instead of being mistaken for application routes.\n return () => server.middlewares.use(handler);\n },\n } satisfies Plugin;\n return plugin;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","names":[],"sources":["../src/server/head.ts","../src/server/document.ts","../src/server/development.ts","../src/server/plugin.ts"],"sourcesContent":["import { parseFragment, serialize, type DefaultTreeAdapterMap } from \"parse5\";\n\nconst htmlNamespace = \"http://www.w3.org/1999/xhtml\";\nconst linkAttributes = new Set([\n \"as\",\n \"crossorigin\",\n \"data-askr-head\",\n \"fetchpriority\",\n \"href\",\n \"hreflang\",\n \"imagesizes\",\n \"imagesrcset\",\n \"media\",\n \"referrerpolicy\",\n \"rel\",\n \"sizes\",\n \"type\",\n]);\n\nfunction headMarkupError(message: string): never {\n throw new TypeError(`Invalid x-askr-head metadata: ${message}`);\n}\n\nfunction attributesOf(node: DefaultTreeAdapterMap[\"element\"]): Map<string, string> {\n const attributes = new Map<string, string>();\n for (const attribute of node.attrs) {\n if (attribute.namespace || attribute.prefix)\n headMarkupError(\"namespaced attributes are not allowed.\");\n attributes.set(attribute.name.toLowerCase(), attribute.value);\n }\n return attributes;\n}\n\nfunction requireAllowedAttributes(\n attributes: Map<string, string>,\n allowed: ReadonlySet<string>,\n): void {\n for (const name of attributes.keys()) {\n if (!allowed.has(name)) headMarkupError(`attribute ${name} is not allowed.`);\n }\n if (attributes.get(\"data-askr-head\") !== \"\")\n headMarkupError(\"every metadata node must be Askr-owned.\");\n}\n\nfunction isTextNode(\n node: DefaultTreeAdapterMap[\"childNode\"],\n): node is DefaultTreeAdapterMap[\"textNode\"] {\n return \"value\" in node;\n}\n\nfunction textContent(node: DefaultTreeAdapterMap[\"element\"]): string {\n let value = \"\";\n for (const child of node.childNodes) {\n if (!isTextNode(child)) headMarkupError(`${node.tagName} must contain only text.`);\n value += child.value;\n }\n return value;\n}\n\nfunction validateHeadElement(node: DefaultTreeAdapterMap[\"element\"]): void {\n if (node.namespaceURI !== htmlNamespace) headMarkupError(\"foreign elements are not allowed.\");\n const attributes = attributesOf(node);\n if (node.tagName === \"title\") {\n requireAllowedAttributes(attributes, new Set([\"data-askr-head\"]));\n textContent(node);\n return;\n }\n if (node.tagName === \"meta\") {\n requireAllowedAttributes(\n attributes,\n new Set([\"content\", \"data-askr-head\", \"name\", \"property\"]),\n );\n const hasName = attributes.has(\"name\");\n const hasProperty = attributes.has(\"property\");\n if (hasName === hasProperty || !attributes.has(\"content\"))\n headMarkupError(\"meta requires content and exactly one of name or property.\");\n if (node.childNodes.length) headMarkupError(\"meta cannot contain child nodes.\");\n return;\n }\n if (node.tagName === \"link\") {\n requireAllowedAttributes(attributes, linkAttributes);\n if (!attributes.has(\"rel\") || !attributes.has(\"href\"))\n headMarkupError(\"link requires rel and href.\");\n if (node.childNodes.length) headMarkupError(\"link cannot contain child nodes.\");\n return;\n }\n if (node.tagName === \"script\") {\n requireAllowedAttributes(attributes, new Set([\"data-askr-head\", \"type\"]));\n if (attributes.get(\"type\") !== \"application/ld+json\")\n headMarkupError(\"only application/ld+json script nodes are allowed.\");\n const json = textContent(node);\n try {\n JSON.parse(json);\n } catch {\n headMarkupError(\"JSON-LD content must be valid JSON.\");\n }\n return;\n }\n headMarkupError(`element ${node.tagName} is not allowed.`);\n}\n\nexport function normalizeAskrHead(head: string): string {\n const fragment = parseFragment(head);\n for (const node of fragment.childNodes) {\n if (isTextNode(node)) {\n if (node.value.trim()) headMarkupError(\"top-level text is not allowed.\");\n continue;\n }\n if (!(\"tagName\" in node)) headMarkupError(\"non-element nodes are not allowed.\");\n validateHeadElement(node);\n }\n return serialize(fragment);\n}\n","import type { ServerApp } from \"@askrjs/server\";\nimport { normalizeAskrHead } from \"./head\";\n\ninterface ViteTelemetryFields {\n status?: number;\n}\n\ninterface ViteTelemetry {\n viteDocument?<T>(fields: ViteTelemetryFields, work: () => T): T;\n}\n\n/** Options for composing a rendered Askr fragment into the HTML document. */\nexport interface AskrDocumentOptions {\n telemetry?: ViteTelemetry;\n}\n\n/** Placeholder marker in `index.html` replaced with the rendered app fragment. */\nexport const ASKR_APP_MARKER = \"<!--askr-app-->\";\n/** Placeholder marker in `index.html` replaced with rendered `<head>` content. */\nexport const ASKR_HEAD_MARKER = \"<!--askr-head-->\";\n\nfunction markerCount(document: string): number {\n return document.split(ASKR_APP_MARKER).length - 1;\n}\n\nfunction headMarkerCount(document: string): number {\n return document.split(ASKR_HEAD_MARKER).length - 1;\n}\n\nfunction escapeAttribute(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nfunction patchHtmlAttribute(document: string, name: \"lang\" | \"dir\", value: string): string {\n return document.replace(/<html\\b([^>]*)>/i, (_match, attributes: string) => {\n const matcher = new RegExp(\n `\\\\s+${name}(?:\\\\s*=\\\\s*(?:\"[^\"]*\"|'[^']*'|[^\\\\s\"'=<>\\u0060]+))?`,\n \"gi\",\n );\n const withoutExisting = attributes.replace(matcher, \"\");\n return `<html${withoutExisting} ${name}=\"${escapeAttribute(value)}\">`;\n });\n}\n\n/**\n * Replace the single {@link ASKR_APP_MARKER} in `document` with `fragment`.\n *\n * @throws If `document` does not contain exactly one app marker.\n */\nexport function insertAskrFragment(document: string, fragment: string): string {\n const count = markerCount(document);\n if (count !== 1) {\n throw new Error(\n `index.html must contain exactly one ${ASKR_APP_MARKER} marker; found ${count}.`,\n );\n }\n return document.replace(ASKR_APP_MARKER, fragment);\n}\n\n/**\n * Replace the {@link ASKR_HEAD_MARKER} in `document` with normalized `head`\n * markup, and patch the `<html>` tag's `lang`/`dir` attributes when given.\n */\nexport function composeAskrHead(\n document: string,\n head: string,\n lang?: string,\n dir?: string,\n): string {\n let output = document.replace(ASKR_HEAD_MARKER, normalizeAskrHead(head));\n if (lang) output = patchHtmlAttribute(output, \"lang\", lang);\n if (dir) output = patchHtmlAttribute(output, \"dir\", dir);\n return output;\n}\n\n/** Whether `response` carries the `askr-fragment=1` content-type marker. */\nexport function isAskrFragment(response: Response): boolean {\n return (\n response.headers\n .get(\"content-type\")\n ?.split(\";\")\n .some((part) => part.trim().toLowerCase() === \"askr-fragment=1\") ?? false\n );\n}\n\nfunction documentHeaders(response: Response): Headers {\n const headers = new Headers(response.headers);\n const type = response.headers\n .get(\"content-type\")\n ?.split(\";\")\n .map((part) => part.trim())\n .filter((part) => part.toLowerCase() !== \"askr-fragment=1\")\n .join(\"; \");\n if (type) headers.set(\"content-type\", type);\n for (const name of [\n \"accept-ranges\",\n \"content-digest\",\n \"content-encoding\",\n \"content-length\",\n \"content-md5\",\n \"content-range\",\n \"digest\",\n \"etag\",\n \"last-modified\",\n \"repr-digest\",\n \"trailer\",\n ]) {\n headers.delete(name);\n }\n const internalHeaders: string[] = [];\n headers.forEach((_value, key) => {\n if (key.toLowerCase().startsWith(\"x-askr-\")) internalHeaders.push(key);\n });\n for (const key of internalHeaders) headers.delete(key);\n return headers;\n}\n\nfunction composeDocumentBody(\n fragment: ReadableStream<Uint8Array> | null,\n prefix: string,\n suffix: string,\n): BodyInit {\n if (!fragment) return `${prefix}${suffix}`;\n const encoder = new TextEncoder();\n const reader = fragment.getReader();\n let prefixPending = true;\n let suffixPending = true;\n let reading = false;\n let cancelled = false;\n\n return new ReadableStream<Uint8Array>({\n pull(controller) {\n if (prefixPending) {\n prefixPending = false;\n if (prefix) controller.enqueue(encoder.encode(prefix));\n return;\n }\n if (reading) return;\n reading = true;\n void reader.read().then(\n (part) => {\n reading = false;\n if (cancelled) return;\n if (!part.done) {\n controller.enqueue(part.value);\n return;\n }\n if (suffixPending && suffix) controller.enqueue(encoder.encode(suffix));\n suffixPending = false;\n controller.close();\n },\n (error) => {\n reading = false;\n if (cancelled) return;\n controller.error(error);\n void reader.cancel(error).catch(() => undefined);\n },\n );\n },\n async cancel(reason) {\n cancelled = true;\n await reader.cancel(reason).catch(() => undefined);\n },\n });\n}\n\n/**\n * Compose an Askr fragment response into the full `transformedDocument` HTML,\n * streaming the fragment's body between the document prefix and suffix.\n * Non-fragment responses are returned unchanged.\n *\n * @param response The upstream response, expected to be an Askr fragment.\n * @param transformedDocument The `index.html` document with app/head markers.\n * @param options Optional telemetry hook wrapping the compose work.\n * @returns The composed full-document `Response`, or `response` unchanged.\n */\nexport async function composeAskrDocumentResponse(\n response: Response,\n transformedDocument: string,\n options: AskrDocumentOptions = {},\n): Promise<Response> {\n if (!isAskrFragment(response)) return response;\n const compose = () => {\n if (headMarkerCount(transformedDocument) !== 1) {\n throw new Error(\n `index.html must contain exactly one ${ASKR_HEAD_MARKER} marker; found ${headMarkerCount(transformedDocument)}.`,\n );\n }\n const withHead = composeAskrHead(\n transformedDocument,\n response.headers.get(\"x-askr-head\") ?? \"\",\n response.headers.get(\"x-askr-html-lang\") ?? undefined,\n response.headers.get(\"x-askr-html-dir\") ?? undefined,\n );\n const appCount = markerCount(withHead);\n if (appCount !== 1) {\n throw new Error(\n `index.html must contain exactly one ${ASKR_APP_MARKER} marker; found ${appCount}.`,\n );\n }\n const markerIndex = withHead.indexOf(ASKR_APP_MARKER);\n const prefix = withHead.slice(0, markerIndex);\n const suffix = withHead.slice(markerIndex + ASKR_APP_MARKER.length);\n return new Response(composeDocumentBody(response.body, prefix, suffix), {\n status: response.status,\n statusText: response.statusText,\n headers: documentHeaders(response),\n });\n };\n return options.telemetry?.viteDocument\n ? options.telemetry.viteDocument({ status: response.status }, compose)\n : compose();\n}\n\n/**\n * Wrap `app` so every response is composed into `transformedDocument` via\n * {@link composeAskrDocumentResponse}.\n */\nexport function createDocumentApp(\n app: ServerApp,\n transformedDocument: string,\n options: AskrDocumentOptions = {},\n): ServerApp {\n return {\n async fetch(request) {\n return composeAskrDocumentResponse(await app.fetch(request), transformedDocument, options);\n },\n };\n}\n","import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport type { ServerApp } from \"@askrjs/server\";\nimport type { ViteDevServer } from \"vite\";\nimport { composeAskrDocumentResponse, isAskrFragment } from \"./document\";\nimport type { AskrServerOptions } from \"./types\";\n\nfunction serverApp(module: Record<string, unknown>, options: AskrServerOptions): ServerApp {\n const value = module[options.exportName ?? \"app\"] ?? module.default;\n if (!value || typeof (value as ServerApp).fetch !== \"function\") {\n throw new Error(\n `@askrjs/vite: ${options.entry} must export a ServerApp as ${options.exportName ?? \"app\"} or default`,\n );\n }\n return value as ServerApp;\n}\n\nfunction moduleTelemetry(module: Record<string, unknown>) {\n const telemetry = module[\"telemetry\"];\n return telemetry && typeof telemetry === \"object\"\n ? {\n telemetry: telemetry as NonNullable<\n Parameters<typeof composeAskrDocumentResponse>[2]\n >[\"telemetry\"],\n }\n : undefined;\n}\n\nexport function createDevelopmentApp(server: ViteDevServer, options: AskrServerOptions): ServerApp {\n return {\n async fetch(request) {\n const module = await server.ssrLoadModule(options.entry);\n const response = await serverApp(module, options).fetch(request);\n if (!isAskrFragment(response)) return response;\n const file = resolve(server.config.root, options.indexHtml ?? \"index.html\");\n const document = await readFile(file, \"utf8\");\n const transformed = await server.transformIndexHtml(new URL(request.url).pathname, document);\n return composeAskrDocumentResponse(response, transformed, moduleTelemetry(module));\n },\n };\n}\n","import { createNodeHandler } from \"@askrjs/node\";\nimport { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { Plugin, ResolvedConfig, ViteDevServer } from \"vite\";\nimport { createDevelopmentApp } from \"./development\";\nimport type { AskrServerOptions } from \"./types\";\n\n/** Virtual module id that resolves to the generated server document app. */\nexport const ASKR_SERVER_MODULE_ID = \"virtual:askr-server\";\nconst RESOLVED_SERVER_MODULE_ID = \"\\0askr:server\";\n\n/** Portable public identity for the server integration plugin. */\nexport interface AskrServerPlugin {\n readonly name: \"askr:server\";\n}\n\nfunction createNodeHandlerOptions(server: ViteDevServer): {\n baseUrl?: string;\n allowedHosts?: readonly string[];\n} {\n const serverConfig = server.config?.server;\n const baseUrl = serverConfig?.origin;\n\n if (\n serverConfig?.allowedHosts &&\n serverConfig.allowedHosts !== true &&\n serverConfig.allowedHosts.length > 0\n ) {\n return { baseUrl, allowedHosts: serverConfig.allowedHosts };\n }\n\n if (baseUrl) {\n return { baseUrl };\n }\n\n const host = typeof serverConfig?.host === \"string\" ? serverConfig.host : \"localhost\";\n const allowedHosts = new Set([host, \"localhost\", \"127.0.0.1\", \"[::1]\"]);\n return { allowedHosts: Array.from(allowedHosts) };\n}\n\n/**\n * Create the Vite plugin that serves Askr's server-rendered document during\n * development and generates the {@link ASKR_SERVER_MODULE_ID} virtual module\n * that composes the built server app with the HTML document.\n *\n * @param options Server entry and document configuration.\n * @returns A Vite-compatible plugin object exposing the `askr:server` name.\n */\nexport function askrServer(options: AskrServerOptions): AskrServerPlugin {\n let config: ResolvedConfig | undefined;\n const plugin = {\n name: \"askr:server\" as const,\n config() {\n // Askr owns document routing. Vite should serve modules and assets, but\n // must not rewrite page URLs to /index.html before the Askr fallback.\n // Keep the Askr package family inside Vite's module graph so file-linked\n // peers cannot load a second runtime with a different component context.\n // Vitest derives its dependency inlining from resolve.noExternal, which\n // is also Vite 8's replacement for the deprecated ssr.noExternal option.\n return {\n appType: \"custom\",\n resolve: { noExternal: [\"@askrjs/*\"] },\n };\n },\n configResolved(resolved) {\n config = resolved;\n },\n resolveId(id) {\n return id === ASKR_SERVER_MODULE_ID ? RESOLVED_SERVER_MODULE_ID : null;\n },\n async load(id) {\n if (id !== RESOLVED_SERVER_MODULE_ID) return null;\n if (!config) throw new Error(\"@askrjs/vite: server plugin was not configured.\");\n const sourceDocument = resolve(config.root, options.indexHtml ?? \"index.html\");\n const serverOutDocument = resolve(config.root, config.build.outDir, \"index.html\");\n const clientOutDocument = resolve(config.root, config.build.outDir, \"..\", \"index.html\");\n const builtDocument = [serverOutDocument, clientOutDocument].find(existsSync);\n const document = await readFile(builtDocument ?? sourceDocument, \"utf8\");\n const entry = resolve(config.root, options.entry);\n const exportName = options.exportName ?? \"app\";\n return [\n `import * as source from ${JSON.stringify(entry)};`,\n `import { createDocumentApp } from '@askrjs/vite/server';`,\n `const sourceApp = source[${JSON.stringify(exportName)}] ?? source.default;`,\n `const sourceTelemetry = Reflect.get(source, 'telemetry');`,\n `if (!sourceApp?.fetch) throw new Error(${JSON.stringify(`@askrjs/vite: ${options.entry} must export a ServerApp`)});`,\n `export const app = createDocumentApp(sourceApp, ${JSON.stringify(document)}, sourceTelemetry ? { telemetry: sourceTelemetry } : undefined);`,\n `export default app;`,\n ].join(\"\\n\");\n },\n configureServer(server) {\n const handler = createNodeHandler(\n createDevelopmentApp(server, options),\n createNodeHandlerOptions(server),\n );\n // Page rendering is the development fallback. Register it after Vite's\n // module, asset, and HTML middleware so client entries and imported CSS\n // are served by Vite instead of being mistaken for application routes.\n return () => server.middlewares.use(handler);\n },\n } satisfies Plugin;\n return plugin;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askrjs/vite",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "Vite plugin for Askr JSX and template transforms",
|
|
5
5
|
"homepage": "https://github.com/askrjs/askr-vite#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"README.md"
|
|
21
21
|
],
|
|
22
22
|
"type": "module",
|
|
23
|
+
"sideEffects": false,
|
|
23
24
|
"main": "./dist/index.js",
|
|
24
25
|
"types": "./dist/index.d.ts",
|
|
25
26
|
"exports": {
|
|
@@ -58,25 +59,26 @@
|
|
|
58
59
|
"prepublishOnly": "npm run check"
|
|
59
60
|
},
|
|
60
61
|
"dependencies": {
|
|
61
|
-
"@askrjs/node": ">=0.0.
|
|
62
|
-
"
|
|
62
|
+
"@askrjs/node": ">=0.0.8 <0.1.0",
|
|
63
|
+
"oxc-parser": "^0.144.0",
|
|
64
|
+
"parse5": "^8.0.1"
|
|
63
65
|
},
|
|
64
66
|
"devDependencies": {
|
|
65
|
-
"@askrjs/askr": ">=0.0.
|
|
66
|
-
"@askrjs/server": ">=0.0.
|
|
67
|
-
"@types/node": "^26.
|
|
68
|
-
"publint": "^0.3.
|
|
67
|
+
"@askrjs/askr": ">=0.0.88 <0.1.0",
|
|
68
|
+
"@askrjs/server": ">=0.0.11 <0.1.0",
|
|
69
|
+
"@types/node": "^26.2.0",
|
|
70
|
+
"publint": "^0.3.23",
|
|
69
71
|
"sharp": "^0.35.3",
|
|
70
|
-
"typescript": "^
|
|
71
|
-
"vite": "^8.
|
|
72
|
-
"vite-plus": "^0.2.
|
|
72
|
+
"typescript": "^7.0.2",
|
|
73
|
+
"vite": "^8.2.1",
|
|
74
|
+
"vite-plus": "^0.2.8",
|
|
73
75
|
"vitest": "^4.1.10"
|
|
74
76
|
},
|
|
75
77
|
"peerDependencies": {
|
|
76
|
-
"@askrjs/askr": ">=0.0.
|
|
78
|
+
"@askrjs/askr": ">=0.0.88 <0.1.0",
|
|
77
79
|
"sharp": "^0.35.3",
|
|
78
|
-
"vite": "^8.
|
|
79
|
-
"vite-plus": "^0.2.
|
|
80
|
+
"vite": "^8.2.1",
|
|
81
|
+
"vite-plus": "^0.2.8"
|
|
80
82
|
},
|
|
81
83
|
"peerDependenciesMeta": {
|
|
82
84
|
"sharp": {
|