tkeron 5.2.0 → 5.3.0
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/changelog.md +15 -3
- package/examples/with_style_dedup/websrc/index.html +29 -0
- package/examples/with_style_dedup/websrc/tag-chip.com.ts +19 -0
- package/package.json +2 -11
- package/src/build.ts +3 -0
- package/src/deduplicateComStyles.ts +41 -0
- package/src/processCom.ts +2 -2
- package/src/processComTs.ts +2 -2
package/changelog.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# v5.3.0
|
|
2
|
+
|
|
3
|
+
## Feature: Automatic component style deduplication
|
|
4
|
+
|
|
5
|
+
- Component `<style data-tk-com>` elements are now automatically deduplicated at build time
|
|
6
|
+
- When a component is used multiple times, only one copy of its `<style>` is kept — moved to `<head>`
|
|
7
|
+
- Runs as a new build step (`deduplicateComStyles`) between component resolution and `.post.ts` execution
|
|
8
|
+
- The `.post.ts` script now receives an already-clean DOM with no duplicate styles
|
|
9
|
+
- Added example `with_style_dedup` demonstrating the feature
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
1
13
|
# v5.2.0
|
|
2
14
|
|
|
3
15
|
## Feature: `.post.ts` post-processing support
|
|
@@ -8,10 +20,10 @@
|
|
|
8
20
|
- Useful for final DOM manipulation, injecting metadata, or any transformation after components are resolved
|
|
9
21
|
- `processPost` returns `false` when no `.post.ts` files are found (no-op)
|
|
10
22
|
|
|
11
|
-
## Feature: `data-tk-
|
|
23
|
+
## Feature: `data-tk-com` attribute on component `<style>` elements
|
|
12
24
|
|
|
13
|
-
- Root-level `<style>` elements in component output now receive a `data-tk-
|
|
14
|
-
- Nested `<style>` elements (inside wrappers) also receive `data-tk-
|
|
25
|
+
- Root-level `<style>` elements in component output now receive a `data-tk-com="component-name"` attribute
|
|
26
|
+
- Nested `<style>` elements (inside wrappers) also receive `data-tk-com`
|
|
15
27
|
- Applies to both `.com.html` and `.com.ts` components
|
|
16
28
|
- Enables per-component style scoping and identification in the final HTML
|
|
17
29
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Style Deduplication Example</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<h1>Auto Style Deduplication</h1>
|
|
10
|
+
<p>
|
|
11
|
+
Each <code><tag-chip></code> component has its own
|
|
12
|
+
<code><style></code>. tkeron automatically keeps only one copy in
|
|
13
|
+
<code><head></code> — no matter how many times the component is
|
|
14
|
+
used.
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<tag-chip label="TypeScript"></tag-chip>
|
|
18
|
+
<tag-chip label="HTML"></tag-chip>
|
|
19
|
+
<tag-chip label="CSS"></tag-chip>
|
|
20
|
+
<tag-chip label="Bun"></tag-chip>
|
|
21
|
+
<tag-chip label="tkeron"></tag-chip>
|
|
22
|
+
<tag-chip label="zero deps"></tag-chip>
|
|
23
|
+
|
|
24
|
+
<p>
|
|
25
|
+
6 chips above → 1 <code><style data-tk-com="tag-chip"></code> in
|
|
26
|
+
<code><head></code>.
|
|
27
|
+
</p>
|
|
28
|
+
</body>
|
|
29
|
+
</html>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const label = com.getAttribute("label") || "tag";
|
|
2
|
+
|
|
3
|
+
com.innerHTML = `
|
|
4
|
+
<style>
|
|
5
|
+
.tag-chip {
|
|
6
|
+
display: inline-block;
|
|
7
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
8
|
+
color: white;
|
|
9
|
+
padding: 0.2rem 0.65rem;
|
|
10
|
+
border-radius: 999px;
|
|
11
|
+
font-size: 0.75rem;
|
|
12
|
+
font-weight: 600;
|
|
13
|
+
margin: 0.2rem;
|
|
14
|
+
font-family: monospace;
|
|
15
|
+
letter-spacing: 0.02em;
|
|
16
|
+
}
|
|
17
|
+
</style>
|
|
18
|
+
<span class="tag-chip">${label}</span>
|
|
19
|
+
`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tkeron",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"description": "CLI build tool for vanilla web development with TypeScript.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -18,16 +18,7 @@
|
|
|
18
18
|
"scripts": {
|
|
19
19
|
"tk": "bun index.ts ",
|
|
20
20
|
"test": "bun test --concurrent",
|
|
21
|
-
"lint": "prettier --write ."
|
|
22
|
-
"sample1": "bun . build examples/basic_build/src",
|
|
23
|
-
"sample2": "bun . build examples/with_assets/src",
|
|
24
|
-
"sample3": "bun . build examples/with_pre/src",
|
|
25
|
-
"sample4": "bun . build examples/with_com_html_priority/src",
|
|
26
|
-
"sample5": "bun . build examples/with_com_ts/src",
|
|
27
|
-
"sample6": "bun . build examples/with_com_ts_priority/src",
|
|
28
|
-
"sample7": "bun . build examples/with_com_mixed_priority/src",
|
|
29
|
-
"sample8": "bun . build examples/with_com_html_in_ts/src",
|
|
30
|
-
"build_examples": "bun run sample1 && bun run sample2 && bun run sample3 && bun run sample4 && bun run sample5 && bun run sample6 && bun run sample7 && bun run sample8"
|
|
21
|
+
"lint": "prettier --write ."
|
|
31
22
|
},
|
|
32
23
|
"author": "tkeron",
|
|
33
24
|
"license": "MIT",
|
package/src/build.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { processCom } from "./processCom";
|
|
|
5
5
|
import { processComTs } from "./processComTs";
|
|
6
6
|
import { processComMd } from "./processComMd";
|
|
7
7
|
import { processPost } from "./processPost";
|
|
8
|
+
import { deduplicateComStyles } from "./deduplicateComStyles";
|
|
8
9
|
import { rm, exists, mkdir, cp } from "fs/promises";
|
|
9
10
|
import type { Logger } from "@tkeron/tools";
|
|
10
11
|
import { silentLogger } from "@tkeron/tools";
|
|
@@ -57,6 +58,8 @@ export const build = async (options: BuildOptions) => {
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
await deduplicateComStyles(tempDir);
|
|
62
|
+
|
|
60
63
|
await processPost(tempDir, { logger: log, projectRoot: sourceParent });
|
|
61
64
|
|
|
62
65
|
if (await exists(target)) {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { parseHTML } from "@tkeron/html-parser";
|
|
2
|
+
import { getFilePaths } from "@tkeron/tools";
|
|
3
|
+
|
|
4
|
+
const DOCTYPE = "<!doctype html>\n";
|
|
5
|
+
|
|
6
|
+
export const deduplicateComStyles = async (tempDir: string): Promise<void> => {
|
|
7
|
+
if (!tempDir || typeof tempDir !== "string") return;
|
|
8
|
+
|
|
9
|
+
const htmlFiles = getFilePaths(tempDir, "**/*.html", true).filter(
|
|
10
|
+
(p) => !p.endsWith(".com.html"),
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
await Promise.all(
|
|
14
|
+
htmlFiles.map(async (htmlFile) => {
|
|
15
|
+
const htmlContent = await Bun.file(htmlFile).text();
|
|
16
|
+
const document = parseHTML(htmlContent);
|
|
17
|
+
|
|
18
|
+
const allStyles = document.querySelectorAll("style[data-tk-com]");
|
|
19
|
+
if (!allStyles || allStyles.length === 0) return;
|
|
20
|
+
|
|
21
|
+
const seen = new Set<string>();
|
|
22
|
+
const head = document.querySelector("head");
|
|
23
|
+
|
|
24
|
+
for (const style of allStyles) {
|
|
25
|
+
const tkId = style.getAttribute("data-tk-com");
|
|
26
|
+
if (!tkId) continue;
|
|
27
|
+
|
|
28
|
+
if (seen.has(tkId)) {
|
|
29
|
+
style.remove();
|
|
30
|
+
} else {
|
|
31
|
+
seen.add(tkId);
|
|
32
|
+
if (head) head.appendChild(style);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const htmlElement = document.documentElement;
|
|
37
|
+
const output = DOCTYPE + (htmlElement?.outerHTML || "");
|
|
38
|
+
await Bun.write(htmlFile, output);
|
|
39
|
+
}),
|
|
40
|
+
);
|
|
41
|
+
};
|
package/src/processCom.ts
CHANGED
|
@@ -192,11 +192,11 @@ const processComponents = async (
|
|
|
192
192
|
for (const node of nodesToInsert) {
|
|
193
193
|
if ((node as any).nodeType === 1) {
|
|
194
194
|
if ((node as any).tagName?.toLowerCase() === "style") {
|
|
195
|
-
(node as any).setAttribute("data-tk-
|
|
195
|
+
(node as any).setAttribute("data-tk-com", tagName);
|
|
196
196
|
}
|
|
197
197
|
const nested = (node as any).querySelectorAll?.("style") || [];
|
|
198
198
|
for (const styleEl of nested) {
|
|
199
|
-
(styleEl as any).setAttribute("data-tk-
|
|
199
|
+
(styleEl as any).setAttribute("data-tk-com", tagName);
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
}
|
package/src/processComTs.ts
CHANGED
|
@@ -338,11 +338,11 @@ ${codeWithoutImports}
|
|
|
338
338
|
for (const node of nodesToInsert) {
|
|
339
339
|
if ((node as any).nodeType === 1) {
|
|
340
340
|
if ((node as any).tagName?.toLowerCase() === "style") {
|
|
341
|
-
(node as any).setAttribute("data-tk-
|
|
341
|
+
(node as any).setAttribute("data-tk-com", tagName);
|
|
342
342
|
}
|
|
343
343
|
const nested = (node as any).querySelectorAll?.("style") || [];
|
|
344
344
|
for (const styleEl of nested) {
|
|
345
|
-
(styleEl as any).setAttribute("data-tk-
|
|
345
|
+
(styleEl as any).setAttribute("data-tk-com", tagName);
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
348
|
}
|