@yak/react 0.0.0-stage → 10.0.0-rc.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.
Files changed (91) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +114 -2
  3. package/dist/context/baseContext.d.ts +5 -0
  4. package/dist/context/baseContext.js +8 -0
  5. package/dist/context/baseContext.js.map +1 -0
  6. package/dist/context/index.d.ts +20 -0
  7. package/dist/context/index.js +15 -0
  8. package/dist/context/index.js.map +1 -0
  9. package/dist/context/index.server.d.ts +9 -0
  10. package/dist/context/index.server.js +17 -0
  11. package/dist/context/index.server.js.map +1 -0
  12. package/dist/cross-file-resolver/index.d.ts +199 -0
  13. package/dist/cross-file-resolver/index.js +569 -0
  14. package/dist/cross-file-resolver/index.js.map +1 -0
  15. package/dist/index.d.ts +320 -0
  16. package/dist/index.js +2 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/internal.d.ts +452 -0
  19. package/dist/internal.js +363 -0
  20. package/dist/internal.js.map +1 -0
  21. package/dist/isolated-source-eval/index.d.ts +30 -0
  22. package/dist/isolated-source-eval/index.js +317 -0
  23. package/dist/isolated-source-eval/index.js.map +1 -0
  24. package/dist/isolated-source-eval/worker.js +59 -0
  25. package/dist/isolated-source-eval/worker.js.map +1 -0
  26. package/dist/jsx-dev-runtime.d.ts +7 -0
  27. package/dist/jsx-dev-runtime.js +2 -0
  28. package/dist/jsx-dev-runtime.js.map +1 -0
  29. package/dist/jsx-runtime.d.ts +38 -0
  30. package/dist/jsx-runtime.js +2 -0
  31. package/dist/jsx-runtime.js.map +1 -0
  32. package/dist/loaders/turbo-loader.d.ts +15 -0
  33. package/dist/loaders/turbo-loader.js +816 -0
  34. package/dist/loaders/turbo-loader.js.map +1 -0
  35. package/dist/loaders/vite-plugin.d.ts +103 -0
  36. package/dist/loaders/vite-plugin.js +885 -0
  37. package/dist/loaders/vite-plugin.js.map +1 -0
  38. package/dist/loaders/webpack-loader.d.ts +12 -0
  39. package/dist/loaders/webpack-loader.js +710 -0
  40. package/dist/loaders/webpack-loader.js.map +1 -0
  41. package/dist/rsbuild/index.d.ts +29 -0
  42. package/dist/rsbuild/index.js +51 -0
  43. package/dist/rsbuild/index.js.map +1 -0
  44. package/dist/static/chunk-DK3Fl9T5.js +1 -0
  45. package/dist/static/index.d.ts +28 -0
  46. package/dist/static/index.js +2 -0
  47. package/dist/static/index.js.map +1 -0
  48. package/dist/withYak/index.d.ts +112 -0
  49. package/dist/withYak/index.js +171 -0
  50. package/dist/withYak/index.js.map +1 -0
  51. package/loaders/lib/resolveCrossFileSelectors.ts +161 -0
  52. package/loaders/turbo-evaluator.ts +134 -0
  53. package/loaders/turbo-loader.ts +184 -0
  54. package/loaders/vite-plugin.ts +28 -0
  55. package/loaders/webpack-loader.ts +41 -0
  56. package/package.json +155 -3
  57. package/rsbuild/index.ts +91 -0
  58. package/runtime/__tests__/atoms.test.tsx +48 -0
  59. package/runtime/__tests__/attrs.test.tsx +490 -0
  60. package/runtime/__tests__/cssLiteral.test.tsx +503 -0
  61. package/runtime/__tests__/cssProp.test.tsx +392 -0
  62. package/runtime/__tests__/cssPropTest.tsx +227 -0
  63. package/runtime/__tests__/foldedJsxParity.test.tsx +117 -0
  64. package/runtime/__tests__/styled.test.tsx +653 -0
  65. package/runtime/__tests__/tsconfig.json +18 -0
  66. package/runtime/__tests__/typeTest.tsx +374 -0
  67. package/runtime/atoms.tsx +36 -0
  68. package/runtime/context/README.md +84 -0
  69. package/runtime/context/baseContext.tsx +5 -0
  70. package/runtime/context/index.server.tsx +22 -0
  71. package/runtime/context/index.tsx +36 -0
  72. package/runtime/cssLiteral.tsx +214 -0
  73. package/runtime/globalStyle.tsx +54 -0
  74. package/runtime/index.ts +37 -0
  75. package/runtime/internal.ts +42 -0
  76. package/runtime/internals/mergeClassNames.ts +23 -0
  77. package/runtime/internals/mergeCssProp.ts +69 -0
  78. package/runtime/internals/propMarkers.ts +20 -0
  79. package/runtime/internals/unitPostFix.ts +34 -0
  80. package/runtime/jsx-dev-runtime.ts +6 -0
  81. package/runtime/jsx-runtime.ts +48 -0
  82. package/runtime/keyframes.tsx +30 -0
  83. package/runtime/mocks/cssLiteral.ts +74 -0
  84. package/runtime/mocks/globalStyle.ts +14 -0
  85. package/runtime/mocks/keyframes.ts +29 -0
  86. package/runtime/mocks/styled.ts +8 -0
  87. package/runtime/publicStyledApi.ts +159 -0
  88. package/runtime/styled.tsx +372 -0
  89. package/runtime/styledDom.tsx +139 -0
  90. package/withYak/allow-global-css.ts +94 -0
  91. package/withYak/index.ts +268 -0
