getfilepress 0.1.11 → 0.1.12
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/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Essay chrome
|
|
3
|
-
* Site rules
|
|
4
|
-
*
|
|
2
|
+
* Layer order is declared first. Essay chrome, then preset, then site theme.
|
|
3
|
+
* Site rules live in `@layer site` so they win even if Vite injects Essay CSS
|
|
4
|
+
* after the site sheet (dev) or splits the CSS (build).
|
|
5
5
|
*/
|
|
6
|
+
import './theme-layers.css';
|
|
6
7
|
import '@filepress/core/theme';
|
|
7
8
|
import '$site-preset';
|
|
8
9
|
import '$site-theme';
|
|
@@ -2,28 +2,42 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
|
2
2
|
import type { Plugin } from 'vite';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* @import cannot live inside @layer. Pull them out, wrap the rest.
|
|
6
|
+
* Quoted URLs may contain `;` (Google Fonts `wght@400;700`).
|
|
7
7
|
*/
|
|
8
|
-
|
|
9
|
-
const chunks: string[] = [];
|
|
8
|
+
const IMPORT_RE = /@import\s+(?:url\(\s*)?(["'])(?:\\.|(?!\1).)*\1\s*\)?\s*;/g;
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
export function takeImports(css: string): { imports: string[]; rest: string } {
|
|
11
|
+
const imports: string[] = [];
|
|
12
|
+
const rest = css.replace(IMPORT_RE, (m) => {
|
|
13
|
+
imports.push(m.trim());
|
|
14
|
+
return '';
|
|
15
|
+
});
|
|
16
|
+
return { imports, rest };
|
|
17
|
+
}
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
export function hoistImportsAndLayer(css: string, layer: string): string {
|
|
20
|
+
const { imports, rest } = takeImports(css);
|
|
21
|
+
const body = rest.trim();
|
|
22
|
+
const hoisted = imports.length ? `${imports.join('\n')}\n` : '';
|
|
23
|
+
if (!body) return hoisted;
|
|
24
|
+
return `${hoisted}@layer ${layer} {\n${body}\n}\n`;
|
|
25
|
+
}
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
/** Site tokens must beat later Essay `:root` (same specificity, later source). */
|
|
28
|
+
export function boostRoot(css: string): string {
|
|
29
|
+
return css.replace(/:root(?::root)?/g, ':root:root');
|
|
30
|
+
}
|
|
25
31
|
|
|
26
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Inline the site theme for first paint (minus remote @import).
|
|
34
|
+
* Cascade layer `site` wins over Essay even after Vite injects core CSS.
|
|
35
|
+
*/
|
|
36
|
+
export function extractCriticalTheme(css: string): string {
|
|
37
|
+
const withoutImport = takeImports(css).rest;
|
|
38
|
+
const meaningful = withoutImport.replace(/\/\*[\s\S]*?\*\//g, '').trim();
|
|
39
|
+
if (!meaningful) return '';
|
|
40
|
+
return `@layer filepress, site;\n${hoistImportsAndLayer(boostRoot(withoutImport), 'site')}`;
|
|
27
41
|
}
|
|
28
42
|
|
|
29
43
|
export function writeCriticalThemeModule(siteThemePath: string, outPath: string): string {
|
|
@@ -41,16 +55,32 @@ export function writeCriticalThemeModule(siteThemePath: string, outPath: string)
|
|
|
41
55
|
return critical;
|
|
42
56
|
}
|
|
43
57
|
|
|
58
|
+
function fileId(id: string): string {
|
|
59
|
+
return id.replace(/\\/g, '/').split('?')[0] ?? id;
|
|
60
|
+
}
|
|
61
|
+
|
|
44
62
|
/**
|
|
45
|
-
* Keep `$
|
|
46
|
-
*
|
|
63
|
+
* Keep `$critical-theme` in sync, and put Essay vs site CSS in cascade
|
|
64
|
+
* layers so Vite's inject order cannot flash the default look.
|
|
47
65
|
*/
|
|
48
66
|
export function criticalThemePlugin(siteThemePath: string, outPath: string): Plugin {
|
|
67
|
+
const siteNorm = siteThemePath.replace(/\\/g, '/');
|
|
68
|
+
|
|
49
69
|
return {
|
|
50
70
|
name: 'filepress-critical-theme',
|
|
51
71
|
buildStart() {
|
|
52
72
|
writeCriticalThemeModule(siteThemePath, outPath);
|
|
53
73
|
},
|
|
74
|
+
transform(code, id) {
|
|
75
|
+
const path = fileId(id);
|
|
76
|
+
if (path === siteNorm) {
|
|
77
|
+
return hoistImportsAndLayer(boostRoot(code), 'site');
|
|
78
|
+
}
|
|
79
|
+
if (path.endsWith('/lib/styles/theme.css') || path.includes('/lib/styles/presets/')) {
|
|
80
|
+
return hoistImportsAndLayer(code, 'filepress');
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
},
|
|
54
84
|
configureServer(server) {
|
|
55
85
|
writeCriticalThemeModule(siteThemePath, outPath);
|
|
56
86
|
server.watcher.add(siteThemePath);
|