@animus-ui/next-plugin 0.1.25 → 0.1.27

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/dist/index.mjs CHANGED
@@ -1,9 +1,31 @@
1
- import { a as resolveTurbopackMode, i as resolveTurbopackLoaderPath, n as buildTurbopackConfig, o as turbopackSideEffectsLimits, r as isTurbopackDevelopment, s as resolveAnimusLoaderPath, t as ANIMUS_TURBOPACK_RULE_GLOB } from "./turbopack-config-BdfqxwT0.mjs";
2
- import { assembleStylesheet, assertKnownOptionKeys, assertNoRetiredEngineSelection, buildPathAliasesJson, isEngineTransformExtension, isPathWithinRoot, keepsKitSourceEffects, readTsconfigAliasPairs, resolveMode, sourceKitDependencies } from "@animus-ui/extract/pipeline";
3
- import { ANIMUS_CSS_MODULE_ID, ANIMUS_CSS_MODULE_ID as ANIMUS_CSS_MODULE_ID$1, ExtractionSession, TURBOPACK_SYSTEM_PROPS_ID, getAnalysisStartedPromise, getReplacementEpoch, getSharedCss, getSharedExternalDirs, getSharedExternalEntries, getSharedExternalSideEffects, replacementEpochPath, resetAnalysisStartedPromise, runSessionPipeline, sessionArtifactDir, setAnalysisStartedPromise, setSharedEngine, startTurbopackWatcher, stylesPath, systemPropsPath } from "@animus-ui/extract/session";
4
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
5
- import { dirname, join } from "path";
1
+ import { a as resolveTurbopackMode, i as resolveTurbopackLoaderPath, n as buildTurbopackConfig, o as turbopackSideEffectsLimits, r as isTurbopackDevelopment, s as resolveAnimusLoaderPath, t as ANIMUS_TURBOPACK_RULE_GLOB } from "./turbopack-config-3jtLDAIM.mjs";
2
+ import { AnimusConfigError, assembleStylesheet, assertKnownOptionKeys, assertSupportedEngine, buildPathAliasesJson, builtInAssetClassification, isEngineTransformExtension, isPathWithinRoot, keepsKitSourceEffects, nextImageAssetClassification, outputExclusion, resolveMode, sourceKitDependencies, turbopackExtensionPolicy, webpackExtensionPolicy } from "@animus-ui/extract/pipeline";
3
+ import { ANIMUS_CSS_MODULE_ID, ANIMUS_CSS_MODULE_ID as ANIMUS_CSS_MODULE_ID$1, ExtractionSession, TURBOPACK_SYSTEM_PROPS_ID, createBuildId, getAnalysisStartedPromise, getReplacementEpoch, getSharedCss, getSharedExternalDirs, getSharedExternalEntries, getSharedExternalSideEffects, replacementEpochPath, requireEngine, resetAnalysisStartedPromise, runSessionPipeline, sessionArtifactDir, setAnalysisStartedPromise, startTurbopackWatcher, stylesPath, systemPropsPath } from "@animus-ui/extract/session";
4
+ import { existsSync, mkdirSync, readFileSync, realpathSync, statSync, writeFileSync } from "fs";
5
+ import { dirname, join, resolve } from "path";
6
6
  import { fileURLToPath } from "url";
7
+ //#region src/same-directory.ts
8
+ /** Whether two paths name one directory: by real path, which resolves a
9
+ * trailing slash, a symlink and the filesystem's own spelling, else by
10
+ * device and inode. */
11
+ function sameDirectory(a, b) {
12
+ const real = (path) => {
13
+ try {
14
+ return realpathSync.native(path);
15
+ } catch {
16
+ return resolve(path);
17
+ }
18
+ };
19
+ if (real(a) === real(b)) return true;
20
+ try {
21
+ const left = statSync(a);
22
+ const right = statSync(b);
23
+ return left.dev === right.dev && left.ino === right.ino;
24
+ } catch {
25
+ return false;
26
+ }
27
+ }
28
+ //#endregion
7
29
  //#region src/plugin.ts
8
30
  /** The value arrives from a consumer's `next.config`, so the union above is a
9
31
  * model of what webpack accepts, not a proof about the value in hand. */
