@rohal12/twee-ts 1.15.0 → 1.15.3
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 +5567 -5267
- 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 +5365 -5125
- 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 +5329 -5062
- 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 -22
- package/dist/plugins/vite.js +452 -300
- package/dist/plugins/vite.js.map +1 -1
- package/dist/types-BFyb40Zq.d.ts +49 -0
- package/package.json +10 -10
- package/dist/chunk-W3SNMQO4.js +0 -4809
- package/dist/chunk-W3SNMQO4.js.map +0 -1
- package/dist/types-FHZ3rZD6.d.ts +0 -48
package/dist/plugins/vite.js
CHANGED
|
@@ -1,340 +1,492 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// src/plugins/paths.ts
|
|
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. */
|
|
13
12
|
function toPosix(path) {
|
|
14
|
-
|
|
13
|
+
return path.replace(/\\/g, "/");
|
|
15
14
|
}
|
|
15
|
+
/** Whether `file` is one of `dirs` or inside one of them. All paths in forward-slash form. */
|
|
16
16
|
function isInside(file, dirs) {
|
|
17
|
-
|
|
17
|
+
return dirs.some((dir) => file === dir || file.startsWith(dir.endsWith("/") ? dir : `${dir}/`));
|
|
18
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
|
+
*/
|
|
19
24
|
function isViteConfigTemp(file) {
|
|
20
|
-
|
|
25
|
+
return /\.timestamp-\d+-[0-9a-f]*\.mjs$/.test(file);
|
|
21
26
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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);
|
|
30
57
|
function formatDiagnostic(d) {
|
|
31
|
-
|
|
32
|
-
const message = d.file && d.line ? d.message.replace(/^line \d+: /, "") : d.message;
|
|
33
|
-
return `${where}${message}`;
|
|
58
|
+
return `${d.file ? `${d.file}${d.line ? `:${d.line}` : ""}: ` : ""}${d.file && d.line ? d.message.replace(/^line \d+: /, "") : d.message}`;
|
|
34
59
|
}
|
|
60
|
+
/** Returns the warnings; throws a LocatedError when the compile reported errors. */
|
|
35
61
|
function splitDiagnostics(result) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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;
|
|
45
75
|
}
|
|
76
|
+
/** An error thrown by the compiler or bundler, with a TweeTsError's error diagnostics folded into its message. */
|
|
46
77
|
function fatalError(e) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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));
|
|
52
83
|
}
|
|
53
84
|
function buildCompileOptions(options, entry) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
+
};
|
|
64
101
|
}
|
|
102
|
+
/** Whether the user's config names build inputs of its own. */
|
|
65
103
|
function hasUserInput(userConfig) {
|
|
66
|
-
|
|
67
|
-
|
|
104
|
+
const build = userConfig.build;
|
|
105
|
+
return build?.["rolldownOptions"]?.input !== void 0 || build?.["rollupOptions"]?.input !== void 0;
|
|
68
106
|
}
|
|
107
|
+
/** Build settings naming one input, under the option name this Vite version reads. */
|
|
69
108
|
function inputOnly(input) {
|
|
70
|
-
|
|
109
|
+
return viteMajor >= 8 ? { rolldownOptions: { input } } : { rollupOptions: { input } };
|
|
71
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
|
+
*/
|
|
72
116
|
function entryBuildOptions(entryPath) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
+
};
|
|
81
129
|
}
|
|
130
|
+
/** Removes a trailing source-map comment that points at a file (a data: URL map stays). */
|
|
82
131
|
function dropFileSourceMapComment(code) {
|
|
83
|
-
|
|
132
|
+
return code.replace(/\n?\/\/# sourceMappingURL=(?!data:)\S*\s*$/, "").replace(/\n?\/\*# sourceMappingURL=(?!data:)[^*]*\*\/\s*$/, "");
|
|
84
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
|
+
*/
|
|
85
140
|
function takeEntryFromBundle(bundle) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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(fileOfId(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;
|
|
107
162
|
}
|
|
163
|
+
/** Absolute forward-slash paths whose changes recompile the story: sources, head file, modules. */
|
|
108
164
|
function watchedInputs(options) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
165
|
+
const extra = options.compileOptions;
|
|
166
|
+
return [
|
|
167
|
+
...options.sources,
|
|
168
|
+
...extra?.headFile ? [extra.headFile] : [],
|
|
169
|
+
...extra?.modules ?? []
|
|
170
|
+
].map((p) => toPosix(resolve(p)));
|
|
113
171
|
}
|
|
172
|
+
/** Adds Vite's client to the page so reloads and the error overlay reach it. */
|
|
114
173
|
function injectViteClient(html, base) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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);
|
|
120
179
|
}
|
|
180
|
+
/** Served until the first successful compile, so the overlay has a page to appear on. */
|
|
121
181
|
function waitingPage(base) {
|
|
122
|
-
|
|
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>`;
|
|
123
183
|
}
|
|
124
184
|
function toOverlayError(e) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
};
|
|
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
|
+
};
|
|
134
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
|
+
*/
|
|
135
200
|
function entryBuildLogger(outer) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return outer.hasWarned;
|
|
148
|
-
}
|
|
149
|
-
};
|
|
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
|
+
};
|
|
150
212
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
+
}
|
|
157
223
|
};
|
|
224
|
+
/** Build-phase plugin hooks that may call `this.addWatchFile`. */
|
|
225
|
+
const WATCH_FILE_HOOKS = [
|
|
226
|
+
"buildStart",
|
|
227
|
+
"resolveId",
|
|
228
|
+
"resolveDynamicImport",
|
|
229
|
+
"load",
|
|
230
|
+
"transform",
|
|
231
|
+
"moduleParsed",
|
|
232
|
+
"buildEnd"
|
|
233
|
+
];
|
|
234
|
+
/** A module id or watched file as a forward-slash file path, without a query or hash (like Vite's cleanUrl). */
|
|
235
|
+
function fileOfId(id) {
|
|
236
|
+
return toPosix(id.replace(/[?#].*$/s, ""));
|
|
237
|
+
}
|
|
238
|
+
/** A plugin context whose `addWatchFile` also records the file in `files`. */
|
|
239
|
+
function recordingContext(context, files) {
|
|
240
|
+
return new Proxy(context, { get(target, key) {
|
|
241
|
+
const value = Reflect.get(target, key, target);
|
|
242
|
+
if (typeof value !== "function") return value;
|
|
243
|
+
if (key !== "addWatchFile") return value.bind(target);
|
|
244
|
+
return (id) => {
|
|
245
|
+
if (!id.startsWith("\0")) files.add(fileOfId(resolve(id)));
|
|
246
|
+
return value.call(target, id);
|
|
247
|
+
};
|
|
248
|
+
} });
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* A copy of `plugin` whose hooks record `addWatchFile` calls in `files`. The
|
|
252
|
+
* original stays untouched, so a plugin object shared across entry builds never
|
|
253
|
+
* collects wrappers. The copy keeps the prototype, so class-based plugins keep
|
|
254
|
+
* their methods, and object-form hooks keep `order`, `filter` and the rest. A
|
|
255
|
+
* plugin with no such hooks (a built-in one, for instance) is returned as is.
|
|
256
|
+
*/
|
|
257
|
+
function recordingPlugin(plugin, files) {
|
|
258
|
+
if (typeof plugin !== "object" || plugin === null) return plugin;
|
|
259
|
+
const hooks = plugin;
|
|
260
|
+
const hookHandler = (hook) => typeof hook === "object" && hook !== null ? hook.handler : hook;
|
|
261
|
+
if (!WATCH_FILE_HOOKS.some((name) => typeof hookHandler(hooks[name]) === "function")) return plugin;
|
|
262
|
+
const copy = Object.create(Object.getPrototypeOf(plugin), Object.getOwnPropertyDescriptors(plugin));
|
|
263
|
+
for (const name of WATCH_FILE_HOOKS) {
|
|
264
|
+
const hook = hooks[name];
|
|
265
|
+
const handler = hookHandler(hook);
|
|
266
|
+
if (typeof handler !== "function") continue;
|
|
267
|
+
const wrapped = function(...args) {
|
|
268
|
+
return handler.apply(recordingContext(this, files), args);
|
|
269
|
+
};
|
|
270
|
+
copy[name] = typeof hook === "function" ? wrapped : {
|
|
271
|
+
...hook,
|
|
272
|
+
handler: wrapped
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
return copy;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Collects the files the entry build's plugins add with `addWatchFile`. These
|
|
279
|
+
* are not modules of the bundle: Vite's CSS plugin adds the stylesheets pulled
|
|
280
|
+
* in by `@import` and the files `url()` points at this way. The build runs on
|
|
281
|
+
* recording copies of its plugins. They are made in the bundler's `options`
|
|
282
|
+
* hook, which sees the final plugin list, including the plugins Vite resolves
|
|
283
|
+
* per environment (`applyToEnvironment`) after `configResolved`.
|
|
284
|
+
*/
|
|
285
|
+
function recordWatchFiles(files) {
|
|
286
|
+
return {
|
|
287
|
+
name: "twee-ts:record-watch-files",
|
|
288
|
+
options: {
|
|
289
|
+
order: "post",
|
|
290
|
+
async handler(inputOptions) {
|
|
291
|
+
const plugins = (await flattenPlugins(inputOptions.plugins)).map((p) => recordingPlugin(p, files));
|
|
292
|
+
return {
|
|
293
|
+
...inputOptions,
|
|
294
|
+
plugins
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
/** A plugin option (nested arrays, promises, falsy entries) as one flat list. */
|
|
301
|
+
async function flattenPlugins(option) {
|
|
302
|
+
const value = await option;
|
|
303
|
+
if (Array.isArray(value)) return (await Promise.all(value.map(flattenPlugins))).flat();
|
|
304
|
+
return value ? [value] : [];
|
|
305
|
+
}
|
|
306
|
+
/** Bundles the entry for dev with the user's own Vite config, unminified, with an inline source map. */
|
|
158
307
|
async function bundleEntryForDev(config, entryPath) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
308
|
+
const watchFiles = /* @__PURE__ */ new Set();
|
|
309
|
+
const inline = {
|
|
310
|
+
configFile: config.configFile ?? false,
|
|
311
|
+
root: config.root,
|
|
312
|
+
mode: config.mode,
|
|
313
|
+
customLogger: entryBuildLogger(config.logger),
|
|
314
|
+
publicDir: false,
|
|
315
|
+
...config.configFile ? {} : {
|
|
316
|
+
define: config.define,
|
|
317
|
+
resolve: { alias: config.resolve.alias }
|
|
318
|
+
},
|
|
319
|
+
build: {
|
|
320
|
+
...entryBuildOptions(entryPath),
|
|
321
|
+
write: false,
|
|
322
|
+
minify: false,
|
|
323
|
+
sourcemap: "inline",
|
|
324
|
+
emptyOutDir: false,
|
|
325
|
+
copyPublicDir: false,
|
|
326
|
+
watch: null
|
|
327
|
+
},
|
|
328
|
+
plugins: [oneOffEntryBuild, recordWatchFiles(watchFiles)],
|
|
329
|
+
[INNER_BUILD_FLAG]: true
|
|
330
|
+
};
|
|
331
|
+
const out = await build(inline);
|
|
332
|
+
const bundle = {};
|
|
333
|
+
for (const result of Array.isArray(out) ? out : [out]) {
|
|
334
|
+
if (!("output" in result)) {
|
|
335
|
+
await result.close();
|
|
336
|
+
throw new Error("twee-ts: the entry build returned a watcher instead of a bundle.");
|
|
337
|
+
}
|
|
338
|
+
for (const item of result.output) bundle[item.fileName] = item;
|
|
339
|
+
}
|
|
340
|
+
const entry = takeEntryFromBundle(bundle);
|
|
341
|
+
for (const file of watchFiles) entry.files.add(file);
|
|
342
|
+
return entry;
|
|
190
343
|
}
|
|
191
344
|
function tweeTsPlugin(options) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
};
|
|
345
|
+
const outputFilename = options.outputFilename ?? "index.html";
|
|
346
|
+
const cache = /* @__PURE__ */ new Map();
|
|
347
|
+
let innerBuild = false;
|
|
348
|
+
let stopDev;
|
|
349
|
+
if (options.entry && viteMajor < 8) throw new Error(`twee-ts: the entry option needs Vite 8 or newer (found ${version}).`);
|
|
350
|
+
return {
|
|
351
|
+
name: "twee-ts",
|
|
352
|
+
config(userConfig, env) {
|
|
353
|
+
innerBuild = userConfig[INNER_BUILD_FLAG] === true;
|
|
354
|
+
if (innerBuild || env.command !== "build") return void 0;
|
|
355
|
+
if (options.entry) return { build: entryBuildOptions(resolve(options.entry)) };
|
|
356
|
+
if (hasUserInput(userConfig)) return void 0;
|
|
357
|
+
return { build: inputOnly(EMPTY_INPUT) };
|
|
358
|
+
},
|
|
359
|
+
configResolved(config) {
|
|
360
|
+
if (innerBuild || !options.entry) return;
|
|
361
|
+
const sources = options.sources.map((p) => toPosix(resolve(p)));
|
|
362
|
+
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\`.`);
|
|
363
|
+
},
|
|
364
|
+
resolveId(id) {
|
|
365
|
+
return id === EMPTY_INPUT ? RESOLVED_EMPTY_INPUT : void 0;
|
|
366
|
+
},
|
|
367
|
+
load(id) {
|
|
368
|
+
return id === RESOLVED_EMPTY_INPUT ? "globalThis.tweeTsEmptyInput = true;" : void 0;
|
|
369
|
+
},
|
|
370
|
+
generateBundle: {
|
|
371
|
+
order: "post",
|
|
372
|
+
async handler(_outputOptions, bundle) {
|
|
373
|
+
if (innerBuild) return;
|
|
374
|
+
for (const [fileName, item] of Object.entries(bundle)) if (item.type === "chunk" && item.facadeModuleId === RESOLVED_EMPTY_INPUT) delete bundle[fileName];
|
|
375
|
+
const entry = options.entry ? takeEntryFromBundle(bundle) : void 0;
|
|
376
|
+
let result;
|
|
377
|
+
try {
|
|
378
|
+
result = await compileIncremental(buildCompileOptions(options, entry), cache);
|
|
379
|
+
} catch (e) {
|
|
380
|
+
return this.error(fatalError(e));
|
|
381
|
+
}
|
|
382
|
+
let warnings;
|
|
383
|
+
try {
|
|
384
|
+
warnings = splitDiagnostics(result);
|
|
385
|
+
} catch (e) {
|
|
386
|
+
return this.error(e);
|
|
387
|
+
}
|
|
388
|
+
for (const w of warnings) this.warn(formatDiagnostic(w));
|
|
389
|
+
this.emitFile({
|
|
390
|
+
type: "asset",
|
|
391
|
+
fileName: outputFilename,
|
|
392
|
+
source: result.output
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
async configureServer(server) {
|
|
397
|
+
if (innerBuild) return;
|
|
398
|
+
const base = server.config.base;
|
|
399
|
+
const servePaths = outputFilename === "index.html" ? [base, `${base}index.html`] : [`${base}${outputFilename}`];
|
|
400
|
+
const inputs = watchedInputs(options);
|
|
401
|
+
const entryPath = options.entry ? resolve(options.entry) : void 0;
|
|
402
|
+
const root = toPosix(server.config.root);
|
|
403
|
+
server.watcher.add(inputs);
|
|
404
|
+
let html = "";
|
|
405
|
+
let lastError;
|
|
406
|
+
let entry;
|
|
407
|
+
let entryStale = true;
|
|
408
|
+
let queue = Promise.resolve();
|
|
409
|
+
let pending = /* @__PURE__ */ new Set();
|
|
410
|
+
let timer;
|
|
411
|
+
let closed = false;
|
|
412
|
+
stopDev = () => {
|
|
413
|
+
closed = true;
|
|
414
|
+
clearTimeout(timer);
|
|
415
|
+
pending.clear();
|
|
416
|
+
};
|
|
417
|
+
const touchesEntry = (file) => entryPath !== void 0 && (entryStale ? isInside(file, [root]) : entry?.files.has(file) ?? false);
|
|
418
|
+
const rebuild = async (changed, initial = false) => {
|
|
419
|
+
if (closed) return;
|
|
420
|
+
for (const key of [...cache.keys()]) if (changed.has(toPosix(resolve(key)))) cache.delete(key);
|
|
421
|
+
try {
|
|
422
|
+
if (entryPath && (entryStale || [...changed].some(touchesEntry))) {
|
|
423
|
+
entryStale = true;
|
|
424
|
+
entry = await bundleEntryForDev(server.config, entryPath);
|
|
425
|
+
entryStale = false;
|
|
426
|
+
}
|
|
427
|
+
const result = await compileIncremental(buildCompileOptions(options, entry), cache);
|
|
428
|
+
for (const w of splitDiagnostics(result)) server.config.logger.warn(`[twee-ts] ${formatDiagnostic(w)}`);
|
|
429
|
+
html = injectViteClient(result.output, base);
|
|
430
|
+
lastError = void 0;
|
|
431
|
+
if (!initial) server.ws.send({ type: "full-reload" });
|
|
432
|
+
} catch (e) {
|
|
433
|
+
lastError = toOverlayError(e);
|
|
434
|
+
server.config.logger.error(`[twee-ts] ${lastError.message}`);
|
|
435
|
+
server.ws.send({
|
|
436
|
+
type: "error",
|
|
437
|
+
err: lastError
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
const keepQueueAlive = (e) => {
|
|
442
|
+
try {
|
|
443
|
+
server.config.logger.error(`[twee-ts] ${fatalError(e).message}`);
|
|
444
|
+
} catch {}
|
|
445
|
+
};
|
|
446
|
+
await rebuild(/* @__PURE__ */ new Set(), true);
|
|
447
|
+
server.watcher.on("all", (event, file) => {
|
|
448
|
+
if (event !== "add" && event !== "change" && event !== "unlink") return;
|
|
449
|
+
const changed = toPosix(resolve(file));
|
|
450
|
+
if (isViteConfigTemp(changed)) return;
|
|
451
|
+
if (!isInside(changed, inputs) && !touchesEntry(changed)) return;
|
|
452
|
+
pending.add(changed);
|
|
453
|
+
clearTimeout(timer);
|
|
454
|
+
timer = setTimeout(() => {
|
|
455
|
+
const files = pending;
|
|
456
|
+
pending = /* @__PURE__ */ new Set();
|
|
457
|
+
queue = queue.then(() => rebuild(files)).catch(keepQueueAlive);
|
|
458
|
+
}, 50);
|
|
459
|
+
});
|
|
460
|
+
server.ws.on("connection", () => {
|
|
461
|
+
if (lastError) server.ws.send({
|
|
462
|
+
type: "error",
|
|
463
|
+
err: lastError
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
server.middlewares.use((req, res, next) => {
|
|
467
|
+
const path = (req.url ?? "").split("?")[0] ?? "";
|
|
468
|
+
if (servePaths.includes(path)) {
|
|
469
|
+
res.statusCode = 200;
|
|
470
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
471
|
+
res.end(html || waitingPage(base));
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
const asset = path.startsWith(base) ? entry?.assets.get(path.slice(base.length)) : void 0;
|
|
475
|
+
if (asset !== void 0) {
|
|
476
|
+
res.statusCode = 200;
|
|
477
|
+
res.setHeader("Content-Type", mediaTypeFromFilename(path));
|
|
478
|
+
res.end(asset);
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
next();
|
|
482
|
+
});
|
|
483
|
+
},
|
|
484
|
+
closeBundle() {
|
|
485
|
+
stopDev?.();
|
|
486
|
+
}
|
|
487
|
+
};
|
|
336
488
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
489
|
+
//#endregion
|
|
490
|
+
export { tweeTsPlugin };
|
|
491
|
+
|
|
340
492
|
//# sourceMappingURL=vite.js.map
|