@@ -0,0 +1,139 @@
1
+ import { styled } from "./styled.js";
2
+ /// Internal API to create styled components
3
+ /// Optimization for faster rendering and smaller bundle size in production
4
+ /// thanks to better minification and dead code elimination
5
+ ///
6
+ /// List taken from https://github.com/styled-components/styled-components/blob/e0019ba666fab4b5aaa2bff71ba6ad0005a299fd/packages/styled-components/src/utils/domElements.ts#L90
7
+ export const __yak_a = /*#__PURE__*/ styled("a");
8
+ export const __yak_abbr = /*#__PURE__*/ styled("abbr");
9
+ export const __yak_address = /*#__PURE__*/ styled("address");
10
+ export const __yak_area = /*#__PURE__*/ styled("area");
11
+ export const __yak_article = /*#__PURE__*/ styled("article");
12
+ export const __yak_aside = /*#__PURE__*/ styled("aside");
13
+ export const __yak_audio = /*#__PURE__*/ styled("audio");
14
+ export const __yak_b = /*#__PURE__*/ styled("b");
15
+ export const __yak_base = /*#__PURE__*/ styled("base");
16
+ export const __yak_bdi = /*#__PURE__*/ styled("bdi");
17
+ export const __yak_bdo = /*#__PURE__*/ styled("bdo");
18
+ export const __yak_big = /*#__PURE__*/ styled("big");
19
+ export const __yak_blockquote = /*#__PURE__*/ styled("blockquote");
20
+ export const __yak_body = /*#__PURE__*/ styled("body");
21
+ export const __yak_br = /*#__PURE__*/ styled("br");
22
+ export const __yak_button = /*#__PURE__*/ styled("button");
23
+ export const __yak_canvas = /*#__PURE__*/ styled("canvas");
24
+ export const __yak_caption = /*#__PURE__*/ styled("caption");
25
+ export const __yak_cite = /*#__PURE__*/ styled("cite");
26
+ export const __yak_code = /*#__PURE__*/ styled("code");
27
+ export const __yak_col = /*#__PURE__*/ styled("col");
28
+ export const __yak_colgroup = /*#__PURE__*/ styled("colgroup");
29
+ export const __yak_data = /*#__PURE__*/ styled("data");
30
+ export const __yak_datalist = /*#__PURE__*/ styled("datalist");
31
+ export const __yak_dd = /*#__PURE__*/ styled("dd");
32
+ export const __yak_del = /*#__PURE__*/ styled("del");
33
+ export const __yak_details = /*#__PURE__*/ styled("details");
34
+ export const __yak_dfn = /*#__PURE__*/ styled("dfn");
35
+ export const __yak_dialog = /*#__PURE__*/ styled("dialog");
36
+ export const __yak_div = /*#__PURE__*/ styled("div");
37
+ export const __yak_dl = /*#__PURE__*/ styled("dl");
38
+ export const __yak_dt = /*#__PURE__*/ styled("dt");
39
+ export const __yak_em = /*#__PURE__*/ styled("em");
40
+ export const __yak_embed = /*#__PURE__*/ styled("embed");
41
+ export const __yak_fieldset = /*#__PURE__*/ styled("fieldset");
42
+ export const __yak_figcaption = /*#__PURE__*/ styled("figcaption");
43
+ export const __yak_figure = /*#__PURE__*/ styled("figure");
44
+ export const __yak_footer = /*#__PURE__*/ styled("footer");
45
+ export const __yak_form = /*#__PURE__*/ styled("form");
46
+ export const __yak_h1 = /*#__PURE__*/ styled("h1");
47
+ export const __yak_h2 = /*#__PURE__*/ styled("h2");
48
+ export const __yak_h3 = /*#__PURE__*/ styled("h3");
49
+ export const __yak_h4 = /*#__PURE__*/ styled("h4");
50
+ export const __yak_h5 = /*#__PURE__*/ styled("h5");
51
+ export const __yak_h6 = /*#__PURE__*/ styled("h6");
52
+ export const __yak_header = /*#__PURE__*/ styled("header");
53
+ export const __yak_hgroup = /*#__PURE__*/ styled("hgroup");
54
+ export const __yak_hr = /*#__PURE__*/ styled("hr");
55
+ export const __yak_html = /*#__PURE__*/ styled("html");
56
+ export const __yak_i = /*#__PURE__*/ styled("i");
57
+ export const __yak_iframe = /*#__PURE__*/ styled("iframe");
58
+ export const __yak_img = /*#__PURE__*/ styled("img");
59
+ export const __yak_input = /*#__PURE__*/ styled("input");
60
+ export const __yak_ins = /*#__PURE__*/ styled("ins");
61
+ export const __yak_kbd = /*#__PURE__*/ styled("kbd");
62
+ export const __yak_keygen = /*#__PURE__*/ styled("keygen");
63
+ export const __yak_label = /*#__PURE__*/ styled("label");
64
+ export const __yak_legend = /*#__PURE__*/ styled("legend");
65
+ export const __yak_li = /*#__PURE__*/ styled("li");
66
+ export const __yak_link = /*#__PURE__*/ styled("link");
67
+ export const __yak_main = /*#__PURE__*/ styled("main");
68
+ export const __yak_map = /*#__PURE__*/ styled("map");
69
+ export const __yak_mark = /*#__PURE__*/ styled("mark");
70
+ export const __yak_menu = /*#__PURE__*/ styled("menu");
71
+ export const __yak_menuitem = /*#__PURE__*/ styled("menuitem");
72
+ export const __yak_meta = /*#__PURE__*/ styled("meta");
73
+ export const __yak_meter = /*#__PURE__*/ styled("meter");
74
+ export const __yak_nav = /*#__PURE__*/ styled("nav");
75
+ export const __yak_noscript = /*#__PURE__*/ styled("noscript");
76
+ export const __yak_object = /*#__PURE__*/ styled("object");
77
+ export const __yak_ol = /*#__PURE__*/ styled("ol");
78
+ export const __yak_optgroup = /*#__PURE__*/ styled("optgroup");
79
+ export const __yak_option = /*#__PURE__*/ styled("option");
80
+ export const __yak_output = /*#__PURE__*/ styled("output");
81
+ export const __yak_p = /*#__PURE__*/ styled("p");
82
+ export const __yak_param = /*#__PURE__*/ styled("param");
83
+ export const __yak_picture = /*#__PURE__*/ styled("picture");
84
+ export const __yak_pre = /*#__PURE__*/ styled("pre");
85
+ export const __yak_progress = /*#__PURE__*/ styled("progress");
86
+ export const __yak_q = /*#__PURE__*/ styled("q");
87
+ export const __yak_rp = /*#__PURE__*/ styled("rp");
88
+ export const __yak_rt = /*#__PURE__*/ styled("rt");
89
+ export const __yak_ruby = /*#__PURE__*/ styled("ruby");
90
+ export const __yak_s = /*#__PURE__*/ styled("s");
91
+ export const __yak_samp = /*#__PURE__*/ styled("samp");
92
+ export const __yak_script = /*#__PURE__*/ styled("script");
93
+ export const __yak_section = /*#__PURE__*/ styled("section");
94
+ export const __yak_select = /*#__PURE__*/ styled("select");
95
+ export const __yak_small = /*#__PURE__*/ styled("small");
96
+ export const __yak_source = /*#__PURE__*/ styled("source");
97
+ export const __yak_span = /*#__PURE__*/ styled("span");
98
+ export const __yak_strong = /*#__PURE__*/ styled("strong");
99
+ export const __yak_style = /*#__PURE__*/ styled("style");
100
+ export const __yak_sub = /*#__PURE__*/ styled("sub");
101
+ export const __yak_summary = /*#__PURE__*/ styled("summary");
102
+ export const __yak_sup = /*#__PURE__*/ styled("sup");
103
+ export const __yak_table = /*#__PURE__*/ styled("table");
104
+ export const __yak_tbody = /*#__PURE__*/ styled("tbody");
105
+ export const __yak_td = /*#__PURE__*/ styled("td");
106
+ export const __yak_textarea = /*#__PURE__*/ styled("textarea");
107
+ export const __yak_tfoot = /*#__PURE__*/ styled("tfoot");
108
+ export const __yak_th = /*#__PURE__*/ styled("th");
109
+ export const __yak_thead = /*#__PURE__*/ styled("thead");
110
+ export const __yak_time = /*#__PURE__*/ styled("time");
111
+ export const __yak_tr = /*#__PURE__*/ styled("tr");
112
+ export const __yak_track = /*#__PURE__*/ styled("track");
113
+ export const __yak_u = /*#__PURE__*/ styled("u");
114
+ export const __yak_ul = /*#__PURE__*/ styled("ul");
115
+ export const __yak_use = /*#__PURE__*/ styled("use");
116
+ export const __yak_var = /*#__PURE__*/ styled("var");
117
+ export const __yak_video = /*#__PURE__*/ styled("video");
118
+ export const __yak_wbr = /*#__PURE__*/ styled("wbr");
119
+ export const __yak_circle = /*#__PURE__*/ styled("circle");
120
+ export const __yak_clipPath = /*#__PURE__*/ styled("clipPath");
121
+ export const __yak_defs = /*#__PURE__*/ styled("defs");
122
+ export const __yak_ellipse = /*#__PURE__*/ styled("ellipse");
123
+ export const __yak_foreignObject = /*#__PURE__*/ styled("foreignObject");
124
+ export const __yak_g = /*#__PURE__*/ styled("g");
125
+ export const __yak_image = /*#__PURE__*/ styled("image");
126
+ export const __yak_line = /*#__PURE__*/ styled("line");
127
+ export const __yak_linearGradient = /*#__PURE__*/ styled("linearGradient");
128
+ export const __yak_marker = /*#__PURE__*/ styled("marker");
129
+ export const __yak_mask = /*#__PURE__*/ styled("mask");
130
+ export const __yak_path = /*#__PURE__*/ styled("path");
131
+ export const __yak_pattern = /*#__PURE__*/ styled("pattern");
132
+ export const __yak_polygon = /*#__PURE__*/ styled("polygon");
133
+ export const __yak_polyline = /*#__PURE__*/ styled("polyline");
134
+ export const __yak_radialGradient = /*#__PURE__*/ styled("radialGradient");
135
+ export const __yak_rect = /*#__PURE__*/ styled("rect");
136
+ export const __yak_stop = /*#__PURE__*/ styled("stop");
137
+ export const __yak_svg = /*#__PURE__*/ styled("svg");
138
+ export const __yak_text = /*#__PURE__*/ styled("text");
139
+ export const __yak_tspan = /*#__PURE__*/ styled("tspan");
@@ -0,0 +1,94 @@
1
+ import { existsSync } from "node:fs";
2
+ import path from "node:path";
3
+
4
+ interface WebpackConfig {
5
+ module?: { rules?: unknown[] };
6
+ }
7
+
8
+ interface Rule {
9
+ test?: unknown;
10
+ issuer?: unknown;
11
+ use?: unknown;
12
+ oneOf?: unknown;
13
+ rules?: unknown;
14
+ }
15
+
16
+ export function hasAppDir(projectDir: string): boolean {
17
+ return (
18
+ // mirrors next.js's `findDir(dir, "app")`
19
+ // https://github.com/vercel/next.js/blob/v16.3.4/packages/next/src/lib/find-pages-dir.ts#L4-L13
20
+ existsSync(path.join(projectDir, "app")) || existsSync(path.join(projectDir, "src", "app"))
21
+ );
22
+ }
23
+
24
+ /**
25
+ * Next.js (pages router) only allows global CSS imports from `_app`.
26
+ * Everywhere else it expects CSS Modules. Yak's co-located `*.yak.css`
27
+ * files are plain global CSS, because yak already hashes the class names
28
+ * itself, so there's no risk of leaking styles
29
+ *
30
+ * Next.js has no option to allow this, so we copy its `_app` global CSS
31
+ * rule without the `_app` issuer check and limit the copy to `.yak.css`.
32
+ * The copy goes to the start of the same `oneOf`, so it matches before
33
+ * Next's error rules.
34
+ */
35
+ export function allowYakGlobalCss(webpackConfig: WebpackConfig) {
36
+ const rules = webpackConfig.module?.rules;
37
+ if (!Array.isArray(rules)) {
38
+ return;
39
+ }
40
+
41
+ // Next.js's internal `regexCssGlobal` source
42
+ // https://github.com/vercel/next.js/blob/v16.3.4/packages/next/src/build/webpack/config/blocks/css/index.ts#L23
43
+ const nextGlobalCssRegExpSource = "(?<!\\.module)\\.css$";
44
+
45
+ const isRule = (value: unknown): value is Rule =>
46
+ typeof value === "object" && value !== null && !Array.isArray(value);
47
+
48
+ // Next.js sets `issuer: { and: [ctx.customAppFile] }`, where
49
+ // `customAppFile` is a RegExp for the path of `pages/_app`
50
+ // https://github.com/vercel/next.js/blob/v16.3.4/packages/next/src/build/webpack-config.ts#L2550-L2552
51
+ const hasAppIssuer = (rule: Rule): boolean => {
52
+ if (!isRule(rule.issuer)) return false;
53
+ const and = (rule.issuer as { and?: unknown }).and;
54
+ return Array.isArray(and) && and[0] instanceof RegExp && and[0].source.endsWith("_app");
55
+ };
56
+
57
+ const isAppGlobalCssRule = (rule: Rule): boolean =>
58
+ rule.test instanceof RegExp &&
59
+ rule.test.source === nextGlobalCssRegExpSource &&
60
+ hasAppIssuer(rule) &&
61
+ Array.isArray(rule.use);
62
+
63
+ const findAppRule = (ruleList: unknown): { oneOf: unknown[]; appRule: Rule } | undefined => {
64
+ if (!Array.isArray(ruleList)) return undefined;
65
+ for (const rule of ruleList) {
66
+ if (!isRule(rule)) continue;
67
+ if (Array.isArray(rule.oneOf)) {
68
+ const appRule = rule.oneOf.find(
69
+ (item): item is Rule => isRule(item) && isAppGlobalCssRule(item),
70
+ );
71
+ if (appRule) return { oneOf: rule.oneOf, appRule };
72
+ }
73
+ const found = findAppRule(rule.oneOf) ?? findAppRule(rule.rules);
74
+ if (found) return found;
75
+ }
76
+ return undefined;
77
+ };
78
+
79
+ const found = findAppRule(rules);
80
+ if (!found) {
81
+ console.warn(
82
+ "@yak/react: could not find the next.js global-CSS rules. " +
83
+ "Please report this issue with your Next.js version at " +
84
+ "https://github.com/DigitecGalaxus/next-yak/issues/new",
85
+ );
86
+ return;
87
+ }
88
+
89
+ found.oneOf.unshift({
90
+ test: /\.yak\.css$/,
91
+ sideEffects: true,
92
+ use: [...(found.appRule.use as unknown[])],
93
+ });
94
+ }
@@ -0,0 +1,268 @@
1
+ /// <reference types="node" />
2
+ import type { NextConfig } from "next";
3
+ import path from "node:path";
4
+ import { allowYakGlobalCss, hasAppDir } from "./allow-global-css.ts";
5
+ import {
6
+ buildYakPluginOptions,
7
+ resolveYakContext,
8
+ type YakConfigOptions,
9
+ } from "yak-internals/config";
10
+
11
+ export { buildYakPluginOptions, resolveYakContext } from "yak-internals/config";
12
+ export type { YakConfigOptions } from "yak-internals/config";
13
+
14
+ const currentDir = import.meta.dirname;
15
+
16
+ const addYak = (yakOptions: YakConfigOptions, nextConfig: NextConfig) => {
17
+ const yakPluginOptions = buildYakPluginOptions(yakOptions, currentDir);
18
+
19
+ if (process.env.TURBOPACK === "1" || process.env.TURBOPACK === "auto") {
20
+ addYakTurbopack(nextConfig, yakOptions, {
21
+ ...yakPluginOptions,
22
+ importMode: {
23
+ value: "data:text/css;base64,",
24
+ encoding: "Base64",
25
+ },
26
+ });
27
+ } else {
28
+ addYakWebpack(nextConfig, yakOptions, {
29
+ ...yakPluginOptions,
30
+ importMode: {
31
+ value: "./{{__BASE_NAME__}}.yak.css!=!./{{__BASE_NAME__}}?./{{__BASE_NAME__}}.yak.css",
32
+ encoding: "None",
33
+ },
34
+ });
35
+ }
36
+ return nextConfig;
37
+ };
38
+
39
+ /**
40
+ * Configure Turbopack with yak loader for CSS-in-JS transformation
41
+ * @param nextConfig - Next.js configuration object
42
+ * @param yakOptions - Yak configuration options
43
+ * @param yakPluginOptions - Processed plugin options for yak-swc
44
+ */
45
+ function addYakTurbopack(
46
+ nextConfig: NextConfig,
47
+ yakOptions: YakConfigOptions,
48
+ yakPluginOptions: {
49
+ minify: boolean;
50
+ basePath: string;
51
+ prefix?: string;
52
+ displayNames: boolean;
53
+ foldStatic: boolean;
54
+ strictCssProp: boolean;
55
+ importMode: {
56
+ value: string;
57
+ encoding: string;
58
+ };
59
+ },
60
+ ) {
61
+ // turbopack can't handle options with undefined values, so we remove them
62
+ const yakLoader = removeUndefinedRecursive({
63
+ loader: path.join(currentDir, "../loaders/turbo-loader.js"),
64
+ options: {
65
+ yakOptions: yakOptions,
66
+ yakPluginOptions: yakPluginOptions,
67
+ },
68
+ }) as { loader: string; options: {} };
69
+
70
+ nextConfig.turbopack ||= {};
71
+ nextConfig.turbopack.rules ||= {};
72
+
73
+ const ruleKey = "*.{js,jsx,cjs,mjs,ts,tsx,cts,mts}";
74
+ const rule = {
75
+ loaders: [] as { loader: string; options: {} }[],
76
+ ...nextConfig.turbopack.rules[ruleKey],
77
+ };
78
+ rule.loaders.push(yakLoader);
79
+ nextConfig.turbopack.rules[ruleKey] = rule;
80
+
81
+ // Configure resolveAlias for custom yak context (similar to webpack)
82
+ // This allows users to provide a custom context file that will be used
83
+ // instead of the default baseContext
84
+ const yakContext = resolveYakContext(yakOptions.contextPath, process.cwd());
85
+ if (yakContext) {
86
+ nextConfig.turbopack.resolveAlias ||= {};
87
+ nextConfig.turbopack.resolveAlias["@yak/react/context/baseContext"] =
88
+ // This is a hack around the fact that turbopack currently only supports relative paths
89
+ // turbopack: "server relative imports are not implemented yet"
90
+ // Relative is quite dangerous here as it relies on the cwd being the starting point
91
+ `./${path.relative(process.cwd(), yakContext)}`;
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Configure Webpack with yak SWC plugin and webpack loader for CSS-in-JS transformation
97
+ * @param nextConfig - Next.js configuration object
98
+ * @param yakOptions - Yak configuration options
99
+ * @param yakPluginOptions - Processed plugin options for yak-swc
100
+ */
101
+ function addYakWebpack(
102
+ nextConfig: NextConfig,
103
+ yakOptions: YakConfigOptions,
104
+ yakPluginOptions: {
105
+ minify: boolean;
106
+ basePath: string;
107
+ prefix?: string;
108
+ displayNames: boolean;
109
+ foldStatic: boolean;
110
+ strictCssProp: boolean;
111
+ importMode: {
112
+ value: string;
113
+ encoding: string;
114
+ };
115
+ },
116
+ ) {
117
+ // Add SWC plugin for Webpack
118
+ nextConfig.experimental ||= {};
119
+ nextConfig.experimental.swcPlugins ||= [];
120
+ nextConfig.experimental.swcPlugins.push(["@yak/swc", yakPluginOptions]);
121
+
122
+ // Configure webpack loader
123
+ const previousConfig = nextConfig.webpack;
124
+ nextConfig.webpack = (webpackConfig, options) => {
125
+ if (previousConfig) {
126
+ webpackConfig = previousConfig(webpackConfig, options);
127
+ }
128
+
129
+ if (!options.isServer && !hasAppDir(options.dir)) {
130
+ // Next.js restricts global CSS imports only in the client build of a pages-only project, so only patch its rules there
131
+ allowYakGlobalCss(webpackConfig);
132
+ }
133
+
134
+ webpackConfig.module.rules.push({
135
+ test: /\.yak\.css$/,
136
+ loader: path.join(currentDir, "../loaders/webpack-loader.js"),
137
+ options: yakOptions,
138
+ });
139
+
140
+ // With the following alias the internal @yak/react code
141
+ // is able to import a context which works for server components
142
+ const yakContext = resolveYakContext(
143
+ yakOptions.contextPath,
144
+ webpackConfig.context || process.cwd(),
145
+ );
146
+ if (yakContext) {
147
+ webpackConfig.resolve.alias["@yak/react/context/baseContext"] = yakContext;
148
+ }
149
+
150
+ return webpackConfig;
151
+ };
152
+ }
153
+
154
+ /**
155
+ * Recursively removes undefined values from an object or array.
156
+ *
157
+ * This function deeply traverses the input object/array and creates a new structure
158
+ * with all undefined values filtered out. For objects, properties with undefined values
159
+ * are omitted. For arrays, undefined elements are removed from the result.
160
+ *
161
+ * @param obj - The object or array to process
162
+ * @returns A new object/array with undefined values removed, or the original value if no changes were needed
163
+ */
164
+ function removeUndefinedRecursive<T>(obj: T): {} {
165
+ if (typeof obj !== "object" || obj === null) {
166
+ return obj as {};
167
+ }
168
+
169
+ if (Array.isArray(obj)) {
170
+ const filtered: unknown[] = [];
171
+ for (let i = 0; i < obj.length; i++) {
172
+ const processed = removeUndefinedRecursive(obj[i]);
173
+ if (processed !== undefined) {
174
+ filtered.push(processed);
175
+ }
176
+ }
177
+ return filtered as {};
178
+ }
179
+
180
+ const newObj: Record<string, unknown> = {};
181
+ let hasChanges = false;
182
+
183
+ for (const key in obj) {
184
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
185
+ const value = removeUndefinedRecursive((obj as any)[key]);
186
+ if (value !== undefined) {
187
+ newObj[key] = value;
188
+ hasChanges = true;
189
+ }
190
+ }
191
+ }
192
+
193
+ return hasChanges ? (newObj as {}) : obj;
194
+ }
195
+
196
+ // Wrapper to allow sync, async, and function configuration of Next.js
197
+ /**
198
+ * Add Yak to your Next.js app
199
+ *
200
+ * @usage
201
+ *
202
+ * ```ts
203
+ * // next.config.js
204
+ * const { withYak } = require("@yak/react/withYak");
205
+ * const nextConfig = {
206
+ * // your next config here
207
+ * };
208
+ * module.exports = withYak(nextConfig);
209
+ * ```
210
+ *
211
+ * With a custom yakConfig
212
+ *
213
+ * ```ts
214
+ * // next.config.js
215
+ * const { withYak } = require("@yak/react/withYak");
216
+ * const nextConfig = {
217
+ * // your next config here
218
+ * };
219
+ * const yakConfig = {
220
+ * // Optional prefix for generated CSS identifiers
221
+ * prefix: "my-app",
222
+ * // Other yak config options...
223
+ * };
224
+ * module.exports = withYak(yakConfig, nextConfig);
225
+ * ```
226
+ */
227
+ export const withYak: {
228
+ <
229
+ T extends
230
+ | Record<string, any>
231
+ | ((...args: any[]) => Record<string, any>)
232
+ | ((...args: any[]) => Promise<Record<string, any>>),
233
+ >(
234
+ yakOptions: YakConfigOptions,
235
+ nextConfig: T,
236
+ ): T;
237
+ // no yakConfig
238
+ <
239
+ T extends
240
+ | Record<string, any>
241
+ | ((...args: any[]) => Record<string, any>)
242
+ | ((...args: any[]) => Promise<Record<string, any>>),
243
+ >(
244
+ nextConfig: T,
245
+ _?: undefined,
246
+ ): T;
247
+ } = (maybeYakOptions, nextConfig) => {
248
+ if (nextConfig === undefined) {
249
+ return withYak({}, maybeYakOptions);
250
+ }
251
+ // If the second parameter is present the first parameter must be a YakConfigOptions
252
+ const yakOptions = maybeYakOptions as YakConfigOptions;
253
+ if (typeof nextConfig === "function") {
254
+ /**
255
+ * A NextConfig can be a sync or async function
256
+ * https://nextjs.org/docs/pages/api-reference/next-config-js
257
+ * @param {any[]} args
258
+ */
259
+ return (...args) => {
260
+ /** Dynamic Next Configs can be async or sync */
261
+ const config = nextConfig(...args) as NextConfig | Promise<NextConfig>;
262
+ return config instanceof Promise
263
+ ? config.then((config) => addYak(yakOptions, config))
264
+ : addYak(yakOptions, config);
265
+ };
266
+ }
267
+ return addYak(yakOptions, nextConfig);
268
+ };