@rohal12/twee-ts 1.14.0 → 1.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bin/twee-ts.js +5570 -5232
- package/dist/bin/twee-ts.js.map +1 -1
- package/dist/compiler-Bfi1w-to.js +5074 -0
- package/dist/compiler-Bfi1w-to.js.map +1 -0
- package/dist/index.cjs +5368 -5089
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +306 -331
- package/dist/index.d.ts +306 -331
- package/dist/index.js +5332 -5027
- package/dist/index.js.map +1 -1
- package/dist/plugins/rollup.d.ts +21 -27
- package/dist/plugins/rollup.js +23 -31
- package/dist/plugins/rollup.js.map +1 -1
- package/dist/plugins/vite.d.ts +21 -56
- package/dist/plugins/vite.js +404 -67
- package/dist/plugins/vite.js.map +1 -1
- package/dist/types-BFyb40Zq.d.ts +49 -0
- package/package.json +23 -9
- package/dist/chunk-Z2CNKPVJ.js +0 -4771
- package/dist/chunk-Z2CNKPVJ.js.map +0 -1
- package/dist/types-FHZ3rZD6.d.ts +0 -48
package/dist/plugins/rollup.d.ts
CHANGED
|
@@ -1,29 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
format?: string;
|
|
13
|
-
/** Output filename. Default: 'index.html'. */
|
|
14
|
-
outputFilename?: string;
|
|
15
|
-
/** Additional compile options. */
|
|
16
|
-
compileOptions?: Partial<CompileOptions>;
|
|
1
|
+
import { t as CompileOptions } from "../types-BFyb40Zq.js";
|
|
2
|
+
//#region src/plugins/rollup.d.ts
|
|
3
|
+
export interface TweeTsRollupPluginOptions {
|
|
4
|
+
/** Source directories/files to compile. */
|
|
5
|
+
sources: string[];
|
|
6
|
+
/** Story format ID. */
|
|
7
|
+
format?: string;
|
|
8
|
+
/** Output filename. Default: 'index.html'. */
|
|
9
|
+
outputFilename?: string;
|
|
10
|
+
/** Additional compile options. */
|
|
11
|
+
compileOptions?: Partial<CompileOptions>;
|
|
17
12
|
}
|
|
18
|
-
declare function tweeTsPlugin(options: TweeTsRollupPluginOptions): {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
13
|
+
export declare function tweeTsPlugin(options: TweeTsRollupPluginOptions): {
|
|
14
|
+
name: string;
|
|
15
|
+
generateBundle(this: {
|
|
16
|
+
emitFile: (opts: {
|
|
17
|
+
type: string;
|
|
18
|
+
fileName: string;
|
|
19
|
+
source: string;
|
|
20
|
+
}) => void;
|
|
21
|
+
}): Promise<void>;
|
|
27
22
|
};
|
|
28
|
-
|
|
29
|
-
export { type TweeTsRollupPluginOptions, tweeTsPlugin };
|
|
23
|
+
//#endregion
|
package/dist/plugins/rollup.js
CHANGED
|
@@ -1,34 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
} from "../chunk-Z2CNKPVJ.js";
|
|
4
|
-
|
|
5
|
-
// src/plugins/rollup.ts
|
|
1
|
+
import { n as compile } from "../compiler-Bfi1w-to.js";
|
|
2
|
+
//#region src/plugins/rollup.ts
|
|
6
3
|
function tweeTsPlugin(options) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
console.error(`[twee-ts] ${d.message}`);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
};
|
|
4
|
+
const outputFilename = options.outputFilename ?? "index.html";
|
|
5
|
+
return {
|
|
6
|
+
name: "twee-ts",
|
|
7
|
+
async generateBundle() {
|
|
8
|
+
const result = await compile({
|
|
9
|
+
sources: options.sources,
|
|
10
|
+
formatId: options.format,
|
|
11
|
+
...options.compileOptions
|
|
12
|
+
});
|
|
13
|
+
this.emitFile({
|
|
14
|
+
type: "asset",
|
|
15
|
+
fileName: outputFilename,
|
|
16
|
+
source: result.output
|
|
17
|
+
});
|
|
18
|
+
for (const d of result.diagnostics) if (d.level === "warning") console.warn(`[twee-ts] ${d.message}`);
|
|
19
|
+
else console.error(`[twee-ts] ${d.message}`);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
30
22
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
23
|
+
//#endregion
|
|
24
|
+
export { tweeTsPlugin };
|
|
25
|
+
|
|
34
26
|
//# sourceMappingURL=rollup.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugins/rollup.ts"],"sourcesContent":["/**\n * Ready-made Rollup plugin for twee-ts.\n * Compiles .tw files and emits HTML as an asset.\n */\nimport type { CompileOptions } from '../types.js';\nimport { compile } from '../compiler.js';\n\nexport interface TweeTsRollupPluginOptions {\n /** Source directories/files to compile. */\n sources: string[];\n /** Story format ID. */\n format?: string;\n /** Output filename. Default: 'index.html'. */\n outputFilename?: string;\n /** Additional compile options. */\n compileOptions?: Partial<CompileOptions>;\n}\n\nexport function tweeTsPlugin(options: TweeTsRollupPluginOptions) {\n const outputFilename = options.outputFilename ?? 'index.html';\n\n return {\n name: 'twee-ts',\n\n async generateBundle(this: { emitFile: (opts: { type: string; fileName: string; source: string }) => void }) {\n const result = await compile({\n sources: options.sources,\n formatId: options.format,\n ...options.compileOptions,\n });\n\n this.emitFile({\n type: 'asset',\n fileName: outputFilename,\n source: result.output,\n });\n\n for (const d of result.diagnostics) {\n if (d.level === 'warning') {\n console.warn(`[twee-ts] ${d.message}`);\n } else {\n console.error(`[twee-ts] ${d.message}`);\n }\n }\n },\n };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"rollup.js","names":[],"sources":["../../src/plugins/rollup.ts"],"sourcesContent":["/**\n * Ready-made Rollup plugin for twee-ts.\n * Compiles .tw files and emits HTML as an asset.\n */\nimport type { CompileOptions } from '../types.js';\nimport { compile } from '../compiler.js';\n\nexport interface TweeTsRollupPluginOptions {\n /** Source directories/files to compile. */\n sources: string[];\n /** Story format ID. */\n format?: string;\n /** Output filename. Default: 'index.html'. */\n outputFilename?: string;\n /** Additional compile options. */\n compileOptions?: Partial<CompileOptions>;\n}\n\nexport function tweeTsPlugin(options: TweeTsRollupPluginOptions) {\n const outputFilename = options.outputFilename ?? 'index.html';\n\n return {\n name: 'twee-ts',\n\n async generateBundle(this: { emitFile: (opts: { type: string; fileName: string; source: string }) => void }) {\n const result = await compile({\n sources: options.sources,\n formatId: options.format,\n ...options.compileOptions,\n });\n\n this.emitFile({\n type: 'asset',\n fileName: outputFilename,\n source: result.output,\n });\n\n for (const d of result.diagnostics) {\n if (d.level === 'warning') {\n console.warn(`[twee-ts] ${d.message}`);\n } else {\n console.error(`[twee-ts] ${d.message}`);\n }\n }\n },\n };\n}\n"],"mappings":";;AAkBA,SAAgB,aAAa,SAAoC;CAC/D,MAAM,iBAAiB,QAAQ,kBAAkB;CAEjD,OAAO;EACL,MAAM;EAEN,MAAM,iBAAuG;GAC3G,MAAM,SAAS,MAAM,QAAQ;IAC3B,SAAS,QAAQ;IACjB,UAAU,QAAQ;IAClB,GAAG,QAAQ;GACb,CAAC;GAED,KAAK,SAAS;IACZ,MAAM;IACN,UAAU;IACV,QAAQ,OAAO;GACjB,CAAC;GAED,KAAK,MAAM,KAAK,OAAO,aACrB,IAAI,EAAE,UAAU,WACd,QAAQ,KAAK,aAAa,EAAE,SAAS;QAErC,QAAQ,MAAM,aAAa,EAAE,SAAS;EAG5C;CACF;AACF"}
|
package/dist/plugins/vite.d.ts
CHANGED
|
@@ -1,57 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
import { t as CompileOptions } from "../types-BFyb40Zq.js";
|
|
2
|
+
import { Plugin } from "vite";
|
|
3
|
+
//#region src/plugins/vite.d.ts
|
|
4
|
+
export interface TweeTsVitePluginOptions {
|
|
5
|
+
/** Source directories/files to compile, relative to the working directory. */
|
|
6
|
+
sources: string[];
|
|
7
|
+
/** Story format ID. */
|
|
8
|
+
format?: string;
|
|
9
|
+
/** Output filename in build output. Default: 'index.html'. */
|
|
10
|
+
outputFilename?: string;
|
|
11
|
+
/** Additional compile options. `sources` and `formatId` come from the options above. */
|
|
12
|
+
compileOptions?: Partial<CompileOptions>;
|
|
13
|
+
/**
|
|
14
|
+
* A JS or TS file, relative to the working directory. Vite bundles it and
|
|
15
|
+
* everything it imports into one self-contained script that becomes the
|
|
16
|
+
* story's Story JavaScript; CSS it imports becomes the Story Stylesheet.
|
|
17
|
+
* Requires Vite 8.
|
|
18
|
+
*/
|
|
19
|
+
entry?: string;
|
|
17
20
|
}
|
|
18
|
-
declare function tweeTsPlugin(options: TweeTsVitePluginOptions):
|
|
19
|
-
|
|
20
|
-
buildStart(): Promise<void>;
|
|
21
|
-
generateBundle(this: {
|
|
22
|
-
emitFile: (opts: {
|
|
23
|
-
type: string;
|
|
24
|
-
fileName: string;
|
|
25
|
-
source: string;
|
|
26
|
-
}) => void;
|
|
27
|
-
}): Promise<void>;
|
|
28
|
-
configureServer(server: {
|
|
29
|
-
watcher: {
|
|
30
|
-
add: (path: string) => void;
|
|
31
|
-
};
|
|
32
|
-
ws: {
|
|
33
|
-
send: (data: {
|
|
34
|
-
type: string;
|
|
35
|
-
}) => void;
|
|
36
|
-
};
|
|
37
|
-
middlewares: {
|
|
38
|
-
use: (fn: (req: {
|
|
39
|
-
url?: string;
|
|
40
|
-
}, res: {
|
|
41
|
-
end: (data: string) => void;
|
|
42
|
-
}, next: () => void) => void) => void;
|
|
43
|
-
};
|
|
44
|
-
}): Promise<void>;
|
|
45
|
-
handleHotUpdate(ctx: {
|
|
46
|
-
file: string;
|
|
47
|
-
server: {
|
|
48
|
-
ws: {
|
|
49
|
-
send: (data: {
|
|
50
|
-
type: string;
|
|
51
|
-
}) => void;
|
|
52
|
-
};
|
|
53
|
-
};
|
|
54
|
-
}): Promise<void>;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export { type TweeTsVitePluginOptions, tweeTsPlugin };
|
|
21
|
+
export declare function tweeTsPlugin(options: TweeTsVitePluginOptions): Plugin;
|
|
22
|
+
//#endregion
|
package/dist/plugins/vite.js
CHANGED
|
@@ -1,70 +1,407 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
} from "
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
function logDiagnostics(diagnostics) {
|
|
17
|
-
for (const d of diagnostics) {
|
|
18
|
-
if (d.level === "warning") {
|
|
19
|
-
console.warn(`[twee-ts] ${d.message}`);
|
|
20
|
-
} else {
|
|
21
|
-
console.error(`[twee-ts] ${d.message}`);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
1
|
+
import { i as mediaTypeFromFilename, r as compileIncremental, t as TweeTsError } from "../compiler-Bfi1w-to.js";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { stripVTControlCharacters } from "node:util";
|
|
4
|
+
import { build, version } from "vite";
|
|
5
|
+
//#region src/plugins/paths.ts
|
|
6
|
+
/**
|
|
7
|
+
* Path helpers for the Vite plugin. Vite reports module ids with forward
|
|
8
|
+
* slashes on every platform, while node:path gives backslashes on Windows, so
|
|
9
|
+
* the plugin compares paths in forward-slash form only.
|
|
10
|
+
*/
|
|
11
|
+
/** The path with Windows separators turned into forward slashes. */
|
|
12
|
+
function toPosix(path) {
|
|
13
|
+
return path.replace(/\\/g, "/");
|
|
24
14
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
15
|
+
/** Whether `file` is one of `dirs` or inside one of them. All paths in forward-slash form. */
|
|
16
|
+
function isInside(file, dirs) {
|
|
17
|
+
return dirs.some((dir) => file === dir || file.startsWith(dir.endsWith("/") ? dir : `${dir}/`));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Whether `file` is a temporary copy of a Vite config file. Vite writes one next
|
|
21
|
+
* to the config file each time it loads it (when no node_modules folder is
|
|
22
|
+
* above the config, and always under Deno), then deletes it.
|
|
23
|
+
*/
|
|
24
|
+
function isViteConfigTemp(file) {
|
|
25
|
+
return /\.timestamp-\d+-[0-9a-f]*\.mjs$/.test(file);
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/plugins/vite.ts
|
|
29
|
+
/**
|
|
30
|
+
* Ready-made Vite plugin for twee-ts.
|
|
31
|
+
*
|
|
32
|
+
* Compiles Twee sources into the story HTML. With `entry`, Vite also bundles a
|
|
33
|
+
* script, and the CSS it imports, into the story as its Story JavaScript and
|
|
34
|
+
* Story Stylesheet.
|
|
35
|
+
*
|
|
36
|
+
* In dev the compiled HTML is served at the base URL with Vite's client added.
|
|
37
|
+
* Every change to a source, the head file, a module or a file the entry imports
|
|
38
|
+
* recompiles it and reloads the page, and errors appear in Vite's overlay.
|
|
39
|
+
*/
|
|
40
|
+
/** Passage names the bundled entry takes inside the story. */
|
|
41
|
+
const ENTRY_SCRIPT_NAME = "twee-ts-entry.js";
|
|
42
|
+
const ENTRY_STYLE_NAME = "twee-ts-entry.css";
|
|
43
|
+
/**
|
|
44
|
+
* Set on the inline config of the build this plugin starts itself to bundle the
|
|
45
|
+
* entry in dev. The plugin instance that build loads from the user's config file
|
|
46
|
+
* sees it and stands aside.
|
|
47
|
+
*/
|
|
48
|
+
const INNER_BUILD_FLAG = "__tweeTsEntryBuild";
|
|
49
|
+
/**
|
|
50
|
+
* A build input that stands in when there is no entry, so Vite does not look
|
|
51
|
+
* for an index.html (whose page would replace the story). Its empty chunk is
|
|
52
|
+
* dropped from the output.
|
|
53
|
+
*/
|
|
54
|
+
const EMPTY_INPUT = "virtual:twee-ts-empty-input";
|
|
55
|
+
const RESOLVED_EMPTY_INPUT = "\0" + EMPTY_INPUT;
|
|
56
|
+
const viteMajor = Number.parseInt(version, 10);
|
|
57
|
+
function formatDiagnostic(d) {
|
|
58
|
+
return `${d.file ? `${d.file}${d.line ? `:${d.line}` : ""}: ` : ""}${d.file && d.line ? d.message.replace(/^line \d+: /, "") : d.message}`;
|
|
59
|
+
}
|
|
60
|
+
/** Returns the warnings; throws a LocatedError when the compile reported errors. */
|
|
61
|
+
function splitDiagnostics(result) {
|
|
62
|
+
const errors = result.diagnostics.filter((d) => d.level === "error");
|
|
63
|
+
if (errors.length === 0) return result.diagnostics.filter((d) => d.level === "warning");
|
|
64
|
+
const error = new Error(errors.map(formatDiagnostic).join("\n"));
|
|
65
|
+
const [first] = errors;
|
|
66
|
+
if (first?.file) {
|
|
67
|
+
error.id = first.file;
|
|
68
|
+
error.loc = {
|
|
69
|
+
file: first.file,
|
|
70
|
+
line: first.line ?? 1,
|
|
71
|
+
column: 1
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
/** An error thrown by the compiler or bundler, with a TweeTsError's error diagnostics folded into its message. */
|
|
77
|
+
function fatalError(e) {
|
|
78
|
+
if (e instanceof TweeTsError) {
|
|
79
|
+
const errors = e.diagnostics.filter((d) => d.level === "error").map(formatDiagnostic);
|
|
80
|
+
return new Error([...errors, e.message].join("\n"));
|
|
81
|
+
}
|
|
82
|
+
return e instanceof Error ? e : new Error(String(e));
|
|
83
|
+
}
|
|
84
|
+
function buildCompileOptions(options, entry) {
|
|
85
|
+
const inline = [];
|
|
86
|
+
if (entry) {
|
|
87
|
+
inline.push({
|
|
88
|
+
filename: ENTRY_SCRIPT_NAME,
|
|
89
|
+
content: entry.script
|
|
90
|
+
});
|
|
91
|
+
if (entry.style !== "") inline.push({
|
|
92
|
+
filename: ENTRY_STYLE_NAME,
|
|
93
|
+
content: entry.style
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
...options.compileOptions,
|
|
98
|
+
sources: [...options.sources, ...inline],
|
|
99
|
+
formatId: options.format ?? options.compileOptions?.formatId
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/** Whether the user's config names build inputs of its own. */
|
|
103
|
+
function hasUserInput(userConfig) {
|
|
104
|
+
const build = userConfig.build;
|
|
105
|
+
return build?.["rolldownOptions"]?.input !== void 0 || build?.["rollupOptions"]?.input !== void 0;
|
|
106
|
+
}
|
|
107
|
+
/** Build settings naming one input, under the option name this Vite version reads. */
|
|
108
|
+
function inputOnly(input) {
|
|
109
|
+
return viteMajor >= 8 ? { rolldownOptions: { input } } : { rollupOptions: { input } };
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Build settings that turn the entry into one IIFE script and one stylesheet.
|
|
113
|
+
* Fonts and images the entry uses are inlined as data URLs, so the story stays
|
|
114
|
+
* one file; only an import marked `?no-inline` is still emitted separately.
|
|
115
|
+
*/
|
|
116
|
+
function entryBuildOptions(entryPath) {
|
|
117
|
+
return {
|
|
118
|
+
cssCodeSplit: false,
|
|
119
|
+
assetsInlineLimit: () => true,
|
|
120
|
+
rolldownOptions: {
|
|
121
|
+
input: entryPath,
|
|
122
|
+
output: {
|
|
123
|
+
format: "iife",
|
|
124
|
+
entryFileNames: ENTRY_SCRIPT_NAME,
|
|
125
|
+
assetFileNames: "[name][extname]"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/** Removes a trailing source-map comment that points at a file (a data: URL map stays). */
|
|
131
|
+
function dropFileSourceMapComment(code) {
|
|
132
|
+
return code.replace(/\n?\/\/# sourceMappingURL=(?!data:)\S*\s*$/, "").replace(/\n?\/\*# sourceMappingURL=(?!data:)[^*]*\*\/\s*$/, "");
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Takes the entry's script and stylesheet out of the bundle, together with
|
|
136
|
+
* their map files, which the story cannot ship. Anything else the bundler
|
|
137
|
+
* emitted stays in the bundle, so a build writes it next to the HTML, and is
|
|
138
|
+
* also returned, so the dev server can serve it.
|
|
139
|
+
*/
|
|
140
|
+
function takeEntryFromBundle(bundle) {
|
|
141
|
+
const entry = {
|
|
142
|
+
script: "",
|
|
143
|
+
style: "",
|
|
144
|
+
files: /* @__PURE__ */ new Set(),
|
|
145
|
+
assets: /* @__PURE__ */ new Map()
|
|
146
|
+
};
|
|
147
|
+
const styles = [];
|
|
148
|
+
for (const [fileName, item] of Object.entries(bundle)) if (item.type === "chunk") {
|
|
149
|
+
if (item.isEntry) {
|
|
150
|
+
entry.script = dropFileSourceMapComment(item.code);
|
|
151
|
+
for (const id of item.moduleIds) if (!id.startsWith("\0")) entry.files.add(toPosix(id));
|
|
152
|
+
}
|
|
153
|
+
delete bundle[fileName];
|
|
154
|
+
} else if (fileName.endsWith(".css")) {
|
|
155
|
+
const css = typeof item.source === "string" ? item.source : new TextDecoder().decode(item.source);
|
|
156
|
+
styles.push(dropFileSourceMapComment(css));
|
|
157
|
+
delete bundle[fileName];
|
|
158
|
+
} else if (fileName.endsWith(".map")) delete bundle[fileName];
|
|
159
|
+
else entry.assets.set(fileName, item.source);
|
|
160
|
+
entry.style = styles.join("\n");
|
|
161
|
+
return entry;
|
|
162
|
+
}
|
|
163
|
+
/** Absolute forward-slash paths whose changes recompile the story: sources, head file, modules. */
|
|
164
|
+
function watchedInputs(options) {
|
|
165
|
+
const extra = options.compileOptions;
|
|
166
|
+
return [
|
|
167
|
+
...options.sources,
|
|
168
|
+
...extra?.headFile ? [extra.headFile] : [],
|
|
169
|
+
...extra?.modules ?? []
|
|
170
|
+
].map((p) => toPosix(resolve(p)));
|
|
171
|
+
}
|
|
172
|
+
/** Adds Vite's client to the page so reloads and the error overlay reach it. */
|
|
173
|
+
function injectViteClient(html, base) {
|
|
174
|
+
const tag = `<script type="module" src="${base}@vite/client"><\/script>`;
|
|
175
|
+
const head = /<head[^>]*>/i.exec(html);
|
|
176
|
+
if (!head) return tag + html;
|
|
177
|
+
const at = head.index + head[0].length;
|
|
178
|
+
return html.slice(0, at) + tag + html.slice(at);
|
|
179
|
+
}
|
|
180
|
+
/** Served until the first successful compile, so the overlay has a page to appear on. */
|
|
181
|
+
function waitingPage(base) {
|
|
182
|
+
return `<!doctype html><html><head><meta charset="utf-8"><script type="module" src="${base}@vite/client"><\/script><title>twee-ts</title></head><body><p>The story has not compiled yet.</p></body></html>`;
|
|
183
|
+
}
|
|
184
|
+
function toOverlayError(e) {
|
|
185
|
+
const error = fatalError(e);
|
|
186
|
+
return {
|
|
187
|
+
message: stripVTControlCharacters(error.message),
|
|
188
|
+
stack: "",
|
|
189
|
+
plugin: "twee-ts",
|
|
190
|
+
...error.id ? { id: error.id } : {},
|
|
191
|
+
...error.loc ? { loc: error.loc } : {}
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/** Bundles the entry for dev with the user's own Vite config, unminified, with an inline source map. */
|
|
195
|
+
/**
|
|
196
|
+
* The entry build's logger: its warnings go to the dev server's logger; its
|
|
197
|
+
* progress lines and its own "build failed" line are dropped, because the plugin
|
|
198
|
+
* reports a failed bundle itself.
|
|
199
|
+
*/
|
|
200
|
+
function entryBuildLogger(outer) {
|
|
201
|
+
return {
|
|
202
|
+
info: () => {},
|
|
203
|
+
warn: (message, options) => outer.warn(message, options),
|
|
204
|
+
warnOnce: (message, options) => outer.warnOnce(message, options),
|
|
205
|
+
error: () => {},
|
|
206
|
+
clearScreen: () => {},
|
|
207
|
+
hasErrorLogged: () => false,
|
|
208
|
+
get hasWarned() {
|
|
209
|
+
return outer.hasWarned;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Keeps the entry build a one-off even when the user's config sets build.watch:
|
|
215
|
+
* Vite's config merge skips a null, so the inline `watch: null` alone can't.
|
|
216
|
+
*/
|
|
217
|
+
const oneOffEntryBuild = {
|
|
218
|
+
name: "twee-ts:one-off-entry-build",
|
|
219
|
+
enforce: "post",
|
|
220
|
+
config(userConfig) {
|
|
221
|
+
if (userConfig.build) userConfig.build.watch = null;
|
|
222
|
+
}
|
|
69
223
|
};
|
|
224
|
+
/** Bundles the entry for dev with the user's own Vite config, unminified, with an inline source map. */
|
|
225
|
+
async function bundleEntryForDev(config, entryPath) {
|
|
226
|
+
const inline = {
|
|
227
|
+
configFile: config.configFile ?? false,
|
|
228
|
+
root: config.root,
|
|
229
|
+
mode: config.mode,
|
|
230
|
+
customLogger: entryBuildLogger(config.logger),
|
|
231
|
+
publicDir: false,
|
|
232
|
+
...config.configFile ? {} : {
|
|
233
|
+
define: config.define,
|
|
234
|
+
resolve: { alias: config.resolve.alias }
|
|
235
|
+
},
|
|
236
|
+
build: {
|
|
237
|
+
...entryBuildOptions(entryPath),
|
|
238
|
+
write: false,
|
|
239
|
+
minify: false,
|
|
240
|
+
sourcemap: "inline",
|
|
241
|
+
emptyOutDir: false,
|
|
242
|
+
copyPublicDir: false,
|
|
243
|
+
watch: null
|
|
244
|
+
},
|
|
245
|
+
plugins: [oneOffEntryBuild],
|
|
246
|
+
[INNER_BUILD_FLAG]: true
|
|
247
|
+
};
|
|
248
|
+
const out = await build(inline);
|
|
249
|
+
const bundle = {};
|
|
250
|
+
for (const result of Array.isArray(out) ? out : [out]) {
|
|
251
|
+
if (!("output" in result)) {
|
|
252
|
+
await result.close();
|
|
253
|
+
throw new Error("twee-ts: the entry build returned a watcher instead of a bundle.");
|
|
254
|
+
}
|
|
255
|
+
for (const item of result.output) bundle[item.fileName] = item;
|
|
256
|
+
}
|
|
257
|
+
return takeEntryFromBundle(bundle);
|
|
258
|
+
}
|
|
259
|
+
function tweeTsPlugin(options) {
|
|
260
|
+
const outputFilename = options.outputFilename ?? "index.html";
|
|
261
|
+
const cache = /* @__PURE__ */ new Map();
|
|
262
|
+
let innerBuild = false;
|
|
263
|
+
let stopDev;
|
|
264
|
+
if (options.entry && viteMajor < 8) throw new Error(`twee-ts: the entry option needs Vite 8 or newer (found ${version}).`);
|
|
265
|
+
return {
|
|
266
|
+
name: "twee-ts",
|
|
267
|
+
config(userConfig, env) {
|
|
268
|
+
innerBuild = userConfig[INNER_BUILD_FLAG] === true;
|
|
269
|
+
if (innerBuild || env.command !== "build") return void 0;
|
|
270
|
+
if (options.entry) return { build: entryBuildOptions(resolve(options.entry)) };
|
|
271
|
+
if (hasUserInput(userConfig)) return void 0;
|
|
272
|
+
return { build: inputOnly(EMPTY_INPUT) };
|
|
273
|
+
},
|
|
274
|
+
configResolved(config) {
|
|
275
|
+
if (innerBuild || !options.entry) return;
|
|
276
|
+
const sources = options.sources.map((p) => toPosix(resolve(p)));
|
|
277
|
+
if (isInside(toPosix(resolve(options.entry)), sources)) config.logger.warn(`[twee-ts] The entry ${options.entry} is inside the story sources (${options.sources.join(", ")}). twee-ts also loads the .js and .css files it finds in source folders, unbundled, as Story JavaScript and Story Stylesheet; keep the entry's folder out of \`sources\`.`);
|
|
278
|
+
},
|
|
279
|
+
resolveId(id) {
|
|
280
|
+
return id === EMPTY_INPUT ? RESOLVED_EMPTY_INPUT : void 0;
|
|
281
|
+
},
|
|
282
|
+
load(id) {
|
|
283
|
+
return id === RESOLVED_EMPTY_INPUT ? "globalThis.tweeTsEmptyInput = true;" : void 0;
|
|
284
|
+
},
|
|
285
|
+
generateBundle: {
|
|
286
|
+
order: "post",
|
|
287
|
+
async handler(_outputOptions, bundle) {
|
|
288
|
+
if (innerBuild) return;
|
|
289
|
+
for (const [fileName, item] of Object.entries(bundle)) if (item.type === "chunk" && item.facadeModuleId === RESOLVED_EMPTY_INPUT) delete bundle[fileName];
|
|
290
|
+
const entry = options.entry ? takeEntryFromBundle(bundle) : void 0;
|
|
291
|
+
let result;
|
|
292
|
+
try {
|
|
293
|
+
result = await compileIncremental(buildCompileOptions(options, entry), cache);
|
|
294
|
+
} catch (e) {
|
|
295
|
+
return this.error(fatalError(e));
|
|
296
|
+
}
|
|
297
|
+
let warnings;
|
|
298
|
+
try {
|
|
299
|
+
warnings = splitDiagnostics(result);
|
|
300
|
+
} catch (e) {
|
|
301
|
+
return this.error(e);
|
|
302
|
+
}
|
|
303
|
+
for (const w of warnings) this.warn(formatDiagnostic(w));
|
|
304
|
+
this.emitFile({
|
|
305
|
+
type: "asset",
|
|
306
|
+
fileName: outputFilename,
|
|
307
|
+
source: result.output
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
async configureServer(server) {
|
|
312
|
+
if (innerBuild) return;
|
|
313
|
+
const base = server.config.base;
|
|
314
|
+
const servePaths = outputFilename === "index.html" ? [base, `${base}index.html`] : [`${base}${outputFilename}`];
|
|
315
|
+
const inputs = watchedInputs(options);
|
|
316
|
+
const entryPath = options.entry ? resolve(options.entry) : void 0;
|
|
317
|
+
const root = toPosix(server.config.root);
|
|
318
|
+
server.watcher.add(inputs);
|
|
319
|
+
let html = "";
|
|
320
|
+
let lastError;
|
|
321
|
+
let entry;
|
|
322
|
+
let entryStale = true;
|
|
323
|
+
let queue = Promise.resolve();
|
|
324
|
+
let pending = /* @__PURE__ */ new Set();
|
|
325
|
+
let timer;
|
|
326
|
+
let closed = false;
|
|
327
|
+
stopDev = () => {
|
|
328
|
+
closed = true;
|
|
329
|
+
clearTimeout(timer);
|
|
330
|
+
pending.clear();
|
|
331
|
+
};
|
|
332
|
+
const touchesEntry = (file) => entryPath !== void 0 && (entryStale ? isInside(file, [root]) : entry?.files.has(file) ?? false);
|
|
333
|
+
const rebuild = async (changed, initial = false) => {
|
|
334
|
+
if (closed) return;
|
|
335
|
+
for (const key of [...cache.keys()]) if (changed.has(toPosix(resolve(key)))) cache.delete(key);
|
|
336
|
+
try {
|
|
337
|
+
if (entryPath && (entryStale || [...changed].some(touchesEntry))) {
|
|
338
|
+
entryStale = true;
|
|
339
|
+
entry = await bundleEntryForDev(server.config, entryPath);
|
|
340
|
+
entryStale = false;
|
|
341
|
+
}
|
|
342
|
+
const result = await compileIncremental(buildCompileOptions(options, entry), cache);
|
|
343
|
+
for (const w of splitDiagnostics(result)) server.config.logger.warn(`[twee-ts] ${formatDiagnostic(w)}`);
|
|
344
|
+
html = injectViteClient(result.output, base);
|
|
345
|
+
lastError = void 0;
|
|
346
|
+
if (!initial) server.ws.send({ type: "full-reload" });
|
|
347
|
+
} catch (e) {
|
|
348
|
+
lastError = toOverlayError(e);
|
|
349
|
+
server.config.logger.error(`[twee-ts] ${lastError.message}`);
|
|
350
|
+
server.ws.send({
|
|
351
|
+
type: "error",
|
|
352
|
+
err: lastError
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
const keepQueueAlive = (e) => {
|
|
357
|
+
try {
|
|
358
|
+
server.config.logger.error(`[twee-ts] ${fatalError(e).message}`);
|
|
359
|
+
} catch {}
|
|
360
|
+
};
|
|
361
|
+
await rebuild(/* @__PURE__ */ new Set(), true);
|
|
362
|
+
server.watcher.on("all", (event, file) => {
|
|
363
|
+
if (event !== "add" && event !== "change" && event !== "unlink") return;
|
|
364
|
+
const changed = toPosix(resolve(file));
|
|
365
|
+
if (isViteConfigTemp(changed)) return;
|
|
366
|
+
if (!isInside(changed, inputs) && !touchesEntry(changed)) return;
|
|
367
|
+
pending.add(changed);
|
|
368
|
+
clearTimeout(timer);
|
|
369
|
+
timer = setTimeout(() => {
|
|
370
|
+
const files = pending;
|
|
371
|
+
pending = /* @__PURE__ */ new Set();
|
|
372
|
+
queue = queue.then(() => rebuild(files)).catch(keepQueueAlive);
|
|
373
|
+
}, 50);
|
|
374
|
+
});
|
|
375
|
+
server.ws.on("connection", () => {
|
|
376
|
+
if (lastError) server.ws.send({
|
|
377
|
+
type: "error",
|
|
378
|
+
err: lastError
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
server.middlewares.use((req, res, next) => {
|
|
382
|
+
const path = (req.url ?? "").split("?")[0] ?? "";
|
|
383
|
+
if (servePaths.includes(path)) {
|
|
384
|
+
res.statusCode = 200;
|
|
385
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
386
|
+
res.end(html || waitingPage(base));
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const asset = path.startsWith(base) ? entry?.assets.get(path.slice(base.length)) : void 0;
|
|
390
|
+
if (asset !== void 0) {
|
|
391
|
+
res.statusCode = 200;
|
|
392
|
+
res.setHeader("Content-Type", mediaTypeFromFilename(path));
|
|
393
|
+
res.end(asset);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
next();
|
|
397
|
+
});
|
|
398
|
+
},
|
|
399
|
+
closeBundle() {
|
|
400
|
+
stopDev?.();
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
//#endregion
|
|
405
|
+
export { tweeTsPlugin };
|
|
406
|
+
|
|
70
407
|
//# sourceMappingURL=vite.js.map
|