next-yak 0.2.2 → 0.2.4

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 (36) hide show
  1. package/README.md +21 -18
  2. package/dist/loaders/css-loader.cjs +219 -0
  3. package/dist/loaders/css-loader.cjs.map +1 -0
  4. package/dist/loaders/css-loader.d.cts +11 -0
  5. package/dist/loaders/{tsloader.cjs → ts-loader.cjs} +53 -29
  6. package/dist/loaders/ts-loader.cjs.map +1 -0
  7. package/dist/loaders/ts-loader.d.cts +9 -0
  8. package/dist/withYak/index.cjs +8 -4
  9. package/dist/withYak/index.cjs.map +1 -1
  10. package/dist/withYak/index.d.cts +3 -0
  11. package/dist/withYak/index.d.ts +3 -0
  12. package/dist/withYak/index.js +8 -4
  13. package/dist/withYak/index.js.map +1 -1
  14. package/loaders/__tests__/cssloader.test.ts +65 -81
  15. package/loaders/__tests__/tsloader.test.ts +45 -7
  16. package/loaders/babel-yak-plugin.ts +26 -14
  17. package/loaders/css-loader.ts +38 -0
  18. package/loaders/lib/getConstantValues.ts +28 -5
  19. package/loaders/lib/resolveCrossFileSelectors.ts +262 -0
  20. package/loaders/lib/transpileCssProp.ts +1 -5
  21. package/loaders/{tsloader.ts → ts-loader.ts} +8 -3
  22. package/package.json +7 -7
  23. package/withYak/index.ts +12 -3
  24. package/dist/loaders/cssloader.cjs +0 -61
  25. package/dist/loaders/cssloader.cjs.map +0 -1
  26. package/dist/loaders/cssloader.d.cts +0 -8
  27. package/dist/loaders/cssloader.d.ts +0 -8
  28. package/dist/loaders/cssloader.js +0 -30
  29. package/dist/loaders/cssloader.js.map +0 -1
  30. package/dist/loaders/tsloader.cjs.map +0 -1
  31. package/dist/loaders/tsloader.d.cts +0 -6
  32. package/dist/loaders/tsloader.d.ts +0 -6
  33. package/dist/loaders/tsloader.js +0 -1109
  34. package/dist/loaders/tsloader.js.map +0 -1
  35. package/loaders/cssloader.ts +0 -35
  36. package/loaders/lib/stripCssComments.ts +0 -52
