From e7d47e5be139ba041159735e52a728515eb90c03 Mon Sep 17 00:00:00 2001 From: Gaubee Date: Mon, 21 Apr 2025 17:11:25 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=94=A7=20add=20vscode=20recommend=20?= =?UTF-8?q?=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 ++- .vscode/extensions.json | 5 +++++ .vscode/settings.recommend.json | 8 ++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.recommend.json diff --git a/.gitignore b/.gitignore index 246e8b2..c98486e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules scripts/dist packages/*/dist -.turbo \ No newline at end of file +.turbo +.vscode/settings.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..a5824a5 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "biomejs.biome" + ] +} \ No newline at end of file diff --git a/.vscode/settings.recommend.json b/.vscode/settings.recommend.json new file mode 100644 index 0000000..d83931f --- /dev/null +++ b/.vscode/settings.recommend.json @@ -0,0 +1,8 @@ +{ + "[json]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome" + }, +} \ No newline at end of file From 0dbfb4276a155976a6058f9b8d1afd704a759f56 Mon Sep 17 00:00:00 2001 From: Gaubee Date: Mon, 21 Apr 2025 17:19:13 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E2=9C=A8=20[minify-literals]=20better=20cs?= =?UTF-8?q?sText=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit getPlaceholder now supports "strict mode" (return `string[]`), whereas it originally returne `string` ("loose mode"). This better supports CSSminify. The following Template literals syntax patterns are supported: ``` 1. selector ${selector} { } 2. key selector { ${key}: value; } 3. rule [selector {}] ${rule} [selector {}] 4. number-literal selector{ key: ${param}px; } 5. value selector { key: ${value}; key: ${value} } 6. param selector{ key: fun(${param}[, ${param}]); } ``` --- packages/minify-literals/lib/index.test.ts | 63 ++++++++- packages/minify-literals/lib/index.ts | 10 +- packages/minify-literals/lib/strategy.test.ts | 9 +- packages/minify-literals/lib/strategy.ts | 123 ++++++++++++++++-- .../package.json | 2 +- 5 files changed, 186 insertions(+), 21 deletions(-) diff --git a/packages/minify-literals/lib/index.test.ts b/packages/minify-literals/lib/index.test.ts index 5607a98..6a2b042 100644 --- a/packages/minify-literals/lib/index.test.ts +++ b/packages/minify-literals/lib/index.test.ts @@ -12,11 +12,68 @@ import { } from "./"; import { defaultMinifyOptions, defaultStrategy } from "./strategy"; +/** + * get code snippet from function body + */ +const fn_body = (fn: Function, tabSize = 2) => { + const fn_str = fn.toString(); + const body_str = fn_str + .slice(fn_str.indexOf("{") + 1, fn_str.lastIndexOf("}")) + // remove trailing whitespace + .trimEnd() + // remove empty lines + .replace(/^([\s\t]*$\r?\n)+/gm, "") + // use spaces uniformly: current indentStyle is "tab",and tab-width == 2(spaces) + .replace(/^\t+/gm, (tabs) => " ".repeat(tabs.length * tabSize)); + /// remove indent + const indent = body_str.match(/\s+/)?.[0]; + if (!indent) { + return body_str.trim(); + } + const indent_reg = new RegExp(`^\\s{${indent.length}}`, "gm"); + return body_str.replace(indent_reg, ""); +}; // https://github.com/explodingcamera/esm/issues/1 describe("handle key value pairs correctly", () => { - it("should minify html", async () => { - const source = `const css = css\`:host{\${"color"}: \${"red"}}\``; - expect((await minifyHTMLLiterals(source))?.code).toMatch('const css = css`:host{${"color"}:${"red"}}`'); + it("should minify css", async () => { + const source = fn_body((css = String.raw) => { + const cssText = css`:host{ + ${"color"}: ${"red"}; + }`; + }); + + expect((await minifyHTMLLiterals(source))?.code).toMatch( + fn_body((css = String.raw) => { + const cssText = css`:host{${"color"}:${"red"}}`; + }), + ); + }); + + it("should minify css with unit", async () => { + const source = fn_body((css = String.raw) => { + const cssText = css`:host{ + ${"width"}: ${10}px; + }`; + }); + + expect((await minifyHTMLLiterals(source))?.code).toMatch( + fn_body((css = String.raw) => { + const cssText = css`:host{${"width"}:${10}px}`; + }), + ); + }); + it("should minify css within css-function", async () => { + const source = fn_body((css = String.raw) => { + const cssText = css`:host{ + ${"width"}: calc(${10}px + ${"var(--data)"}); + }`; + }); + + expect((await minifyHTMLLiterals(source))?.code).toMatch( + fn_body((css = String.raw) => { + const cssText = css`:host{${"width"}:calc(${10}px + ${"var(--data)"})}`; + }), + ); }); }); diff --git a/packages/minify-literals/lib/index.ts b/packages/minify-literals/lib/index.ts index 93d0699..a09f923 100644 --- a/packages/minify-literals/lib/index.ts +++ b/packages/minify-literals/lib/index.ts @@ -210,9 +210,13 @@ export function defaultShouldMinifyCSS(template: Template) { */ export const defaultValidation: Validation = { ensurePlaceholderValid(placeholder) { - if (typeof placeholder !== "string" || !placeholder.length) { - throw new Error("getPlaceholder() must return a non-empty string"); + if (typeof placeholder === "string" && placeholder.length > 0) { + return; } + if (Array.isArray(placeholder) && placeholder.every((ph) => ph.length > 0)) { + return; + } + throw new Error("getPlaceholder() must return a non-empty string | string[]"); }, ensureHTMLPartsValid(parts, htmlParts) { if (parts.length !== htmlParts.length) { @@ -291,7 +295,7 @@ export async function minifyHTMLLiterals(source: string, options: Options = {}): if (!(minifyHTML || minifyCSS)) return; - const placeholder = strategy.getPlaceholder(template.parts); + const placeholder = strategy.getPlaceholder(template.parts, template.tag); if (validate) { validate.ensurePlaceholderValid(placeholder); } diff --git a/packages/minify-literals/lib/strategy.test.ts b/packages/minify-literals/lib/strategy.test.ts index 7ac991d..929f0bf 100644 --- a/packages/minify-literals/lib/strategy.test.ts +++ b/packages/minify-literals/lib/strategy.test.ts @@ -26,10 +26,12 @@ describe("strategy", () => { }); it('should append "_" if placeholder exists in templates', () => { - const regularPlaceholder = defaultStrategy.getPlaceholder(parts); + const regularPlaceholder = defaultStrategy.getPlaceholder(parts) as string; + expect(regularPlaceholder).toBeTypeOf("string"); const oneUnderscore = defaultStrategy.getPlaceholder([ { text: regularPlaceholder, start: 0, end: regularPlaceholder.length }, - ]); + ]) as string; + expect(oneUnderscore).toBeTypeOf("string"); expect(oneUnderscore).not.toEqual(regularPlaceholder); expect(oneUnderscore.includes("_")).toEqual(true); @@ -53,7 +55,8 @@ describe("strategy", () => { }); it("should return a value that is preserved by html-minifier when splitting", async () => { - const placeholder = defaultStrategy.getPlaceholder(parts); + const placeholder = defaultStrategy.getPlaceholder(parts) as string; + expect(placeholder).toBeTypeOf("string"); const minHtml = await defaultStrategy.minifyHTML( `