@shortwind/next 0.1.0-beta.10 → 0.1.0-beta.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/dist/index.d.ts +5 -27
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +67 -6
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +3 -0
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +44 -4
- package/dist/loader.js.map +1 -1
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -12,15 +12,19 @@ npm i -D @shortwind/next@beta @shortwind/cli@beta
|
|
|
12
12
|
|
|
13
13
|
## Usage
|
|
14
14
|
|
|
15
|
-
Wrap your Next config
|
|
15
|
+
Wrap your Next config. `withShortwind` is curried — the first call takes
|
|
16
|
+
Shortwind options (usually none), the second your Next config:
|
|
16
17
|
|
|
17
18
|
```ts
|
|
18
19
|
// next.config.ts
|
|
20
|
+
import type { NextConfig } from "next";
|
|
19
21
|
import { withShortwind } from "@shortwind/next";
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
const nextConfig: NextConfig = {
|
|
22
24
|
// your Next config
|
|
23
|
-
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default withShortwind()(nextConfig);
|
|
24
28
|
```
|
|
25
29
|
|
|
26
30
|
Reads recipes from `./recipes/`. Run `npx @shortwind/cli@beta init` first to scaffold the catalog, theme, and `SKILL.md`.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,35 +1,13 @@
|
|
|
1
|
+
import type { NextConfig } from "next";
|
|
1
2
|
export type ShortwindNextOptions = {
|
|
2
3
|
recipesDir?: string;
|
|
3
4
|
cwd?: string;
|
|
4
|
-
|
|
5
|
-
type WebpackConfig = {
|
|
6
|
-
module?: {
|
|
7
|
-
rules?: unknown[];
|
|
8
|
-
};
|
|
9
|
-
[k: string]: unknown;
|
|
10
|
-
};
|
|
11
|
-
type WebpackContext = {
|
|
12
|
-
dev: boolean;
|
|
13
|
-
isServer: boolean;
|
|
14
|
-
};
|
|
15
|
-
type TurbopackRule = {
|
|
16
|
-
loaders: Array<{
|
|
17
|
-
loader: string;
|
|
18
|
-
options?: unknown;
|
|
19
|
-
}>;
|
|
20
|
-
[k: string]: unknown;
|
|
21
|
-
};
|
|
22
|
-
type TurbopackConfig = {
|
|
23
|
-
rules?: Record<string, TurbopackRule>;
|
|
24
|
-
[k: string]: unknown;
|
|
25
|
-
};
|
|
26
|
-
type NextConfig = {
|
|
27
|
-
webpack?: (config: WebpackConfig, ctx: WebpackContext) => WebpackConfig;
|
|
28
|
-
turbopack?: TurbopackConfig;
|
|
29
|
-
experimental?: Record<string, unknown>;
|
|
30
|
-
[k: string]: unknown;
|
|
5
|
+
strict?: boolean;
|
|
31
6
|
};
|
|
32
7
|
export declare function withShortwind(options?: ShortwindNextOptions): (nextConfig?: NextConfig) => NextConfig;
|
|
33
8
|
export { default as shortwindLoader } from "./loader.js";
|
|
34
9
|
export type { ShortwindLoaderOptions } from "./loader.js";
|
|
10
|
+
export { expandClassList } from "@shortwind/core";
|
|
11
|
+
export { loadRegistryFromDir } from "@shortwind/tailwind";
|
|
12
|
+
export type { Registry } from "@shortwind/core";
|
|
35
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAEvC,MAAM,MAAM,oBAAoB,GAAG;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IAKb,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAcF,wBAAgB,aAAa,CAC3B,OAAO,GAAE,oBAAyB,GACjC,CAAC,UAAU,CAAC,EAAE,UAAU,KAAK,UAAU,CAuDzC;AAyCD,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAO1D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,YAAY,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { detectTailwindMajor, findTailwindEntryCssFiles, loadRegistryFromDir, syncSourceDirectiveToFile, TailwindAdapterError, } from "@shortwind/tailwind";
|
|
3
4
|
import { clearRegistryCache } from "./loader.js";
|
|
4
5
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
5
6
|
// Resolves to the compiled ESM sibling. If we ever ship a dual CJS/ESM build,
|
|
@@ -9,13 +10,28 @@ const SOURCE_TEST = /\.(?:tsx?|jsx?|mdx?)$/;
|
|
|
9
10
|
export function withShortwind(options = {}) {
|
|
10
11
|
const cwd = options.cwd ?? process.cwd();
|
|
11
12
|
const recipesDir = options.recipesDir ?? path.join(cwd, "recipes");
|
|
13
|
+
// Recipe expansions exist only in loader output, which Tailwind never sees:
|
|
14
|
+
// in Next, Tailwind v4 reads the entry CSS FROM DISK (PostCSS/Turbopack) and
|
|
15
|
+
// scans on-disk sources — there is no CSS pipeline hook equivalent to Vite's
|
|
16
|
+
// load phase. So the registry-derived `@source inline(...)` safelist must
|
|
17
|
+
// live on disk too (#73). next.config is evaluated at the start of every
|
|
18
|
+
// `next dev`/`next build`, which makes this the reliable sync point for both
|
|
19
|
+
// bundlers; the loader refreshes the same files when recipes change
|
|
20
|
+
// mid-session (see loader.ts).
|
|
21
|
+
const entryCss = syncSafelist(cwd, recipesDir);
|
|
12
22
|
return (nextConfig = {}) => {
|
|
13
|
-
const loaderOptions = { recipesDir };
|
|
23
|
+
const loaderOptions = { recipesDir, strict: options.strict ?? false, entryCss };
|
|
14
24
|
const previousWebpack = nextConfig.webpack;
|
|
15
25
|
const wrapped = {
|
|
16
26
|
...nextConfig,
|
|
27
|
+
// Next types the hook's config as `any`; narrow it locally to the slice
|
|
28
|
+
// we touch and let `ctx` take its contextual WebpackConfigContext type.
|
|
29
|
+
// The truthy guard also covers `webpack: null`, which Next's config type
|
|
30
|
+
// explicitly allows.
|
|
17
31
|
webpack(config, ctx) {
|
|
18
|
-
const next = previousWebpack
|
|
32
|
+
const next = previousWebpack
|
|
33
|
+
? previousWebpack(config, ctx)
|
|
34
|
+
: config;
|
|
19
35
|
next.module ??= {};
|
|
20
36
|
next.module.rules ??= [];
|
|
21
37
|
const rule = {
|
|
@@ -33,10 +49,10 @@ export function withShortwind(options = {}) {
|
|
|
33
49
|
const turbo = nextConfig.turbopack ?? {};
|
|
34
50
|
const rules = { ...(turbo.rules ?? {}) };
|
|
35
51
|
// Asymmetry vs the webpack rule's `exclude: /node_modules/`: Turbopack rule
|
|
36
|
-
// keys are globs with no negation syntax, so a node_modules exclude can't
|
|
37
|
-
// expressed here
|
|
38
|
-
// node_modules
|
|
39
|
-
//
|
|
52
|
+
// keys are globs with no negation syntax, so a node_modules exclude can't
|
|
53
|
+
// be expressed here — and Next 16's Turbopack DOES apply custom loader
|
|
54
|
+
// rules to node_modules. The loader itself skips vendored paths (#75), so
|
|
55
|
+
// dependency files pass through untransformed and unscanned.
|
|
40
56
|
rules["*.{tsx,ts,jsx,js,mdx,md}"] = {
|
|
41
57
|
loaders: [{ loader: LOADER_PATH, options: loaderOptions }],
|
|
42
58
|
};
|
|
@@ -44,5 +60,50 @@ export function withShortwind(options = {}) {
|
|
|
44
60
|
return wrapped;
|
|
45
61
|
};
|
|
46
62
|
}
|
|
63
|
+
// Upsert the safelist into every Tailwind v4 entry stylesheet. Failures are
|
|
64
|
+
// reported, never thrown — a broken recipe or a read-only filesystem must not
|
|
65
|
+
// take down config evaluation (the loader will surface recipe errors with
|
|
66
|
+
// proper module attribution).
|
|
67
|
+
function syncSafelist(cwd, recipesDir) {
|
|
68
|
+
try {
|
|
69
|
+
const registry = loadRegistryFromDir(recipesDir);
|
|
70
|
+
const files = findTailwindEntryCssFiles(cwd);
|
|
71
|
+
if (Object.keys(registry.flattened).length > 0 && files.length === 0 && isTailwind4(cwd)) {
|
|
72
|
+
console.warn(`[shortwind] no Tailwind entry CSS found under ${cwd} (a .css with @import "tailwindcss") — ` +
|
|
73
|
+
`recipe-only utilities won't reach Tailwind's generator and will render unstyled`);
|
|
74
|
+
}
|
|
75
|
+
for (const file of files) {
|
|
76
|
+
try {
|
|
77
|
+
syncSourceDirectiveToFile(file, registry);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
console.warn(`[shortwind] could not write safelist to ${file}: ${String(err)}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return files;
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
if (err instanceof TailwindAdapterError) {
|
|
87
|
+
console.error(`[shortwind] ${err.message}`);
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function isTailwind4(cwd) {
|
|
94
|
+
try {
|
|
95
|
+
return detectTailwindMajor(cwd) === 4;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
47
101
|
export { default as shortwindLoader } from "./loader.js";
|
|
102
|
+
// Re-exported so the documented rc() escape hatch resolves from the package
|
|
103
|
+
// init actually installs — `@shortwind/core` is only a transitive dependency
|
|
104
|
+
// (#63). In Next the registry load is server-side (loadRegistryFromDir reads
|
|
105
|
+
// recipes/ from disk); expand in a server component or route and pass the
|
|
106
|
+
// resulting plain-Tailwind string to the client as a prop.
|
|
107
|
+
export { expandClassList } from "@shortwind/core";
|
|
108
|
+
export { loadRegistryFromDir } from "@shortwind/tailwind";
|
|
48
109
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/loader.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { type TransformOptions } from "@shortwind/tailwind";
|
|
|
2
2
|
export type ShortwindLoaderOptions = {
|
|
3
3
|
recipesDir: string;
|
|
4
4
|
mode?: TransformOptions["mode"];
|
|
5
|
+
strict?: boolean;
|
|
6
|
+
entryCss?: readonly string[];
|
|
5
7
|
};
|
|
6
8
|
export declare function clearRegistryCache(): void;
|
|
7
9
|
type LoaderContext = {
|
|
@@ -10,6 +12,7 @@ type LoaderContext = {
|
|
|
10
12
|
addDependency?: (file: string) => void;
|
|
11
13
|
addContextDependency?: (dir: string) => void;
|
|
12
14
|
emitError?: (err: Error) => void;
|
|
15
|
+
emitWarning?: (err: Error) => void;
|
|
13
16
|
};
|
|
14
17
|
export default function shortwindLoader(this: LoaderContext, source: string): string;
|
|
15
18
|
export {};
|
package/dist/loader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAEA,OAAO,EAQL,KAAK,gBAAgB,EACtB,MAAM,qBAAqB,CAAC;AAG7B,MAAM,MAAM,sBAAsB,GAAG;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAIhC,MAAM,CAAC,EAAE,OAAO,CAAC;IAKjB,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B,CAAC;AAgDF,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED,KAAK,aAAa,GAAG;IACnB,UAAU,EAAE,MAAM,sBAAsB,CAAC;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,oBAAoB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;CACpC,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAmDnF"}
|
package/dist/loader.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { loadRegistryFromDir, modeForFile, transformContent, } from "@shortwind/tailwind";
|
|
3
|
+
import { findResidualRecipeTokens, findUnexpandedRecipes, loadRegistryFromDir, modeForFile, residualRecipeMessage, syncSourceDirectiveToFile, transformContent, } from "@shortwind/tailwind";
|
|
4
4
|
const registryCache = new Map();
|
|
5
5
|
function recipesSignature(recipesDir) {
|
|
6
6
|
if (!existsSync(recipesDir))
|
|
@@ -16,7 +16,7 @@ function recipesSignature(recipesDir) {
|
|
|
16
16
|
}
|
|
17
17
|
return { signature: parts.join("|"), files };
|
|
18
18
|
}
|
|
19
|
-
function getRegistry(recipesDir) {
|
|
19
|
+
function getRegistry(recipesDir, entryCss = []) {
|
|
20
20
|
const { signature, files } = recipesSignature(recipesDir);
|
|
21
21
|
const cached = registryCache.get(recipesDir);
|
|
22
22
|
if (cached && cached.signature === signature)
|
|
@@ -27,18 +27,40 @@ function getRegistry(recipesDir) {
|
|
|
27
27
|
signature,
|
|
28
28
|
};
|
|
29
29
|
registryCache.set(recipesDir, entry);
|
|
30
|
+
// Recipes changed since withShortwind's config-eval sync — refresh the
|
|
31
|
+
// on-disk safelist so a recipe authored mid-`next dev` renders styled (#73).
|
|
32
|
+
// The write is content-guarded (no-op when nothing changed) and best-effort:
|
|
33
|
+
// a read-only filesystem must not fail the module.
|
|
34
|
+
for (const cssPath of entryCss) {
|
|
35
|
+
try {
|
|
36
|
+
syncSourceDirectiveToFile(cssPath, entry.registry);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// covered again at the next config evaluation
|
|
40
|
+
}
|
|
41
|
+
}
|
|
30
42
|
return entry;
|
|
31
43
|
}
|
|
32
44
|
export function clearRegistryCache() {
|
|
33
45
|
registryCache.clear();
|
|
34
46
|
}
|
|
35
47
|
export default function shortwindLoader(source) {
|
|
48
|
+
// Never transform or strict-scan vendored code (#75). The webpack rule
|
|
49
|
+
// excludes node_modules, but Turbopack rule keys are include-globs with no
|
|
50
|
+
// negation syntax — and Next 16's Turbopack applies custom loader rules to
|
|
51
|
+
// node_modules, so without this guard strict mode fails the build on files
|
|
52
|
+
// the user doesn't own (a JSDoc `{@link …}` in next's own dist collided
|
|
53
|
+
// with the catalog's @link recipe). Guarding here makes the scan scope
|
|
54
|
+
// bundler-independent, matching @shortwind/vite's transform.
|
|
55
|
+
if (this.resourcePath.split(path.sep).join("/").includes("/node_modules/")) {
|
|
56
|
+
return source;
|
|
57
|
+
}
|
|
36
58
|
const options = this.getOptions();
|
|
37
59
|
if (this.addContextDependency)
|
|
38
60
|
this.addContextDependency(options.recipesDir);
|
|
39
61
|
let entry;
|
|
40
62
|
try {
|
|
41
|
-
entry = getRegistry(options.recipesDir);
|
|
63
|
+
entry = getRegistry(options.recipesDir, options.entryCss ?? []);
|
|
42
64
|
}
|
|
43
65
|
catch (err) {
|
|
44
66
|
const wrapped = err instanceof Error ? err : new Error(`shortwind: failed to load registry: ${String(err)}`);
|
|
@@ -51,6 +73,24 @@ export default function shortwindLoader(source) {
|
|
|
51
73
|
this.addDependency(file);
|
|
52
74
|
}
|
|
53
75
|
const mode = options.mode ?? modeForFile(this.resourcePath);
|
|
54
|
-
|
|
76
|
+
const out = transformContent(source, entry.registry, { mode });
|
|
77
|
+
// Leak reporting (#67), consistent with @shortwind/vite: strict mode scans
|
|
78
|
+
// the whole output (the class-value scan can't see a recipe assigned to a
|
|
79
|
+
// variable/prop) and errors the module so `next build` fails instead of
|
|
80
|
+
// shipping unstyled UI; the default surfaces a webpack warning for the
|
|
81
|
+
// class-value cases it can attribute.
|
|
82
|
+
if (options.strict) {
|
|
83
|
+
const residual = findResidualRecipeTokens(out, entry.registry);
|
|
84
|
+
if (residual.length > 0 && this.emitError) {
|
|
85
|
+
this.emitError(new Error(`${residualRecipeMessage(this.resourcePath, residual)} (strict mode: failing the build — pass strict: false to demote this to a warning)`));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const leftover = findUnexpandedRecipes(out, entry.registry);
|
|
90
|
+
if (leftover.length > 0 && this.emitWarning) {
|
|
91
|
+
this.emitWarning(new Error(residualRecipeMessage(this.resourcePath, leftover)));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return out;
|
|
55
95
|
}
|
|
56
96
|
//# sourceMappingURL=loader.js.map
|
package/dist/loader.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,mBAAmB,EACnB,WAAW,EACX,gBAAgB,GAEjB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shortwind/next",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.12",
|
|
4
4
|
"description": "Next.js plugin for Shortwind. Webpack and Turbopack.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -12,11 +12,12 @@
|
|
|
12
12
|
"next": ">=14.0.0"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@shortwind/core": "0.1.0-beta.
|
|
16
|
-
"@shortwind/tailwind": "0.1.0-beta.
|
|
15
|
+
"@shortwind/core": "0.1.0-beta.12",
|
|
16
|
+
"@shortwind/tailwind": "0.1.0-beta.12"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@types/node": "^25.7.0"
|
|
19
|
+
"@types/node": "^25.7.0",
|
|
20
|
+
"next": "^16.2.6"
|
|
20
21
|
},
|
|
21
22
|
"publishConfig": {
|
|
22
23
|
"access": "public",
|
|
@@ -33,7 +34,7 @@
|
|
|
33
34
|
},
|
|
34
35
|
"scripts": {
|
|
35
36
|
"build": "tsc",
|
|
36
|
-
"typecheck": "tsc --noEmit",
|
|
37
|
+
"typecheck": "tsc --noEmit && tsc -p tsconfig.typetest.json",
|
|
37
38
|
"test": "vitest run"
|
|
38
39
|
}
|
|
39
40
|
}
|