package/README.md CHANGED
@@ -39,17 +39,17 @@ Try it on [stackblitz](https://stackblitz.com/edit/stackblitz-starters-dfykqy?fi
39
39
 
40
40
  1. Install **next-yak** in your Next.js project.
41
41
 
42
- 2. Add next-yak to your `next.config.js`:
42
+ 2. Add next-yak to your `next.config.mjs`:
43
43
 
44
44
  ```js
45
45
  // next.config.js
46
- const { withYak } = require("next-yak/withYak");
46
+ import { withYak } from "next-yak/withYak";
47
47
 
48
48
  const nextConfig = {
49
49
  // your next.js config
50
50
  };
51
51
 
52
- module.exports = withYak(nextConfig);
52
+ export default withYak(nextConfig);
53
53
  ```
54
54
 
55
55
  3. Ready to go:
@@ -266,31 +266,34 @@ const Container = styled.div`
266
266
 
267
267
  [Build time constants (video)](https://github.com/jantimon/next-yak/assets/4113649/2c83246c-a03b-4c57-8814-32a7248983ac)
268
268
 
269
- ## Todos:
269
+ ## Yak shaving
270
270
 
271
- next-yak is currently in the development phase, with several todos that must be completed before it is ready for production:
272
-
273
- - [ ] improve js parsing - right now it not reusing babel..
274
- - [ ] better sourcemaps
275
- - [ ] improve runtime code size and typings
276
- - [ ] maybe remove proxy by compiling `styled.button -> styled("button")`
277
- - [ ] better error messages
278
- - [x] replace the current config apporach with a solution similar to vanilla-extracts `.styles.ts` files
279
- - [x] add theme provider (which works for Server Components)
280
- - [x] add support for forwardRef
281
- - [x] add support for attrs
282
- - [x] config hot module reloading
283
-
271
+ While trying to get next-yak to work properly we stumbled accross several bugs.
272
+ Thanks for merging our prs fixes in next.js and postcss ❤️
284
273
 
285
274
  <details>
286
- <summary>prs</summary>
275
+ <summary>PRS</summary>
287
276
 
288
277
  - https://github.com/vercel/next.js/pull/51115
289
278
  - https://github.com/vercel/next.js/pull/53796
290
279
  - https://github.com/css-modules/postcss-modules-local-by-default/pull/64
280
+ - https://github.com/css-modules/postcss-modules-local-by-default/pull/72
281
+ - https://github.com/vercel/next.js/pull/62644
282
+ - https://github.com/vercel/next.js/pull/62639
283
+ - https://github.com/webpack-contrib/mini-css-extract-plugin/pull/1084
284
+ - https://github.com/vercel/next.js/pull/62733
285
+ - https://github.com/vercel/next.js/pull/64551
291
286
 
292
287
  </details>
293
288
 
289
+ <details>
290
+ <summary>Experiments</summary>
291
+ Incomplete work in progress experiments to test the features and performance of next-yak:
292
+
293
+ - https://next-yak-benchmark.vercel.app/
294
+ - https://yacijs.vercel.app/
295
+ </details>
296
+
294
297
  ## Acknowledgments
295
298
 
296
299
  Special thanks to the contributors and the inspiring projects that influenced next-yak:
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // loaders/css-loader.ts
31
+ var css_loader_exports = {};
32
+ __export(css_loader_exports, {
33
+ default: () => cssExtractLoader
34
+ });
35
+ module.exports = __toCommonJS(css_loader_exports);
36
+
37
+ // loaders/lib/resolveCrossFileSelectors.ts
38
+ var import_path = __toESM(require("path"), 1);
39
+ var import_core = __toESM(require("@babel/core"), 1);
40
+ var import_plugin_syntax_typescript = __toESM(require("@babel/plugin-syntax-typescript"), 1);
41
+ var import_getCssModuleLocalIdent = require("next/dist/build/webpack/config/blocks/css/loaders/getCssModuleLocalIdent.js");
42
+ async function resolveCrossFileSelectors(loader, css) {
43
+ const moduleSelectorRegex = /:module-selector-import\(([^)]+) from '([^']+)'\)/g;
44
+ const matches = [...css.matchAll(moduleSelectorRegex)];
45
+ const firstMatchPosition = matches[0]?.index;
46
+ if (firstMatchPosition === void 0) {
47
+ return css;
48
+ }
49
+ let result = "";
50
+ for (let i = matches.length - 1; i >= 0; i--) {
51
+ const match = matches[i];
52
+ const index = match.index;
53
+ if (index === void 0) {
54
+ throw new Error("Match index is undefined");
55
+ }
56
+ const namedExport = match[1];
57
+ const importPath = match[2];
58
+ const resolved = await resolveIdentifier(
59
+ loader,
60
+ loader.context,
61
+ importPath,
62
+ namedExport
63
+ );
64
+ if (resolved.type === "unsupported") {
65
+ throw new Error(
66
+ `yak could not import ${namedExport} from ${importPath} - only styled-components, strings and numbers are supported`
67
+ );
68
+ }
69
+ const replacement = resolved.type === "styled-component" ? `:global(.${(0, import_getCssModuleLocalIdent.getCssModuleLocalIdent)(
70
+ {
71
+ rootContext: loader.rootContext,
72
+ resourcePath: resolved.from
73
+ },
74
+ null,
75
+ resolved.name,
76
+ {}
77
+ )})` : resolved.value;
78
+ result = String(replacement) + css.slice(index + match[0].length, matches[i + 1]?.index) + result;
79
+ }
80
+ result = css.slice(0, firstMatchPosition) + result;
81
+ return result;
82
+ }
83
+ async function resolveIdentifier(loader, context, sourcePath, identifier) {
84
+ const resolved = await new Promise((resolve, reject) => {
85
+ loader.resolve(context, sourcePath, (err, result) => {
86
+ if (err) {
87
+ return reject(err);
88
+ }
89
+ if (!result) {
90
+ return reject(new Error(`Could not resolve ${sourcePath}`));
91
+ }
92
+ resolve(result);
93
+ });
94
+ });
95
+ loader.addDependency(resolved);
96
+ const exports = await getAllExports(
97
+ loader,
98
+ resolved,
99
+ resolved.endsWith(".tsx")
100
+ );
101
+ const exportForIdentifier = exports[identifier];
102
+ if (!exportForIdentifier) {
103
+ throw new Error(`Could not find export ${identifier} in ${resolved}
104
+ Currently only named exports are supported.
105
+ Available exports: ${Object.keys(exports).join(", ")}`);
106
+ }
107
+ if (exportForIdentifier.type === "styled-component") {
108
+ return {
109
+ type: "styled-component",
110
+ from: resolved,
111
+ name: exportForIdentifier.name
112
+ };
113
+ }
114
+ return exportForIdentifier.type !== "named-export" ? exportForIdentifier : resolveIdentifier(
115
+ loader,
116
+ import_path.default.dirname(resolved),
117
+ exportForIdentifier.from,
118
+ exportForIdentifier.name
119
+ );
120
+ }
121
+ var exportsCache = /* @__PURE__ */ new WeakMap();
122
+ async function getAllExports(loader, source, isTSX) {
123
+ const compilationCache = loader._compilation && exportsCache.get(loader._compilation)?.get(source);
124
+ if (compilationCache) {
125
+ return compilationCache;
126
+ }
127
+ const sourceContents = await new Promise(
128
+ (resolve, reject) => loader.fs.readFile(source, "utf-8", (err, result2) => {
129
+ if (err) {
130
+ return reject(err);
131
+ }
132
+ resolve(result2 || "");
133
+ })
134
+ );
135
+ let result = {};
136
+ import_core.default.transformSync(sourceContents, {
137
+ configFile: false,
138
+ plugins: [
139
+ [import_plugin_syntax_typescript.default, { isTSX }],
140
+ [
141
+ () => ({
142
+ visitor: {
143
+ ExportNamedDeclaration({ node }) {
144
+ if (node.source) {
145
+ node.specifiers.forEach((specifier) => {
146
+ const exportSource = node.source?.value;
147
+ if (specifier.exported.type === "Identifier" && specifier.exported.name && specifier.type === "ExportSpecifier" && specifier.local.type === "Identifier" && specifier.local.name && exportSource) {
148
+ result[specifier.exported.name] = {
149
+ type: "named-export",
150
+ name: specifier.local.name,
151
+ from: exportSource
152
+ };
153
+ }
154
+ });
155
+ } else if (node.declaration?.type === "VariableDeclaration") {
156
+ node.declaration.declarations.forEach((declaration) => {
157
+ if (declaration.id.type === "Identifier" && declaration.id.name && declaration.init) {
158
+ if (declaration.init.type === "CallExpression" || declaration.init.type === "TaggedTemplateExpression") {
159
+ result[declaration.id.name] = {
160
+ type: "styled-component",
161
+ name: declaration.id.name
162
+ };
163
+ } else if (declaration.init.type === "StringLiteral" || declaration.init.type === "NumericLiteral") {
164
+ result[declaration.id.name] = {
165
+ type: "constant",
166
+ value: declaration.init.value
167
+ };
168
+ } else {
169
+ result[declaration.id.name] = {
170
+ type: "unsupported",
171
+ name: declaration.id.name
172
+ };
173
+ }
174
+ }
175
+ });
176
+ }
177
+ },
178
+ ExportDefaultDeclaration() {
179
+ }
180
+ }
181
+ })
182
+ ]
183
+ ]
184
+ });
185
+ if (loader._compilation) {
186
+ const compilationCache2 = exportsCache.get(loader._compilation);
187
+ const exportsPerFile = compilationCache2 || /* @__PURE__ */ new Map();
188
+ exportsPerFile.set(source, result);
189
+ if (!compilationCache2) {
190
+ exportsCache.set(loader._compilation, exportsPerFile);
191
+ }
192
+ }
193
+ return result;
194
+ }
195
+
196
+ // loaders/css-loader.ts
197
+ async function cssExtractLoader(_code, sourceMap) {
198
+ const callback = this.async();
199
+ return this.loadModule(this.resourcePath, (err, source) => {
200
+ if (err) {
201
+ return callback(err);
202
+ }
203
+ const css = extractCss(source);
204
+ return resolveCrossFileSelectors(this, css).then(
205
+ (result) => callback(null, result, sourceMap),
206
+ callback
207
+ );
208
+ });
209
+ }
210
+ function extractCss(code) {
211
+ const codeParts = code.split("/*YAK Extracted CSS:\n");
212
+ let result = "";
213
+ for (let i = 1; i < codeParts.length; i++) {
214
+ const codeUntilEnd = codeParts[i].split("*/")[0];
215
+ result += codeUntilEnd;
216
+ }
217
+ return result;
218
+ }
219
+ //# sourceMappingURL=css-loader.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../loaders/css-loader.ts","../../loaders/lib/resolveCrossFileSelectors.ts"],"sourcesContent":["import type { LoaderContext } from \"webpack\";\nimport { resolveCrossFileSelectors } from \"./lib/resolveCrossFileSelectors.js\";\n/**\n * Transform typescript to css\n *\n * This loader takes the cached result from the yak tsloader\n * and extracts the css from the generated comments\n */\nexport default async function cssExtractLoader(\n this: LoaderContext<{}>,\n // Instead of the source code, we receive the extracted css\n // from the ts-loader transformation\n _code: string,\n sourceMap: string | undefined,\n): Promise<string | void> {\n const callback = this.async();\n // Load the module from the original typescript request (without !=! and the query)\n return this.loadModule(this.resourcePath, (err, source) => {\n if (err) {\n return callback(err);\n }\n const css = extractCss(source);\n return resolveCrossFileSelectors(this, css).then(\n (result) => callback(null, result, sourceMap),\n callback,\n );\n });\n}\n\nfunction extractCss(code: string): string {\n const codeParts = code.split(\"/*YAK Extracted CSS:\\n\");\n let result = \"\";\n for (let i = 1; i < codeParts.length; i++) {\n const codeUntilEnd = codeParts[i].split(\"*/\")[0];\n result += codeUntilEnd;\n }\n return result;\n}\n","import path from \"path\";\nimport babel from \"@babel/core\";\n// @ts-expect-error - this is used by babel directly so we ignore that it is not typed\nimport babelPlugin from \"@babel/plugin-syntax-typescript\";\nimport type { Compilation, LoaderContext } from \"webpack\";\nimport { getCssModuleLocalIdent } from \"next/dist/build/webpack/config/blocks/css/loaders/getCssModuleLocalIdent.js\";\n\nexport async function resolveCrossFileSelectors(\n loader: LoaderContext<{}>,\n css: string,\n): Promise<string> {\n // Search for :module-selector-import(FOO from 'bar')\n // generated by the yak babel plugin\n const moduleSelectorRegex =\n /:module-selector-import\\(([^)]+) from '([^']+)'\\)/g;\n const matches = [...css.matchAll(moduleSelectorRegex)];\n const firstMatchPosition = matches[0]?.index;\n if (firstMatchPosition === undefined) {\n return css;\n }\n let result = \"\";\n for (let i = matches.length - 1; i >= 0; i--) {\n const match = matches[i];\n const index = match.index;\n if (index === undefined) {\n throw new Error(\"Match index is undefined\");\n }\n const namedExport = match[1];\n const importPath = match[2];\n\n const resolved = await resolveIdentifier(\n loader,\n loader.context,\n importPath,\n namedExport,\n );\n if (resolved.type === \"unsupported\") {\n throw new Error(\n `yak could not import ${namedExport} from ${importPath} - only styled-components, strings and numbers are supported`,\n );\n }\n\n const replacement =\n resolved.type === \"styled-component\"\n ? `:global(.${getCssModuleLocalIdent(\n {\n rootContext: loader.rootContext,\n resourcePath: resolved.from,\n },\n null,\n resolved.name,\n {},\n )})`\n : resolved.value;\n\n // should be the internal namedExport identifier not the exported one\n result =\n String(replacement) +\n css.slice(index + match[0].length, matches[i + 1]?.index) +\n result;\n }\n result = css.slice(0, firstMatchPosition) + result;\n return result;\n}\n\n/**\n * Recursively follows the import chain to resolve the identifiers\n * type, name and value.\n *\n * Currently only supports named exports\n */\nasync function resolveIdentifier(\n loader: LoaderContext<{}>,\n context: string,\n sourcePath: string,\n identifier: string,\n): Promise<\n | {\n type: \"styled-component\";\n from: string;\n name: string;\n }\n | {\n type: \"unsupported\";\n name: string;\n }\n | {\n type: \"constant\";\n value: string | number;\n }\n> {\n const resolved = await new Promise<string>((resolve, reject) => {\n loader.resolve(context, sourcePath, (err, result) => {\n if (err) {\n return reject(err);\n }\n if (!result) {\n return reject(new Error(`Could not resolve ${sourcePath}`));\n }\n resolve(result);\n });\n });\n loader.addDependency(resolved);\n const exports = await getAllExports(\n loader,\n resolved,\n resolved.endsWith(\".tsx\"),\n );\n const exportForIdentifier = exports[identifier];\n if (!exportForIdentifier) {\n throw new Error(`Could not find export ${identifier} in ${resolved}\nCurrently only named exports are supported.\nAvailable exports: ${Object.keys(exports).join(\", \")}`);\n }\n if (exportForIdentifier.type === \"styled-component\") {\n return {\n type: \"styled-component\",\n from: resolved,\n name: exportForIdentifier.name,\n };\n }\n return exportForIdentifier.type !== \"named-export\"\n ? exportForIdentifier\n : resolveIdentifier(\n loader,\n path.dirname(resolved),\n exportForIdentifier.from,\n exportForIdentifier.name,\n );\n}\n\ntype ResolvedExport =\n | {\n type: \"unsupported\";\n name: string;\n }\n | {\n type: \"styled-component\";\n name: string;\n }\n | {\n type: \"constant\";\n value: string | number;\n }\n | {\n type: \"named-export\";\n name: string;\n from: string;\n };\n\n/**\n * Cache the exports per file name to avoid parsing the same file multiple times\n */\nconst exportsCache = new WeakMap<\n Compilation,\n Map<string, Record<string, ResolvedExport>>\n>();\n\n/**\n * Use babel together with the \"@babel/plugin-syntax-typescript\" to extract all exports from a typescript file\n */\nasync function getAllExports(\n loader: LoaderContext<{}>,\n source: string,\n isTSX: boolean,\n): Promise<{ [key: string]: ResolvedExport }> {\n const compilationCache =\n loader._compilation && exportsCache.get(loader._compilation)?.get(source);\n if (compilationCache) {\n return compilationCache;\n }\n\n const sourceContents = await new Promise<string>((resolve, reject) =>\n loader.fs.readFile(source, \"utf-8\", (err, result) => {\n if (err) {\n return reject(err);\n }\n resolve(result || \"\");\n }),\n );\n\n let result: { [key: string]: ResolvedExport } = {};\n babel.transformSync(sourceContents, {\n configFile: false,\n plugins: [\n [babelPlugin, { isTSX }],\n [\n (): babel.PluginObj => ({\n visitor: {\n ExportNamedDeclaration({ node }) {\n // reexports e.g. export { Baz as Bar } from \"./foo\"\n if (node.source) {\n node.specifiers.forEach((specifier) => {\n const exportSource = node.source?.value;\n if (\n specifier.exported.type === \"Identifier\" &&\n specifier.exported.name &&\n specifier.type === \"ExportSpecifier\" &&\n specifier.local.type === \"Identifier\" &&\n specifier.local.name &&\n exportSource\n ) {\n result[specifier.exported.name] = {\n type: \"named-export\",\n name: specifier.local.name,\n from: exportSource,\n };\n }\n });\n } // named export e.g. export const Foo = 1\n else if (node.declaration?.type === \"VariableDeclaration\") {\n node.declaration.declarations.forEach((declaration) => {\n if (\n declaration.id.type === \"Identifier\" &&\n declaration.id.name &&\n declaration.init\n ) {\n // TODO: check if this is a styled component, or constant, or sth unsupported\n if (\n declaration.init.type === \"CallExpression\" ||\n declaration.init.type === \"TaggedTemplateExpression\"\n ) {\n result[declaration.id.name] = {\n type: \"styled-component\",\n name: declaration.id.name,\n };\n } else if (\n declaration.init.type === \"StringLiteral\" ||\n declaration.init.type === \"NumericLiteral\"\n ) {\n result[declaration.id.name] = {\n type: \"constant\",\n value: declaration.init.value,\n };\n } else {\n result[declaration.id.name] = {\n type: \"unsupported\",\n name: declaration.id.name,\n };\n }\n }\n });\n }\n },\n ExportDefaultDeclaration() {\n // TODO: add support for default exports\n },\n },\n }),\n ],\n ],\n });\n if (loader._compilation) {\n const compilationCache = exportsCache.get(loader._compilation);\n const exportsPerFile = compilationCache || new Map();\n exportsPerFile.set(source, result);\n if (!compilationCache) {\n exportsCache.set(loader._compilation, exportsPerFile);\n }\n }\n return result;\n}\n"],"mappings":"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","names":["path","result","babel","babelPlugin","compilationCache"]}
@@ -0,0 +1,11 @@
1
+ import { LoaderContext } from 'webpack';
2
+
3
+ /**
4
+ * Transform typescript to css
5
+ *
6
+ * This loader takes the cached result from the yak tsloader
7
+ * and extracts the css from the generated comments
8
+ */
9
+ declare function cssExtractLoader(this: LoaderContext<{}>, _code: string, sourceMap: string | undefined): Promise<string | void>;
10
+
11
+ export { cssExtractLoader as default };
@@ -27,12 +27,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  ));
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
- // loaders/tsloader.ts
31
- var tsloader_exports = {};
32
- __export(tsloader_exports, {
30
+ // loaders/ts-loader.ts
31
+ var ts_loader_exports = {};
32
+ __export(ts_loader_exports, {
33
33
  default: () => tsloader
34
34
  });
35
- module.exports = __toCommonJS(tsloader_exports);
35
+ module.exports = __toCommonJS(ts_loader_exports);
36
36
  var babel = __toESM(require("@babel/core"), 1);
37
37
  var import_plugin_syntax_typescript = __toESM(require("@babel/plugin-syntax-typescript"), 1);
38
38
 
@@ -85,10 +85,23 @@ function getConstantValues(path, t) {
85
85
  const bindings = Object.entries(path.scope.bindings);
86
86
  for (const [name, binding] of bindings) {
87
87
  if (binding.kind === "module") {
88
- topLevelConstBindings.set(name, {
89
- value: null,
90
- type: "module"
91
- });
88
+ const node = binding.path.node;
89
+ const parent = binding.path.parent;
90
+ if (node.type === "ImportSpecifier" && parent?.type === "ImportDeclaration" && node.imported.type === "Identifier") {
91
+ topLevelConstBindings.set(name, {
92
+ value: null,
93
+ type: "module",
94
+ name: node.imported.name,
95
+ source: parent.source.value
96
+ });
97
+ } else {
98
+ topLevelConstBindings.set(name, {
99
+ value: null,
100
+ type: "module",
101
+ name,
102
+ source: null
103
+ });
104
+ }
92
105
  continue;
93
106
  }
94
107
  if (binding.kind === "let" || binding.kind === "var" || binding.kind === "const") {
@@ -657,7 +670,7 @@ function babel_yak_plugin_default(babel2, options) {
657
670
  enter(path) {
658
671
  this.topLevelConstBindings = getConstantValues(path, t);
659
672
  },
660
- exit(path, state) {
673
+ exit(_path, state) {
661
674
  if (!this.isImportedInCurrentFile) {
662
675
  return;
663
676
  }
@@ -690,7 +703,8 @@ function babel_yak_plugin_default(babel2, options) {
690
703
  this.runtimeInternalHelpers,
691
704
  getComponentTypes(this.yakTemplateExpressionsByPath),
692
705
  this.topLevelConstBindings,
693
- state.file
706
+ state.file,
707
+ options.crossFile
694
708
  );
695
709
  }
696
710
  );
@@ -705,7 +719,7 @@ function babel_yak_plugin_default(babel2, options) {
705
719
  }
706
720
  }
707
721
  },
708
- JSXElement(path, state) {
722
+ JSXElement(path) {
709
723
  if (!this.isImportedInCurrentFile || !this.yakImportPath) {
710
724
  return;
711
725
  }
@@ -758,7 +772,7 @@ function babel_yak_plugin_default(babel2, options) {
758
772
  * - styled.div.attrs({})`...`
759
773
  * - keyframes`...`
760
774
  */
761
- TaggedTemplateExpression(path, state) {
775
+ TaggedTemplateExpression(path) {
762
776
  if (!this.isImportedInCurrentFile) {
763
777
  return;
764
778
  }
@@ -915,7 +929,7 @@ function visitYakExpression(yakTemplateExpressions, visitor) {
915
929
  });
916
930
  }
917
931
  var rootExpressionCssDeclarations = /* @__PURE__ */ new WeakMap();
918
- function transformYakExpressions(expression, rootExpression, cssParserState, visitChildren, createUniqueName, runtimeInternalHelpers, componentTypeMapping, constantValues, file) {
932
+ function transformYakExpressions(expression, rootExpression, cssParserState, visitChildren, createUniqueName, runtimeInternalHelpers, componentTypeMapping, constantValues, file, crossFileSelectors) {
919
933
  const identifier2 = createUniqueName(
920
934
  expression === rootExpression ? expression.name : `${rootExpression.name}__${expression.name}`
921
935
  );
@@ -946,23 +960,32 @@ function transformYakExpressions(expression, rootExpression, cssParserState, vis
946
960
  quasiExpression,
947
961
  file
948
962
  );
949
- }
950
- if (constantValue.type === "module") {
951
- throw new InvalidPositionError(
952
- `Imported values cannot be used as constants`,
953
- quasiExpression,
954
- file,
955
- "Move the constant into the current file or into a .yak file"
956
- );
957
- }
958
- if (constantValue.type === "function") {
963
+ } else if (constantValue.type === "function") {
959
964
  throw new InvalidPositionError(
960
965
  `Function constants are not supported yet`,
961
966
  quasiExpression,
962
967
  file
963
968
  );
969
+ } else if (constantValue.type === "module") {
970
+ if (!crossFileSelectors) {
971
+ throw new InvalidPositionError(
972
+ `Module constants are not allowed in this context`,
973
+ quasiExpression,
974
+ file,
975
+ `Use the 'experiments.crossFileSelectors' option to enable cross file selectors`
976
+ );
977
+ }
978
+ if (constantValue.source === null) {
979
+ throw new InvalidPositionError(
980
+ `Module constant could not be resolved`,
981
+ quasiExpression,
982
+ file
983
+ );
984
+ }
985
+ replaceValue = `:module-selector-import(${constantValue.name} from '${constantValue.source}')`;
986
+ } else {
987
+ replaceValue = String(constantValue?.value);
964
988
  }
965
- replaceValue = String(constantValue?.value);
966
989
  } else {
967
990
  }
968
991
  if (replaceValue !== null) {
@@ -1087,14 +1110,14 @@ function getComponentTypes(yakTemplateExpressions) {
1087
1110
  return Object.fromEntries(nameTypeMap);
1088
1111
  }
1089
1112
 
1090
- // loaders/tsloader.ts
1113
+ // loaders/ts-loader.ts
1091
1114
  async function tsloader(source) {
1092
1115
  if (!source.includes("next-yak")) {
1093
1116
  return source;
1094
1117
  }
1095
1118
  const callback = this.async();
1096
1119
  const { rootContext, resourcePath } = this;
1097
- const isYakFile = /\.yak\.(j|t)sx?$/.test(resourcePath.matches);
1120
+ const isYakFile = /\.yak\.(j|t)sx?$/.test(resourcePath);
1098
1121
  const importedYakConstants = isYakFile ? [] : getYakImports_default(source);
1099
1122
  const replaces = {};
1100
1123
  await Promise.all(
@@ -1119,7 +1142,8 @@ async function tsloader(source) {
1119
1142
  {
1120
1143
  replaces,
1121
1144
  rootContext,
1122
- devMode: this.mode === "development"
1145
+ devMode: this.mode === "development",
1146
+ crossFile: this.getOptions().experiments?.crossFileSelectors ?? false
1123
1147
  }
1124
1148
  ]
1125
1149
  ]
@@ -1135,6 +1159,6 @@ async function tsloader(source) {
1135
1159
  if (!result?.code) {
1136
1160
  return callback(new Error("babel transform failed"));
1137
1161
  }
1138
- return callback(null, result.code, result.map);
1162
+ return callback(null, result.code, result.map ?? void 0);
1139
1163
  }
1140
- //# sourceMappingURL=tsloader.cjs.map
1164
+ //# sourceMappingURL=ts-loader.cjs.map