@@ -15,6 +37,9 @@ var AnimusWebpackPlugin = class {
15
37
  options;
16
38
  session;
17
39
  initialized = false;
40
+ /** Left its build: the next turn joins again and catches up, retried
41
+ * until it succeeds, never reusing the startup it already consumed. */
42
+ rejoining = false;
18
43
  aliasesExtracted = false;
19
44
  animusLoaderPaths;
20
45
  lastBuiltEpoch = null;
@@ -24,13 +49,15 @@ var AnimusWebpackPlugin = class {
24
49
  watchFailure = null;
25
50
  /** `development` is `next dev`: an error-level diagnostic reports and the
26
51
  * compilation keeps publishing, whatever the emission mode. */
27
- constructor(options, { development = false } = {}) {
52
+ constructor(options, { development = false, build } = {}) {
28
53
  this.options = options;
29
- assertNoRetiredEngineSelection(options.engine);
30
- setSharedEngine(options.engine ?? "v2");
31
- this.session = new ExtractionSession(options);
54
+ assertSupportedEngine(options.engine);
55
+ this.session = new ExtractionSession(options, { build });
32
56
  this.session.development = development;
33
- this.session.systemPropsModuleId = TURBOPACK_SYSTEM_PROPS_ID;
57
+ this.session.delivery = {
58
+ ...this.session.delivery,
59
+ systemPropsModuleId: TURBOPACK_SYSTEM_PROPS_ID
60
+ };
34
61
  this.animusLoaderPaths = /* @__PURE__ */ new Set([resolveAnimusLoaderPath()]);
35
62
  if (options.loaderPath) this.animusLoaderPaths.add(options.loaderPath);
36
63
  }
@@ -54,10 +81,18 @@ var AnimusWebpackPlugin = class {
54
81
  else if (isWatchIgnoreMatcher(ignored)) watchOptions.ignored = (path) => path === epochPath || Boolean(ignored(path));
55
82
  }
56
83
  /** Webpack's export conditions select the system's kit files as they
57
- * select the bundle's; `...`, webpack's own defaults, names none. */
84
+ * select the bundle's; `...`, webpack's own defaults, names none. Its
85
+ * extension order and aliases are captured alongside. */
58
86
  extractConditions(compiler) {
59
- const names = compiler.options?.resolve?.conditionNames ?? [];
87
+ const resolve = compiler.options?.resolve;
88
+ const names = resolve?.conditionNames ?? [];
60
89
  this.session.conditions = names.filter((name) => name !== "...");
90
+ const resolverFactory = compiler.resolverFactory;
91
+ if (resolverFactory !== void 0) this.session.hostResolve = (specifier, importer) => new Promise((done) => {
92
+ resolverFactory.get("normal", { dependencyType: "esm" }).resolve({}, importer === void 0 ? compiler.context : dirname(importer), specifier, {}, (error, result) => done(error !== null || !result ? null : result));
93
+ });
94
+ this.session.assetClassification = builtInAssetClassification("hostOptionUnreadable", "next-webpack rules not modelled");
95
+ this.session.extensionPolicy = webpackExtensionPolicy("next-webpack", resolve ?? {}, compiler.webpack?.version);
61
96
  }
62
97
  extractAliases(compiler) {
63
98
  if (this.aliasesExtracted) return;
@@ -81,6 +116,13 @@ var AnimusWebpackPlugin = class {
81
116
  if (built) this.session.pathAliasesJson = built.json;
82
117
  }
83
118
  apply(compiler) {
119
+ const leave = () => {
120
+ this.session.close();
121
+ this.initialized = false;
122
+ this.rejoining = true;
123
+ };
124
+ compiler.hooks.shutdown?.tap(PLUGIN_NAME, leave);
125
+ compiler.hooks.watchClose?.tap(PLUGIN_NAME, leave);
84
126
  if (compiler.options?.name === "edge-server") return;
85
127
  const NormalModule = compiler.webpack?.NormalModule;
86
128
  if (NormalModule?.getCompilationHooks === void 0) throw new Error(UNSUPPORTED_WEBPACK_MESSAGE);
@@ -101,11 +143,11 @@ var AnimusWebpackPlugin = class {
101
143
  });
102
144
  compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
103
145
  const registerSystemDependencies = () => {
104
- for (const dep of this.session.systemDependencyPaths) if (existsSync(dep)) compilation.fileDependencies.add(dep);
105
- else compilation.missingDependencies.add(dep);
106
- for (const dep of this.session.assetDependencyPaths) if (existsSync(dep)) compilation.fileDependencies.add(dep);
107
- else compilation.missingDependencies.add(dep);
108
- for (const root of this.session.externalWatchRoots) compilation.contextDependencies.add(root);
146
+ const plan = this.session.watchPlan();
147
+ for (const path of plan.files) if (existsSync(path)) compilation.fileDependencies.add(path);
148
+ else compilation.missingDependencies.add(path);
149
+ for (const path of plan.missing) compilation.missingDependencies.add(path);
150
+ for (const root of plan.directories) compilation.contextDependencies.add(root);
109
151
  };
110
152
  registerSystemDependencies();
111
153
  const stage = compiler.webpack?.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL ?? -2e3;
@@ -115,7 +157,7 @@ var AnimusWebpackPlugin = class {
115
157
  stage
116
158
  }, () => {
117
159
  registerSystemDependencies();
118
- const css = getSharedCss();
160
+ const css = this.session.rootDir ? getSharedCss(this.session.key) : "";
119
161
  if (!css || !RawSource) return;
120
162
  const rootDir = this.session.rootDir || compiler.context;
121
163
  const cssPath = stylesPath(sessionArtifactDir(rootDir, this.session.sessionId));
@@ -130,13 +172,18 @@ var AnimusWebpackPlugin = class {
130
172
  this.adoptCompilerContext(_compiler);
131
173
  this.extractAliases(_compiler);
132
174
  this.extractConditions(_compiler);
133
- const existing = getAnalysisStartedPromise();
175
+ if (await this.rejoin()) {
176
+ this.session.agreeWithSystemAuthority();
177
+ return;
178
+ }
179
+ const existing = getAnalysisStartedPromise(this.session.key);
134
180
  if (existing) {
135
181
  await existing;
182
+ this.session.agreeWithSystemAuthority();
136
183
  return;
137
184
  }
138
185
  const promise = this.session.runFullPipeline();
139
- setAnalysisStartedPromise(promise);
186
+ setAnalysisStartedPromise(this.session.key, promise);
140
187
  await promise;
141
188
  });
142
189
  compiler.hooks.watchRun.tapPromise(PLUGIN_NAME, async (_compiler) => {
@@ -153,21 +200,38 @@ var AnimusWebpackPlugin = class {
153
200
  }
154
201
  /** Rejects with the analysis error; the published generation stays the
155
202
  * last successful one. */
203
+ /** Joins the build this compiler left and catches up with it: true when
204
+ * the build was live, false when it starts as at first. */
205
+ async rejoin() {
206
+ if (!this.rejoining) return false;
207
+ this.session.reattach();
208
+ const live = await this.session.catchUp();
209
+ this.rejoining = false;
210
+ return live;
211
+ }
156
212
  async analyzeWatchTurn(compiler) {
213
+ if (!this.initialized && await this.rejoin()) {
214
+ this.session.agreeWithSystemAuthority();
215
+ this.initialized = true;
216
+ this.lastBuiltEpoch = getReplacementEpoch(this.session.key);
217
+ this.epochMovedForNextCompilation = true;
218
+ return;
219
+ }
157
220
  if (!this.initialized) {
158
- let startup = getAnalysisStartedPromise();
221
+ let startup = getAnalysisStartedPromise(this.session.key);
159
222
  if (!startup) {
160
223
  startup = this.session.runFullPipeline();
161
- setAnalysisStartedPromise(startup);
224
+ setAnalysisStartedPromise(this.session.key, startup);
162
225
  }
163
226
  try {
164
227
  await startup;
165
228
  } catch (err) {
166
- if (getAnalysisStartedPromise() === startup) resetAnalysisStartedPromise();
229
+ if (getAnalysisStartedPromise(this.session.key) === startup) resetAnalysisStartedPromise(this.session.key);
167
230
  throw err;
168
231
  }
232
+ this.session.agreeWithSystemAuthority();
169
233
  this.initialized = true;
170
- this.lastBuiltEpoch = getReplacementEpoch();
234
+ this.lastBuiltEpoch = getReplacementEpoch(this.session.key);
171
235
  this.epochMovedForNextCompilation = this.watchFailure !== null;
172
236
  return;
173
237
  }
@@ -175,7 +239,8 @@ var AnimusWebpackPlugin = class {
175
239
  modifiedFiles: compiler.modifiedFiles,
176
240
  removedFiles: compiler.removedFiles
177
241
  });
178
- const epoch = getReplacementEpoch();
242
+ this.session.agreeWithSystemAuthority();
243
+ const epoch = getReplacementEpoch(this.session.key);
179
244
  this.epochMovedForNextCompilation = this.lastBuiltEpoch !== null && epoch !== null && epoch !== this.lastBuiltEpoch;
180
245
  if (epoch !== null) this.lastBuiltEpoch = epoch;
181
246
  }
@@ -188,21 +253,23 @@ var AnimusWebpackPlugin = class {
188
253
  setRootDir(rootDir) {
189
254
  this.session.rootDir = rootDir;
190
255
  }
191
- warnedRootDivergence = false;
256
+ /** Keeps Next's output directory out of discovery, whatever the user's
257
+ * exclude list says. Call after `setRootDir`. */
258
+ excludeOutputDir(outDir) {
259
+ const pattern = outputExclusion(this.session.rootDir, outDir);
260
+ if (pattern !== null) this.session.structuralExclude = [pattern];
261
+ }
192
262
  /** Adopts `compiler.context` only when no config-time root exists: every
193
263
  * frozen derivation came from that root, so an overwrite re-keys it.
194
264
  * Stub path, css alias, virtual system-props target and watch-ignore are
195
- * all frozen from it, so a disagreement is warned, never reconciled. */
265
+ * all frozen from it, so a disagreement fails, never reconciled. */
196
266
  adoptCompilerContext(compiler) {
197
267
  const context = compiler.context;
198
268
  if (!this.session.rootDir) {
199
269
  this.session.rootDir = context;
200
270
  return;
201
271
  }
202
- if (context && this.session.rootDir !== context && !this.warnedRootDivergence) {
203
- this.warnedRootDivergence = true;
204
- console.warn(`[animus-extract] compiler.context (${context}) differs from the configured project root (${this.session.rootDir}); keeping the configured root — run next against the app directory (or align your custom webpack context) so both agree`);
205
- }
272
+ if (context && !sameDirectory(context, this.session.rootDir)) throw new AnimusConfigError(`[animus-extract] compiler.context (${context}) differs from the configured project root (${this.session.rootDir}). Run next against the app directory, or align your custom webpack context, so both agree.`);
206
273
  }
207
274
  get sessionDir() {
208
275
  return this.session.sessionDir;
@@ -211,15 +278,20 @@ var AnimusWebpackPlugin = class {
211
278
  return this.options;
212
279
  }
213
280
  getExternalPackageDirs() {
214
- return this.session.externalPackageDirs.length > 0 ? this.session.externalPackageDirs : getSharedExternalDirs();
281
+ return this.session.externalPackageDirs.length > 0 ? this.session.externalPackageDirs : getSharedExternalDirs(this.session.key);
282
+ }
283
+ /** An import webpack resolved while bundling, with the resolve options of
284
+ * the rules its importer matches (spec §2.2 A4). */
285
+ reportHostResolution(importer, request, resolved) {
286
+ this.session.reportHostResolution(importer, request, resolved);
215
287
  }
216
288
  getExternalSourceEntries() {
217
- return this.session.externalSourceEntries.size > 0 ? this.session.externalSourceEntries : getSharedExternalEntries();
289
+ return this.session.externalSourceEntries.size > 0 ? this.session.externalSourceEntries : getSharedExternalEntries(this.session.key);
218
290
  }
219
291
  /** The classification of the entries `getExternalSourceEntries` returns,
220
292
  * from the same source. */
221
293
  getExternalSourceSideEffects() {
222
- return this.session.externalSourceEntries.size > 0 ? this.session.externalSourceSideEffects : getSharedExternalSideEffects();
294
+ return this.session.externalSourceEntries.size > 0 ? this.session.externalSourceSideEffects : getSharedExternalSideEffects(this.session.key);
223
295
  }
224
296
  };
225
297
  //#endregion
@@ -233,6 +305,7 @@ const PHASE_PRODUCTION_BUILD = "phase-production-build";
233
305
  let warnedGitignore = false;
234
306
  let warnedUnstableTurbopack = false;
235
307
  function withAnimus(options) {
308
+ assertSupportedEngine(options.engine);
236
309
  if (!options.system) throw new Error("[animus-extract] Missing required option `system`. Provide the path to your SystemInstance module: withAnimus({ system: \"./src/ds.ts\" })");
237
310
  assertKnownOptionKeys({ ...options }, [
238
311
  "cssImportTarget",
@@ -240,10 +313,7 @@ function withAnimus(options) {
240
313
  "unstable_turbopack",
241
314
  "loaderPath",
242
315
  "phase"
243
- ], [{
244
- key: "root",
245
- reason: "this driver derives its own root — Next's `dir` under webpack, `process.cwd()` under Turbopack (Next passes no dir to a config module)"
246
- }], {
316
+ ], [], {
247
317
  onUnknownKey: "warn",
248
318
  warn: (message) => console.warn(`[animus-extract] ${message}`)
249
319
  });
@@ -251,21 +321,31 @@ function withAnimus(options) {
251
321
  warnedUnstableTurbopack = true;
252
322
  console.warn("[animus-extract] `unstable_turbopack` is deprecated — rename it to `turbopack` (same shape)");
253
323
  }
324
+ const build = createBuildId();
325
+ const appRoot = options.root === void 0 ? process.cwd() : resolve(options.root);
254
326
  return (authoredConfig) => {
255
- const nextConfig = withSourceKits(authoredConfig, process.cwd());
256
- if (resolveTurbopackMode(options)) return turbopackConfig(nextConfig, options);
327
+ const nextConfig = withSourceKits(authoredConfig, appRoot);
328
+ if (resolveTurbopackMode(options)) {
329
+ warnTurbopackCwdRoot(options, appRoot);
330
+ return turbopackConfig(nextConfig, options, build, appRoot);
331
+ }
257
332
  const existingWebpack = nextConfig.webpack;
258
333
  return {
259
334
  ...nextConfig,
260
335
  webpack(config, context) {
261
336
  if (existingWebpack) config = existingWebpack(config, context);
262
- const rootDir = context.dir?.length ? context.dir : process.cwd();
337
+ if (context.dir?.length && !sameDirectory(context.dir, appRoot)) throw new AnimusConfigError(`[animus-extract] Next builds ${context.dir}, but Animus read the app's source kits from ${appRoot}. Run next from the app directory, or pass withAnimus({ root }) naming it.`);
338
+ const rootDir = appRoot;
263
339
  const { mode } = resolveMode(options.mode, () => context.dev === true ? "development" : "production");
264
340
  const plugin = new AnimusWebpackPlugin({
265
341
  ...options,
266
342
  mode
267
- }, { development: context.dev === true });
343
+ }, {
344
+ development: context.dev === true,
345
+ build
346
+ });
268
347
  plugin.setRootDir(rootDir);
348
+ if (nextConfig.distDir) plugin.excludeOutputDir(resolve(rootDir, nextConfig.distDir));
269
349
  const sessionDir = plugin.sessionDir;
270
350
  if (!existsSync(sessionDir)) mkdirSync(sessionDir, { recursive: true });
271
351
  const stubCssPath = stylesPath(sessionDir);
@@ -310,6 +390,9 @@ function withAnimus(options) {
310
390
  }
311
391
  });
312
392
  nmf.hooks.afterResolve.tap("AnimusVirtualResolve", (resolveData) => {
393
+ const issuer = resolveData.contextInfo?.issuer;
394
+ const resolved = resolveData.createData?.resource;
395
+ if (issuer && resolved !== void 0) plugin.reportHostResolution(issuer, resolveData.request, resolved);
313
396
  const sideEffects = redirectSideEffects.get(resolveData);
314
397
  const settings = resolveData.createData?.settings;
315
398
  if (!settings) return;
@@ -335,9 +418,10 @@ function withAnimus(options) {
335
418
  use: [{
336
419
  loader: actualLoaderPath,
337
420
  options: {
338
- strict: options.strict,
339
421
  development: context.dev === true,
340
- cssImportTarget: options.cssImportTarget
422
+ cssImportTarget: options.cssImportTarget,
423
+ build,
424
+ root: rootDir
341
425
  }
342
426
  }]
343
427
  });
@@ -358,17 +442,35 @@ function bindTurbopackWatchDeathReport(outcome, rootDir) {
358
442
  * source, but Next's server keeps an installed package external, and so
359
443
  * loads its runtime entry, unless the package is transpiled; transpiling
360
444
  * also compiles its TypeScript source. */
445
+ let warnedTurbopackCwd = false;
446
+ /** Turbopack's loaders get no app dir either, so a cwd that is not the app
447
+ * cannot be detected later: warn at startup when the cwd holds no Next
448
+ * config and no `root` names the app. */
449
+ function warnTurbopackCwdRoot(options, appRoot) {
450
+ if (options.root !== void 0 || warnedTurbopackCwd) return;
451
+ if ([
452
+ "js",
453
+ "mjs",
454
+ "cjs",
455
+ "ts",
456
+ "mts"
457
+ ].some((ext) => existsSync(join(appRoot, `next.config.${ext}`)))) return;
458
+ warnedTurbopackCwd = true;
459
+ console.warn(`[animus-extract] the current directory (${appRoot}) holds no next.config: under Turbopack, Animus reads the app from the current directory. Run next from the app directory, or pass withAnimus({ root }) naming it.`);
460
+ }
361
461
  function withSourceKits(nextConfig, rootDir) {
362
462
  const declared = nextConfig.transpilePackages ?? [];
363
- const kits = sourceKitDependencies(rootDir).map((kit) => kit.name).filter((name) => !declared.includes(name));
463
+ const kits = sourceKitDependencies(rootDir, requireEngine()).map((kit) => kit.name).filter((name) => !declared.includes(name));
364
464
  if (kits.length === 0) return nextConfig;
365
465
  return {
366
466
  ...nextConfig,
367
467
  transpilePackages: [...declared, ...kits]
368
468
  };
369
469
  }
370
- function turbopackConfig(nextConfig, options) {
371
- const load = (phase) => loadTurbopackFragment(options, phase).then((fragment) => mergeTurbopackFragment(nextConfig, fragment));
470
+ function turbopackConfig(nextConfig, options, build, appRoot) {
471
+ const resolveExtensions = nextConfig.turbopack?.resolveExtensions ?? nextConfig.experimental?.turbo?.resolveExtensions;
472
+ const outputExclude = nextConfig.distDir ? outputExclusion(appRoot, resolve(appRoot, nextConfig.distDir)) : null;
473
+ const load = (phase) => loadTurbopackFragment(options, phase, resolveExtensions, outputExclude, nextConfig.images?.disableStaticImages === true, build, appRoot).then((fragment) => mergeTurbopackFragment(nextConfig, fragment));
372
474
  function then(onResolved, onRejected) {
373
475
  const phase = options.phase ?? (isTurbopackDevelopment() ? PHASE_DEVELOPMENT_SERVER : PHASE_PRODUCTION_BUILD);
374
476
  return load(phase).then(onResolved, onRejected);
@@ -377,49 +479,67 @@ function turbopackConfig(nextConfig, options) {
377
479
  Object.defineProperty(config, "then", { enumerable: false });
378
480
  return config;
379
481
  }
380
- let liveTurbopackSession = null;
381
- let liveTurbopackWatcher = null;
382
- /** The load the live session came from. Next loads the config again after
383
- * Ready (validateTurboNextConfig), and a user config may await this one
384
- * besides: the same phase and root share one analysis and keep the watcher.
385
- * A rejected load is dropped, so a repaired source loads again. */
386
- let liveTurbopackLoad = null;
387
- function loadTurbopackFragment(options, phase) {
388
- const rootDir = process.cwd();
389
- const key = JSON.stringify([phase, rootDir]);
390
- if (liveTurbopackLoad?.key === key) return liveTurbopackLoad.fragment;
391
- const fragment = analyzeForTurbopack(options, phase, rootDir);
482
+ /** Each wrapper's owner, by the build it created: another wrapper of the
483
+ * same root is another build and never shares or closes this one's. */
484
+ const turbopackOwners = /* @__PURE__ */ new Map();
485
+ function turbopackOwner(build) {
486
+ let owner = turbopackOwners.get(build);
487
+ if (owner === void 0) {
488
+ owner = {
489
+ session: null,
490
+ watcher: null,
491
+ load: null
492
+ };
493
+ turbopackOwners.set(build, owner);
494
+ }
495
+ return owner;
496
+ }
497
+ function loadTurbopackFragment(options, phase, resolveExtensions, outputExclude, disableStaticImages, build, rootDir) {
498
+ const key = JSON.stringify([
499
+ phase,
500
+ rootDir,
501
+ resolveExtensions ?? null,
502
+ disableStaticImages
503
+ ]);
504
+ const owner = turbopackOwner(build);
505
+ if (owner.load?.key === key) return owner.load.fragment;
506
+ const fragment = analyzeForTurbopack(options, phase, rootDir, resolveExtensions, outputExclude, disableStaticImages, build);
392
507
  const load = {
393
508
  key,
394
509
  fragment
395
510
  };
396
- liveTurbopackLoad = load;
511
+ owner.load = load;
397
512
  fragment.catch(() => {
398
- if (liveTurbopackLoad === load) liveTurbopackLoad = null;
513
+ if (owner.load === load) owner.load = null;
399
514
  });
400
515
  return fragment;
401
516
  }
402
- async function analyzeForTurbopack(options, phase, rootDir) {
517
+ async function analyzeForTurbopack(options, phase, rootDir, resolveExtensions, outputExclude, disableStaticImages, build) {
403
518
  const development = phase === PHASE_DEVELOPMENT_SERVER;
404
519
  const { mode } = resolveMode(options.mode, () => development ? "development" : "production");
405
520
  const session = new ExtractionSession({
406
521
  ...options,
407
522
  mode
408
- }, { unbundledComputedImports: true });
409
- liveTurbopackSession?.close();
410
- liveTurbopackWatcher?.close();
411
- liveTurbopackWatcher = null;
412
- liveTurbopackSession = session;
523
+ }, {
524
+ unbundledComputedImports: true,
525
+ build: `${build}-${phase}`
526
+ });
527
+ const owner = turbopackOwner(build);
528
+ owner.session?.close();
529
+ owner.watcher?.close();
530
+ owner.watcher = null;
531
+ owner.session = session;
413
532
  session.development = development;
414
533
  session.rootDir = rootDir;
415
- const aliasPairs = readTsconfigAliasPairs(rootDir);
416
- const builtAliases = buildPathAliasesJson(aliasPairs, rootDir);
417
- if (builtAliases) session.pathAliasesJson = builtAliases.json;
534
+ if (outputExclude !== null) session.structuralExclude = [outputExclude];
535
+ session.extensionPolicy = turbopackExtensionPolicy(resolveExtensions);
536
+ session.assetClassification = nextImageAssetClassification(rootDir, disableStaticImages);
537
+ session.aliasesFromTsconfig = true;
418
538
  await runSessionPipeline(session);
419
- if (development && liveTurbopackSession === session) {
539
+ if (development && owner.session === session) {
420
540
  const outcome = startTurbopackWatcher(session, rootDir);
421
541
  bindTurbopackWatchDeathReport(outcome, rootDir);
422
- if (outcome.kind === "started") liveTurbopackWatcher = outcome.handle;
542
+ if (outcome.kind === "started") owner.watcher = outcome.handle;
423
543
  }
424
544
  for (const line of turbopackSideEffectsLimits(rootDir, session.externalSourceEntries, session.externalSourceSideEffects)) console.warn(line);
425
545
  return buildTurbopackConfig({
@@ -61,12 +61,26 @@ function extensionLineage(files, analyzedHashes) {
61
61
  const lineage = files.map((file) => `${file}\0${analyzedHashes?.get(file) ?? ""}`).join("\0");
62
62
  return `\nvoid "animus-lineage:${(0, _animus_ui_extract_pipeline.contentHash)(lineage)}";\n`;
63
63
  }
64
+ let parsedManifest = null;
65
+ /** What a manifest's transform serves, parsed once per manifest: every
66
+ * module of a compilation reads the same one. */
67
+ function manifestServedFiles(manifestJson) {
68
+ if (parsedManifest?.json !== manifestJson) parsedManifest = {
69
+ json: manifestJson,
70
+ served: (0, _animus_ui_extract_pipeline.servedFiles)(JSON.parse(manifestJson))
71
+ };
72
+ return parsedManifest.served;
73
+ }
64
74
  function transformWithManifest(args) {
65
75
  const { source, filename, manifestJson, engineApi, opts } = args;
66
76
  const isRootEntry = isCssImportTarget(filename, opts.cssImportTarget);
67
77
  try {
68
78
  const { transformFile } = engineApi();
69
79
  const result = transformFile(source, filename, manifestJson);
80
+ const served = manifestServedFiles(manifestJson);
81
+ const drop = served.dropped.get(filename);
82
+ if (drop !== void 0) throw new Error((0, _animus_ui_extract_pipeline.droppedExtensionMessage)(drop));
83
+ if (!result.hasComponents && served.listed.has(filename)) throw new Error(`the analysis extracted components from ${filename}, but its transform found none`);
70
84
  let code = result.hasComponents ? result.code : source;
71
85
  code = code.replace(CSS_IMPORT_RE, "");
72
86
  if (isRootEntry && !code.includes(_animus_ui_extract_session.ANIMUS_CSS_MODULE_ID)) {
@@ -79,10 +93,7 @@ function transformWithManifest(args) {
79
93
  return code;
80
94
  } catch (e) {
81
95
  const msg = e instanceof Error ? e.message : String(e);
82
- if (opts.strict && !opts.development) throw new Error(`[animus-extract] Transform failed for ${filename}: ${msg}`, { cause: e });
83
- if (opts.strict) console.error(`[animus-extract] Transform failed for ${filename}: ${msg}`);
84
- else console.warn(`[animus-extract] Transform failed for ${filename}:`, msg);
85
- return source;
96
+ throw new Error(`[animus-extract] Transform failed for ${filename}: ${msg}`, { cause: e });
86
97
  }
87
98
  }
88
99
  //#endregion
@@ -1,4 +1,4 @@
1
- import { contentHash } from "@animus-ui/extract/pipeline";
1
+ import { contentHash, droppedExtensionMessage, servedFiles } from "@animus-ui/extract/pipeline";
2
2
  import { ANIMUS_CSS_MODULE_ID } from "@animus-ui/extract/session";
3
3
  //#region src/loader-core.ts
4
4
  /** Matches every already-emitted stylesheet import — arbitrary relative
@@ -61,12 +61,26 @@ function extensionLineage(files, analyzedHashes) {
61
61
  const lineage = files.map((file) => `${file}\0${analyzedHashes?.get(file) ?? ""}`).join("\0");
62
62
  return `\nvoid "animus-lineage:${contentHash(lineage)}";\n`;
63
63
  }
64
+ let parsedManifest = null;
65
+ /** What a manifest's transform serves, parsed once per manifest: every
66
+ * module of a compilation reads the same one. */
67
+ function manifestServedFiles(manifestJson) {
68
+ if (parsedManifest?.json !== manifestJson) parsedManifest = {
69
+ json: manifestJson,
70
+ served: servedFiles(JSON.parse(manifestJson))
71
+ };
72
+ return parsedManifest.served;
73
+ }
64
74
  function transformWithManifest(args) {
65
75
  const { source, filename, manifestJson, engineApi, opts } = args;
66
76
  const isRootEntry = isCssImportTarget(filename, opts.cssImportTarget);
67
77
  try {
68
78
  const { transformFile } = engineApi();
69
79
  const result = transformFile(source, filename, manifestJson);
80
+ const served = manifestServedFiles(manifestJson);
81
+ const drop = served.dropped.get(filename);
82
+ if (drop !== void 0) throw new Error(droppedExtensionMessage(drop));
83
+ if (!result.hasComponents && served.listed.has(filename)) throw new Error(`the analysis extracted components from ${filename}, but its transform found none`);
70
84
  let code = result.hasComponents ? result.code : source;
71
85
  code = code.replace(CSS_IMPORT_RE, "");
72
86
  if (isRootEntry && !code.includes(ANIMUS_CSS_MODULE_ID)) {
@@ -79,10 +93,7 @@ function transformWithManifest(args) {
79
93
  return code;
80
94
  } catch (e) {
81
95
  const msg = e instanceof Error ? e.message : String(e);
82
- if (opts.strict && !opts.development) throw new Error(`[animus-extract] Transform failed for ${filename}: ${msg}`, { cause: e });
83
- if (opts.strict) console.error(`[animus-extract] Transform failed for ${filename}: ${msg}`);
84
- else console.warn(`[animus-extract] Transform failed for ${filename}:`, msg);
85
- return source;
96
+ throw new Error(`[animus-extract] Transform failed for ${filename}: ${msg}`, { cause: e });
86
97
  }
87
98
  }
88
99
  //#endregion
@@ -1,9 +1,14 @@
1
1
  export interface LoaderPolicyOptions {
2
- strict?: boolean;
3
- /** `next dev`: a strict transform failure reports and delivers the
4
- * source, as a non-strict one does, instead of failing the module. */
2
+ /** `next dev`: the Turbopack loader waits for and re-delivers the dev
3
+ * watcher's generations. A transform failure fails the module in every
4
+ * mode (SA1). */
5
5
  development?: boolean;
6
6
  cssImportTarget?: string;
7
+ /** The build the config wrapper created, which the loader reads the
8
+ * analysis of. */
9
+ build?: string;
10
+ /** The root that build's plugin analyses. */
11
+ root?: string;
7
12
  }
8
13
  export interface LoaderContextBase<O extends LoaderPolicyOptions = LoaderPolicyOptions> {
9
14
  resourcePath: string;
@@ -1 +1 @@
1
- {"version":3,"file":"loader-core.d.ts","sourceRoot":"","sources":["../src/loader-core.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;2EACuE;IACvE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB,CAChC,CAAC,SAAS,mBAAmB,GAAG,mBAAmB;IAEnD,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,CAAC;IACpB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AA0DD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,SAAS,MAAM,EAAE,CAKnB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,GAC7D,MAAM,CAMR;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IAErB,SAAS,EAAE,MAAM,GAAG,CAAC;IACrB,IAAI,EAAE,mBAAmB,CAAC;CAC3B,GAAG,MAAM,CA6CT"}
1
+ {"version":3,"file":"loader-core.d.ts","sourceRoot":"","sources":["../src/loader-core.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,mBAAmB;IAClC;;sBAEkB;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;uBACmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB,CAChC,CAAC,SAAS,mBAAmB,GAAG,mBAAmB;IAEnD,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,CAAC;IACpB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AA0DD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,SAAS,MAAM,EAAE,CAKnB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,GAC7D,MAAM,CAMR;AAiBD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IAErB,SAAS,EAAE,MAAM,GAAG,CAAC;IACrB,IAAI,EAAE,mBAAmB,CAAC;CAC3B,GAAG,MAAM,CAiDT"}
package/dist/loader.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_loader_core = require("./loader-core-CAr8opFH.cjs");
1
+ const require_loader_core = require("./loader-core-Bz52QNm3.cjs");
2
2
  let _animus_ui_extract_pipeline = require("@animus-ui/extract/pipeline");
3
3
  let _animus_ui_extract_session = require("@animus-ui/extract/session");
4
4
  let fs = require("fs");
@@ -6,8 +6,11 @@ let path = require("path");
6
6
  //#region src/loader.ts
7
7
  const epochSeenForSessionDir = /* @__PURE__ */ new Set();
8
8
  function animusLoader(source) {
9
+ const opts = this.getOptions?.() ?? {};
10
+ if (opts.build === void 0) throw new _animus_ui_extract_pipeline.AnimusConfigError(`[animus-extract] the Animus loader for ${(0, path.relative)(this.rootContext, this.resourcePath)} names no Animus build; it runs only as withAnimus() configures it.`);
11
+ const key = (0, _animus_ui_extract_session.sessionKey)(opts.build, opts.root ?? this.rootContext);
9
12
  if (this.addDependency !== void 0) {
10
- const sessionDir = (0, _animus_ui_extract_session.getSessionArtifactDir)();
13
+ const sessionDir = (0, _animus_ui_extract_session.getSessionArtifactDir)(key);
11
14
  if (sessionDir) {
12
15
  const epochPath = (0, _animus_ui_extract_session.replacementEpochPath)(sessionDir);
13
16
  if (epochSeenForSessionDir.has(sessionDir) || (0, fs.existsSync)(epochPath)) {
@@ -16,29 +19,29 @@ function animusLoader(source) {
16
19
  }
17
20
  }
18
21
  }
19
- let manifestJson = (0, _animus_ui_extract_session.getManifestJson)();
20
- if (!manifestJson) return source;
22
+ let manifestJson = (0, _animus_ui_extract_session.getManifestJson)(key);
23
+ if (!manifestJson) throw new Error(`[animus-extract] no analysis is available to transform ${(0, path.relative)(this.rootContext, this.resourcePath)}: the project analysis failed; see the error above.`);
21
24
  const filename = (0, path.relative)(this.rootContext, this.resourcePath);
22
- const analyzedHash = (0, _animus_ui_extract_session.getAnalyzedHashes)()?.get(filename);
25
+ const analyzedHash = (0, _animus_ui_extract_session.getAnalyzedHashes)(key)?.get(filename);
23
26
  if (analyzedHash !== void 0) {
24
27
  const sourceHash = (0, _animus_ui_extract_pipeline.contentHash)(source);
25
28
  if (sourceHash !== analyzedHash) {
26
- const refreshedHash = (0, _animus_ui_extract_session.getAnalyzedHashes)()?.get(filename);
29
+ const refreshedHash = (0, _animus_ui_extract_session.getAnalyzedHashes)(key)?.get(filename);
27
30
  if (refreshedHash === void 0 || sourceHash !== refreshedHash) throw new Error(`ANIMUS_ANALYSIS_CATCHING_UP: ${filename} changed after the current analysis; retrying on the next watch turn`);
28
- manifestJson = (0, _animus_ui_extract_session.getManifestJson)() ?? manifestJson;
31
+ manifestJson = (0, _animus_ui_extract_session.getManifestJson)(key) ?? manifestJson;
29
32
  }
30
33
  }
31
34
  const code = require_loader_core.transformWithManifest({
32
35
  source,
33
36
  filename,
34
37
  manifestJson,
35
- engineApi: _animus_ui_extract_session.engineApi,
36
- opts: this.getOptions?.() ?? {}
38
+ engineApi: () => (0, _animus_ui_extract_session.engineApi)(key),
39
+ opts
37
40
  });
38
41
  if (!(this.mode !== "production") || this.addDependency === void 0) return code;
39
42
  const extended = require_loader_core.extendedFiles(manifestJson, filename);
40
43
  for (const file of extended) this.addDependency((0, path.join)(this.rootContext, file));
41
- return code + require_loader_core.extensionLineage(extended, (0, _animus_ui_extract_session.getAnalyzedHashes)());
44
+ return code + require_loader_core.extensionLineage(extended, (0, _animus_ui_extract_session.getAnalyzedHashes)(key));
42
45
  }
43
46
  //#endregion
44
47
  module.exports = animusLoader;
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAIvD,KAAK,aAAa,GAAG,iBAAiB,GAAG;IACvC,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,GAAG,MAAM,CAAC;CAC9C,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,YAAY,CAClC,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,MAAM,GACb,MAAM,CAkDR"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAIvD,KAAK,aAAa,GAAG,iBAAiB,GAAG;IACvC,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,GAAG,MAAM,CAAC;CAC9C,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,YAAY,CAClC,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,MAAM,GACb,MAAM,CAuER"}