@lithent/lithent-template-vite 0.1.1 → 0.2.0

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 CHANGED
@@ -16,12 +16,14 @@ conditional and iterative markup while compiling straight to `h()` calls.
16
16
  - **Document pipeline** – scans entire source files, replaces Lithent markup
17
17
  with generated `h()` calls, and forwards source maps downstream.
18
18
  - **Custom extensions** – default support for `.ljsx` and `.ltsx`, with full
19
- control over additional extensions and associated esbuild loaders.
19
+ control over additional extensions and associated script loaders.
20
20
  - **HTML entry transform** – `<script type="module" src="*.ltsx">` tags are
21
21
  automatically rewritten to inline imports so the browser receives valid JS.
22
22
  - **Tooling-friendly** – exposes warnings, preserves source maps in production,
23
23
  and keeps untouched code intact.
24
24
 
25
+ Requires Vite 8. Script transforms use Oxc; opt-in JSON/CSS loaders retain an explicit esbuild fallback.
26
+
25
27
  ## Installation
26
28
 
27
29
  ```bash
@@ -47,7 +49,9 @@ If you prefer a static HTML entry in development, the safest option is to inline
47
49
  the import yourself so the browser receives JavaScript immediately:
48
50
 
49
51
  ```html
50
- <script type="module">import "/src/dev/main.ltsx";</script>
52
+ <script type="module">
53
+ import '/src/dev/main.ltsx';
54
+ </script>
51
55
  ```
52
56
 
53
57
  This pattern works in both dev and build modes and avoids relying on HTML entry
@@ -70,7 +74,7 @@ lithentTemplateVite({
70
74
  - `extensions` (string[]) – list of file extensions to treat as Lithent
71
75
  templates. Values are normalised (leading `.` is optional). Defaults to
72
76
  `['.ljsx', '.ltsx']`.
73
- - `extensionLoaders` (Record<string, LoaderValue>) – override the esbuild loader
77
+ - `extensionLoaders` (Record<string, LoaderValue>) – override the source loader
74
78
  used for a given extension (`'js' | 'jsx' | 'ts' | 'tsx' | 'json' | 'css'`).
75
79
  When omitted, the loader is inferred from the extension suffix (e.g. `.ltsx`
76
80
  → `'ts'`).
package/dist/index.mjs CHANGED
@@ -1,122 +1,87 @@
1
- import { readFile as v } from "node:fs/promises";
2
- import p from "node:path";
3
- import { normalizePath as h, transformWithEsbuild as A } from "vite";
4
- import { transformDocument as P } from "@lithent/lithent-template-parser";
5
- const R = [".ljsx", ".ltsx"], S = (e) => e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), z = (e) => e.startsWith(".") ? e : `.${e}`, D = (e) => {
6
- const s = (e && e.length > 0 ? e : Array.from(R)).map(z);
7
- return Array.from(new Set(s));
8
- }, y = (e) => e.endsWith("tsx") || e.endsWith("ts") ? "ts" : (e.endsWith("jsx"), "js"), L = (e, r) => e ? Array.isArray(e) ? e : [e] : r, j = (e, r) => e.some((s) => s.test(r)), O = (e, r) => {
9
- const [s, m] = e.split("?", 2);
10
- if (m) {
11
- const i = new URLSearchParams(m).get($);
12
- if (i)
13
- return h(i);
14
- }
15
- return s && x(s, r) ? h(s) : null;
16
- }, x = (e, r) => r.find((s) => e.endsWith(s)) ?? null, E = (e, r) => {
17
- const s = new Set(e ?? []);
18
- for (const m of r)
19
- s.add(m);
20
- return Array.from(s);
21
- }, I = (e, r) => ({
22
- ...e ?? {},
23
- ...r
24
- }), $ = "lithent:original";
25
- function M(e = {}) {
26
- const r = D(e.extensions), s = r.reduce((t, n) => {
27
- var c;
28
- const a = ((c = e.extensionLoaders) == null ? void 0 : c[n]) ?? y(n);
29
- return t[n] = a, t;
30
- }, {}), m = r.map(
31
- (t) => new RegExp(`${S(t)}$`)
32
- ), w = L(e.include, m);
33
- let i;
34
- const g = (t) => {
35
- const n = new URLSearchParams({
36
- [$]: t
37
- });
38
- return `${t}?${n.toString()}`;
39
- };
40
- return [{
41
- name: "lithent:template-vite",
42
- enforce: "pre",
43
- config(t) {
44
- var n, a, c, l, o, d, f;
45
- return {
46
- resolve: {
47
- extensions: E(
48
- (n = t.resolve) == null ? void 0 : n.extensions,
49
- r
50
- )
51
- },
52
- optimizeDeps: {
53
- extensions: E(
54
- (a = t.optimizeDeps) == null ? void 0 : a.extensions,
55
- r
56
- ),
57
- esbuildOptions: {
58
- ...((c = t.optimizeDeps) == null ? void 0 : c.esbuildOptions) ?? {},
59
- loader: I(
60
- typeof ((o = (l = t.optimizeDeps) == null ? void 0 : l.esbuildOptions) == null ? void 0 : o.loader) == "object" ? (f = (d = t.optimizeDeps) == null ? void 0 : d.esbuildOptions) == null ? void 0 : f.loader : void 0,
61
- s
62
- )
63
- }
64
- }
65
- };
66
- },
67
- configResolved(t) {
68
- i = t;
69
- },
70
- async resolveId(t, n, a) {
71
- if (!x(t, r))
72
- return null;
73
- const l = (i == null ? void 0 : i.root) ?? process.cwd();
74
- let o;
75
- if (typeof this.resolve == "function") {
76
- const d = await this.resolve(t, n, {
77
- skipSelf: !0,
78
- ...a
79
- });
80
- d != null && d.id && (o = d.id);
81
- }
82
- return o || (p.isAbsolute(t) ? o = t : t.startsWith("/") ? o = p.join(l, t.slice(1)) : n && (t.startsWith("./") || t.startsWith("../")) ? o = p.resolve(p.dirname(n), t) : o = p.resolve(l, t)), o = h(o), j(w, o) ? g(o) : null;
83
- },
84
- async load(t) {
85
- const n = O(t, r);
86
- if (!n)
87
- return null;
88
- const a = x(n, r);
89
- if (!a)
90
- return null;
91
- this.addWatchFile(n);
92
- const c = await v(n, "utf-8"), l = P(c, {
93
- source: n,
94
- generateSourceMap: (i == null ? void 0 : i.command) === "build"
95
- }), o = this.warn ? this.warn.bind(this) : console.warn;
96
- if (l.errors.length > 0)
97
- for (const { error: u } of l.errors) {
98
- const W = u.line || u.column ? ` (line ${u.line}, column ${u.column})` : "";
99
- o(
100
- `[@lithent/lithent-template-vite] Failed to compile template in ${n}${W}: ${u.message}`
101
- );
102
- }
103
- const d = s[a] ?? y(a), f = l.transformed ? l.code : c, b = await A(
104
- f,
105
- n,
106
- {
107
- loader: d,
108
- sourcemap: (i == null ? void 0 : i.command) === "build",
109
- sourcefile: n
110
- }
111
- );
112
- return {
113
- code: b.code,
114
- map: b.map ?? null
115
- };
116
- }
117
- }];
1
+ import { readFile as e } from "node:fs/promises";
2
+ import t from "node:path";
3
+ import { normalizePath as n, transformWithEsbuild as r, transformWithOxc as i } from "vite";
4
+ import { transformDocument as a } from "@lithent/lithent-template-parser";
5
+ // src/plugin.ts
6
+ var o = [".ljsx", ".ltsx"], s = (e) => e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), c = (e) => e.startsWith(".") ? e : `.${e}`, l = (e) => {
7
+ let t = (e && e.length > 0 ? e : Array.from(o)).map(c);
8
+ return Array.from(new Set(t));
9
+ }, u = (e) => e.endsWith("tsx") || e.endsWith("ts") ? "ts" : (e.endsWith("jsx"), "js"), d = (e, t) => e ? Array.isArray(e) ? e : [e] : t, f = (e, t) => e.some((e) => e.test(t)), p = (e, t) => {
10
+ let [r, i] = e.split("?", 2);
11
+ if (i) {
12
+ let e = new URLSearchParams(i).get(g);
13
+ if (e) return n(e);
14
+ }
15
+ return r && m(r, t) ? n(r) : null;
16
+ }, m = (e, t) => t.find((t) => e.endsWith(t)) ?? null, h = (e, t) => {
17
+ let n = new Set(e ?? []);
18
+ for (let e of t) n.add(e);
19
+ return Array.from(n);
20
+ }, g = "lithent:original";
21
+ function _(o = {}) {
22
+ let c = l(o.extensions), _ = c.reduce((e, t) => {
23
+ var n;
24
+ return e[t] = ((n = o.extensionLoaders) == null ? void 0 : n[t]) ?? u(t), e;
25
+ }, {}), v = Object.fromEntries(Object.entries(_).map(([e, t]) => [e, t === "ts" ? "tsx" : t === "js" ? "jsx" : t])), y = c.map((e) => RegExp(`${s(e)}$`)), b = d(o.include, y), x, S = (e) => `${e}?${new URLSearchParams({ [g]: e }).toString()}`;
26
+ return [{
27
+ name: "lithent:template-vite",
28
+ enforce: "pre",
29
+ config(e) {
30
+ var t, n, r, i;
31
+ return {
32
+ resolve: { extensions: h((t = e.resolve) == null ? void 0 : t.extensions, c) },
33
+ optimizeDeps: {
34
+ extensions: h((n = e.optimizeDeps) == null ? void 0 : n.extensions, c),
35
+ rolldownOptions: {
36
+ ...(r = e.optimizeDeps) == null ? void 0 : r.rolldownOptions,
37
+ moduleTypes: {
38
+ ...(i = e.optimizeDeps) == null || (i = i.rolldownOptions) == null ? void 0 : i.moduleTypes,
39
+ ...v
40
+ }
41
+ }
42
+ }
43
+ };
44
+ },
45
+ configResolved(e) {
46
+ x = e;
47
+ },
48
+ async resolveId(e, r, i) {
49
+ if (!m(e, c)) return null;
50
+ let a = (x == null ? void 0 : x.root) ?? process.cwd(), o;
51
+ if (typeof this.resolve == "function") {
52
+ let t = await this.resolve(e, r, {
53
+ skipSelf: !0,
54
+ ...i
55
+ });
56
+ t != null && t.id && (o = t.id);
57
+ }
58
+ return o || (o = t.isAbsolute(e) ? e : e.startsWith("/") ? t.join(a, e.slice(1)) : r && (e.startsWith("./") || e.startsWith("../")) ? t.resolve(t.dirname(r), e) : t.resolve(a, e)), o = n(o), f(b, o) ? S(o) : null;
59
+ },
60
+ async load(t) {
61
+ let n = p(t, c);
62
+ if (!n) return null;
63
+ let o = m(n, c);
64
+ if (!o) return null;
65
+ this.addWatchFile(n);
66
+ let s = await e(n, "utf-8"), l = a(s, {
67
+ source: n,
68
+ generateSourceMap: (x == null ? void 0 : x.command) === "build"
69
+ }), d = this.warn ? this.warn.bind(this) : console.warn;
70
+ if (l.errors.length > 0) for (let { error: e } of l.errors) d(`[@lithent/lithent-template-vite] Failed to compile template in ${n}${e.line || e.column ? ` (line ${e.line}, column ${e.column})` : ""}: ${e.message}`);
71
+ let f = _[o] ?? u(o), h = l.transformed ? l.code : s, g = f === "json" || f === "css" ? await r(h, n, {
72
+ loader: f,
73
+ sourcemap: (x == null ? void 0 : x.command) === "build"
74
+ }) : await i(h, n, {
75
+ lang: f,
76
+ sourcemap: (x == null ? void 0 : x.command) === "build"
77
+ });
78
+ return {
79
+ code: g.code,
80
+ map: g.map ?? null
81
+ };
82
+ }
83
+ }];
118
84
  }
119
- export {
120
- M as default
121
- };
122
- //# sourceMappingURL=index.mjs.map
85
+ export { _ as default };
86
+
87
+ //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/plugin.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { Plugin, PluginOption, ResolvedConfig, UserConfig } from 'vite';\nimport { normalizePath, transformWithEsbuild } from 'vite';\nimport { transformDocument } from '@lithent/lithent-template-parser';\n\ntype LoaderValue = 'js' | 'jsx' | 'ts' | 'tsx' | 'json' | 'css';\ntype LoaderMap = Record<string, LoaderValue>;\n\nexport interface LithentTemplateViteOptions {\n include?: RegExp | RegExp[];\n extensions?: string[];\n extensionLoaders?: Record<string, LoaderValue>;\n}\n\nconst DEFAULT_EXTENSIONS = ['.ljsx', '.ltsx'] as const;\n\nconst escapeRegExp = (value: string): string =>\n value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\nconst normalizeExtension = (ext: string): string =>\n ext.startsWith('.') ? ext : `.${ext}`;\n\nconst resolveExtensions = (extensions?: string[]): string[] => {\n const base =\n extensions && extensions.length > 0\n ? extensions\n : Array.from(DEFAULT_EXTENSIONS);\n const normalized = base.map(normalizeExtension);\n return Array.from(new Set(normalized));\n};\n\nconst inferLoader = (ext: string): LoaderValue => {\n if (ext.endsWith('tsx') || ext.endsWith('ts')) {\n return 'ts';\n }\n if (ext.endsWith('jsx')) {\n return 'js';\n }\n return 'js';\n};\n\nconst toRegExpArray = (\n value: RegExp | RegExp[] | undefined,\n fallback: RegExp[]\n): RegExp[] => {\n if (!value) {\n return fallback;\n }\n return Array.isArray(value) ? value : [value];\n};\n\nconst shouldProcess = (patterns: RegExp[], filePath: string): boolean => {\n return patterns.some(pattern => pattern.test(filePath));\n};\n\nconst extractOriginalPath = (\n id: string,\n extensions: string[]\n): string | null => {\n const [filepath, query] = id.split('?', 2);\n if (query) {\n const params = new URLSearchParams(query);\n const original = params.get(VIRTUAL_QUERY);\n if (original) {\n return normalizePath(original);\n }\n }\n if (filepath && matchExtension(filepath, extensions)) {\n return normalizePath(filepath);\n }\n return null;\n};\n\nconst matchExtension = (\n filePath: string,\n extensions: string[]\n): string | null => {\n return extensions.find(ext => filePath.endsWith(ext)) ?? null;\n};\n\nconst mergeExtensions = (\n original: string[] | undefined,\n additions: readonly string[]\n): string[] => {\n const set = new Set(original ?? []);\n for (const ext of additions) {\n set.add(ext);\n }\n return Array.from(set);\n};\n\nconst mergeLoaderMap = (\n original: LoaderMap | undefined,\n additions: LoaderMap\n): LoaderMap => {\n return {\n ...(original ?? {}),\n ...additions,\n };\n};\n\nconst VIRTUAL_QUERY = 'lithent:original';\n\nexport function lithentTemplateVite(\n options: LithentTemplateViteOptions = {}\n): PluginOption {\n const extensions = resolveExtensions(options.extensions);\n const extensionLoaders: LoaderMap = extensions.reduce((acc, ext) => {\n const loader = options.extensionLoaders?.[ext] ?? inferLoader(ext);\n acc[ext] = loader;\n return acc;\n }, {} as LoaderMap);\n const defaultInclude = extensions.map(\n ext => new RegExp(`${escapeRegExp(ext)}$`)\n );\n const includePatterns = toRegExpArray(options.include, defaultInclude);\n let config: ResolvedConfig | undefined;\n\n const createVirtualId = (originalPath: string): string => {\n const query = new URLSearchParams({\n [VIRTUAL_QUERY]: originalPath,\n });\n return `${originalPath}?${query.toString()}`;\n };\n\n const templatePlugin: Plugin = {\n name: 'lithent:template-vite',\n enforce: 'pre',\n config(userConfig: UserConfig) {\n return {\n resolve: {\n extensions: mergeExtensions(\n userConfig.resolve?.extensions,\n extensions\n ),\n },\n optimizeDeps: {\n extensions: mergeExtensions(\n userConfig.optimizeDeps?.extensions,\n extensions\n ),\n esbuildOptions: {\n ...(userConfig.optimizeDeps?.esbuildOptions ?? {}),\n loader: mergeLoaderMap(\n typeof userConfig.optimizeDeps?.esbuildOptions?.loader ===\n 'object'\n ? (userConfig.optimizeDeps?.esbuildOptions?.loader as LoaderMap)\n : undefined,\n extensionLoaders\n ),\n },\n },\n };\n },\n configResolved(resolved) {\n config = resolved;\n },\n async resolveId(source, importer, options) {\n const ext = matchExtension(source, extensions);\n if (!ext) {\n return null;\n }\n\n const rootDir = config?.root ?? process.cwd();\n let resolvedPath: string | undefined;\n\n if (typeof this.resolve === 'function') {\n const resolved = await this.resolve(source, importer, {\n skipSelf: true,\n ...options,\n });\n if (resolved?.id) {\n resolvedPath = resolved.id;\n }\n }\n\n if (!resolvedPath) {\n if (path.isAbsolute(source)) {\n resolvedPath = source;\n } else if (source.startsWith('/')) {\n resolvedPath = path.join(rootDir, source.slice(1));\n } else if (\n importer &&\n (source.startsWith('./') || source.startsWith('../'))\n ) {\n resolvedPath = path.resolve(path.dirname(importer), source);\n } else {\n resolvedPath = path.resolve(rootDir, source);\n }\n }\n\n resolvedPath = normalizePath(resolvedPath);\n\n if (!shouldProcess(includePatterns, resolvedPath)) {\n return null;\n }\n\n return createVirtualId(resolvedPath);\n },\n async load(id) {\n const originalPath = extractOriginalPath(id, extensions);\n if (!originalPath) {\n return null;\n }\n\n const ext = matchExtension(originalPath, extensions);\n if (!ext) {\n return null;\n }\n\n this.addWatchFile(originalPath);\n\n const raw = await readFile(originalPath, 'utf-8');\n const result = transformDocument(raw, {\n source: originalPath,\n generateSourceMap: config?.command === 'build',\n });\n\n const warn = this.warn ? this.warn.bind(this) : console.warn;\n if (result.errors.length > 0) {\n for (const { error } of result.errors) {\n const location =\n error.line || error.column\n ? ` (line ${error.line}, column ${error.column})`\n : '';\n warn(\n `[@lithent/lithent-template-vite] Failed to compile template in ${originalPath}${location}: ${error.message}`\n );\n }\n }\n\n const loader = extensionLoaders[ext] ?? inferLoader(ext);\n const transformedCode = result.transformed ? result.code : raw;\n const esbuildResult = await transformWithEsbuild(\n transformedCode,\n originalPath,\n {\n loader,\n sourcemap: config?.command === 'build',\n sourcefile: originalPath,\n }\n );\n\n return {\n code: esbuildResult.code,\n map: esbuildResult.map ?? null,\n };\n },\n };\n\n return [templatePlugin];\n}\n\nexport default lithentTemplateVite;\n"],"names":["DEFAULT_EXTENSIONS","escapeRegExp","value","normalizeExtension","ext","resolveExtensions","extensions","normalized","inferLoader","toRegExpArray","fallback","shouldProcess","patterns","filePath","pattern","extractOriginalPath","id","filepath","query","original","VIRTUAL_QUERY","normalizePath","matchExtension","mergeExtensions","additions","set","mergeLoaderMap","lithentTemplateVite","options","extensionLoaders","acc","loader","_a","defaultInclude","includePatterns","config","createVirtualId","originalPath","userConfig","_b","_c","_e","_d","_g","_f","resolved","source","importer","rootDir","resolvedPath","path","raw","readFile","result","transformDocument","warn","error","location","transformedCode","esbuildResult","transformWithEsbuild"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["path","DEFAULT_EXTENSIONS","escapeRegExp","value","normalizeExtension","ext","resolveExtensions","normalized","extensions","inferLoader","toRegExpArray","fallback","shouldProcess","patterns","pattern","filePath","extractOriginalPath","filepath","query","id","original","VIRTUAL_QUERY","normalizePath","matchExtension","mergeExtensions","set","additions","lithentTemplateVite","options","extensionLoaders","_options$extensionLoa","acc","scanLoaders","loader","defaultInclude","includePatterns","config","createVirtualId","originalPath","_userConfig$resolve","_userConfig$optimizeD","_userConfig$optimizeD2","_userConfig$optimizeD3","userConfig","resolved","source","rootDir","resolvedPath","importer","raw","readFile","result","transformDocument","warn","error","transformedCode","resultCode","transformWithEsbuild","transformWithOxc"],"sources":["../src/plugin.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { Plugin, PluginOption, ResolvedConfig, UserConfig } from 'vite';\nimport { normalizePath, transformWithEsbuild, transformWithOxc } from 'vite';\nimport { transformDocument } from '@lithent/lithent-template-parser';\n\ntype LoaderValue = 'js' | 'jsx' | 'ts' | 'tsx' | 'json' | 'css';\ntype LoaderMap = Record<string, LoaderValue>;\n\nexport interface LithentTemplateViteOptions {\n include?: RegExp | RegExp[];\n extensions?: string[];\n extensionLoaders?: Record<string, LoaderValue>;\n}\n\nconst DEFAULT_EXTENSIONS = ['.ljsx', '.ltsx'] as const;\n\nconst escapeRegExp = (value: string): string =>\n value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\nconst normalizeExtension = (ext: string): string =>\n ext.startsWith('.') ? ext : `.${ext}`;\n\nconst resolveExtensions = (extensions?: string[]): string[] => {\n const base =\n extensions && extensions.length > 0\n ? extensions\n : Array.from(DEFAULT_EXTENSIONS);\n const normalized = base.map(normalizeExtension);\n return Array.from(new Set(normalized));\n};\n\nconst inferLoader = (ext: string): LoaderValue => {\n if (ext.endsWith('tsx') || ext.endsWith('ts')) {\n return 'ts';\n }\n if (ext.endsWith('jsx')) {\n return 'js';\n }\n return 'js';\n};\n\nconst toRegExpArray = (\n value: RegExp | RegExp[] | undefined,\n fallback: RegExp[]\n): RegExp[] => {\n if (!value) {\n return fallback;\n }\n return Array.isArray(value) ? value : [value];\n};\n\nconst shouldProcess = (patterns: RegExp[], filePath: string): boolean => {\n return patterns.some(pattern => pattern.test(filePath));\n};\n\nconst extractOriginalPath = (\n id: string,\n extensions: string[]\n): string | null => {\n const [filepath, query] = id.split('?', 2);\n if (query) {\n const params = new URLSearchParams(query);\n const original = params.get(VIRTUAL_QUERY);\n if (original) {\n return normalizePath(original);\n }\n }\n if (filepath && matchExtension(filepath, extensions)) {\n return normalizePath(filepath);\n }\n return null;\n};\n\nconst matchExtension = (\n filePath: string,\n extensions: string[]\n): string | null => {\n return extensions.find(ext => filePath.endsWith(ext)) ?? null;\n};\n\nconst mergeExtensions = (\n original: string[] | undefined,\n additions: readonly string[]\n): string[] => {\n const set = new Set(original ?? []);\n for (const ext of additions) {\n set.add(ext);\n }\n return Array.from(set);\n};\n\nconst VIRTUAL_QUERY = 'lithent:original';\n\nexport function lithentTemplateVite(\n options: LithentTemplateViteOptions = {}\n): PluginOption {\n const extensions = resolveExtensions(options.extensions);\n const extensionLoaders: LoaderMap = extensions.reduce((acc, ext) => {\n const loader = options.extensionLoaders?.[ext] ?? inferLoader(ext);\n acc[ext] = loader;\n return acc;\n }, {} as LoaderMap);\n // The optimizer scans raw templates before our load hook compiles markup.\n // Its parser must accept JSX even when the compiled document uses plain TS.\n const scanLoaders: LoaderMap = Object.fromEntries(\n Object.entries(extensionLoaders).map(([ext, loader]) => [\n ext,\n loader === 'ts' ? 'tsx' : loader === 'js' ? 'jsx' : loader,\n ])\n );\n const defaultInclude = extensions.map(\n ext => new RegExp(`${escapeRegExp(ext)}$`)\n );\n const includePatterns = toRegExpArray(options.include, defaultInclude);\n let config: ResolvedConfig | undefined;\n\n const createVirtualId = (originalPath: string): string => {\n const query = new URLSearchParams({\n [VIRTUAL_QUERY]: originalPath,\n });\n return `${originalPath}?${query.toString()}`;\n };\n\n const templatePlugin: Plugin = {\n name: 'lithent:template-vite',\n enforce: 'pre',\n config(userConfig: UserConfig) {\n return {\n resolve: {\n extensions: mergeExtensions(\n userConfig.resolve?.extensions,\n extensions\n ),\n },\n optimizeDeps: {\n extensions: mergeExtensions(\n userConfig.optimizeDeps?.extensions,\n extensions\n ),\n rolldownOptions: {\n ...userConfig.optimizeDeps?.rolldownOptions,\n moduleTypes: {\n ...userConfig.optimizeDeps?.rolldownOptions?.moduleTypes,\n ...scanLoaders,\n },\n },\n },\n };\n },\n configResolved(resolved) {\n config = resolved;\n },\n async resolveId(source, importer, options) {\n const ext = matchExtension(source, extensions);\n if (!ext) {\n return null;\n }\n\n const rootDir = config?.root ?? process.cwd();\n let resolvedPath: string | undefined;\n\n if (typeof this.resolve === 'function') {\n const resolved = await this.resolve(source, importer, {\n skipSelf: true,\n ...options,\n });\n if (resolved?.id) {\n resolvedPath = resolved.id;\n }\n }\n\n if (!resolvedPath) {\n if (path.isAbsolute(source)) {\n resolvedPath = source;\n } else if (source.startsWith('/')) {\n resolvedPath = path.join(rootDir, source.slice(1));\n } else if (\n importer &&\n (source.startsWith('./') || source.startsWith('../'))\n ) {\n resolvedPath = path.resolve(path.dirname(importer), source);\n } else {\n resolvedPath = path.resolve(rootDir, source);\n }\n }\n\n resolvedPath = normalizePath(resolvedPath);\n\n if (!shouldProcess(includePatterns, resolvedPath)) {\n return null;\n }\n\n return createVirtualId(resolvedPath);\n },\n async load(id) {\n const originalPath = extractOriginalPath(id, extensions);\n if (!originalPath) {\n return null;\n }\n\n const ext = matchExtension(originalPath, extensions);\n if (!ext) {\n return null;\n }\n\n this.addWatchFile(originalPath);\n\n const raw = await readFile(originalPath, 'utf-8');\n const result = transformDocument(raw, {\n source: originalPath,\n generateSourceMap: config?.command === 'build',\n });\n\n const warn = this.warn ? this.warn.bind(this) : console.warn;\n if (result.errors.length > 0) {\n for (const { error } of result.errors) {\n const location =\n error.line || error.column\n ? ` (line ${error.line}, column ${error.column})`\n : '';\n warn(\n `[@lithent/lithent-template-vite] Failed to compile template in ${originalPath}${location}: ${error.message}`\n );\n }\n }\n\n const loader = extensionLoaders[ext] ?? inferLoader(ext);\n const transformedCode = result.transformed ? result.code : raw;\n // Oxc handles the script loaders. Preserve the existing opt-in JSON/CSS\n // loaders through esbuild, which is an explicit plugin dependency.\n const resultCode =\n loader === 'json' || loader === 'css'\n ? await transformWithEsbuild(transformedCode, originalPath, {\n loader,\n sourcemap: config?.command === 'build',\n })\n : await transformWithOxc(transformedCode, originalPath, {\n lang: loader,\n sourcemap: config?.command === 'build',\n });\n\n return {\n code: resultCode.code,\n map: resultCode.map ?? null,\n };\n },\n };\n\n return [templatePlugin];\n}\n\nexport default lithentTemplateVite;\n"],"mappings":"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"}
package/dist/plugin.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import type { PluginOption } from 'vite';
1
+ import { PluginOption } from 'vite';
2
2
  type LoaderValue = 'js' | 'jsx' | 'ts' | 'tsx' | 'json' | 'css';
3
3
  export interface LithentTemplateViteOptions {
4
4
  include?: RegExp | RegExp[];
package/dist/plugin.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { PluginOption } from 'vite';
1
+ import { PluginOption } from 'vite';
2
2
  type LoaderValue = 'js' | 'jsx' | 'ts' | 'tsx' | 'json' | 'css';
3
3
  export interface LithentTemplateViteOptions {
4
4
  include?: RegExp | RegExp[];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@lithent/lithent-template-vite",
4
- "version": "0.1.1",
4
+ "version": "0.2.0",
5
5
  "description": "Vite plugin that compiles Lithent’s JSX-like template syntax into h() calls.",
6
6
  "main": "./dist/index.mjs",
7
7
  "module": "./dist/index.mjs",
@@ -9,14 +9,16 @@
9
9
  "exports": {
10
10
  ".": {
11
11
  "types": "./dist/index.d.ts",
12
- "import": "./dist/index.mjs"
12
+ "import": "./dist/index.mjs",
13
+ "default": "./dist/index.mjs"
13
14
  }
14
15
  },
15
16
  "dependencies": {
16
- "@lithent/lithent-template-parser": "0.1.1"
17
+ "@lithent/lithent-template-parser": "0.1.3",
18
+ "esbuild": "^0.28.2"
17
19
  },
18
20
  "devDependencies": {
19
- "lithent": "1.25.0"
21
+ "lithent": "1.25.7"
20
22
  },
21
23
  "keywords": [
22
24
  "lithent",
@@ -31,15 +33,12 @@
31
33
  "url": "https://github.com/superlucky84/lithent.git"
32
34
  },
33
35
  "peerDependencies": {
34
- "vite": "^5.0.0"
36
+ "vite": "^8.0.0"
35
37
  },
36
38
  "files": [
37
39
  "dist",
38
40
  "src"
39
41
  ],
40
- "volta": {
41
- "node": "20.3.0"
42
- },
43
42
  "scripts": {
44
43
  "dev": "vite --config vite.config.plugin.ts",
45
44
  "dev:lib": "vite",
package/src/plugin.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import type { Plugin, PluginOption, ResolvedConfig, UserConfig } from 'vite';
4
- import { normalizePath, transformWithEsbuild } from 'vite';
4
+ import { normalizePath, transformWithEsbuild, transformWithOxc } from 'vite';
5
5
  import { transformDocument } from '@lithent/lithent-template-parser';
6
6
 
7
7
  type LoaderValue = 'js' | 'jsx' | 'ts' | 'tsx' | 'json' | 'css';
@@ -90,16 +90,6 @@ const mergeExtensions = (
90
90
  return Array.from(set);
91
91
  };
92
92
 
93
- const mergeLoaderMap = (
94
- original: LoaderMap | undefined,
95
- additions: LoaderMap
96
- ): LoaderMap => {
97
- return {
98
- ...(original ?? {}),
99
- ...additions,
100
- };
101
- };
102
-
103
93
  const VIRTUAL_QUERY = 'lithent:original';
104
94
 
105
95
  export function lithentTemplateVite(
@@ -111,6 +101,14 @@ export function lithentTemplateVite(
111
101
  acc[ext] = loader;
112
102
  return acc;
113
103
  }, {} as LoaderMap);
104
+ // The optimizer scans raw templates before our load hook compiles markup.
105
+ // Its parser must accept JSX even when the compiled document uses plain TS.
106
+ const scanLoaders: LoaderMap = Object.fromEntries(
107
+ Object.entries(extensionLoaders).map(([ext, loader]) => [
108
+ ext,
109
+ loader === 'ts' ? 'tsx' : loader === 'js' ? 'jsx' : loader,
110
+ ])
111
+ );
114
112
  const defaultInclude = extensions.map(
115
113
  ext => new RegExp(`${escapeRegExp(ext)}$`)
116
114
  );
@@ -140,15 +138,12 @@ export function lithentTemplateVite(
140
138
  userConfig.optimizeDeps?.extensions,
141
139
  extensions
142
140
  ),
143
- esbuildOptions: {
144
- ...(userConfig.optimizeDeps?.esbuildOptions ?? {}),
145
- loader: mergeLoaderMap(
146
- typeof userConfig.optimizeDeps?.esbuildOptions?.loader ===
147
- 'object'
148
- ? (userConfig.optimizeDeps?.esbuildOptions?.loader as LoaderMap)
149
- : undefined,
150
- extensionLoaders
151
- ),
141
+ rolldownOptions: {
142
+ ...userConfig.optimizeDeps?.rolldownOptions,
143
+ moduleTypes: {
144
+ ...userConfig.optimizeDeps?.rolldownOptions?.moduleTypes,
145
+ ...scanLoaders,
146
+ },
152
147
  },
153
148
  },
154
149
  };
@@ -232,19 +227,22 @@ export function lithentTemplateVite(
232
227
 
233
228
  const loader = extensionLoaders[ext] ?? inferLoader(ext);
234
229
  const transformedCode = result.transformed ? result.code : raw;
235
- const esbuildResult = await transformWithEsbuild(
236
- transformedCode,
237
- originalPath,
238
- {
239
- loader,
240
- sourcemap: config?.command === 'build',
241
- sourcefile: originalPath,
242
- }
243
- );
230
+ // Oxc handles the script loaders. Preserve the existing opt-in JSON/CSS
231
+ // loaders through esbuild, which is an explicit plugin dependency.
232
+ const resultCode =
233
+ loader === 'json' || loader === 'css'
234
+ ? await transformWithEsbuild(transformedCode, originalPath, {
235
+ loader,
236
+ sourcemap: config?.command === 'build',
237
+ })
238
+ : await transformWithOxc(transformedCode, originalPath, {
239
+ lang: loader,
240
+ sourcemap: config?.command === 'build',
241
+ });
244
242
 
245
243
  return {
246
- code: esbuildResult.code,
247
- map: esbuildResult.map ?? null,
244
+ code: resultCode.code,
245
+ map: resultCode.map ?? null,
248
246
  };
249
247
  },
250
248
  };