refactor: migrate to vite for critical scss bundling, remove dart sass dependency

Signed-off-by: Sped0n <hi@sped0n.com>
This commit is contained in:
Sped0n
2025-11-12 16:56:30 +08:00
committed by Ryan
parent 8b3b5cd77a
commit 4b1f529589
9 changed files with 309 additions and 30 deletions

5
.gitignore vendored
View File

@@ -1,6 +1,6 @@
# Hugo default output directory # Hugo default output directory
public/ public/
/exampleSite/resources/ exampleSite/resources/
node_modules/ node_modules/
build/ build/
@@ -25,3 +25,6 @@ jsconfig.json
# css map # css map
*.css.map *.css.map
# dummmy file
assets/bundled/critical.js

View File

@@ -1,5 +1,7 @@
node_modules node_modules/
static static/
exmapleSite exmapleSite/
single.json single.json
pnpm-lock.yaml pnpm-lock.yaml
assets/bundled/
assets/bundled/

263
assets/bundled/critical.css Normal file
View File

@@ -0,0 +1,263 @@
/***
The new CSS reset - version 1.11.1 (last updated 24.10.2023)
GitHub page: https://github.com/elad2412/the-new-css-reset
***/
/*
Remove all the styles of the "User-Agent-Stylesheet", except for the 'display' property
- The "symbol *" part is to solve Firefox SVG sprite bug
- The "html" element is excluded, otherwise a bug in Chrome breaks the CSS hyphens property (https://github.com/elad2412/the-new-css-reset/issues/36)
*/
*:where(:not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)) {
all: unset;
display: revert;
}
/* Preferred box-sizing value */
*,
*::before,
*::after {
box-sizing: border-box;
}
/* Fix mobile Safari increase font-size on landscape mode */
html {
-moz-text-size-adjust: none;
-webkit-text-size-adjust: none;
text-size-adjust: none;
}
/* Reapply the pointer cursor for anchor tags */
a,
button {
cursor: revert;
}
/* Remove list styles (bullets/numbers) */
ol,
ul,
menu,
summary {
list-style: none;
}
/* For images to not be able to exceed their container */
img {
max-inline-size: 100%;
max-block-size: 100%;
}
/* removes spacing between cells in tables */
table {
border-collapse: collapse;
}
/* Safari - solving issue when using user-select:none on the <body> text input doesn't working */
input,
textarea {
-webkit-user-select: auto;
}
/* revert the 'white-space' property for textarea elements on Safari */
textarea {
white-space: revert;
}
/* minimum style to allow to style meter element */
meter {
-webkit-appearance: revert;
appearance: revert;
}
/* preformatted text - use only for this feature */
:where(pre) {
all: revert;
box-sizing: border-box;
}
/* reset default text opacity of input placeholder */
::placeholder {
color: unset;
}
/* fix the feature of 'hidden' attribute.
display:revert; revert to element instead of attribute */
:where([hidden]) {
display: none;
}
/* revert for bug in Chromium browsers
- fix for the content editable attribute will work properly.
- webkit-user-select: auto; added for Safari in case of using user-select:none on wrapper element*/
:where([contenteditable]:not([contenteditable=false])) {
-moz-user-modify: read-write;
-webkit-user-modify: read-write;
overflow-wrap: break-word;
-webkit-line-break: after-white-space;
-webkit-user-select: auto;
}
/* apply back the draggable feature - exist only in Chromium and Safari */
:where([draggable=true]) {
-webkit-user-drag: element;
}
/* Revert Modal native behavior */
:where(dialog:modal) {
all: revert;
box-sizing: border-box;
}
@font-face {
font-family: "Geist";
src: url('{{- "lib/fonts/GeistVF.woff2" | absURL -}}') format("woff2 supports variations"), url('{{- "lib/fonts/GeistVF.woff2" | absURL -}}') format("woff2-variations");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "FW";
src: url('{{- "lib/fonts/fw.woff2" | absURL -}}') format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
body {
line-height: 1.2;
font-size: 16px;
font-family: "Geist", sans-serif;
}
body button {
font-family: "FW", sans-serif;
}
@media (min-width: 768px) {
body {
font-size: 18px;
}
}
@media (min-width: 1024px) {
body {
font-size: 19px;
}
}
:root {
--window-height: 100vh;
--nav-height: 2rem;
--space-standard: 0.625rem;
--z-curtain: 200;
--z-nav-gallery: 500;
--z-cursor: 600;
--z-nav: 800;
}
* {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
user-select: none;
background: white;
}
html,
body {
overscroll-behavior-y: none;
}
a,
button {
cursor: pointer;
}
nav {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: var(--nav-height);
padding: 0 var(--space-standard);
position: fixed;
bottom: 0;
background: white;
z-index: var(--z-nav);
pointer-events: all;
}
.num {
width: 0.625em;
display: inline-block;
text-align: center;
}
.current {
font-style: italic;
text-decoration: underline;
}
@media (max-width: 767px), (hover: none) {
nav {
top: 0;
}
.index,
.threshold {
display: none;
}
}
article {
padding: var(--space-standard);
max-width: 25em;
}
article p {
margin-bottom: 1em;
}
article u {
text-decoration: underline;
}
article > h1 {
font-size: 1.6em;
}
article > h2 {
font-size: 1.5em;
}
article > h3 {
font-size: 1.375em;
}
article > h4 {
font-size: 1.25em;
}
article > h5 {
font-size: 1.125em;
}
article h1,
article h2,
article h3,
article h4,
article h5,
article h6 {
font-weight: bold;
margin: 1.2rem 0;
}
@media (max-width: 767px), (hover: none) {
article {
margin-top: var(--nav-height);
}
}
@media (max-width: 767px), (hover: none) {
.container {
position: fixed;
top: 0;
z-index: 0;
width: 100vw;
height: var(--window-height);
overflow-y: scroll;
overflow-x: hidden;
background: white;
overscroll-behavior: none;
-webkit-overflow-scrolling: none;
}
.disableScroll {
pointer-events: none;
}
}

View File

@@ -1,9 +1,10 @@
@font-face { @font-face {
font-family: 'Geist'; font-family: 'Geist';
src: src:
url('{{- "lib/fonts/GeistVF.woff2" | absURL -}}') url(/* @vite-ignore */'{{- "lib/fonts/GeistVF.woff2" | absURL -}}')
format('woff2 supports variations'), format('woff2 supports variations'),
url('{{- "lib/fonts/GeistVF.woff2" | absURL -}}') format('woff2-variations'); url(/* @vite-ignore */'{{- "lib/fonts/GeistVF.woff2" | absURL -}}')
format('woff2-variations');
font-weight: 400; font-weight: 400;
font-style: normal; font-style: normal;
font-display: swap; font-display: swap;
@@ -11,7 +12,7 @@
@font-face { @font-face {
font-family: 'FW'; font-family: 'FW';
src: url('{{- "lib/fonts/fw.woff2" | absURL -}}') format('woff2'); src: url(/* @vite-ignore */'{{- "lib/fonts/fw.woff2" | absURL -}}') format('woff2');
font-weight: 400; font-weight: 400;
font-style: normal; font-style: normal;
font-display: swap; font-display: swap;

2
assets/ts/critical.ts Normal file
View File

@@ -0,0 +1,2 @@
// this is a dummy file to trick vite to generate a critical.css file
import '../scss/critical.scss'

16
docs.md
View File

@@ -33,19 +33,6 @@ _[Contents](#contents)_
hugo v0.152.2+extended+withdeploy darwin/arm64 BuildDate=unknown VendorInfo=nixpkgs hugo v0.152.2+extended+withdeploy darwin/arm64 BuildDate=unknown VendorInfo=nixpkgs
``` ```
- [Dart Sass](https://gohugo.io/functions/css/sass/#dart-sass) (or install it with `npm install -g sass-embedded`)
```bash
sass --embedded --version
{
"protocolVersion": "2.4.0",
"compilerVersion": "1.70.0",
"implementationVersion": "1.70.0",
"implementationName": "dart-sass",
"id": 0
}
```
- [pnpm](https://pnpm.io/installation) and [Node.js](https://nodejs.org/en/download), please note that these two are only needed for customizations or development. - [pnpm](https://pnpm.io/installation) and [Node.js](https://nodejs.org/en/download), please note that these two are only needed for customizations or development.
```bash ```bash
@@ -273,8 +260,7 @@ https://gohugo.io/templates/sitemap-template/#configuration
_[Contents](#contents)_ _[Contents](#contents)_
- Ensure `sass --embedded --version` return a valid result. Bridget will work as a normal Hugo theme (if you don't have needs to customize), https://gohugo.io/getting-started/usage/ is a great start.
- Run `hugo` command.
For further reading, you can refer to the `scripts` field of `package.json`. For further reading, you can refer to the `scripts` field of `package.json`.

View File

@@ -12,7 +12,13 @@ export default defineConfig([
tseslint.configs.recommended, tseslint.configs.recommended,
importPlugin.flatConfigs.recommended, importPlugin.flatConfigs.recommended,
solid, solid,
globalIgnores(['**/node_modules', '**/static', '**/exampleSite', '*.mjs']), globalIgnores([
'node_modules/',
'static/',
'exampleSite/',
'*.mjs',
'assets/bundled/'
]),
{ {
...love, ...love,
...prettier, ...prettier,

View File

@@ -2,8 +2,8 @@
{{- $fingerprint := .Scratch.Get "fingerprint" | default "" -}} {{- $fingerprint := .Scratch.Get "fingerprint" | default "" -}}
{{- /* critical style */ -}} {{- /* critical style */ -}}
{{- $style := dict "Source" "scss/critical.scss" "Fingerprint" $fingerprint -}} {{- $style := dict "Source" "bundled/critical.css" "Fingerprint" $fingerprint -}}
{{- $options := dict "enableSourceMap" true "includePaths" (slice "node_modules") "transpiler" "dartsass" -}} {{- $options := dict "enableSourceMap" false -}}
{{- $style = dict "Context" . "ToCSS" $options "Inline" true "Template" true | merge $style -}} {{- $style = dict "Context" . "ToCSS" $options "Inline" true "Template" true | merge $style -}}
{{- partial "plugin/style.html" $style -}} {{- partial "plugin/style.html" $style -}}

View File

@@ -4,21 +4,37 @@ import solidPlugin from 'vite-plugin-solid'
export default defineConfig({ export default defineConfig({
plugins: [solidPlugin()], plugins: [solidPlugin()],
build: { build: {
outDir: './static/bundled', outDir: './',
watch: process.env.DISABLE_WATCH watch: process.env.DISABLE_WATCH
? null ? null
: { : {
include: 'assets/**' include: 'assets/**'
}, },
rollupOptions: { rollupOptions: {
input: './assets/ts/main.tsx', input: {
main: './assets/ts/main.tsx',
critical: './assets/ts/critical.ts'
},
output: { output: {
format: 'es', format: 'es',
entryFileNames: 'js/[name].js', entryFileNames: (chunkInfo) =>
chunkFileNames: 'js/[hash:6].js', chunkInfo.name === 'critical'
assetFileNames: '[ext]/[name].[ext]', ? 'assets/bundled/[name].js'
: 'static/bundled/js/[name].js',
chunkFileNames: 'static/bundled/js/[hash:6].js',
assetFileNames: (assetInfo) =>
assetInfo.names[0]?.startsWith('critical')
? 'assets/bundled/[name].[ext]'
: 'static/bundled/[ext]/[name].[ext]',
compact: true compact: true
} }
} }
},
css: {
preprocessorOptions: {
scss: {
loadPaths: ['./assets/scss']
}
}
} }
}) })