@asheeui/next 0.3.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ashee Softworks
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.cjs ADDED
@@ -0,0 +1,290 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let node_fs = require("node:fs");
3
+ let node_path = require("node:path");
4
+ let _asheeui_utils_node = require("@asheeui/utils/node");
5
+ //#region src/generate.ts
6
+ /**
7
+ * The import specifier used across AsheeUI for the config module.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import config from "virtual:ashee-config";
12
+ * ```
13
+ */
14
+ const VIRTUAL_ID = "virtual:ashee-config";
15
+ /**
16
+ * Location of the generated shim, relative to the project root.
17
+ *
18
+ * Deliberately kept outside `node_modules`: package managers and CI
19
+ * treat `node_modules` as fully disposable, and a shim the dev server
20
+ * depends on should not live somewhere that can vanish out from under
21
+ * it.
22
+ */
23
+ const SHIM_RELATIVE_PATH = ".ashee/generated-config.mjs";
24
+ /**
25
+ * Resolve the absolute path of the generated shim for a project root.
26
+ *
27
+ * @param root - Project root directory. Defaults to `process.cwd()`.
28
+ * @returns Absolute path of the shim file.
29
+ */
30
+ function resolveShimPath(root) {
31
+ return (0, node_path.resolve)(root ?? process.cwd(), SHIM_RELATIVE_PATH);
32
+ }
33
+ /**
34
+ * Resolve every candidate config filename to an absolute path under
35
+ * `root`, whether or not the files currently exist.
36
+ *
37
+ * These paths are registered as webpack "missing dependencies" so that
38
+ * creating a config file for the first time triggers a rebuild.
39
+ *
40
+ * @param root - Project root directory. Defaults to `process.cwd()`.
41
+ * @returns Absolute paths for every known config filename.
42
+ */
43
+ function resolveCandidatePaths(root) {
44
+ const base = root ?? process.cwd();
45
+ return _asheeui_utils_node.CANDIDATES.map((file) => (0, node_path.resolve)(base, file));
46
+ }
47
+ /**
48
+ * Build an import specifier for `toFile` relative to `fromFile`'s directory.
49
+ *
50
+ * Turbopack rejects absolute ("server-relative") import specifiers, so the
51
+ * shim must reference the discovered config with a path relative to itself.
52
+ *
53
+ * @param fromFile - Absolute path of the importing file.
54
+ * @param toFile - Absolute path of the imported file.
55
+ * @returns A `./`-prefixed relative specifier.
56
+ */
57
+ function toRelativeSpecifier(fromFile, toFile) {
58
+ const rel = (0, node_path.relative)((0, node_path.dirname)(fromFile), toFile).replaceAll("\\", "/");
59
+ return rel.startsWith(".") ? rel : `./${rel}`;
60
+ }
61
+ /**
62
+ * Regenerate the config shim, mirroring `@asheeui/vite`'s virtual module:
63
+ * if a config file exists we re-export its default export, otherwise we
64
+ * export `undefined`.
65
+ *
66
+ * The write is skipped when the content is unchanged, so webpack's
67
+ * `beforeCompile` hook does not churn the file (or Turbopack's watcher)
68
+ * on every rebuild.
69
+ *
70
+ * @param root - Project root directory. Defaults to `process.cwd()`.
71
+ * @returns The absolute path of the regenerated shim file.
72
+ */
73
+ function generateShim(root) {
74
+ const shimPath = resolveShimPath(root);
75
+ const configPath = (0, _asheeui_utils_node.discoverConfig)(root);
76
+ const content = configPath ? `export { default } from ${JSON.stringify(toRelativeSpecifier(shimPath, configPath))};\n` : "export default undefined;\n";
77
+ if (!(0, node_fs.existsSync)(shimPath) || (0, node_fs.readFileSync)(shimPath, "utf8") !== content) {
78
+ (0, node_fs.mkdirSync)((0, node_path.dirname)(shimPath), { recursive: true });
79
+ (0, node_fs.writeFileSync)(shimPath, content, "utf8");
80
+ }
81
+ return shimPath;
82
+ }
83
+ //#endregion
84
+ //#region src/turbopack.ts
85
+ /**
86
+ * Point `virtual:ashee-config` at the generated shim inside a Turbopack
87
+ * config section.
88
+ *
89
+ * The given `target` object is mutated and then returned so the caller
90
+ * can use it in an inline expression.
91
+ *
92
+ * @param target - Turbopack config section (stable or experimental).
93
+ * @param shimPath - Project-root-relative path of the generated shim.
94
+ * @returns The same `target` object, with the alias registered.
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * const turbopack = addAsheeConfigResolveAlias(
99
+ * { resolveAlias: {} },
100
+ * "./.ashee/generated-config.mjs",
101
+ * );
102
+ * ```
103
+ */
104
+ function addAsheeConfigResolveAlias(target, shimPath) {
105
+ target.resolveAlias ??= {};
106
+ target.resolveAlias[VIRTUAL_ID] = shimPath;
107
+ return target;
108
+ }
109
+ //#endregion
110
+ //#region src/webpack.ts
111
+ /**
112
+ * Exact-match alias key (`$`-suffixed) so a hypothetical future
113
+ * `virtual:ashee-config/foo` import does not also resolve through this
114
+ * alias.
115
+ */
116
+ const EXACT_VIRTUAL_ID = `${VIRTUAL_ID}$`;
117
+ /**
118
+ * Point `virtual:ashee-config` at the generated shim so app code keeps
119
+ * using the same import specifier as Vite.
120
+ *
121
+ * @param config - Webpack config section to patch (mutated in place).
122
+ * @param shimPath - Absolute path of the generated shim.
123
+ * @returns The same `config` object, with the alias registered.
124
+ *
125
+ * @example
126
+ * ```ts
127
+ * const config = addAsheeConfigAlias(
128
+ * { resolve: { alias: {} } },
129
+ * "/proj/.ashee/generated-config.mjs",
130
+ * );
131
+ * ```
132
+ */
133
+ function addAsheeConfigAlias(config, shimPath) {
134
+ config.resolve ??= {};
135
+ config.resolve.alias ??= {};
136
+ config.resolve.alias[EXACT_VIRTUAL_ID] = shimPath;
137
+ return config;
138
+ }
139
+ /**
140
+ * Create a dev-only webpack plugin that regenerates the shim before
141
+ * every compile so edits to an existing config file are always picked
142
+ * up.
143
+ *
144
+ * The plugin also registers every candidate filename as a webpack
145
+ * "missing dependency": the shim has no reference to a file that does
146
+ * not exist yet, so without this, *creating* the config file for the
147
+ * first time would never trigger a rebuild on its own. Writes are
148
+ * skipped when content is unchanged, keeping rebuilds cheap.
149
+ *
150
+ * @param regenerate - Callback that rewrites the shim file.
151
+ * @param candidatePaths - Absolute candidate config paths to watch as
152
+ * missing dependencies.
153
+ * @returns A webpack plugin object.
154
+ */
155
+ function createBeforeCompilePlugin(regenerate, candidatePaths) {
156
+ return { apply(compiler) {
157
+ compiler.hooks.beforeCompile.tap("ashee:virtual-config", () => {
158
+ regenerate();
159
+ });
160
+ compiler.hooks.afterCompile.tap("ashee:virtual-config", (compilation) => {
161
+ for (const path of candidatePaths) compilation.missingDependencies.add(path);
162
+ });
163
+ } };
164
+ }
165
+ /**
166
+ * Create the webpack hook that Next invokes when building.
167
+ *
168
+ * The returned hook always adds the config alias; in dev mode it also
169
+ * installs the `beforeCompile` regeneration plugin and the
170
+ * missing-dependency watcher.
171
+ *
172
+ * @param options - Hook options.
173
+ * @param options.shimPath - Absolute path of the generated shim.
174
+ * @param options.candidatePaths - Absolute candidate config paths.
175
+ * @param options.root - Project root used when regenerating the shim.
176
+ * @param options.regenerate - Function that regenerates the shim for a
177
+ * given root directory.
178
+ * @returns A webpack config hook matching Next's `webpack` signature.
179
+ */
180
+ function createWebpackHook(options) {
181
+ const { shimPath, candidatePaths, regenerate, root } = options;
182
+ return (config, context) => {
183
+ addAsheeConfigAlias(config, shimPath);
184
+ if (context.dev) {
185
+ config.plugins ??= [];
186
+ config.plugins.push(createBeforeCompilePlugin(() => regenerate(root), candidatePaths));
187
+ }
188
+ return config;
189
+ };
190
+ }
191
+ //#endregion
192
+ //#region src/with-ashee-ui.ts
193
+ /**
194
+ * AsheeUI packages that ship TypeScript source and must be compiled by
195
+ * Next.
196
+ *
197
+ * `transpilePackages` takes npm package names, deduped against any the
198
+ * consumer provides.
199
+ */
200
+ const ASHEE_TRANSPILE_PACKAGES = ["asheeui"];
201
+ /**
202
+ * Wrap a `next.config.mjs`/`next.config.ts` object with AsheeUI
203
+ * integration.
204
+ *
205
+ * The wrapper:
206
+ * 1. Generates a config shim at `.ashee/generated-config.mjs` (same
207
+ * resolution as `@asheeui/vite`'s `virtual:ashee-config`).
208
+ * 2. Adds a `virtual:ashee-config` alias for Webpack and Turbopack so
209
+ * app code uses the identical import specifier in both bundlers.
210
+ * Webpack gets an absolute path (it resolves against its own
211
+ * context, not the `root` override), Turbopack gets a
212
+ * project-root-relative one (it rejects absolute targets).
213
+ * 3. Merges `transpilePackages` so AsheeUI's source-shipping packages
214
+ * are compiled by Next.
215
+ *
216
+ * @param config - Next config to wrap. AsheeUI override keys (`root`,
217
+ * `transpilePackages`) are consumed and stripped from the returned
218
+ * `NextConfig`. Defaults to `{}`.
219
+ * @returns A plain `NextConfig` with the AsheeUI integration applied.
220
+ *
221
+ * @example
222
+ * ```ts
223
+ * // next.config.ts
224
+ * import { withAsheeUI } from "@asheeui/next";
225
+ *
226
+ * export default withAsheeUI({
227
+ * transpilePackages: ["@my-org/ui"],
228
+ * });
229
+ * ```
230
+ */
231
+ function withAsheeUI(config = {}) {
232
+ const { root, transpilePackages: extraTranspilePackages, ...nextConfig } = config;
233
+ const baseDir = root ?? process.cwd();
234
+ const legacyConfig = nextConfig;
235
+ generateShim(baseDir);
236
+ const absoluteShimPath = resolveShimPath(baseDir);
237
+ const relativeShimPath = `./${SHIM_RELATIVE_PATH}`;
238
+ const candidatePaths = resolveCandidatePaths(baseDir);
239
+ const transpilePackages = [.../* @__PURE__ */ new Set([
240
+ ...ASHEE_TRANSPILE_PACKAGES,
241
+ ...legacyConfig.transpilePackages ?? [],
242
+ ...extraTranspilePackages ?? []
243
+ ])];
244
+ const userWebpack = nextConfig.webpack;
245
+ const webpack = ((config, context) => {
246
+ const patchConfig = config;
247
+ const patchContext = context;
248
+ const hook = createWebpackHook({
249
+ shimPath: absoluteShimPath,
250
+ candidatePaths,
251
+ root: baseDir,
252
+ regenerate: generateShim
253
+ });
254
+ if (userWebpack) return hook(userWebpack(patchConfig, patchContext), patchContext);
255
+ return hook(patchConfig, patchContext);
256
+ });
257
+ const turbopackResolveAlias = {
258
+ ...nextConfig.turbopack?.resolveAlias ?? {},
259
+ [VIRTUAL_ID]: relativeShimPath
260
+ };
261
+ const turbopack = {
262
+ ...nextConfig.turbopack,
263
+ resolveAlias: turbopackResolveAlias
264
+ };
265
+ const patchedConfig = {
266
+ ...nextConfig,
267
+ transpilePackages,
268
+ webpack,
269
+ turbopack
270
+ };
271
+ if (legacyConfig.experimental?.turbo) {
272
+ const turboPatch = addAsheeConfigResolveAlias(legacyConfig.experimental.turbo, relativeShimPath);
273
+ patchedConfig.experimental = {
274
+ ...nextConfig.experimental,
275
+ turbo: turboPatch
276
+ };
277
+ }
278
+ return patchedConfig;
279
+ }
280
+ //#endregion
281
+ exports.SHIM_RELATIVE_PATH = SHIM_RELATIVE_PATH;
282
+ exports.VIRTUAL_ID = VIRTUAL_ID;
283
+ exports.addAsheeConfigAlias = addAsheeConfigAlias;
284
+ exports.addAsheeConfigResolveAlias = addAsheeConfigResolveAlias;
285
+ exports.createBeforeCompilePlugin = createBeforeCompilePlugin;
286
+ exports.createWebpackHook = createWebpackHook;
287
+ exports.generateShim = generateShim;
288
+ exports.resolveCandidatePaths = resolveCandidatePaths;
289
+ exports.resolveShimPath = resolveShimPath;
290
+ exports.withAsheeUI = withAsheeUI;
@@ -0,0 +1,256 @@
1
+ import { NextConfig } from "next";
2
+ //#region src/generate.d.ts
3
+ /**
4
+ * The import specifier used across AsheeUI for the config module.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import config from "virtual:ashee-config";
9
+ * ```
10
+ */
11
+ declare const VIRTUAL_ID = "virtual:ashee-config";
12
+ /**
13
+ * Location of the generated shim, relative to the project root.
14
+ *
15
+ * Deliberately kept outside `node_modules`: package managers and CI
16
+ * treat `node_modules` as fully disposable, and a shim the dev server
17
+ * depends on should not live somewhere that can vanish out from under
18
+ * it.
19
+ */
20
+ declare const SHIM_RELATIVE_PATH = ".ashee/generated-config.mjs";
21
+ /**
22
+ * Resolve the absolute path of the generated shim for a project root.
23
+ *
24
+ * @param root - Project root directory. Defaults to `process.cwd()`.
25
+ * @returns Absolute path of the shim file.
26
+ */
27
+ declare function resolveShimPath(root?: string): string;
28
+ /**
29
+ * Resolve every candidate config filename to an absolute path under
30
+ * `root`, whether or not the files currently exist.
31
+ *
32
+ * These paths are registered as webpack "missing dependencies" so that
33
+ * creating a config file for the first time triggers a rebuild.
34
+ *
35
+ * @param root - Project root directory. Defaults to `process.cwd()`.
36
+ * @returns Absolute paths for every known config filename.
37
+ */
38
+ declare function resolveCandidatePaths(root?: string): string[];
39
+ /**
40
+ * Regenerate the config shim, mirroring `@asheeui/vite`'s virtual module:
41
+ * if a config file exists we re-export its default export, otherwise we
42
+ * export `undefined`.
43
+ *
44
+ * The write is skipped when the content is unchanged, so webpack's
45
+ * `beforeCompile` hook does not churn the file (or Turbopack's watcher)
46
+ * on every rebuild.
47
+ *
48
+ * @param root - Project root directory. Defaults to `process.cwd()`.
49
+ * @returns The absolute path of the regenerated shim file.
50
+ */
51
+ declare function generateShim(root?: string): string;
52
+ //#endregion
53
+ //#region src/turbopack.d.ts
54
+ /**
55
+ * The part of Next's Turbopack config that this package patches.
56
+ *
57
+ * Next exposes the same shape both at the stable `turbopack` key
58
+ * (`>= 15.1`) and at the deprecated `experimental.turbo` key, so one
59
+ * structural type covers both merge targets.
60
+ */
61
+ interface TurbopackPatch {
62
+ /** Alias map used to redirect module specifiers during resolution. */
63
+ resolveAlias?: Record<string, string>;
64
+ }
65
+ /**
66
+ * Point `virtual:ashee-config` at the generated shim inside a Turbopack
67
+ * config section.
68
+ *
69
+ * The given `target` object is mutated and then returned so the caller
70
+ * can use it in an inline expression.
71
+ *
72
+ * @param target - Turbopack config section (stable or experimental).
73
+ * @param shimPath - Project-root-relative path of the generated shim.
74
+ * @returns The same `target` object, with the alias registered.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * const turbopack = addAsheeConfigResolveAlias(
79
+ * { resolveAlias: {} },
80
+ * "./.ashee/generated-config.mjs",
81
+ * );
82
+ * ```
83
+ */
84
+ declare function addAsheeConfigResolveAlias(target: TurbopackPatch, shimPath: string): TurbopackPatch;
85
+ //#endregion
86
+ //#region src/types.d.ts
87
+ /**
88
+ * AsheeUI-specific overrides that can be spread into a `NextConfig`
89
+ * when calling {@link withAsheeUI}.
90
+ */
91
+ interface AsheeUIConfigOverrides {
92
+ /**
93
+ * Override the directory to look for `asheeui.config.*` in.
94
+ *
95
+ * Defaults to the project root (the directory containing
96
+ * `next.config.*`).
97
+ */
98
+ root?: string;
99
+ /**
100
+ * Extra packages appended to `transpilePackages`, deduped against the
101
+ * built-in AsheeUI package list.
102
+ */
103
+ transpilePackages?: string[];
104
+ }
105
+ /**
106
+ * The config object accepted by `withAsheeUI`: a standard `NextConfig`
107
+ * merged with AsheeUI overrides.
108
+ */
109
+ type WithAsheeUIConfig = NextConfig & AsheeUIConfigOverrides;
110
+ /**
111
+ * Structural view of the webpack config sections that AsheeUI patches.
112
+ *
113
+ * Kept deliberately minimal so this package does not need a webpack
114
+ * type dependency.
115
+ */
116
+ interface WebpackConfigPatch {
117
+ /** Webpack resolution options. */
118
+ resolve?: {
119
+ /** Module alias map. */
120
+ alias?: Record<string, string>;
121
+ };
122
+ /** Webpack plugins to append to. */
123
+ plugins?: WebpackPluginLike[];
124
+ }
125
+ /**
126
+ * Structural view of the compilation object passed to webpack's
127
+ * `afterCompile` hook.
128
+ */
129
+ interface WebpackCompilationLike {
130
+ /** Collector for files webpack should watch even when missing. */
131
+ missingDependencies: {
132
+ add: (path: string) => void;
133
+ };
134
+ }
135
+ /**
136
+ * Minimal structural view of a webpack plugin used by this package.
137
+ *
138
+ * Only the `apply` method and the `beforeCompile`/`afterCompile` hooks
139
+ * are modelled.
140
+ */
141
+ interface WebpackPluginLike {
142
+ /** Install the plugin onto the compiler. */
143
+ apply: (compiler: {
144
+ hooks: {
145
+ /** Fired before each compilation begins. */
146
+ beforeCompile: {
147
+ tap: (name: string, callback: () => void) => void;
148
+ };
149
+ /** Fired after each compilation finishes. */
150
+ afterCompile: {
151
+ tap: (name: string, callback: (compilation: WebpackCompilationLike) => void) => void;
152
+ };
153
+ };
154
+ }) => void;
155
+ }
156
+ /**
157
+ * Minimal structural view of the webpack context object passed to the
158
+ * `webpack` config function by Next.
159
+ */
160
+ interface WebpackContextLike {
161
+ /** `true` when Next is running a development build. */
162
+ dev: boolean;
163
+ }
164
+ //#endregion
165
+ //#region src/webpack.d.ts
166
+ /**
167
+ * Point `virtual:ashee-config` at the generated shim so app code keeps
168
+ * using the same import specifier as Vite.
169
+ *
170
+ * @param config - Webpack config section to patch (mutated in place).
171
+ * @param shimPath - Absolute path of the generated shim.
172
+ * @returns The same `config` object, with the alias registered.
173
+ *
174
+ * @example
175
+ * ```ts
176
+ * const config = addAsheeConfigAlias(
177
+ * { resolve: { alias: {} } },
178
+ * "/proj/.ashee/generated-config.mjs",
179
+ * );
180
+ * ```
181
+ */
182
+ declare function addAsheeConfigAlias(config: WebpackConfigPatch, shimPath: string): WebpackConfigPatch;
183
+ /**
184
+ * Create a dev-only webpack plugin that regenerates the shim before
185
+ * every compile so edits to an existing config file are always picked
186
+ * up.
187
+ *
188
+ * The plugin also registers every candidate filename as a webpack
189
+ * "missing dependency": the shim has no reference to a file that does
190
+ * not exist yet, so without this, *creating* the config file for the
191
+ * first time would never trigger a rebuild on its own. Writes are
192
+ * skipped when content is unchanged, keeping rebuilds cheap.
193
+ *
194
+ * @param regenerate - Callback that rewrites the shim file.
195
+ * @param candidatePaths - Absolute candidate config paths to watch as
196
+ * missing dependencies.
197
+ * @returns A webpack plugin object.
198
+ */
199
+ declare function createBeforeCompilePlugin(regenerate: () => void, candidatePaths: string[]): WebpackPluginLike;
200
+ /**
201
+ * Create the webpack hook that Next invokes when building.
202
+ *
203
+ * The returned hook always adds the config alias; in dev mode it also
204
+ * installs the `beforeCompile` regeneration plugin and the
205
+ * missing-dependency watcher.
206
+ *
207
+ * @param options - Hook options.
208
+ * @param options.shimPath - Absolute path of the generated shim.
209
+ * @param options.candidatePaths - Absolute candidate config paths.
210
+ * @param options.root - Project root used when regenerating the shim.
211
+ * @param options.regenerate - Function that regenerates the shim for a
212
+ * given root directory.
213
+ * @returns A webpack config hook matching Next's `webpack` signature.
214
+ */
215
+ declare function createWebpackHook(options: {
216
+ shimPath: string;
217
+ candidatePaths: string[];
218
+ root?: string;
219
+ regenerate: (root?: string) => string;
220
+ }): (config: WebpackConfigPatch, context: WebpackContextLike) => WebpackConfigPatch;
221
+ //#endregion
222
+ //#region src/with-ashee-ui.d.ts
223
+ /**
224
+ * Wrap a `next.config.mjs`/`next.config.ts` object with AsheeUI
225
+ * integration.
226
+ *
227
+ * The wrapper:
228
+ * 1. Generates a config shim at `.ashee/generated-config.mjs` (same
229
+ * resolution as `@asheeui/vite`'s `virtual:ashee-config`).
230
+ * 2. Adds a `virtual:ashee-config` alias for Webpack and Turbopack so
231
+ * app code uses the identical import specifier in both bundlers.
232
+ * Webpack gets an absolute path (it resolves against its own
233
+ * context, not the `root` override), Turbopack gets a
234
+ * project-root-relative one (it rejects absolute targets).
235
+ * 3. Merges `transpilePackages` so AsheeUI's source-shipping packages
236
+ * are compiled by Next.
237
+ *
238
+ * @param config - Next config to wrap. AsheeUI override keys (`root`,
239
+ * `transpilePackages`) are consumed and stripped from the returned
240
+ * `NextConfig`. Defaults to `{}`.
241
+ * @returns A plain `NextConfig` with the AsheeUI integration applied.
242
+ *
243
+ * @example
244
+ * ```ts
245
+ * // next.config.ts
246
+ * import { withAsheeUI } from "@asheeui/next";
247
+ *
248
+ * export default withAsheeUI({
249
+ * transpilePackages: ["@my-org/ui"],
250
+ * });
251
+ * ```
252
+ */
253
+ declare function withAsheeUI(config?: WithAsheeUIConfig): NextConfig;
254
+ //#endregion
255
+ export { AsheeUIConfigOverrides, SHIM_RELATIVE_PATH, TurbopackPatch, VIRTUAL_ID, WebpackCompilationLike, WebpackConfigPatch, WebpackContextLike, WebpackPluginLike, WithAsheeUIConfig, addAsheeConfigAlias, addAsheeConfigResolveAlias, createBeforeCompilePlugin, createWebpackHook, generateShim, resolveCandidatePaths, resolveShimPath, withAsheeUI };
256
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/generate.ts","../src/turbopack.ts","../src/types.ts","../src/webpack.ts","../src/with-ashee-ui.ts"],"mappings":";;;;;;;;;;cAYa;;;;;;;;;cAUA;;;;;;;iBAQG,gBAAgB;;;;;;;;;;;iBAchB,sBAAsB;;;;;;;;;;;;;iBAgCtB,aAAa;;;;;;;;;;UCnEZ;;EAEf,eAAe;;;;;;;;;;;;;;;;;;;;;iBAsBD,2BACd,QAAQ,gBACR,mBACC;;;;;;;UC9Bc;;;;;;;EAOf;;;;;EAKA;;;;;;KAOU,oBAAoB,aAAa;;;;;;;UAQ5B;;EAEf;;IAEE,QAAQ;;;EAGV,UAAU;;;;;;UAOK;;EAEf;IAAuB,MAAM;;;;;;;;;UASd;;EAEf,QAAQ;IACN;;MAEE;QACE,MAAM,cAAc;;;MAGtB;QACE,MACE,cACA,WAAW,aAAa;;;;;;;;;UAWjB;;EAEf;;;;;;;;;;;;;;;;;;;;iBCrDc,oBACd,QAAQ,oBACR,mBACC;;;;;;;;;;;;;;;;;iBAuBa,0BACd,wBACA,2BACC;;;;;;;;;;;;;;;;iBA8Ba,kBAAkB;EAChC;EACA;EACA;EACA,aAAa;KAEb,QAAQ,oBACR,SAAS,uBACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCxBW,YAAY,SAAQ,oBAAyB"}
@@ -0,0 +1,256 @@
1
+ import { NextConfig } from "next";
2
+ //#region src/generate.d.ts
3
+ /**
4
+ * The import specifier used across AsheeUI for the config module.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import config from "virtual:ashee-config";
9
+ * ```
10
+ */
11
+ declare const VIRTUAL_ID = "virtual:ashee-config";
12
+ /**
13
+ * Location of the generated shim, relative to the project root.
14
+ *
15
+ * Deliberately kept outside `node_modules`: package managers and CI
16
+ * treat `node_modules` as fully disposable, and a shim the dev server
17
+ * depends on should not live somewhere that can vanish out from under
18
+ * it.
19
+ */
20
+ declare const SHIM_RELATIVE_PATH = ".ashee/generated-config.mjs";
21
+ /**
22
+ * Resolve the absolute path of the generated shim for a project root.
23
+ *
24
+ * @param root - Project root directory. Defaults to `process.cwd()`.
25
+ * @returns Absolute path of the shim file.
26
+ */
27
+ declare function resolveShimPath(root?: string): string;
28
+ /**
29
+ * Resolve every candidate config filename to an absolute path under
30
+ * `root`, whether or not the files currently exist.
31
+ *
32
+ * These paths are registered as webpack "missing dependencies" so that
33
+ * creating a config file for the first time triggers a rebuild.
34
+ *
35
+ * @param root - Project root directory. Defaults to `process.cwd()`.
36
+ * @returns Absolute paths for every known config filename.
37
+ */
38
+ declare function resolveCandidatePaths(root?: string): string[];
39
+ /**
40
+ * Regenerate the config shim, mirroring `@asheeui/vite`'s virtual module:
41
+ * if a config file exists we re-export its default export, otherwise we
42
+ * export `undefined`.
43
+ *
44
+ * The write is skipped when the content is unchanged, so webpack's
45
+ * `beforeCompile` hook does not churn the file (or Turbopack's watcher)
46
+ * on every rebuild.
47
+ *
48
+ * @param root - Project root directory. Defaults to `process.cwd()`.
49
+ * @returns The absolute path of the regenerated shim file.
50
+ */
51
+ declare function generateShim(root?: string): string;
52
+ //#endregion
53
+ //#region src/turbopack.d.ts
54
+ /**
55
+ * The part of Next's Turbopack config that this package patches.
56
+ *
57
+ * Next exposes the same shape both at the stable `turbopack` key
58
+ * (`>= 15.1`) and at the deprecated `experimental.turbo` key, so one
59
+ * structural type covers both merge targets.
60
+ */
61
+ interface TurbopackPatch {
62
+ /** Alias map used to redirect module specifiers during resolution. */
63
+ resolveAlias?: Record<string, string>;
64
+ }
65
+ /**
66
+ * Point `virtual:ashee-config` at the generated shim inside a Turbopack
67
+ * config section.
68
+ *
69
+ * The given `target` object is mutated and then returned so the caller
70
+ * can use it in an inline expression.
71
+ *
72
+ * @param target - Turbopack config section (stable or experimental).
73
+ * @param shimPath - Project-root-relative path of the generated shim.
74
+ * @returns The same `target` object, with the alias registered.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * const turbopack = addAsheeConfigResolveAlias(
79
+ * { resolveAlias: {} },
80
+ * "./.ashee/generated-config.mjs",
81
+ * );
82
+ * ```
83
+ */
84
+ declare function addAsheeConfigResolveAlias(target: TurbopackPatch, shimPath: string): TurbopackPatch;
85
+ //#endregion
86
+ //#region src/types.d.ts
87
+ /**
88
+ * AsheeUI-specific overrides that can be spread into a `NextConfig`
89
+ * when calling {@link withAsheeUI}.
90
+ */
91
+ interface AsheeUIConfigOverrides {
92
+ /**
93
+ * Override the directory to look for `asheeui.config.*` in.
94
+ *
95
+ * Defaults to the project root (the directory containing
96
+ * `next.config.*`).
97
+ */
98
+ root?: string;
99
+ /**
100
+ * Extra packages appended to `transpilePackages`, deduped against the
101
+ * built-in AsheeUI package list.
102
+ */
103
+ transpilePackages?: string[];
104
+ }
105
+ /**
106
+ * The config object accepted by `withAsheeUI`: a standard `NextConfig`
107
+ * merged with AsheeUI overrides.
108
+ */
109
+ type WithAsheeUIConfig = NextConfig & AsheeUIConfigOverrides;
110
+ /**
111
+ * Structural view of the webpack config sections that AsheeUI patches.
112
+ *
113
+ * Kept deliberately minimal so this package does not need a webpack
114
+ * type dependency.
115
+ */
116
+ interface WebpackConfigPatch {
117
+ /** Webpack resolution options. */
118
+ resolve?: {
119
+ /** Module alias map. */
120
+ alias?: Record<string, string>;
121
+ };
122
+ /** Webpack plugins to append to. */
123
+ plugins?: WebpackPluginLike[];
124
+ }
125
+ /**
126
+ * Structural view of the compilation object passed to webpack's
127
+ * `afterCompile` hook.
128
+ */
129
+ interface WebpackCompilationLike {
130
+ /** Collector for files webpack should watch even when missing. */
131
+ missingDependencies: {
132
+ add: (path: string) => void;
133
+ };
134
+ }
135
+ /**
136
+ * Minimal structural view of a webpack plugin used by this package.
137
+ *
138
+ * Only the `apply` method and the `beforeCompile`/`afterCompile` hooks
139
+ * are modelled.
140
+ */
141
+ interface WebpackPluginLike {
142
+ /** Install the plugin onto the compiler. */
143
+ apply: (compiler: {
144
+ hooks: {
145
+ /** Fired before each compilation begins. */
146
+ beforeCompile: {
147
+ tap: (name: string, callback: () => void) => void;
148
+ };
149
+ /** Fired after each compilation finishes. */
150
+ afterCompile: {
151
+ tap: (name: string, callback: (compilation: WebpackCompilationLike) => void) => void;
152
+ };
153
+ };
154
+ }) => void;
155
+ }
156
+ /**
157
+ * Minimal structural view of the webpack context object passed to the
158
+ * `webpack` config function by Next.
159
+ */
160
+ interface WebpackContextLike {
161
+ /** `true` when Next is running a development build. */
162
+ dev: boolean;
163
+ }
164
+ //#endregion
165
+ //#region src/webpack.d.ts
166
+ /**
167
+ * Point `virtual:ashee-config` at the generated shim so app code keeps
168
+ * using the same import specifier as Vite.
169
+ *
170
+ * @param config - Webpack config section to patch (mutated in place).
171
+ * @param shimPath - Absolute path of the generated shim.
172
+ * @returns The same `config` object, with the alias registered.
173
+ *
174
+ * @example
175
+ * ```ts
176
+ * const config = addAsheeConfigAlias(
177
+ * { resolve: { alias: {} } },
178
+ * "/proj/.ashee/generated-config.mjs",
179
+ * );
180
+ * ```
181
+ */
182
+ declare function addAsheeConfigAlias(config: WebpackConfigPatch, shimPath: string): WebpackConfigPatch;
183
+ /**
184
+ * Create a dev-only webpack plugin that regenerates the shim before
185
+ * every compile so edits to an existing config file are always picked
186
+ * up.
187
+ *
188
+ * The plugin also registers every candidate filename as a webpack
189
+ * "missing dependency": the shim has no reference to a file that does
190
+ * not exist yet, so without this, *creating* the config file for the
191
+ * first time would never trigger a rebuild on its own. Writes are
192
+ * skipped when content is unchanged, keeping rebuilds cheap.
193
+ *
194
+ * @param regenerate - Callback that rewrites the shim file.
195
+ * @param candidatePaths - Absolute candidate config paths to watch as
196
+ * missing dependencies.
197
+ * @returns A webpack plugin object.
198
+ */
199
+ declare function createBeforeCompilePlugin(regenerate: () => void, candidatePaths: string[]): WebpackPluginLike;
200
+ /**
201
+ * Create the webpack hook that Next invokes when building.
202
+ *
203
+ * The returned hook always adds the config alias; in dev mode it also
204
+ * installs the `beforeCompile` regeneration plugin and the
205
+ * missing-dependency watcher.
206
+ *
207
+ * @param options - Hook options.
208
+ * @param options.shimPath - Absolute path of the generated shim.
209
+ * @param options.candidatePaths - Absolute candidate config paths.
210
+ * @param options.root - Project root used when regenerating the shim.
211
+ * @param options.regenerate - Function that regenerates the shim for a
212
+ * given root directory.
213
+ * @returns A webpack config hook matching Next's `webpack` signature.
214
+ */
215
+ declare function createWebpackHook(options: {
216
+ shimPath: string;
217
+ candidatePaths: string[];
218
+ root?: string;
219
+ regenerate: (root?: string) => string;
220
+ }): (config: WebpackConfigPatch, context: WebpackContextLike) => WebpackConfigPatch;
221
+ //#endregion
222
+ //#region src/with-ashee-ui.d.ts
223
+ /**
224
+ * Wrap a `next.config.mjs`/`next.config.ts` object with AsheeUI
225
+ * integration.
226
+ *
227
+ * The wrapper:
228
+ * 1. Generates a config shim at `.ashee/generated-config.mjs` (same
229
+ * resolution as `@asheeui/vite`'s `virtual:ashee-config`).
230
+ * 2. Adds a `virtual:ashee-config` alias for Webpack and Turbopack so
231
+ * app code uses the identical import specifier in both bundlers.
232
+ * Webpack gets an absolute path (it resolves against its own
233
+ * context, not the `root` override), Turbopack gets a
234
+ * project-root-relative one (it rejects absolute targets).
235
+ * 3. Merges `transpilePackages` so AsheeUI's source-shipping packages
236
+ * are compiled by Next.
237
+ *
238
+ * @param config - Next config to wrap. AsheeUI override keys (`root`,
239
+ * `transpilePackages`) are consumed and stripped from the returned
240
+ * `NextConfig`. Defaults to `{}`.
241
+ * @returns A plain `NextConfig` with the AsheeUI integration applied.
242
+ *
243
+ * @example
244
+ * ```ts
245
+ * // next.config.ts
246
+ * import { withAsheeUI } from "@asheeui/next";
247
+ *
248
+ * export default withAsheeUI({
249
+ * transpilePackages: ["@my-org/ui"],
250
+ * });
251
+ * ```
252
+ */
253
+ declare function withAsheeUI(config?: WithAsheeUIConfig): NextConfig;
254
+ //#endregion
255
+ export { AsheeUIConfigOverrides, SHIM_RELATIVE_PATH, TurbopackPatch, VIRTUAL_ID, WebpackCompilationLike, WebpackConfigPatch, WebpackContextLike, WebpackPluginLike, WithAsheeUIConfig, addAsheeConfigAlias, addAsheeConfigResolveAlias, createBeforeCompilePlugin, createWebpackHook, generateShim, resolveCandidatePaths, resolveShimPath, withAsheeUI };
256
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/generate.ts","../src/turbopack.ts","../src/types.ts","../src/webpack.ts","../src/with-ashee-ui.ts"],"mappings":";;;;;;;;;;cAYa;;;;;;;;;cAUA;;;;;;;iBAQG,gBAAgB;;;;;;;;;;;iBAchB,sBAAsB;;;;;;;;;;;;;iBAgCtB,aAAa;;;;;;;;;;UCnEZ;;EAEf,eAAe;;;;;;;;;;;;;;;;;;;;;iBAsBD,2BACd,QAAQ,gBACR,mBACC;;;;;;;UC9Bc;;;;;;;EAOf;;;;;EAKA;;;;;;KAOU,oBAAoB,aAAa;;;;;;;UAQ5B;;EAEf;;IAEE,QAAQ;;;EAGV,UAAU;;;;;;UAOK;;EAEf;IAAuB,MAAM;;;;;;;;;UASd;;EAEf,QAAQ;IACN;;MAEE;QACE,MAAM,cAAc;;;MAGtB;QACE,MACE,cACA,WAAW,aAAa;;;;;;;;;UAWjB;;EAEf;;;;;;;;;;;;;;;;;;;;iBCrDc,oBACd,QAAQ,oBACR,mBACC;;;;;;;;;;;;;;;;;iBAuBa,0BACd,wBACA,2BACC;;;;;;;;;;;;;;;;iBA8Ba,kBAAkB;EAChC;EACA;EACA;EACA,aAAa;KAEb,QAAQ,oBACR,SAAS,uBACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCxBW,YAAY,SAAQ,oBAAyB"}
package/dist/index.mjs ADDED
@@ -0,0 +1,282 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname, relative, resolve } from "node:path";
3
+ import { CANDIDATES, discoverConfig } from "@asheeui/utils/node";
4
+ //#region src/generate.ts
5
+ /**
6
+ * The import specifier used across AsheeUI for the config module.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import config from "virtual:ashee-config";
11
+ * ```
12
+ */
13
+ const VIRTUAL_ID = "virtual:ashee-config";
14
+ /**
15
+ * Location of the generated shim, relative to the project root.
16
+ *
17
+ * Deliberately kept outside `node_modules`: package managers and CI
18
+ * treat `node_modules` as fully disposable, and a shim the dev server
19
+ * depends on should not live somewhere that can vanish out from under
20
+ * it.
21
+ */
22
+ const SHIM_RELATIVE_PATH = ".ashee/generated-config.mjs";
23
+ /**
24
+ * Resolve the absolute path of the generated shim for a project root.
25
+ *
26
+ * @param root - Project root directory. Defaults to `process.cwd()`.
27
+ * @returns Absolute path of the shim file.
28
+ */
29
+ function resolveShimPath(root) {
30
+ return resolve(root ?? process.cwd(), SHIM_RELATIVE_PATH);
31
+ }
32
+ /**
33
+ * Resolve every candidate config filename to an absolute path under
34
+ * `root`, whether or not the files currently exist.
35
+ *
36
+ * These paths are registered as webpack "missing dependencies" so that
37
+ * creating a config file for the first time triggers a rebuild.
38
+ *
39
+ * @param root - Project root directory. Defaults to `process.cwd()`.
40
+ * @returns Absolute paths for every known config filename.
41
+ */
42
+ function resolveCandidatePaths(root) {
43
+ const base = root ?? process.cwd();
44
+ return CANDIDATES.map((file) => resolve(base, file));
45
+ }
46
+ /**
47
+ * Build an import specifier for `toFile` relative to `fromFile`'s directory.
48
+ *
49
+ * Turbopack rejects absolute ("server-relative") import specifiers, so the
50
+ * shim must reference the discovered config with a path relative to itself.
51
+ *
52
+ * @param fromFile - Absolute path of the importing file.
53
+ * @param toFile - Absolute path of the imported file.
54
+ * @returns A `./`-prefixed relative specifier.
55
+ */
56
+ function toRelativeSpecifier(fromFile, toFile) {
57
+ const rel = relative(dirname(fromFile), toFile).replaceAll("\\", "/");
58
+ return rel.startsWith(".") ? rel : `./${rel}`;
59
+ }
60
+ /**
61
+ * Regenerate the config shim, mirroring `@asheeui/vite`'s virtual module:
62
+ * if a config file exists we re-export its default export, otherwise we
63
+ * export `undefined`.
64
+ *
65
+ * The write is skipped when the content is unchanged, so webpack's
66
+ * `beforeCompile` hook does not churn the file (or Turbopack's watcher)
67
+ * on every rebuild.
68
+ *
69
+ * @param root - Project root directory. Defaults to `process.cwd()`.
70
+ * @returns The absolute path of the regenerated shim file.
71
+ */
72
+ function generateShim(root) {
73
+ const shimPath = resolveShimPath(root);
74
+ const configPath = discoverConfig(root);
75
+ const content = configPath ? `export { default } from ${JSON.stringify(toRelativeSpecifier(shimPath, configPath))};\n` : "export default undefined;\n";
76
+ if (!existsSync(shimPath) || readFileSync(shimPath, "utf8") !== content) {
77
+ mkdirSync(dirname(shimPath), { recursive: true });
78
+ writeFileSync(shimPath, content, "utf8");
79
+ }
80
+ return shimPath;
81
+ }
82
+ //#endregion
83
+ //#region src/turbopack.ts
84
+ /**
85
+ * Point `virtual:ashee-config` at the generated shim inside a Turbopack
86
+ * config section.
87
+ *
88
+ * The given `target` object is mutated and then returned so the caller
89
+ * can use it in an inline expression.
90
+ *
91
+ * @param target - Turbopack config section (stable or experimental).
92
+ * @param shimPath - Project-root-relative path of the generated shim.
93
+ * @returns The same `target` object, with the alias registered.
94
+ *
95
+ * @example
96
+ * ```ts
97
+ * const turbopack = addAsheeConfigResolveAlias(
98
+ * { resolveAlias: {} },
99
+ * "./.ashee/generated-config.mjs",
100
+ * );
101
+ * ```
102
+ */
103
+ function addAsheeConfigResolveAlias(target, shimPath) {
104
+ target.resolveAlias ??= {};
105
+ target.resolveAlias[VIRTUAL_ID] = shimPath;
106
+ return target;
107
+ }
108
+ //#endregion
109
+ //#region src/webpack.ts
110
+ /**
111
+ * Exact-match alias key (`$`-suffixed) so a hypothetical future
112
+ * `virtual:ashee-config/foo` import does not also resolve through this
113
+ * alias.
114
+ */
115
+ const EXACT_VIRTUAL_ID = `${VIRTUAL_ID}$`;
116
+ /**
117
+ * Point `virtual:ashee-config` at the generated shim so app code keeps
118
+ * using the same import specifier as Vite.
119
+ *
120
+ * @param config - Webpack config section to patch (mutated in place).
121
+ * @param shimPath - Absolute path of the generated shim.
122
+ * @returns The same `config` object, with the alias registered.
123
+ *
124
+ * @example
125
+ * ```ts
126
+ * const config = addAsheeConfigAlias(
127
+ * { resolve: { alias: {} } },
128
+ * "/proj/.ashee/generated-config.mjs",
129
+ * );
130
+ * ```
131
+ */
132
+ function addAsheeConfigAlias(config, shimPath) {
133
+ config.resolve ??= {};
134
+ config.resolve.alias ??= {};
135
+ config.resolve.alias[EXACT_VIRTUAL_ID] = shimPath;
136
+ return config;
137
+ }
138
+ /**
139
+ * Create a dev-only webpack plugin that regenerates the shim before
140
+ * every compile so edits to an existing config file are always picked
141
+ * up.
142
+ *
143
+ * The plugin also registers every candidate filename as a webpack
144
+ * "missing dependency": the shim has no reference to a file that does
145
+ * not exist yet, so without this, *creating* the config file for the
146
+ * first time would never trigger a rebuild on its own. Writes are
147
+ * skipped when content is unchanged, keeping rebuilds cheap.
148
+ *
149
+ * @param regenerate - Callback that rewrites the shim file.
150
+ * @param candidatePaths - Absolute candidate config paths to watch as
151
+ * missing dependencies.
152
+ * @returns A webpack plugin object.
153
+ */
154
+ function createBeforeCompilePlugin(regenerate, candidatePaths) {
155
+ return { apply(compiler) {
156
+ compiler.hooks.beforeCompile.tap("ashee:virtual-config", () => {
157
+ regenerate();
158
+ });
159
+ compiler.hooks.afterCompile.tap("ashee:virtual-config", (compilation) => {
160
+ for (const path of candidatePaths) compilation.missingDependencies.add(path);
161
+ });
162
+ } };
163
+ }
164
+ /**
165
+ * Create the webpack hook that Next invokes when building.
166
+ *
167
+ * The returned hook always adds the config alias; in dev mode it also
168
+ * installs the `beforeCompile` regeneration plugin and the
169
+ * missing-dependency watcher.
170
+ *
171
+ * @param options - Hook options.
172
+ * @param options.shimPath - Absolute path of the generated shim.
173
+ * @param options.candidatePaths - Absolute candidate config paths.
174
+ * @param options.root - Project root used when regenerating the shim.
175
+ * @param options.regenerate - Function that regenerates the shim for a
176
+ * given root directory.
177
+ * @returns A webpack config hook matching Next's `webpack` signature.
178
+ */
179
+ function createWebpackHook(options) {
180
+ const { shimPath, candidatePaths, regenerate, root } = options;
181
+ return (config, context) => {
182
+ addAsheeConfigAlias(config, shimPath);
183
+ if (context.dev) {
184
+ config.plugins ??= [];
185
+ config.plugins.push(createBeforeCompilePlugin(() => regenerate(root), candidatePaths));
186
+ }
187
+ return config;
188
+ };
189
+ }
190
+ //#endregion
191
+ //#region src/with-ashee-ui.ts
192
+ /**
193
+ * AsheeUI packages that ship TypeScript source and must be compiled by
194
+ * Next.
195
+ *
196
+ * `transpilePackages` takes npm package names, deduped against any the
197
+ * consumer provides.
198
+ */
199
+ const ASHEE_TRANSPILE_PACKAGES = ["asheeui"];
200
+ /**
201
+ * Wrap a `next.config.mjs`/`next.config.ts` object with AsheeUI
202
+ * integration.
203
+ *
204
+ * The wrapper:
205
+ * 1. Generates a config shim at `.ashee/generated-config.mjs` (same
206
+ * resolution as `@asheeui/vite`'s `virtual:ashee-config`).
207
+ * 2. Adds a `virtual:ashee-config` alias for Webpack and Turbopack so
208
+ * app code uses the identical import specifier in both bundlers.
209
+ * Webpack gets an absolute path (it resolves against its own
210
+ * context, not the `root` override), Turbopack gets a
211
+ * project-root-relative one (it rejects absolute targets).
212
+ * 3. Merges `transpilePackages` so AsheeUI's source-shipping packages
213
+ * are compiled by Next.
214
+ *
215
+ * @param config - Next config to wrap. AsheeUI override keys (`root`,
216
+ * `transpilePackages`) are consumed and stripped from the returned
217
+ * `NextConfig`. Defaults to `{}`.
218
+ * @returns A plain `NextConfig` with the AsheeUI integration applied.
219
+ *
220
+ * @example
221
+ * ```ts
222
+ * // next.config.ts
223
+ * import { withAsheeUI } from "@asheeui/next";
224
+ *
225
+ * export default withAsheeUI({
226
+ * transpilePackages: ["@my-org/ui"],
227
+ * });
228
+ * ```
229
+ */
230
+ function withAsheeUI(config = {}) {
231
+ const { root, transpilePackages: extraTranspilePackages, ...nextConfig } = config;
232
+ const baseDir = root ?? process.cwd();
233
+ const legacyConfig = nextConfig;
234
+ generateShim(baseDir);
235
+ const absoluteShimPath = resolveShimPath(baseDir);
236
+ const relativeShimPath = `./${SHIM_RELATIVE_PATH}`;
237
+ const candidatePaths = resolveCandidatePaths(baseDir);
238
+ const transpilePackages = [.../* @__PURE__ */ new Set([
239
+ ...ASHEE_TRANSPILE_PACKAGES,
240
+ ...legacyConfig.transpilePackages ?? [],
241
+ ...extraTranspilePackages ?? []
242
+ ])];
243
+ const userWebpack = nextConfig.webpack;
244
+ const webpack = ((config, context) => {
245
+ const patchConfig = config;
246
+ const patchContext = context;
247
+ const hook = createWebpackHook({
248
+ shimPath: absoluteShimPath,
249
+ candidatePaths,
250
+ root: baseDir,
251
+ regenerate: generateShim
252
+ });
253
+ if (userWebpack) return hook(userWebpack(patchConfig, patchContext), patchContext);
254
+ return hook(patchConfig, patchContext);
255
+ });
256
+ const turbopackResolveAlias = {
257
+ ...nextConfig.turbopack?.resolveAlias ?? {},
258
+ [VIRTUAL_ID]: relativeShimPath
259
+ };
260
+ const turbopack = {
261
+ ...nextConfig.turbopack,
262
+ resolveAlias: turbopackResolveAlias
263
+ };
264
+ const patchedConfig = {
265
+ ...nextConfig,
266
+ transpilePackages,
267
+ webpack,
268
+ turbopack
269
+ };
270
+ if (legacyConfig.experimental?.turbo) {
271
+ const turboPatch = addAsheeConfigResolveAlias(legacyConfig.experimental.turbo, relativeShimPath);
272
+ patchedConfig.experimental = {
273
+ ...nextConfig.experimental,
274
+ turbo: turboPatch
275
+ };
276
+ }
277
+ return patchedConfig;
278
+ }
279
+ //#endregion
280
+ export { SHIM_RELATIVE_PATH, VIRTUAL_ID, addAsheeConfigAlias, addAsheeConfigResolveAlias, createBeforeCompilePlugin, createWebpackHook, generateShim, resolveCandidatePaths, resolveShimPath, withAsheeUI };
281
+
282
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/generate.ts","../src/turbopack.ts","../src/webpack.ts","../src/with-ashee-ui.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, relative, resolve } from \"node:path\";\nimport { CANDIDATES, discoverConfig } from \"@asheeui/utils/node\";\n\n/**\n * The import specifier used across AsheeUI for the config module.\n *\n * @example\n * ```ts\n * import config from \"virtual:ashee-config\";\n * ```\n */\nexport const VIRTUAL_ID = \"virtual:ashee-config\";\n\n/**\n * Location of the generated shim, relative to the project root.\n *\n * Deliberately kept outside `node_modules`: package managers and CI\n * treat `node_modules` as fully disposable, and a shim the dev server\n * depends on should not live somewhere that can vanish out from under\n * it.\n */\nexport const SHIM_RELATIVE_PATH = \".ashee/generated-config.mjs\";\n\n/**\n * Resolve the absolute path of the generated shim for a project root.\n *\n * @param root - Project root directory. Defaults to `process.cwd()`.\n * @returns Absolute path of the shim file.\n */\nexport function resolveShimPath(root?: string): string {\n return resolve(root ?? process.cwd(), SHIM_RELATIVE_PATH);\n}\n\n/**\n * Resolve every candidate config filename to an absolute path under\n * `root`, whether or not the files currently exist.\n *\n * These paths are registered as webpack \"missing dependencies\" so that\n * creating a config file for the first time triggers a rebuild.\n *\n * @param root - Project root directory. Defaults to `process.cwd()`.\n * @returns Absolute paths for every known config filename.\n */\nexport function resolveCandidatePaths(root?: string): string[] {\n const base = root ?? process.cwd();\n return CANDIDATES.map((file) => resolve(base, file));\n}\n\n/**\n * Build an import specifier for `toFile` relative to `fromFile`'s directory.\n *\n * Turbopack rejects absolute (\"server-relative\") import specifiers, so the\n * shim must reference the discovered config with a path relative to itself.\n *\n * @param fromFile - Absolute path of the importing file.\n * @param toFile - Absolute path of the imported file.\n * @returns A `./`-prefixed relative specifier.\n */\nfunction toRelativeSpecifier(fromFile: string, toFile: string): string {\n const rel = relative(dirname(fromFile), toFile).replaceAll(\"\\\\\", \"/\");\n return rel.startsWith(\".\") ? rel : `./${rel}`;\n}\n\n/**\n * Regenerate the config shim, mirroring `@asheeui/vite`'s virtual module:\n * if a config file exists we re-export its default export, otherwise we\n * export `undefined`.\n *\n * The write is skipped when the content is unchanged, so webpack's\n * `beforeCompile` hook does not churn the file (or Turbopack's watcher)\n * on every rebuild.\n *\n * @param root - Project root directory. Defaults to `process.cwd()`.\n * @returns The absolute path of the regenerated shim file.\n */\nexport function generateShim(root?: string): string {\n const shimPath = resolveShimPath(root);\n const configPath = discoverConfig(root);\n\n const content = configPath\n ? `export { default } from ${JSON.stringify(\n toRelativeSpecifier(shimPath, configPath),\n )};\\n`\n : \"export default undefined;\\n\";\n\n if (!existsSync(shimPath) || readFileSync(shimPath, \"utf8\") !== content) {\n mkdirSync(dirname(shimPath), { recursive: true });\n writeFileSync(shimPath, content, \"utf8\");\n }\n\n return shimPath;\n}\n","import { VIRTUAL_ID } from \"./generate\";\n\n/**\n * The part of Next's Turbopack config that this package patches.\n *\n * Next exposes the same shape both at the stable `turbopack` key\n * (`>= 15.1`) and at the deprecated `experimental.turbo` key, so one\n * structural type covers both merge targets.\n */\nexport interface TurbopackPatch {\n /** Alias map used to redirect module specifiers during resolution. */\n resolveAlias?: Record<string, string>;\n}\n\n/**\n * Point `virtual:ashee-config` at the generated shim inside a Turbopack\n * config section.\n *\n * The given `target` object is mutated and then returned so the caller\n * can use it in an inline expression.\n *\n * @param target - Turbopack config section (stable or experimental).\n * @param shimPath - Project-root-relative path of the generated shim.\n * @returns The same `target` object, with the alias registered.\n *\n * @example\n * ```ts\n * const turbopack = addAsheeConfigResolveAlias(\n * { resolveAlias: {} },\n * \"./.ashee/generated-config.mjs\",\n * );\n * ```\n */\nexport function addAsheeConfigResolveAlias(\n target: TurbopackPatch,\n shimPath: string,\n): TurbopackPatch {\n target.resolveAlias ??= {};\n target.resolveAlias[VIRTUAL_ID] = shimPath;\n return target;\n}\n","import { VIRTUAL_ID } from \"./generate\";\nimport type {\n WebpackConfigPatch,\n WebpackContextLike,\n WebpackPluginLike,\n} from \"./types\";\n\n/**\n * Exact-match alias key (`$`-suffixed) so a hypothetical future\n * `virtual:ashee-config/foo` import does not also resolve through this\n * alias.\n */\nconst EXACT_VIRTUAL_ID = `${VIRTUAL_ID}$`;\n\n/**\n * Point `virtual:ashee-config` at the generated shim so app code keeps\n * using the same import specifier as Vite.\n *\n * @param config - Webpack config section to patch (mutated in place).\n * @param shimPath - Absolute path of the generated shim.\n * @returns The same `config` object, with the alias registered.\n *\n * @example\n * ```ts\n * const config = addAsheeConfigAlias(\n * { resolve: { alias: {} } },\n * \"/proj/.ashee/generated-config.mjs\",\n * );\n * ```\n */\nexport function addAsheeConfigAlias(\n config: WebpackConfigPatch,\n shimPath: string,\n): WebpackConfigPatch {\n config.resolve ??= {};\n config.resolve.alias ??= {};\n config.resolve.alias[EXACT_VIRTUAL_ID] = shimPath;\n return config;\n}\n\n/**\n * Create a dev-only webpack plugin that regenerates the shim before\n * every compile so edits to an existing config file are always picked\n * up.\n *\n * The plugin also registers every candidate filename as a webpack\n * \"missing dependency\": the shim has no reference to a file that does\n * not exist yet, so without this, *creating* the config file for the\n * first time would never trigger a rebuild on its own. Writes are\n * skipped when content is unchanged, keeping rebuilds cheap.\n *\n * @param regenerate - Callback that rewrites the shim file.\n * @param candidatePaths - Absolute candidate config paths to watch as\n * missing dependencies.\n * @returns A webpack plugin object.\n */\nexport function createBeforeCompilePlugin(\n regenerate: () => void,\n candidatePaths: string[],\n): WebpackPluginLike {\n return {\n apply(compiler) {\n compiler.hooks.beforeCompile.tap(\"ashee:virtual-config\", () => {\n regenerate();\n });\n compiler.hooks.afterCompile.tap(\"ashee:virtual-config\", (compilation) => {\n for (const path of candidatePaths) {\n compilation.missingDependencies.add(path);\n }\n });\n },\n };\n}\n\n/**\n * Create the webpack hook that Next invokes when building.\n *\n * The returned hook always adds the config alias; in dev mode it also\n * installs the `beforeCompile` regeneration plugin and the\n * missing-dependency watcher.\n *\n * @param options - Hook options.\n * @param options.shimPath - Absolute path of the generated shim.\n * @param options.candidatePaths - Absolute candidate config paths.\n * @param options.root - Project root used when regenerating the shim.\n * @param options.regenerate - Function that regenerates the shim for a\n * given root directory.\n * @returns A webpack config hook matching Next's `webpack` signature.\n */\nexport function createWebpackHook(options: {\n shimPath: string;\n candidatePaths: string[];\n root?: string;\n regenerate: (root?: string) => string;\n}): (\n config: WebpackConfigPatch,\n context: WebpackContextLike,\n) => WebpackConfigPatch {\n const { shimPath, candidatePaths, regenerate, root } = options;\n\n return (config, context) => {\n addAsheeConfigAlias(config, shimPath);\n\n if (context.dev) {\n config.plugins ??= [];\n config.plugins.push(\n createBeforeCompilePlugin(() => regenerate(root), candidatePaths),\n );\n }\n\n return config;\n };\n}\n","import type { NextConfig } from \"next\";\nimport {\n generateShim,\n resolveCandidatePaths,\n resolveShimPath,\n SHIM_RELATIVE_PATH,\n VIRTUAL_ID,\n} from \"./generate\";\nimport type { TurbopackPatch } from \"./turbopack\";\nimport { addAsheeConfigResolveAlias } from \"./turbopack\";\nimport type {\n WebpackConfigPatch,\n WebpackContextLike,\n WithAsheeUIConfig,\n} from \"./types\";\nimport { createWebpackHook } from \"./webpack\";\n\n/**\n * AsheeUI packages that ship TypeScript source and must be compiled by\n * Next.\n *\n * `transpilePackages` takes npm package names, deduped against any the\n * consumer provides.\n */\nconst ASHEE_TRANSPILE_PACKAGES = [\"asheeui\"];\n\ntype NextWebpack = NonNullable<NextConfig[\"webpack\"]>;\n\n/**\n * Structural superset of `NextConfig` used to reach legacy keys.\n *\n * Next 15 kept `transpilePackages` on `NextConfig` and Turbopack behind\n * `experimental.turbo`; Next 16 removed both (Turbopack is the default).\n * This superset lets one code path type-check against either major\n * version of the peer dependency.\n */\ntype LegacyNextConfig = NextConfig & {\n transpilePackages?: string[];\n experimental?: {\n turbo?: unknown;\n };\n};\n\n/**\n * Wrap a `next.config.mjs`/`next.config.ts` object with AsheeUI\n * integration.\n *\n * The wrapper:\n * 1. Generates a config shim at `.ashee/generated-config.mjs` (same\n * resolution as `@asheeui/vite`'s `virtual:ashee-config`).\n * 2. Adds a `virtual:ashee-config` alias for Webpack and Turbopack so\n * app code uses the identical import specifier in both bundlers.\n * Webpack gets an absolute path (it resolves against its own\n * context, not the `root` override), Turbopack gets a\n * project-root-relative one (it rejects absolute targets).\n * 3. Merges `transpilePackages` so AsheeUI's source-shipping packages\n * are compiled by Next.\n *\n * @param config - Next config to wrap. AsheeUI override keys (`root`,\n * `transpilePackages`) are consumed and stripped from the returned\n * `NextConfig`. Defaults to `{}`.\n * @returns A plain `NextConfig` with the AsheeUI integration applied.\n *\n * @example\n * ```ts\n * // next.config.ts\n * import { withAsheeUI } from \"@asheeui/next\";\n *\n * export default withAsheeUI({\n * transpilePackages: [\"@my-org/ui\"],\n * });\n * ```\n */\nexport function withAsheeUI(config: WithAsheeUIConfig = {}): NextConfig {\n const {\n root,\n transpilePackages: extraTranspilePackages,\n ...nextConfig\n } = config;\n\n const baseDir = root ?? process.cwd();\n\n // Read-only access to config keys that only exist on Next 15.\n const legacyConfig = nextConfig as LegacyNextConfig;\n\n generateShim(baseDir);\n\n const absoluteShimPath = resolveShimPath(baseDir);\n const relativeShimPath = `./${SHIM_RELATIVE_PATH}`;\n const candidatePaths = resolveCandidatePaths(baseDir);\n\n const transpilePackages = [\n ...new Set([\n ...ASHEE_TRANSPILE_PACKAGES,\n ...(legacyConfig.transpilePackages ?? []),\n ...(extraTranspilePackages ?? []),\n ]),\n ];\n\n const userWebpack = nextConfig.webpack;\n\n const webpack: NextWebpack = ((config, context) => {\n const patchConfig = config as unknown as WebpackConfigPatch;\n const patchContext = context as unknown as WebpackContextLike;\n\n const hook = createWebpackHook({\n shimPath: absoluteShimPath,\n candidatePaths,\n root: baseDir,\n regenerate: generateShim,\n });\n\n if (userWebpack) {\n const userResult = userWebpack(\n patchConfig as never,\n patchContext as never,\n );\n return hook(userResult as WebpackConfigPatch, patchContext) as never;\n }\n\n return hook(patchConfig, patchContext) as never;\n }) as NextWebpack;\n\n // Turbopack: patch the stable key, and also the experimental fallback\n // if the consumer configured it on an older Next 15.x.\n const turbopackResolveAlias: Record<string, string> = {\n ...(nextConfig.turbopack?.resolveAlias ?? {}),\n [VIRTUAL_ID]: relativeShimPath,\n };\n\n const turbopack = {\n ...nextConfig.turbopack,\n resolveAlias: turbopackResolveAlias,\n };\n\n const patchedConfig: NextConfig = {\n ...nextConfig,\n transpilePackages,\n webpack,\n turbopack,\n };\n\n if (legacyConfig.experimental?.turbo) {\n const turboPatch = addAsheeConfigResolveAlias(\n legacyConfig.experimental.turbo as TurbopackPatch,\n relativeShimPath,\n ) as never;\n patchedConfig.experimental = {\n ...nextConfig.experimental,\n turbo: turboPatch,\n } as NextConfig[\"experimental\"];\n }\n\n return patchedConfig;\n}\n"],"mappings":";;;;;;;;;;;;AAYA,MAAa,aAAa;;;;;;;;;AAU1B,MAAa,qBAAqB;;;;;;;AAQlC,SAAgB,gBAAgB,MAAuB;CACrD,OAAO,QAAQ,QAAQ,QAAQ,IAAI,GAAG,kBAAkB;AAC1D;;;;;;;;;;;AAYA,SAAgB,sBAAsB,MAAyB;CAC7D,MAAM,OAAO,QAAQ,QAAQ,IAAI;CACjC,OAAO,WAAW,KAAK,SAAS,QAAQ,MAAM,IAAI,CAAC;AACrD;;;;;;;;;;;AAYA,SAAS,oBAAoB,UAAkB,QAAwB;CACrE,MAAM,MAAM,SAAS,QAAQ,QAAQ,GAAG,MAAM,CAAC,CAAC,WAAW,MAAM,GAAG;CACpE,OAAO,IAAI,WAAW,GAAG,IAAI,MAAM,KAAK;AAC1C;;;;;;;;;;;;;AAcA,SAAgB,aAAa,MAAuB;CAClD,MAAM,WAAW,gBAAgB,IAAI;CACrC,MAAM,aAAa,eAAe,IAAI;CAEtC,MAAM,UAAU,aACZ,2BAA2B,KAAK,UAC9B,oBAAoB,UAAU,UAAU,CAC1C,EAAE,OACF;CAEJ,IAAI,CAAC,WAAW,QAAQ,KAAK,aAAa,UAAU,MAAM,MAAM,SAAS;EACvE,UAAU,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;EAChD,cAAc,UAAU,SAAS,MAAM;CACzC;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;AC3DA,SAAgB,2BACd,QACA,UACgB;CAChB,OAAO,iBAAiB,CAAC;CACzB,OAAO,aAAa,cAAc;CAClC,OAAO;AACT;;;;;;;;AC5BA,MAAM,mBAAmB,GAAG,WAAW;;;;;;;;;;;;;;;;;AAkBvC,SAAgB,oBACd,QACA,UACoB;CACpB,OAAO,YAAY,CAAC;CACpB,OAAO,QAAQ,UAAU,CAAC;CAC1B,OAAO,QAAQ,MAAM,oBAAoB;CACzC,OAAO;AACT;;;;;;;;;;;;;;;;;AAkBA,SAAgB,0BACd,YACA,gBACmB;CACnB,OAAO,EACL,MAAM,UAAU;EACd,SAAS,MAAM,cAAc,IAAI,8BAA8B;GAC7D,WAAW;EACb,CAAC;EACD,SAAS,MAAM,aAAa,IAAI,yBAAyB,gBAAgB;GACvE,KAAK,MAAM,QAAQ,gBACjB,YAAY,oBAAoB,IAAI,IAAI;EAE5C,CAAC;CACH,EACF;AACF;;;;;;;;;;;;;;;;AAiBA,SAAgB,kBAAkB,SAQV;CACtB,MAAM,EAAE,UAAU,gBAAgB,YAAY,SAAS;CAEvD,QAAQ,QAAQ,YAAY;EAC1B,oBAAoB,QAAQ,QAAQ;EAEpC,IAAI,QAAQ,KAAK;GACf,OAAO,YAAY,CAAC;GACpB,OAAO,QAAQ,KACb,gCAAgC,WAAW,IAAI,GAAG,cAAc,CAClE;EACF;EAEA,OAAO;CACT;AACF;;;;;;;;;;ACxFA,MAAM,2BAA2B,CAAC,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiD3C,SAAgB,YAAY,SAA4B,CAAC,GAAe;CACtE,MAAM,EACJ,MACA,mBAAmB,wBACnB,GAAG,eACD;CAEJ,MAAM,UAAU,QAAQ,QAAQ,IAAI;CAGpC,MAAM,eAAe;CAErB,aAAa,OAAO;CAEpB,MAAM,mBAAmB,gBAAgB,OAAO;CAChD,MAAM,mBAAmB,KAAK;CAC9B,MAAM,iBAAiB,sBAAsB,OAAO;CAEpD,MAAM,oBAAoB,CACxB,mBAAG,IAAI,IAAI;EACT,GAAG;EACH,GAAI,aAAa,qBAAqB,CAAC;EACvC,GAAI,0BAA0B,CAAC;CACjC,CAAC,CACH;CAEA,MAAM,cAAc,WAAW;CAE/B,MAAM,YAAyB,QAAQ,YAAY;EACjD,MAAM,cAAc;EACpB,MAAM,eAAe;EAErB,MAAM,OAAO,kBAAkB;GAC7B,UAAU;GACV;GACA,MAAM;GACN,YAAY;EACd,CAAC;EAED,IAAI,aAKF,OAAO,KAJY,YACjB,aACA,YAEmB,GAAyB,YAAY;EAG5D,OAAO,KAAK,aAAa,YAAY;CACvC;CAIA,MAAM,wBAAgD;EACpD,GAAI,WAAW,WAAW,gBAAgB,CAAC;GAC1C,aAAa;CAChB;CAEA,MAAM,YAAY;EAChB,GAAG,WAAW;EACd,cAAc;CAChB;CAEA,MAAM,gBAA4B;EAChC,GAAG;EACH;EACA;EACA;CACF;CAEA,IAAI,aAAa,cAAc,OAAO;EACpC,MAAM,aAAa,2BACjB,aAAa,aAAa,OAC1B,gBACF;EACA,cAAc,eAAe;GAC3B,GAAG,WAAW;GACd,OAAO;EACT;CACF;CAEA,OAAO;AACT"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@asheeui/next",
3
+ "version": "0.3.1",
4
+ "type": "module",
5
+ "main": "./dist/index.cjs",
6
+ "types": "./dist/index.d.mts",
7
+ "exports": {
8
+ ".": {
9
+ "import": {
10
+ "types": "./dist/index.d.mts",
11
+ "default": "./dist/index.mjs"
12
+ },
13
+ "require": {
14
+ "types": "./dist/index.d.cts",
15
+ "default": "./dist/index.cjs"
16
+ }
17
+ }
18
+ },
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "dependencies": {
23
+ "@asheeui/utils": "0.3.0"
24
+ },
25
+ "peerDependencies": {
26
+ "next": "^16.0.0",
27
+ "asheeui": "0.5.0"
28
+ },
29
+ "peerDependenciesMeta": {
30
+ "asheeui": {
31
+ "optional": true
32
+ }
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^26.1.2",
36
+ "next": "16.3.1",
37
+ "tsdown": "^0.22.14",
38
+ "typescript": "^5.0.0"
39
+ },
40
+ "license": "MIT",
41
+ "scripts": {
42
+ "build": "tsdown src/index.ts --format esm,cjs --dts --clean",
43
+ "dev": "tsdown src/index.ts --format esm,cjs --dts --watch"
44
+ },
45
+ "module": "./dist/index.mjs"
46
+ }