@animus-ui/unplugin 0.1.24 → 0.1.26
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 +12 -3
- package/dist/{core-CP2SnWlP.mjs → core-CrtP5_Sj.mjs} +243 -30
- package/dist/{core-BqEruPuj.cjs → core-zGWPVkIb.cjs} +241 -28
- package/dist/core.d.ts +13 -1
- package/dist/core.d.ts.map +1 -1
- package/dist/esbuild.cjs +1 -1
- package/dist/esbuild.mjs +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/rollup.cjs +1 -1
- package/dist/rollup.mjs +1 -1
- package/dist/rspack.cjs +1 -1
- package/dist/rspack.mjs +1 -1
- package/dist/webpack.cjs +1 -1
- package/dist/webpack.mjs +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -88,9 +88,18 @@ Options are the shared driver core (`system`, `exclude`, `strict`, `mode`,
|
|
|
88
88
|
default, the dev-signal define, engine dev diagnostics — never process
|
|
89
89
|
lifecycle. When absent, the bundler's own command oracle applies (webpack/
|
|
90
90
|
rspack `compiler.options.mode`, rollup watch mode), else `production`
|
|
91
|
-
(esbuild exposes no signal). `exclude` patterns are glob-aware
|
|
92
|
-
|
|
93
|
-
`.animus`
|
|
91
|
+
(esbuild exposes no signal). `exclude` patterns are glob-aware; a list
|
|
92
|
+
REPLACES the `dist`, `.test.` and `.spec.` defaults, while `node_modules`,
|
|
93
|
+
`.next` and `.animus` always apply. Wherever the bundler writes is
|
|
94
|
+
always excluded too: its output directories (every Vite environment's,
|
|
95
|
+
each output's `dir`, webpack's `output.path` up to its first `[…]`
|
|
96
|
+
placeholder) and its output files by exact name (`outfile`,
|
|
97
|
+
`output.file`). webpack, rspack, esbuild and Vite name them before
|
|
98
|
+
analysis. Rollup and Rolldown name them only after analysis, so a watch
|
|
99
|
+
excludes them from its second build on, and a build that has already
|
|
100
|
+
analysed one reports it (an output file as earlier output; a file inside
|
|
101
|
+
an output directory as earlier output or a source beside the output),
|
|
102
|
+
naming what to add to `exclude`; under `strict` that build fails.
|
|
94
103
|
|
|
95
104
|
The full consumer contract — module-id families, the define contract,
|
|
96
105
|
artifact set, platform matrix — lives in the
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AnimusConfigError, DiagnosticFailure, ENGINE_TRANSFORM_EXTENSIONS, assertKnownOptionKeys,
|
|
2
|
-
import { ANIMUS_CSS_MODULE_ID, ExtractionSession, SESSION_ASSETS_DIR, TURBOPACK_SYSTEM_PROPS_ID, collectSessionAssets, engineApi, getAnalyzedHashes, getManifestJson, getSessionArtifactDir, getSharedCss, getSharedSystemProps } from "@animus-ui/extract/session";
|
|
1
|
+
import { AnimusConfigError, BUILT_IN_EXTENSION_POLICY, DiagnosticFailure, ENGINE_TRANSFORM_EXTENSIONS, analysedOutputs, assertKnownOptionKeys, assertSupportedEngine, builtInAssetClassification, droppedExtensionMessage, esbuildAssetClassification, esbuildExtensionPolicy, esbuildOutputTargets, isEngineTransformExtension, isPathWithinRoot, keepsKitSourceEffects, mergeOutputTargets, noOutputTargets, outputExclusions, resolveMode, rollupExtensionPolicy, rollupOutputTargets, servedFiles, viteAssetClassification, viteExtensionPolicy, viteHostExpander, viteOutputTargets, webpackExtensionPolicy, webpackHostExpander, webpackOutputTargets } from "@animus-ui/extract/pipeline";
|
|
2
|
+
import { ANIMUS_CSS_MODULE_ID, ExtractionSession, SESSION_ASSETS_DIR, TURBOPACK_SYSTEM_PROPS_ID, collectSessionAssets, createBuildId, engineApi, getAnalyzedHashes, getManifestJson, getSessionArtifactDir, getSharedCss, getSharedSystemProps } from "@animus-ui/extract/session";
|
|
3
3
|
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { dirname, join, relative, resolve } from "node:path";
|
|
5
5
|
//#region src/options.ts
|
|
@@ -19,7 +19,7 @@ function hasRequiredSystem(options) {
|
|
|
19
19
|
}
|
|
20
20
|
function resolveHostOptions(raw, cwd = process.cwd()) {
|
|
21
21
|
const options = raw ?? {};
|
|
22
|
-
|
|
22
|
+
assertSupportedEngine(options.engine);
|
|
23
23
|
assertKnownOptionKeys(options, ["watch"]);
|
|
24
24
|
if (!hasRequiredSystem(options)) throw new AnimusConfigError("Missing required option `system` — pass `system: \"./src/ds.ts\"` to the Animus plugin.");
|
|
25
25
|
const root = options.root ? resolve(cwd, options.root) : cwd;
|
|
@@ -52,6 +52,11 @@ function createHostState() {
|
|
|
52
52
|
pipeline: null,
|
|
53
53
|
mode: null,
|
|
54
54
|
cssText: "",
|
|
55
|
+
served: {
|
|
56
|
+
listed: /* @__PURE__ */ new Set(),
|
|
57
|
+
dropped: /* @__PURE__ */ new Map()
|
|
58
|
+
},
|
|
59
|
+
analyzedFiles: [],
|
|
55
60
|
systemPropsJs: "",
|
|
56
61
|
kitRedirects: /* @__PURE__ */ new Map(),
|
|
57
62
|
kitSideEffects: /* @__PURE__ */ new Map(),
|
|
@@ -59,7 +64,8 @@ function createHostState() {
|
|
|
59
64
|
externalPackageDirs: [],
|
|
60
65
|
watchPaths: [],
|
|
61
66
|
transformFile: null,
|
|
62
|
-
sessionDir: null
|
|
67
|
+
sessionDir: null,
|
|
68
|
+
key: null
|
|
63
69
|
};
|
|
64
70
|
}
|
|
65
71
|
function shouldClaimTransform(filePath, state) {
|
|
@@ -81,7 +87,7 @@ async function drivePipeline(state, run, removeDir) {
|
|
|
81
87
|
try {
|
|
82
88
|
await attempt;
|
|
83
89
|
} catch (error) {
|
|
84
|
-
if (!state.sessionDir) state.sessionDir = getSessionArtifactDir();
|
|
90
|
+
if (!state.sessionDir && state.key !== null) state.sessionDir = getSessionArtifactDir(state.key);
|
|
85
91
|
disposeSessionDir(state, removeDir);
|
|
86
92
|
throw error;
|
|
87
93
|
}
|
|
@@ -98,8 +104,20 @@ function substituteDevDefine(code, isDev) {
|
|
|
98
104
|
}
|
|
99
105
|
function transformWithEngine(code, id, ctx) {
|
|
100
106
|
const filename = relative(ctx.rootDir, resolve(id)).split("\\").join("/");
|
|
107
|
+
const drop = ctx.served?.dropped.get(filename);
|
|
108
|
+
if (drop !== void 0) throw new Error(droppedExtensionMessage(drop));
|
|
101
109
|
const result = ctx.transformFile(code, filename, ctx.manifestJson);
|
|
102
|
-
|
|
110
|
+
if (result.hasComponents) return result.code;
|
|
111
|
+
if (ctx.served?.listed.has(filename)) throw new Error(`[animus] the analysis extracted components from ${filename}, but its transform found none`);
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
/** What a manifest's transform serves, parsed once per run. */
|
|
115
|
+
function manifestServedFiles(manifestJson) {
|
|
116
|
+
if (manifestJson === null) return {
|
|
117
|
+
listed: /* @__PURE__ */ new Set(),
|
|
118
|
+
dropped: /* @__PURE__ */ new Map()
|
|
119
|
+
};
|
|
120
|
+
return servedFiles(JSON.parse(manifestJson));
|
|
103
121
|
}
|
|
104
122
|
/** Whether esbuild's `external` option names `specifier`: exactly, as the
|
|
105
123
|
* package a subpath belongs to, or through a `*` wildcard. */
|
|
@@ -118,13 +136,52 @@ function moduleFilePath(id) {
|
|
|
118
136
|
function canResolve(context) {
|
|
119
137
|
return "resolve" in context;
|
|
120
138
|
}
|
|
139
|
+
/** Whether a hook context names the environment it builds (Vite). */
|
|
140
|
+
function hasEnvironment(context) {
|
|
141
|
+
return "environment" in context;
|
|
142
|
+
}
|
|
121
143
|
/** Marks the esbuild resolve that `esbuild.setup` makes for itself. */
|
|
122
144
|
const KIT_SOURCE_RESOLVE = "animus:kit-source-resolve";
|
|
145
|
+
/** Rules as comparable text: a RegExp by its source and flags, a function
|
|
146
|
+
* by its text. */
|
|
147
|
+
function ruleText(rules) {
|
|
148
|
+
return JSON.stringify(rules ?? null, (_key, value) => value instanceof RegExp ? `/${value.source}/${value.flags}` : value instanceof Function ? String(value) : value);
|
|
149
|
+
}
|
|
150
|
+
/** Whether `module.defaultRules` is webpack's own default list: the list
|
|
151
|
+
* webpack's defaults give the compiler's experiments, unchanged. Throws
|
|
152
|
+
* where webpack's option API is not available. */
|
|
153
|
+
function defaultRulesAreWebpacks(compiler) {
|
|
154
|
+
const config = compiler.webpack?.config;
|
|
155
|
+
if (config === void 0) throw new Error("webpack's option defaults are not available");
|
|
156
|
+
const { css, asyncWebAssembly, syncWebAssembly } = compiler.options.experiments ?? {};
|
|
157
|
+
const fresh = config.getNormalizedWebpackOptions({ experiments: {
|
|
158
|
+
css,
|
|
159
|
+
asyncWebAssembly,
|
|
160
|
+
syncWebAssembly
|
|
161
|
+
} });
|
|
162
|
+
config.applyWebpackOptionsDefaults(fresh);
|
|
163
|
+
return ruleText(fresh.module?.defaultRules) === ruleText(compiler.options.module?.defaultRules);
|
|
164
|
+
}
|
|
165
|
+
/** Whether every webpack JavaScript parser keeps the default wrapped
|
|
166
|
+
* context, `/.*\/` and recursive. */
|
|
167
|
+
function wrappedContextDefaults(parser) {
|
|
168
|
+
return Object.entries(parser ?? {}).filter(([type]) => type === "javascript" || type.startsWith("javascript/")).every(([, options]) => (options?.wrappedContextRegExp === void 0 || options.wrappedContextRegExp.source === ".*" && options.wrappedContextRegExp.flags === "") && options?.wrappedContextRecursive !== false);
|
|
169
|
+
}
|
|
170
|
+
function hasPluginResolve(context) {
|
|
171
|
+
return "resolve" in context;
|
|
172
|
+
}
|
|
173
|
+
/** The bundler's resolution through a Rollup-family plugin context (Rollup,
|
|
174
|
+
* Rolldown, Vite); none where the context cannot resolve. */
|
|
175
|
+
function pluginResolver(context) {
|
|
176
|
+
if (!hasPluginResolve(context)) return null;
|
|
177
|
+
return async (specifier, importer) => (await context.resolve(specifier, importer, { skipSelf: true }))?.id ?? null;
|
|
178
|
+
}
|
|
123
179
|
const PLUGIN_NAME = "animus-host";
|
|
124
180
|
const ESBUILD_WATCH_HINT = "If this is an esbuild watch or serve context, pass watch: true to the Animus esbuild plugin.";
|
|
125
181
|
const unpluginFactory = (rawOptions, meta) => {
|
|
126
182
|
const { root, options, watch } = resolveHostOptions(rawOptions);
|
|
127
183
|
const state = createHostState();
|
|
184
|
+
const buildId = createBuildId();
|
|
128
185
|
let activeSession = null;
|
|
129
186
|
let modeOracle = null;
|
|
130
187
|
/** Whether the host is watching, where an error-level diagnostic reports
|
|
@@ -137,6 +194,23 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
137
194
|
/** The bundler's export conditions, in its order, for the system loader;
|
|
138
195
|
* Rollup exposes none. */
|
|
139
196
|
let hostConditions = [];
|
|
197
|
+
/** The bundler's extension order, as its resolved configuration holds
|
|
198
|
+
* it; the built-in policy for a host none is read from (Rolldown). */
|
|
199
|
+
let hostExtensions = BUILT_IN_EXTENSION_POLICY;
|
|
200
|
+
let hostAssets = builtInAssetClassification("noHost");
|
|
201
|
+
/** How the bundler expands computed loads (spec §6.3); none where its
|
|
202
|
+
* expansion is not reproduced. */
|
|
203
|
+
let hostLoadExpander;
|
|
204
|
+
/** The bundler's own resolution, which package discovery asks first
|
|
205
|
+
* (spec §2.2 A4); none where the host exposes no resolver. */
|
|
206
|
+
let hostResolver = null;
|
|
207
|
+
/** What Rollup and Rolldown named at render, which they name only after
|
|
208
|
+
* analysis: this process's later builds exclude it. */
|
|
209
|
+
let learnedOutputTargets = noOutputTargets();
|
|
210
|
+
/** Where the bundler writes, which discovery excludes whatever the
|
|
211
|
+
* user's `exclude` list: read when a run starts, after the bundler
|
|
212
|
+
* applied its defaults. */
|
|
213
|
+
let hostOutputTargets = () => learnedOutputTargets;
|
|
140
214
|
/** Hooks can fire before buildStart (webpack's make taps run
|
|
141
215
|
* concurrently), so joiners await this before awaiting the pipeline. */
|
|
142
216
|
let signalPipelineStarted;
|
|
@@ -150,6 +224,10 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
150
224
|
const unbundledComputedImports = meta.framework === "rollup" || meta.framework === "rolldown" || meta.framework === "esbuild" || meta.framework === "vite";
|
|
151
225
|
async function startPipeline() {
|
|
152
226
|
signalPipelineStarted();
|
|
227
|
+
if (activeSession !== null && (meta.framework === "webpack" || meta.framework === "rspack")) {
|
|
228
|
+
disposeSessionDir(state);
|
|
229
|
+
releaseClaim();
|
|
230
|
+
}
|
|
153
231
|
try {
|
|
154
232
|
await runClaimedPipeline();
|
|
155
233
|
} catch (error) {
|
|
@@ -169,34 +247,100 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
169
247
|
const session = new ExtractionSession({
|
|
170
248
|
...options,
|
|
171
249
|
mode
|
|
172
|
-
}, {
|
|
250
|
+
}, {
|
|
251
|
+
unbundledComputedImports,
|
|
252
|
+
build: buildId
|
|
253
|
+
});
|
|
173
254
|
activeSession = session;
|
|
174
255
|
session.development = watching();
|
|
175
256
|
session.driverLabel = "animus-unplugin";
|
|
176
257
|
session.rootDir = root;
|
|
177
258
|
session.conditions = hostConditions;
|
|
259
|
+
session.extensionPolicy = hostExtensions;
|
|
260
|
+
session.assetClassification = hostAssets;
|
|
261
|
+
session.loadExpander = hostLoadExpander;
|
|
262
|
+
session.hostResolve = hostResolver;
|
|
178
263
|
session.systemPropsModuleId = TURBOPACK_SYSTEM_PROPS_ID;
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
264
|
+
session.structuralExclude = outputExclusions(root, hostOutputTargets());
|
|
265
|
+
session.aliasesFromTsconfig = true;
|
|
266
|
+
state.key = session.key;
|
|
267
|
+
try {
|
|
268
|
+
await session.runFullPipeline();
|
|
269
|
+
} catch (error) {
|
|
270
|
+
state.watchPaths = [
|
|
271
|
+
resolve(root, options.system),
|
|
272
|
+
...session.systemDependencyPaths,
|
|
273
|
+
...session.systemMissingPaths,
|
|
274
|
+
join(root, "tsconfig.json")
|
|
275
|
+
];
|
|
276
|
+
throw error;
|
|
277
|
+
}
|
|
278
|
+
state.sessionDir = getSessionArtifactDir(session.key);
|
|
279
|
+
const analyzed = getAnalyzedHashes(session.key);
|
|
185
280
|
if (!analyzed || analyzed.size === 0) throw new Error(`[animus] discovery found zero source files under ${root} — check the plugin's \`root\` and \`exclude\` options`);
|
|
186
|
-
state.cssText = getSharedCss();
|
|
187
|
-
state.
|
|
281
|
+
state.cssText = getSharedCss(session.key);
|
|
282
|
+
state.served = manifestServedFiles(getManifestJson(session.key));
|
|
283
|
+
state.systemPropsJs = getSharedSystemProps(session.key);
|
|
188
284
|
state.kitRedirects = new Map(session.externalSourceEntries);
|
|
189
285
|
state.kitSideEffects = new Map(session.externalSourceSideEffects);
|
|
190
286
|
state.redirectTargets = new Set(state.kitRedirects.values());
|
|
191
287
|
state.externalPackageDirs = [...session.externalPackageDirs];
|
|
192
|
-
|
|
193
|
-
|
|
288
|
+
state.analyzedFiles = [...analyzed.keys()].map((key) => resolve(root, key));
|
|
289
|
+
const watchPaths = new Set(state.analyzedFiles);
|
|
194
290
|
for (const dep of session.systemDependencyPaths) watchPaths.add(dep);
|
|
291
|
+
for (const path of session.systemMissingPaths) watchPaths.add(path);
|
|
195
292
|
for (const dep of session.assetDependencyPaths) watchPaths.add(dep);
|
|
196
293
|
watchPaths.add(join(root, "tsconfig.json"));
|
|
197
294
|
state.watchPaths = [...watchPaths];
|
|
198
|
-
state.transformFile = engineApi().transformFile;
|
|
295
|
+
state.transformFile = engineApi(session.key).transformFile;
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
/** Each Rollup-family environment build that started and has not ended,
|
|
299
|
+
* by name, with the promise its end settles. A Vite buildApp can build
|
|
300
|
+
* environments in parallel on one plugin instance; they share one
|
|
301
|
+
* pipeline and one Session, retired by the last to end. A build of an
|
|
302
|
+
* environment whose build is open (a reused builder, or a second
|
|
303
|
+
* environment under one name) waits for that build's end, so each build
|
|
304
|
+
* ends only its own generation, once, in buildEnd. webpack-like hosts run
|
|
305
|
+
* one compile at a time and are not tracked. */
|
|
306
|
+
const openBuilds = /* @__PURE__ */ new Map();
|
|
307
|
+
const singleEnvironment = { name: "build" };
|
|
308
|
+
const tracksEnvironments = meta.framework === "rollup" || meta.framework === "rolldown" || meta.framework === "vite";
|
|
309
|
+
function environmentOf(context) {
|
|
310
|
+
return hasEnvironment(context) ? context.environment : singleEnvironment;
|
|
311
|
+
}
|
|
312
|
+
/** Opens this hook's environment build once no build under its name is
|
|
313
|
+
* open; whether another environment's build is open, whose pipeline this
|
|
314
|
+
* build shares. */
|
|
315
|
+
async function openEnvironmentBuild(context) {
|
|
316
|
+
if (!tracksEnvironments) return false;
|
|
317
|
+
const environment = environmentOf(context);
|
|
318
|
+
for (;;) {
|
|
319
|
+
const open = openBuilds.get(environment.name);
|
|
320
|
+
if (open === void 0) break;
|
|
321
|
+
await open.ended;
|
|
322
|
+
}
|
|
323
|
+
let end = () => {};
|
|
324
|
+
const ended = new Promise((settle) => {
|
|
325
|
+
end = settle;
|
|
199
326
|
});
|
|
327
|
+
openBuilds.set(environment.name, {
|
|
328
|
+
environment,
|
|
329
|
+
ended,
|
|
330
|
+
end
|
|
331
|
+
});
|
|
332
|
+
return openBuilds.size > 1;
|
|
333
|
+
}
|
|
334
|
+
/** Ends this hook's environment build; whether none is left open. Only
|
|
335
|
+
* the build that opened an entry ends it. */
|
|
336
|
+
function closeEnvironmentBuild(context) {
|
|
337
|
+
if (!tracksEnvironments) return true;
|
|
338
|
+
const environment = environmentOf(context);
|
|
339
|
+
const open = openBuilds.get(environment.name);
|
|
340
|
+
if (open === void 0 || open.environment !== environment) return false;
|
|
341
|
+
openBuilds.delete(environment.name);
|
|
342
|
+
open.end();
|
|
343
|
+
return openBuilds.size === 0;
|
|
200
344
|
}
|
|
201
345
|
async function joinPipeline() {
|
|
202
346
|
await pipelineStarted;
|
|
@@ -236,6 +380,17 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
236
380
|
source: bytes
|
|
237
381
|
});
|
|
238
382
|
}
|
|
383
|
+
/** Rollup and Rolldown name their output only at render, after
|
|
384
|
+
* analysis: this process's later builds exclude it, and an analysis that
|
|
385
|
+
* already read a file there is reported, failing a build under `strict`. */
|
|
386
|
+
function checkOwnOutput(context, output) {
|
|
387
|
+
const targets = rollupOutputTargets(output);
|
|
388
|
+
learnedOutputTargets = mergeOutputTargets([learnedOutputTargets, targets]);
|
|
389
|
+
const message = analysedOutputs(root, targets, state.analyzedFiles);
|
|
390
|
+
if (message === null) return;
|
|
391
|
+
if (options.strict && !watching()) context.error(message);
|
|
392
|
+
context.warn(message);
|
|
393
|
+
}
|
|
239
394
|
/** Analysis is a filesystem walk, so watch mode misses edits to
|
|
240
395
|
* analyzed-but-unimported files. esbuild has no watch-file seam. */
|
|
241
396
|
function registerWatchTargets(context) {
|
|
@@ -248,8 +403,13 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
248
403
|
name: PLUGIN_NAME,
|
|
249
404
|
enforce: "pre",
|
|
250
405
|
async buildStart() {
|
|
251
|
-
|
|
252
|
-
|
|
406
|
+
if (rollupLike) hostResolver = pluginResolver(this);
|
|
407
|
+
try {
|
|
408
|
+
if (await openEnvironmentBuild(this)) await joinPipeline();
|
|
409
|
+
else await startPipeline();
|
|
410
|
+
} finally {
|
|
411
|
+
registerWatchTargets(this);
|
|
412
|
+
}
|
|
253
413
|
},
|
|
254
414
|
async resolveId(id, importer) {
|
|
255
415
|
const virtual = resolveAnimusId(id);
|
|
@@ -309,12 +469,14 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
309
469
|
await joinPipeline();
|
|
310
470
|
const filePath = moduleFilePath(id);
|
|
311
471
|
let output = code;
|
|
312
|
-
|
|
313
|
-
|
|
472
|
+
const key = state.key;
|
|
473
|
+
if (key !== null && isEngineTransformExtension(filePath)) {
|
|
474
|
+
const transformFile = state.transformFile ?? engineApi(key).transformFile;
|
|
314
475
|
const transformed = transformWithEngine(output, filePath, {
|
|
315
476
|
rootDir: root,
|
|
316
|
-
manifestJson: getManifestJson() ?? "",
|
|
317
|
-
transformFile
|
|
477
|
+
manifestJson: getManifestJson(key) ?? "",
|
|
478
|
+
transformFile,
|
|
479
|
+
served: state.served
|
|
318
480
|
});
|
|
319
481
|
if (transformed !== null) output = transformed;
|
|
320
482
|
}
|
|
@@ -331,18 +493,39 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
331
493
|
try {
|
|
332
494
|
emitCssAsset(this);
|
|
333
495
|
} finally {
|
|
334
|
-
|
|
335
|
-
|
|
496
|
+
if (closeEnvironmentBuild(this)) {
|
|
497
|
+
disposeSessionDir(state);
|
|
498
|
+
releaseClaim();
|
|
499
|
+
}
|
|
336
500
|
}
|
|
337
501
|
},
|
|
338
502
|
vite: { configResolved(config) {
|
|
503
|
+
hostExtensions = viteExtensionPolicy(config.resolve.extensions);
|
|
504
|
+
hostAssets = viteAssetClassification(config.assetsInclude);
|
|
505
|
+
hostLoadExpander = viteHostExpander(config);
|
|
506
|
+
hostOutputTargets = () => viteOutputTargets(config);
|
|
339
507
|
const serving = config.command === "serve" || Boolean(config.build.watch);
|
|
340
508
|
watching = () => serving;
|
|
341
509
|
} },
|
|
342
|
-
rollup: {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
510
|
+
rollup: {
|
|
511
|
+
async buildStart(inputOptions) {
|
|
512
|
+
hostExtensions = rollupExtensionPolicy((inputOptions?.plugins ?? []).some((plugin) => plugin?.name === "node-resolve"));
|
|
513
|
+
hostAssets = builtInAssetClassification("hostOptionUnreadable", "rollup");
|
|
514
|
+
modeOracle = this.meta?.watchMode ? "development" : "production";
|
|
515
|
+
hostResolver = pluginResolver(this);
|
|
516
|
+
try {
|
|
517
|
+
if (await openEnvironmentBuild(this)) await joinPipeline();
|
|
518
|
+
else await startPipeline();
|
|
519
|
+
} finally {
|
|
520
|
+
registerWatchTargets(this);
|
|
521
|
+
}
|
|
522
|
+
},
|
|
523
|
+
renderStart(outputOptions) {
|
|
524
|
+
checkOwnOutput(this, outputOptions);
|
|
525
|
+
}
|
|
526
|
+
},
|
|
527
|
+
rolldown: { renderStart(outputOptions) {
|
|
528
|
+
checkOwnOutput(this, outputOptions);
|
|
346
529
|
} },
|
|
347
530
|
webpack(compiler) {
|
|
348
531
|
wireWebpackLike(compiler);
|
|
@@ -396,7 +579,10 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
396
579
|
},
|
|
397
580
|
config(buildOptions) {
|
|
398
581
|
esbuildOptions = buildOptions;
|
|
582
|
+
hostOutputTargets = () => esbuildOutputTargets(buildOptions);
|
|
399
583
|
hostConditions = buildOptions.conditions ?? [];
|
|
584
|
+
hostExtensions = esbuildExtensionPolicy(buildOptions.resolveExtensions);
|
|
585
|
+
hostAssets = esbuildAssetClassification(buildOptions.loader);
|
|
400
586
|
watching = () => watch;
|
|
401
587
|
buildOptions.define = {
|
|
402
588
|
...buildOptions.define,
|
|
@@ -448,7 +634,30 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
448
634
|
function wireWebpackLike(compiler) {
|
|
449
635
|
modeOracle = compiler.options.mode === "development" ? "development" : "production";
|
|
450
636
|
hostConditions = (compiler.options.resolve?.conditionNames ?? []).filter((name) => name !== "...");
|
|
637
|
+
hostExtensions = webpackExtensionPolicy(meta.framework, compiler.options.resolve ?? {}, compiler.webpack?.version ?? compiler.rspack?.rspackVersion);
|
|
638
|
+
hostAssets = builtInAssetClassification("hostOptionUnreadable", `${meta.framework === "rspack" ? "rspack" : "webpack"} rules not modelled`);
|
|
451
639
|
watching = () => compiler.watchMode === true;
|
|
640
|
+
hostOutputTargets = () => webpackOutputTargets(compiler.options.output?.path);
|
|
641
|
+
const resolverFactory = compiler.resolverFactory;
|
|
642
|
+
hostLoadExpander = meta.framework === "webpack" && resolverFactory !== void 0 ? webpackHostExpander({
|
|
643
|
+
resolveReading: (category) => {
|
|
644
|
+
const read = resolverFactory.get("normal", { dependencyType: category }).options;
|
|
645
|
+
const context = resolverFactory.get("context", { dependencyType: category }).options;
|
|
646
|
+
return {
|
|
647
|
+
extensions: [...read.extensions],
|
|
648
|
+
mainFiles: [...read.mainFiles],
|
|
649
|
+
modules: read.modules,
|
|
650
|
+
fullySpecified: read.fullySpecified === true,
|
|
651
|
+
enforceExtension: read.enforceExtension === true,
|
|
652
|
+
aliasNames: [read, context].flatMap((resolver) => [...resolver.alias ?? [], ...resolver.fallback ?? []].map((entry) => entry.name))
|
|
653
|
+
};
|
|
654
|
+
},
|
|
655
|
+
options: () => ({
|
|
656
|
+
rules: compiler.options.module?.rules ?? [],
|
|
657
|
+
defaultRulesAreWebpacks: defaultRulesAreWebpacks(compiler),
|
|
658
|
+
wrappedDefaults: wrappedContextDefaults(compiler.options.module?.parser)
|
|
659
|
+
})
|
|
660
|
+
}) : void 0;
|
|
452
661
|
const DefinePlugin = compiler.webpack?.DefinePlugin ?? compiler.rspack?.DefinePlugin;
|
|
453
662
|
if (!DefinePlugin) throw new Error("[animus] compiler exposes no DefinePlugin — cannot supply the __ANIMUS_DEV__ dev-signal define");
|
|
454
663
|
new DefinePlugin({ __ANIMUS_DEV__: JSON.stringify(effectiveMode() === "development") }).apply(compiler);
|
|
@@ -460,6 +669,10 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
460
669
|
disposeSessionDir(state);
|
|
461
670
|
releaseClaim();
|
|
462
671
|
});
|
|
672
|
+
compiler.hooks.watchClose?.tap(PLUGIN_NAME, () => {
|
|
673
|
+
disposeSessionDir(state);
|
|
674
|
+
releaseClaim();
|
|
675
|
+
});
|
|
463
676
|
}
|
|
464
677
|
};
|
|
465
678
|
//#endregion
|
|
@@ -19,7 +19,7 @@ function hasRequiredSystem(options) {
|
|
|
19
19
|
}
|
|
20
20
|
function resolveHostOptions(raw, cwd = process.cwd()) {
|
|
21
21
|
const options = raw ?? {};
|
|
22
|
-
(0, _animus_ui_extract_pipeline.
|
|
22
|
+
(0, _animus_ui_extract_pipeline.assertSupportedEngine)(options.engine);
|
|
23
23
|
(0, _animus_ui_extract_pipeline.assertKnownOptionKeys)(options, ["watch"]);
|
|
24
24
|
if (!hasRequiredSystem(options)) throw new _animus_ui_extract_pipeline.AnimusConfigError("Missing required option `system` — pass `system: \"./src/ds.ts\"` to the Animus plugin.");
|
|
25
25
|
const root = options.root ? (0, node_path.resolve)(cwd, options.root) : cwd;
|
|
@@ -52,6 +52,11 @@ function createHostState() {
|
|
|
52
52
|
pipeline: null,
|
|
53
53
|
mode: null,
|
|
54
54
|
cssText: "",
|
|
55
|
+
served: {
|
|
56
|
+
listed: /* @__PURE__ */ new Set(),
|
|
57
|
+
dropped: /* @__PURE__ */ new Map()
|
|
58
|
+
},
|
|
59
|
+
analyzedFiles: [],
|
|
55
60
|
systemPropsJs: "",
|
|
56
61
|
kitRedirects: /* @__PURE__ */ new Map(),
|
|
57
62
|
kitSideEffects: /* @__PURE__ */ new Map(),
|
|
@@ -59,7 +64,8 @@ function createHostState() {
|
|
|
59
64
|
externalPackageDirs: [],
|
|
60
65
|
watchPaths: [],
|
|
61
66
|
transformFile: null,
|
|
62
|
-
sessionDir: null
|
|
67
|
+
sessionDir: null,
|
|
68
|
+
key: null
|
|
63
69
|
};
|
|
64
70
|
}
|
|
65
71
|
function shouldClaimTransform(filePath, state) {
|
|
@@ -81,7 +87,7 @@ async function drivePipeline(state, run, removeDir) {
|
|
|
81
87
|
try {
|
|
82
88
|
await attempt;
|
|
83
89
|
} catch (error) {
|
|
84
|
-
if (!state.sessionDir) state.sessionDir = (0, _animus_ui_extract_session.getSessionArtifactDir)();
|
|
90
|
+
if (!state.sessionDir && state.key !== null) state.sessionDir = (0, _animus_ui_extract_session.getSessionArtifactDir)(state.key);
|
|
85
91
|
disposeSessionDir(state, removeDir);
|
|
86
92
|
throw error;
|
|
87
93
|
}
|
|
@@ -98,8 +104,20 @@ function substituteDevDefine(code, isDev) {
|
|
|
98
104
|
}
|
|
99
105
|
function transformWithEngine(code, id, ctx) {
|
|
100
106
|
const filename = (0, node_path.relative)(ctx.rootDir, (0, node_path.resolve)(id)).split("\\").join("/");
|
|
107
|
+
const drop = ctx.served?.dropped.get(filename);
|
|
108
|
+
if (drop !== void 0) throw new Error((0, _animus_ui_extract_pipeline.droppedExtensionMessage)(drop));
|
|
101
109
|
const result = ctx.transformFile(code, filename, ctx.manifestJson);
|
|
102
|
-
|
|
110
|
+
if (result.hasComponents) return result.code;
|
|
111
|
+
if (ctx.served?.listed.has(filename)) throw new Error(`[animus] the analysis extracted components from ${filename}, but its transform found none`);
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
/** What a manifest's transform serves, parsed once per run. */
|
|
115
|
+
function manifestServedFiles(manifestJson) {
|
|
116
|
+
if (manifestJson === null) return {
|
|
117
|
+
listed: /* @__PURE__ */ new Set(),
|
|
118
|
+
dropped: /* @__PURE__ */ new Map()
|
|
119
|
+
};
|
|
120
|
+
return (0, _animus_ui_extract_pipeline.servedFiles)(JSON.parse(manifestJson));
|
|
103
121
|
}
|
|
104
122
|
/** Whether esbuild's `external` option names `specifier`: exactly, as the
|
|
105
123
|
* package a subpath belongs to, or through a `*` wildcard. */
|
|
@@ -118,13 +136,52 @@ function moduleFilePath(id) {
|
|
|
118
136
|
function canResolve(context) {
|
|
119
137
|
return "resolve" in context;
|
|
120
138
|
}
|
|
139
|
+
/** Whether a hook context names the environment it builds (Vite). */
|
|
140
|
+
function hasEnvironment(context) {
|
|
141
|
+
return "environment" in context;
|
|
142
|
+
}
|
|
121
143
|
/** Marks the esbuild resolve that `esbuild.setup` makes for itself. */
|
|
122
144
|
const KIT_SOURCE_RESOLVE = "animus:kit-source-resolve";
|
|
145
|
+
/** Rules as comparable text: a RegExp by its source and flags, a function
|
|
146
|
+
* by its text. */
|
|
147
|
+
function ruleText(rules) {
|
|
148
|
+
return JSON.stringify(rules ?? null, (_key, value) => value instanceof RegExp ? `/${value.source}/${value.flags}` : value instanceof Function ? String(value) : value);
|
|
149
|
+
}
|
|
150
|
+
/** Whether `module.defaultRules` is webpack's own default list: the list
|
|
151
|
+
* webpack's defaults give the compiler's experiments, unchanged. Throws
|
|
152
|
+
* where webpack's option API is not available. */
|
|
153
|
+
function defaultRulesAreWebpacks(compiler) {
|
|
154
|
+
const config = compiler.webpack?.config;
|
|
155
|
+
if (config === void 0) throw new Error("webpack's option defaults are not available");
|
|
156
|
+
const { css, asyncWebAssembly, syncWebAssembly } = compiler.options.experiments ?? {};
|
|
157
|
+
const fresh = config.getNormalizedWebpackOptions({ experiments: {
|
|
158
|
+
css,
|
|
159
|
+
asyncWebAssembly,
|
|
160
|
+
syncWebAssembly
|
|
161
|
+
} });
|
|
162
|
+
config.applyWebpackOptionsDefaults(fresh);
|
|
163
|
+
return ruleText(fresh.module?.defaultRules) === ruleText(compiler.options.module?.defaultRules);
|
|
164
|
+
}
|
|
165
|
+
/** Whether every webpack JavaScript parser keeps the default wrapped
|
|
166
|
+
* context, `/.*\/` and recursive. */
|
|
167
|
+
function wrappedContextDefaults(parser) {
|
|
168
|
+
return Object.entries(parser ?? {}).filter(([type]) => type === "javascript" || type.startsWith("javascript/")).every(([, options]) => (options?.wrappedContextRegExp === void 0 || options.wrappedContextRegExp.source === ".*" && options.wrappedContextRegExp.flags === "") && options?.wrappedContextRecursive !== false);
|
|
169
|
+
}
|
|
170
|
+
function hasPluginResolve(context) {
|
|
171
|
+
return "resolve" in context;
|
|
172
|
+
}
|
|
173
|
+
/** The bundler's resolution through a Rollup-family plugin context (Rollup,
|
|
174
|
+
* Rolldown, Vite); none where the context cannot resolve. */
|
|
175
|
+
function pluginResolver(context) {
|
|
176
|
+
if (!hasPluginResolve(context)) return null;
|
|
177
|
+
return async (specifier, importer) => (await context.resolve(specifier, importer, { skipSelf: true }))?.id ?? null;
|
|
178
|
+
}
|
|
123
179
|
const PLUGIN_NAME = "animus-host";
|
|
124
180
|
const ESBUILD_WATCH_HINT = "If this is an esbuild watch or serve context, pass watch: true to the Animus esbuild plugin.";
|
|
125
181
|
const unpluginFactory = (rawOptions, meta) => {
|
|
126
182
|
const { root, options, watch } = resolveHostOptions(rawOptions);
|
|
127
183
|
const state = createHostState();
|
|
184
|
+
const buildId = (0, _animus_ui_extract_session.createBuildId)();
|
|
128
185
|
let activeSession = null;
|
|
129
186
|
let modeOracle = null;
|
|
130
187
|
/** Whether the host is watching, where an error-level diagnostic reports
|
|
@@ -137,6 +194,23 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
137
194
|
/** The bundler's export conditions, in its order, for the system loader;
|
|
138
195
|
* Rollup exposes none. */
|
|
139
196
|
let hostConditions = [];
|
|
197
|
+
/** The bundler's extension order, as its resolved configuration holds
|
|
198
|
+
* it; the built-in policy for a host none is read from (Rolldown). */
|
|
199
|
+
let hostExtensions = _animus_ui_extract_pipeline.BUILT_IN_EXTENSION_POLICY;
|
|
200
|
+
let hostAssets = (0, _animus_ui_extract_pipeline.builtInAssetClassification)("noHost");
|
|
201
|
+
/** How the bundler expands computed loads (spec §6.3); none where its
|
|
202
|
+
* expansion is not reproduced. */
|
|
203
|
+
let hostLoadExpander;
|
|
204
|
+
/** The bundler's own resolution, which package discovery asks first
|
|
205
|
+
* (spec §2.2 A4); none where the host exposes no resolver. */
|
|
206
|
+
let hostResolver = null;
|
|
207
|
+
/** What Rollup and Rolldown named at render, which they name only after
|
|
208
|
+
* analysis: this process's later builds exclude it. */
|
|
209
|
+
let learnedOutputTargets = (0, _animus_ui_extract_pipeline.noOutputTargets)();
|
|
210
|
+
/** Where the bundler writes, which discovery excludes whatever the
|
|
211
|
+
* user's `exclude` list: read when a run starts, after the bundler
|
|
212
|
+
* applied its defaults. */
|
|
213
|
+
let hostOutputTargets = () => learnedOutputTargets;
|
|
140
214
|
/** Hooks can fire before buildStart (webpack's make taps run
|
|
141
215
|
* concurrently), so joiners await this before awaiting the pipeline. */
|
|
142
216
|
let signalPipelineStarted;
|
|
@@ -150,6 +224,10 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
150
224
|
const unbundledComputedImports = meta.framework === "rollup" || meta.framework === "rolldown" || meta.framework === "esbuild" || meta.framework === "vite";
|
|
151
225
|
async function startPipeline() {
|
|
152
226
|
signalPipelineStarted();
|
|
227
|
+
if (activeSession !== null && (meta.framework === "webpack" || meta.framework === "rspack")) {
|
|
228
|
+
disposeSessionDir(state);
|
|
229
|
+
releaseClaim();
|
|
230
|
+
}
|
|
153
231
|
try {
|
|
154
232
|
await runClaimedPipeline();
|
|
155
233
|
} catch (error) {
|
|
@@ -169,34 +247,100 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
169
247
|
const session = new _animus_ui_extract_session.ExtractionSession({
|
|
170
248
|
...options,
|
|
171
249
|
mode
|
|
172
|
-
}, {
|
|
250
|
+
}, {
|
|
251
|
+
unbundledComputedImports,
|
|
252
|
+
build: buildId
|
|
253
|
+
});
|
|
173
254
|
activeSession = session;
|
|
174
255
|
session.development = watching();
|
|
175
256
|
session.driverLabel = "animus-unplugin";
|
|
176
257
|
session.rootDir = root;
|
|
177
258
|
session.conditions = hostConditions;
|
|
259
|
+
session.extensionPolicy = hostExtensions;
|
|
260
|
+
session.assetClassification = hostAssets;
|
|
261
|
+
session.loadExpander = hostLoadExpander;
|
|
262
|
+
session.hostResolve = hostResolver;
|
|
178
263
|
session.systemPropsModuleId = _animus_ui_extract_session.TURBOPACK_SYSTEM_PROPS_ID;
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
264
|
+
session.structuralExclude = (0, _animus_ui_extract_pipeline.outputExclusions)(root, hostOutputTargets());
|
|
265
|
+
session.aliasesFromTsconfig = true;
|
|
266
|
+
state.key = session.key;
|
|
267
|
+
try {
|
|
268
|
+
await session.runFullPipeline();
|
|
269
|
+
} catch (error) {
|
|
270
|
+
state.watchPaths = [
|
|
271
|
+
(0, node_path.resolve)(root, options.system),
|
|
272
|
+
...session.systemDependencyPaths,
|
|
273
|
+
...session.systemMissingPaths,
|
|
274
|
+
(0, node_path.join)(root, "tsconfig.json")
|
|
275
|
+
];
|
|
276
|
+
throw error;
|
|
277
|
+
}
|
|
278
|
+
state.sessionDir = (0, _animus_ui_extract_session.getSessionArtifactDir)(session.key);
|
|
279
|
+
const analyzed = (0, _animus_ui_extract_session.getAnalyzedHashes)(session.key);
|
|
185
280
|
if (!analyzed || analyzed.size === 0) throw new Error(`[animus] discovery found zero source files under ${root} — check the plugin's \`root\` and \`exclude\` options`);
|
|
186
|
-
state.cssText = (0, _animus_ui_extract_session.getSharedCss)();
|
|
187
|
-
state.
|
|
281
|
+
state.cssText = (0, _animus_ui_extract_session.getSharedCss)(session.key);
|
|
282
|
+
state.served = manifestServedFiles((0, _animus_ui_extract_session.getManifestJson)(session.key));
|
|
283
|
+
state.systemPropsJs = (0, _animus_ui_extract_session.getSharedSystemProps)(session.key);
|
|
188
284
|
state.kitRedirects = new Map(session.externalSourceEntries);
|
|
189
285
|
state.kitSideEffects = new Map(session.externalSourceSideEffects);
|
|
190
286
|
state.redirectTargets = new Set(state.kitRedirects.values());
|
|
191
287
|
state.externalPackageDirs = [...session.externalPackageDirs];
|
|
192
|
-
|
|
193
|
-
|
|
288
|
+
state.analyzedFiles = [...analyzed.keys()].map((key) => (0, node_path.resolve)(root, key));
|
|
289
|
+
const watchPaths = new Set(state.analyzedFiles);
|
|
194
290
|
for (const dep of session.systemDependencyPaths) watchPaths.add(dep);
|
|
291
|
+
for (const path of session.systemMissingPaths) watchPaths.add(path);
|
|
195
292
|
for (const dep of session.assetDependencyPaths) watchPaths.add(dep);
|
|
196
293
|
watchPaths.add((0, node_path.join)(root, "tsconfig.json"));
|
|
197
294
|
state.watchPaths = [...watchPaths];
|
|
198
|
-
state.transformFile = (0, _animus_ui_extract_session.engineApi)().transformFile;
|
|
295
|
+
state.transformFile = (0, _animus_ui_extract_session.engineApi)(session.key).transformFile;
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
/** Each Rollup-family environment build that started and has not ended,
|
|
299
|
+
* by name, with the promise its end settles. A Vite buildApp can build
|
|
300
|
+
* environments in parallel on one plugin instance; they share one
|
|
301
|
+
* pipeline and one Session, retired by the last to end. A build of an
|
|
302
|
+
* environment whose build is open (a reused builder, or a second
|
|
303
|
+
* environment under one name) waits for that build's end, so each build
|
|
304
|
+
* ends only its own generation, once, in buildEnd. webpack-like hosts run
|
|
305
|
+
* one compile at a time and are not tracked. */
|
|
306
|
+
const openBuilds = /* @__PURE__ */ new Map();
|
|
307
|
+
const singleEnvironment = { name: "build" };
|
|
308
|
+
const tracksEnvironments = meta.framework === "rollup" || meta.framework === "rolldown" || meta.framework === "vite";
|
|
309
|
+
function environmentOf(context) {
|
|
310
|
+
return hasEnvironment(context) ? context.environment : singleEnvironment;
|
|
311
|
+
}
|
|
312
|
+
/** Opens this hook's environment build once no build under its name is
|
|
313
|
+
* open; whether another environment's build is open, whose pipeline this
|
|
314
|
+
* build shares. */
|
|
315
|
+
async function openEnvironmentBuild(context) {
|
|
316
|
+
if (!tracksEnvironments) return false;
|
|
317
|
+
const environment = environmentOf(context);
|
|
318
|
+
for (;;) {
|
|
319
|
+
const open = openBuilds.get(environment.name);
|
|
320
|
+
if (open === void 0) break;
|
|
321
|
+
await open.ended;
|
|
322
|
+
}
|
|
323
|
+
let end = () => {};
|
|
324
|
+
const ended = new Promise((settle) => {
|
|
325
|
+
end = settle;
|
|
199
326
|
});
|
|
327
|
+
openBuilds.set(environment.name, {
|
|
328
|
+
environment,
|
|
329
|
+
ended,
|
|
330
|
+
end
|
|
331
|
+
});
|
|
332
|
+
return openBuilds.size > 1;
|
|
333
|
+
}
|
|
334
|
+
/** Ends this hook's environment build; whether none is left open. Only
|
|
335
|
+
* the build that opened an entry ends it. */
|
|
336
|
+
function closeEnvironmentBuild(context) {
|
|
337
|
+
if (!tracksEnvironments) return true;
|
|
338
|
+
const environment = environmentOf(context);
|
|
339
|
+
const open = openBuilds.get(environment.name);
|
|
340
|
+
if (open === void 0 || open.environment !== environment) return false;
|
|
341
|
+
openBuilds.delete(environment.name);
|
|
342
|
+
open.end();
|
|
343
|
+
return openBuilds.size === 0;
|
|
200
344
|
}
|
|
201
345
|
async function joinPipeline() {
|
|
202
346
|
await pipelineStarted;
|
|
@@ -236,6 +380,17 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
236
380
|
source: bytes
|
|
237
381
|
});
|
|
238
382
|
}
|
|
383
|
+
/** Rollup and Rolldown name their output only at render, after
|
|
384
|
+
* analysis: this process's later builds exclude it, and an analysis that
|
|
385
|
+
* already read a file there is reported, failing a build under `strict`. */
|
|
386
|
+
function checkOwnOutput(context, output) {
|
|
387
|
+
const targets = (0, _animus_ui_extract_pipeline.rollupOutputTargets)(output);
|
|
388
|
+
learnedOutputTargets = (0, _animus_ui_extract_pipeline.mergeOutputTargets)([learnedOutputTargets, targets]);
|
|
389
|
+
const message = (0, _animus_ui_extract_pipeline.analysedOutputs)(root, targets, state.analyzedFiles);
|
|
390
|
+
if (message === null) return;
|
|
391
|
+
if (options.strict && !watching()) context.error(message);
|
|
392
|
+
context.warn(message);
|
|
393
|
+
}
|
|
239
394
|
/** Analysis is a filesystem walk, so watch mode misses edits to
|
|
240
395
|
* analyzed-but-unimported files. esbuild has no watch-file seam. */
|
|
241
396
|
function registerWatchTargets(context) {
|
|
@@ -248,8 +403,13 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
248
403
|
name: PLUGIN_NAME,
|
|
249
404
|
enforce: "pre",
|
|
250
405
|
async buildStart() {
|
|
251
|
-
|
|
252
|
-
|
|
406
|
+
if (rollupLike) hostResolver = pluginResolver(this);
|
|
407
|
+
try {
|
|
408
|
+
if (await openEnvironmentBuild(this)) await joinPipeline();
|
|
409
|
+
else await startPipeline();
|
|
410
|
+
} finally {
|
|
411
|
+
registerWatchTargets(this);
|
|
412
|
+
}
|
|
253
413
|
},
|
|
254
414
|
async resolveId(id, importer) {
|
|
255
415
|
const virtual = resolveAnimusId(id);
|
|
@@ -309,12 +469,14 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
309
469
|
await joinPipeline();
|
|
310
470
|
const filePath = moduleFilePath(id);
|
|
311
471
|
let output = code;
|
|
312
|
-
|
|
313
|
-
|
|
472
|
+
const key = state.key;
|
|
473
|
+
if (key !== null && (0, _animus_ui_extract_pipeline.isEngineTransformExtension)(filePath)) {
|
|
474
|
+
const transformFile = state.transformFile ?? (0, _animus_ui_extract_session.engineApi)(key).transformFile;
|
|
314
475
|
const transformed = transformWithEngine(output, filePath, {
|
|
315
476
|
rootDir: root,
|
|
316
|
-
manifestJson: (0, _animus_ui_extract_session.getManifestJson)() ?? "",
|
|
317
|
-
transformFile
|
|
477
|
+
manifestJson: (0, _animus_ui_extract_session.getManifestJson)(key) ?? "",
|
|
478
|
+
transformFile,
|
|
479
|
+
served: state.served
|
|
318
480
|
});
|
|
319
481
|
if (transformed !== null) output = transformed;
|
|
320
482
|
}
|
|
@@ -331,18 +493,39 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
331
493
|
try {
|
|
332
494
|
emitCssAsset(this);
|
|
333
495
|
} finally {
|
|
334
|
-
|
|
335
|
-
|
|
496
|
+
if (closeEnvironmentBuild(this)) {
|
|
497
|
+
disposeSessionDir(state);
|
|
498
|
+
releaseClaim();
|
|
499
|
+
}
|
|
336
500
|
}
|
|
337
501
|
},
|
|
338
502
|
vite: { configResolved(config) {
|
|
503
|
+
hostExtensions = (0, _animus_ui_extract_pipeline.viteExtensionPolicy)(config.resolve.extensions);
|
|
504
|
+
hostAssets = (0, _animus_ui_extract_pipeline.viteAssetClassification)(config.assetsInclude);
|
|
505
|
+
hostLoadExpander = (0, _animus_ui_extract_pipeline.viteHostExpander)(config);
|
|
506
|
+
hostOutputTargets = () => (0, _animus_ui_extract_pipeline.viteOutputTargets)(config);
|
|
339
507
|
const serving = config.command === "serve" || Boolean(config.build.watch);
|
|
340
508
|
watching = () => serving;
|
|
341
509
|
} },
|
|
342
|
-
rollup: {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
510
|
+
rollup: {
|
|
511
|
+
async buildStart(inputOptions) {
|
|
512
|
+
hostExtensions = (0, _animus_ui_extract_pipeline.rollupExtensionPolicy)((inputOptions?.plugins ?? []).some((plugin) => plugin?.name === "node-resolve"));
|
|
513
|
+
hostAssets = (0, _animus_ui_extract_pipeline.builtInAssetClassification)("hostOptionUnreadable", "rollup");
|
|
514
|
+
modeOracle = this.meta?.watchMode ? "development" : "production";
|
|
515
|
+
hostResolver = pluginResolver(this);
|
|
516
|
+
try {
|
|
517
|
+
if (await openEnvironmentBuild(this)) await joinPipeline();
|
|
518
|
+
else await startPipeline();
|
|
519
|
+
} finally {
|
|
520
|
+
registerWatchTargets(this);
|
|
521
|
+
}
|
|
522
|
+
},
|
|
523
|
+
renderStart(outputOptions) {
|
|
524
|
+
checkOwnOutput(this, outputOptions);
|
|
525
|
+
}
|
|
526
|
+
},
|
|
527
|
+
rolldown: { renderStart(outputOptions) {
|
|
528
|
+
checkOwnOutput(this, outputOptions);
|
|
346
529
|
} },
|
|
347
530
|
webpack(compiler) {
|
|
348
531
|
wireWebpackLike(compiler);
|
|
@@ -396,7 +579,10 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
396
579
|
},
|
|
397
580
|
config(buildOptions) {
|
|
398
581
|
esbuildOptions = buildOptions;
|
|
582
|
+
hostOutputTargets = () => (0, _animus_ui_extract_pipeline.esbuildOutputTargets)(buildOptions);
|
|
399
583
|
hostConditions = buildOptions.conditions ?? [];
|
|
584
|
+
hostExtensions = (0, _animus_ui_extract_pipeline.esbuildExtensionPolicy)(buildOptions.resolveExtensions);
|
|
585
|
+
hostAssets = (0, _animus_ui_extract_pipeline.esbuildAssetClassification)(buildOptions.loader);
|
|
400
586
|
watching = () => watch;
|
|
401
587
|
buildOptions.define = {
|
|
402
588
|
...buildOptions.define,
|
|
@@ -448,7 +634,30 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
448
634
|
function wireWebpackLike(compiler) {
|
|
449
635
|
modeOracle = compiler.options.mode === "development" ? "development" : "production";
|
|
450
636
|
hostConditions = (compiler.options.resolve?.conditionNames ?? []).filter((name) => name !== "...");
|
|
637
|
+
hostExtensions = (0, _animus_ui_extract_pipeline.webpackExtensionPolicy)(meta.framework, compiler.options.resolve ?? {}, compiler.webpack?.version ?? compiler.rspack?.rspackVersion);
|
|
638
|
+
hostAssets = (0, _animus_ui_extract_pipeline.builtInAssetClassification)("hostOptionUnreadable", `${meta.framework === "rspack" ? "rspack" : "webpack"} rules not modelled`);
|
|
451
639
|
watching = () => compiler.watchMode === true;
|
|
640
|
+
hostOutputTargets = () => (0, _animus_ui_extract_pipeline.webpackOutputTargets)(compiler.options.output?.path);
|
|
641
|
+
const resolverFactory = compiler.resolverFactory;
|
|
642
|
+
hostLoadExpander = meta.framework === "webpack" && resolverFactory !== void 0 ? (0, _animus_ui_extract_pipeline.webpackHostExpander)({
|
|
643
|
+
resolveReading: (category) => {
|
|
644
|
+
const read = resolverFactory.get("normal", { dependencyType: category }).options;
|
|
645
|
+
const context = resolverFactory.get("context", { dependencyType: category }).options;
|
|
646
|
+
return {
|
|
647
|
+
extensions: [...read.extensions],
|
|
648
|
+
mainFiles: [...read.mainFiles],
|
|
649
|
+
modules: read.modules,
|
|
650
|
+
fullySpecified: read.fullySpecified === true,
|
|
651
|
+
enforceExtension: read.enforceExtension === true,
|
|
652
|
+
aliasNames: [read, context].flatMap((resolver) => [...resolver.alias ?? [], ...resolver.fallback ?? []].map((entry) => entry.name))
|
|
653
|
+
};
|
|
654
|
+
},
|
|
655
|
+
options: () => ({
|
|
656
|
+
rules: compiler.options.module?.rules ?? [],
|
|
657
|
+
defaultRulesAreWebpacks: defaultRulesAreWebpacks(compiler),
|
|
658
|
+
wrappedDefaults: wrappedContextDefaults(compiler.options.module?.parser)
|
|
659
|
+
})
|
|
660
|
+
}) : void 0;
|
|
452
661
|
const DefinePlugin = compiler.webpack?.DefinePlugin ?? compiler.rspack?.DefinePlugin;
|
|
453
662
|
if (!DefinePlugin) throw new Error("[animus] compiler exposes no DefinePlugin — cannot supply the __ANIMUS_DEV__ dev-signal define");
|
|
454
663
|
new DefinePlugin({ __ANIMUS_DEV__: JSON.stringify(effectiveMode() === "development") }).apply(compiler);
|
|
@@ -460,6 +669,10 @@ const unpluginFactory = (rawOptions, meta) => {
|
|
|
460
669
|
disposeSessionDir(state);
|
|
461
670
|
releaseClaim();
|
|
462
671
|
});
|
|
672
|
+
compiler.hooks.watchClose?.tap(PLUGIN_NAME, () => {
|
|
673
|
+
disposeSessionDir(state);
|
|
674
|
+
releaseClaim();
|
|
675
|
+
});
|
|
463
676
|
}
|
|
464
677
|
};
|
|
465
678
|
//#endregion
|
package/dist/core.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AnimusUnpluginOptions } from './options';
|
|
2
|
-
import type { AnimusMode } from '@animus-ui/extract/pipeline';
|
|
2
|
+
import type { AnimusMode, ServedFiles } from '@animus-ui/extract/pipeline';
|
|
3
|
+
import type { SessionKey } from '@animus-ui/extract/session';
|
|
3
4
|
import type { UnpluginFactory } from 'unplugin';
|
|
4
5
|
/** Extension-free: esbuild picks loaders by extension. No `\0` prefix:
|
|
5
6
|
* webpack's virtual-module bridge requires plain ids. */
|
|
@@ -23,6 +24,14 @@ export interface HostState {
|
|
|
23
24
|
hasComponents: boolean;
|
|
24
25
|
}) | null;
|
|
25
26
|
sessionDir: string | null;
|
|
27
|
+
/** The build of the root this plugin instance analyses, once a pipeline
|
|
28
|
+
* run's session joined it. */
|
|
29
|
+
key: SessionKey | null;
|
|
30
|
+
/** The files the run's analysis extracted components from, and the
|
|
31
|
+
* extensions it dropped over their parent. */
|
|
32
|
+
served: ServedFiles;
|
|
33
|
+
/** Every file the run's analysis read, absolute. */
|
|
34
|
+
analyzedFiles: string[];
|
|
26
35
|
}
|
|
27
36
|
export declare function createHostState(): HostState;
|
|
28
37
|
export declare function shouldClaimTransform(filePath: string, state: Pick<HostState, 'externalPackageDirs' | 'redirectTargets'>): boolean;
|
|
@@ -37,6 +46,9 @@ export declare function transformWithEngine(code: string, id: string, ctx: {
|
|
|
37
46
|
code: string;
|
|
38
47
|
hasComponents: boolean;
|
|
39
48
|
};
|
|
49
|
+
/** The root-relative files the analysis extracted components from,
|
|
50
|
+
* which must transform, and those it dropped over their parent. */
|
|
51
|
+
served?: ServedFiles;
|
|
40
52
|
}): string | null;
|
|
41
53
|
export declare const unpluginFactory: UnpluginFactory<AnimusUnpluginOptions | undefined>;
|
|
42
54
|
//# sourceMappingURL=core.d.ts.map
|
package/dist/core.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AA8CA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,KAAK,EACV,UAAU,EAQV,WAAW,EACZ,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,KAAK,EAIV,eAAe,EAChB,MAAM,UAAU,CAAC;AAElB;0DAC0D;AAC1D,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AAEjD,eAAO,MAAM,gBAAgB,wBAAwB,CAAC;AAQtD,eAAO,MAAM,cAAc,eAAe,CAAC;AAQ3C,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC/B,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC;wCACoC;IACpC,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,aAAa,EACT,CAAC,CACC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,KACjB;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,OAAO,CAAA;KAAE,CAAC,GAC9C,IAAI,CAAC;IACT,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;mCAC+B;IAC/B,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;IACvB;mDAC+C;IAC/C,MAAM,EAAE,WAAW,CAAC;IACpB,oDAAoD;IACpD,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,wBAAgB,eAAe,IAAI,SAAS,CAiB3C;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,qBAAqB,GAAG,iBAAiB,CAAC,GAChE,OAAO,CAMT;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,EAChB,SAAS,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IACmB,GAC9C,IAAI,CAKN;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE,SAAS,EAChB,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EACxB,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAChC,OAAO,CAAC,IAAI,CAAC,CAYf;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASzD;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,GACb,MAAM,GAAG,IAAI,CAGf;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,GAAG,EAAE;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,CACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,KACjB;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,OAAO,CAAA;KAAE,CAAC;IAC9C;wEACoE;IACpE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,GACA,MAAM,GAAG,IAAI,CAgBf;AA8SD,eAAO,MAAM,eAAe,EAAE,eAAe,CAC3C,qBAAqB,GAAG,SAAS,CAqvBlC,CAAC"}
|
package/dist/esbuild.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_core = require("./core-
|
|
5
|
+
const require_core = require("./core-zGWPVkIb.cjs");
|
|
6
6
|
//#region src/esbuild.ts
|
|
7
7
|
const animusEsbuild = (0, require("unplugin").createEsbuildPlugin)(require_core.unpluginFactory);
|
|
8
8
|
//#endregion
|
package/dist/esbuild.mjs
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_core = require("./core-
|
|
5
|
+
const require_core = require("./core-zGWPVkIb.cjs");
|
|
6
6
|
//#region src/index.ts
|
|
7
7
|
const animusUnplugin = (0, require("unplugin").createUnplugin)(require_core.unpluginFactory);
|
|
8
8
|
//#endregion
|
package/dist/index.mjs
CHANGED
package/dist/rollup.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_core = require("./core-
|
|
5
|
+
const require_core = require("./core-zGWPVkIb.cjs");
|
|
6
6
|
//#region src/rollup.ts
|
|
7
7
|
const animusRollup = (0, require("unplugin").createRollupPlugin)(require_core.unpluginFactory);
|
|
8
8
|
//#endregion
|
package/dist/rollup.mjs
CHANGED
package/dist/rspack.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_core = require("./core-
|
|
5
|
+
const require_core = require("./core-zGWPVkIb.cjs");
|
|
6
6
|
//#region src/rspack.ts
|
|
7
7
|
const animusRspack = (0, require("unplugin").createRspackPlugin)(require_core.unpluginFactory);
|
|
8
8
|
//#endregion
|
package/dist/rspack.mjs
CHANGED
package/dist/webpack.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_core = require("./core-
|
|
5
|
+
const require_core = require("./core-zGWPVkIb.cjs");
|
|
6
6
|
//#region src/webpack.ts
|
|
7
7
|
const animusWebpack = (0, require("unplugin").createWebpackPlugin)(require_core.unpluginFactory);
|
|
8
8
|
//#endregion
|
package/dist/webpack.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@animus-ui/unplugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.26",
|
|
4
4
|
"description": "Animus transform host for non-plugin bundlers — unplugin-based rollup/esbuild/rspack/webpack entry points over the one extraction session",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"animus",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"compile": "tsc --noEmit"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@animus-ui/extract": "0.1.
|
|
60
|
+
"@animus-ui/extract": "0.1.26",
|
|
61
61
|
"unplugin": "^3.3.0"
|
|
62
62
|
},
|
|
63
63
|
"engines": {
|