Skip to content

Commit

Permalink
optimize yak in yak (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
jantimon authored Nov 7, 2023
1 parent 5eeb082 commit 2d8eda8
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 7 deletions.
33 changes: 33 additions & 0 deletions packages/next-yak/loaders/__tests__/cssloader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,39 @@ const headline = css\`
`);
});

it("should replace breakpoint references with actual media queries from single quote imports", async () => {
expect(
await cssloader.call(
loaderContext,
`
import { css } from "next-yak";
import { queries } from '@/theme.yak';
const headline = css\`
color: blue;
\${queries.sm} {
color: red;
}
transition: color \${duration} \${easing};
display: block;
\${css\`color: orange\`}
\`;
`
)
).toMatchInlineSnapshot(`
".yak_0 {
color: blue;
@media (min-width: 640px) {
color: red;
}
transition: color var(--🦬18fi82j0) var(--🦬18fi82j1);
display: block;
}
.yak_1 { color: orange }"
`);
});

it("should prevent double escaped chars", async () => {
// in styled-components \\ is replaced with \
// this test verifies that yak provides the same behavior
Expand Down
10 changes: 8 additions & 2 deletions packages/next-yak/loaders/cssloader.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,16 @@ const { relative } = require("path");
* @returns {Promise<string>}
*/
module.exports = async function cssLoader(source) {
const { rootContext, resourcePath } = this;

/** .yak files are constant definition files */
const isYakFile = /\.yak\.(j|t)sx?$/.test(resourcePath.matches);
// The user may import constants from a yak file
// e.g. import { primary } from './colors.yak'
const importedYakConstants = getYakImports(source);
//
// However .yak files inside .yak files are not be compiled
// to avoid performance overhead
const importedYakConstants = isYakFile ? [] : getYakImports(source);
/** @type {Record<string, unknown>} */
const replaces = {};
await Promise.all(importedYakConstants.map(async ({imports, from}) => {
Expand Down Expand Up @@ -57,7 +64,6 @@ module.exports = async function cssLoader(source) {
let varIndex = 0;
/** @type {string | null} */
let hashedFile = null;
const { rootContext, resourcePath } = this;

/**
* find all css template literals in ast
Expand Down
2 changes: 1 addition & 1 deletion packages/next-yak/loaders/lib/getYakImports.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*/
const getYakImports = (code) => {
const codeWithoutComments = code.replace(/\/\*[\s\S]*?\*\//g, '');
const allImports = codeWithoutComments.matchAll(/(^|\n|;)\s*import\s+(?:(\w+(?:\s+as\s+\w+)?)\s*,?\s*)?(?:{([^}]*)})?\s+from\s+"([^"]+\.yak)"(;|\n)/g);
const allImports = codeWithoutComments.matchAll(/(^|\n|;)\s*import\s+(?:(\w+(?:\s+as\s+\w+)?)\s*,?\s*)?(?:{([^}]*)})?\s+from\s+["']([^'"]+\.yak)["'](;|\n)/g);
return [...allImports].map(([, , defaultImport, namedImports, from,]) => {
// parse named imports to { localName: string, importedName: string }[]
const imports = namedImports?.split(',').map((namedImport) => {
Expand Down
11 changes: 8 additions & 3 deletions packages/next-yak/loaders/tsloader.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@ module.exports = async function tsloader(source) {
return source;
}
const callback = this.async();
const { rootContext, resourcePath } = this;

// The user may import constants from a yak file
/** .yak files are constant definition files */
const isYakFile = /\.yak\.(j|t)sx?$/.test(resourcePath.matches);
// The user may import constants from a .yak file
// e.g. import { primary } from './colors.yak'
const importedYakConstantNames = getYakImports(source).map(({ imports }) => imports.map(({ localName }) => localName)).flat(2);
//
// However .yak files inside .yak files are not be compiled
// to avoid performance overhead
const importedYakConstantNames = isYakFile ? [] : getYakImports(source).map(({ imports }) => imports.map(({ localName }) => localName)).flat(2);
const replaces = Object.fromEntries(importedYakConstantNames.map((name) => [name, null]));

const { rootContext, resourcePath } = this;
// Compile the typescript file with babel - this will:
// - inject the import to the css-module (with .yak.module.css extension)
// - replace the css template literal with styles from the css-module
Expand Down
2 changes: 1 addition & 1 deletion packages/next-yak/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "next-yak",
"version": "0.0.13",
"version": "0.0.16",
"type": "module",
"types": "./dist/",
"exports": {
Expand Down

0 comments on commit 2d8eda8

Please sign in to comment.