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.
- package/README.md +21 -18
- package/dist/loaders/css-loader.cjs +219 -0
- package/dist/loaders/css-loader.cjs.map +1 -0
- package/dist/loaders/css-loader.d.cts +11 -0
- package/dist/loaders/{tsloader.cjs → ts-loader.cjs} +53 -29
- package/dist/loaders/ts-loader.cjs.map +1 -0
- package/dist/loaders/ts-loader.d.cts +9 -0
- package/dist/withYak/index.cjs +8 -4
- package/dist/withYak/index.cjs.map +1 -1
- package/dist/withYak/index.d.cts +3 -0
- package/dist/withYak/index.d.ts +3 -0
- package/dist/withYak/index.js +8 -4
- package/dist/withYak/index.js.map +1 -1
- package/loaders/__tests__/cssloader.test.ts +65 -81
- package/loaders/__tests__/tsloader.test.ts +45 -7
- package/loaders/babel-yak-plugin.ts +26 -14
- package/loaders/css-loader.ts +38 -0
- package/loaders/lib/getConstantValues.ts +28 -5
- package/loaders/lib/resolveCrossFileSelectors.ts +262 -0
- package/loaders/lib/transpileCssProp.ts +1 -5
- package/loaders/{tsloader.ts → ts-loader.ts} +8 -3
- package/package.json +7 -7
- package/withYak/index.ts +12 -3
- package/dist/loaders/cssloader.cjs +0 -61
- package/dist/loaders/cssloader.cjs.map +0 -1
- package/dist/loaders/cssloader.d.cts +0 -8
- package/dist/loaders/cssloader.d.ts +0 -8
- package/dist/loaders/cssloader.js +0 -30
- package/dist/loaders/cssloader.js.map +0 -1
- package/dist/loaders/tsloader.cjs.map +0 -1
- package/dist/loaders/tsloader.d.cts +0 -6
- package/dist/loaders/tsloader.d.ts +0 -6
- package/dist/loaders/tsloader.js +0 -1109
- package/dist/loaders/tsloader.js.map +0 -1
- package/loaders/cssloader.ts +0 -35
- 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.
|
|
42
|
+
2. Add next-yak to your `next.config.mjs`:
|
|
43
43
|
|
|
44
44
|
```js
|
|
45
45
|
// next.config.js
|
|
46
|
-
|
|
46
|
+
import { withYak } from "next-yak/withYak";
|
|
47
47
|
|
|
48
48
|
const nextConfig = {
|
|
49
49
|
// your next.js config
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
|
|
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
|
-
##
|
|
269
|
+
## Yak shaving
|
|
270
270
|
|
|
271
|
-
next-yak
|
|
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>
|
|
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/
|
|
31
|
-
var
|
|
32
|
-
__export(
|
|
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(
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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(
|
|
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
|
|
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
|
|
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/
|
|
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
|
|
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=
|
|
1164
|
+
//# sourceMappingURL=ts-loader.cjs.map
|