feat(infra): migrate to rsbuild

This commit is contained in:
deytenit committed 2026-02-12 23:39:20 +03:00
1 parent 97c6347f2e
commit 4628c043ce
95 files changed
+5582 -11282

No files matched your search

-26
View File
@@ -1,26 +0,0 @@
// @ts-check
import react from '@astrojs/react';
import tailwindcss from '@tailwindcss/vite';
import { defineConfig } from 'astro/config';
// https://astro.build/config
export default defineConfig({
site: 'https://static.ermnvldmr.com',
output: 'static',
build: {
format: 'file',
},
srcDir: './src',
integrations: [react()],
vite: {
plugins: [tailwindcss()],
resolve: {
alias: {
'@ermnvldmr/stl': new URL('../../packages/stl/src', import.meta.url).pathname,
'@ermnvldmr/ui': new URL('../../packages/ui/src', import.meta.url).pathname,
'#': new URL('./src/', import.meta.url).pathname,
},
},
},
});
+9 -8
View File
@@ -4,30 +4,31 @@
"description": "static.ermnvldmr.com landing pages",
"type": "module",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro",
"dev": "rsbuild dev",
"build": "rsbuild build",
"preview": "rsbuild preview",
"lint": "eslint src --max-warnings 0",
"format": "prettier --write .",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist .turbo node_modules"
},
"dependencies": {
"@astrojs/react": "^4.2.5",
"@ermnvldmr/stl": "workspace:*",
"@ermnvldmr/ui": "workspace:*",
"astro": "^5.7.5",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"tailwindcss": "^4.1.4"
},
"devDependencies": {
"@ermnvldmr/eslint-config": "workspace:*",
"@tailwindcss/vite": "^4.1.4",
"@ermnvldmr/rsbuild-config": "workspace:*",
"@rsbuild/core": "^1.2.11",
"@tailwindcss/postcss": "^4.1.18",
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.2",
"eslint": "^9.25.1",
"postcss": "^8.5.6",
"prettier": "^3.5.3",
"prettier-plugin-astro": "^0.14.1",
"prettier-plugin-tailwindcss": "^0.6.11",
"typescript": "^5.8.3"
}
+5
View File
@@ -0,0 +1,5 @@
export default {
plugins: {
'@tailwindcss/postcss': {},
},
};
+13
View File
@@ -0,0 +1,13 @@
import { defineServiceConfig } from '@ermnvldmr/rsbuild-config';
export default defineServiceConfig({
source: {
entry: {
index: './src/app/index.tsx',
error: './src/app/error.tsx',
},
},
html: {
title: 'Static Content',
},
});
+72
View File
@@ -0,0 +1,72 @@
import { VStack, HStack, Header, Paragraph, Link } from '@ermnvldmr/ui';
import React, { useEffect, useState } from 'react';
import { createPage } from '../lib/createPage';
import {
AUTHOR_EMAIL,
AUTHOR_NAME,
SITE_URL,
ERROR_TITLE,
ERROR_DESCRIPTION,
} from '../shared/constants';
import { getCurrentYear, getHttpStatusUrl } from '../shared/utils';
createPage(
function ErrorPage() {
const [status, setStatus] = useState<number | null>(null);
useEffect(() => {
/**
* Type guard for PerformanceNavigationTiming.
* @param entry - The performance entry to check.
* @returns True if entry is PerformanceNavigationTiming.
* @example
* ```typescript
* const isNav = isNavigationTiming(entry);
* ```
*/
function isNavigationTiming(
entry: PerformanceEntry
): entry is PerformanceNavigationTiming {
return entry.entryType === 'navigation';
}
const navigationData = window.performance.getEntries().find(isNavigationTiming);
if (navigationData?.responseStatus) {
setStatus(navigationData.responseStatus);
}
}, []);
return (
<main className="h-screen w-screen">
<VStack align="center" className="w-full h-full" justify="center">
<VStack align="start" gap={8}>
<Header level={1}>
Exceptional Situation
{status !== null && (
<>
{' '}
<Link href={getHttpStatusUrl(status)} size="l" type="display">
#{status}
</Link>
</>
)}
</Header> <Paragraph>
This location is unavailable at the moment — static content does not dwell here
</Paragraph>
<HStack className="w-full" justify="between">
<span>
<Link href={`mailto:${AUTHOR_EMAIL}`}>{AUTHOR_NAME}</Link>, {getCurrentYear()}
</span>
<span>
<Link href={SITE_URL}>ermnvldmr.com</Link>
</span>
</HStack>
</VStack>
</VStack>
</main>
);
},
{ title: ERROR_TITLE, description: ERROR_DESCRIPTION }
);
+38
View File
@@ -0,0 +1,38 @@
import { VStack, HStack, Header, Paragraph, Link } from '@ermnvldmr/ui';
import React from 'react';
import { createPage } from '../lib/createPage';
import {
AUTHOR_EMAIL,
AUTHOR_NAME,
SITE_URL,
SITE_TITLE,
SITE_DESCRIPTION,
} from '../shared/constants';
import { getCurrentYear } from '../shared/utils';
createPage(
function Index() {
return (
<main className="h-screen w-screen">
<VStack align="center" className="w-full h-full" justify="center">
<VStack align="start" gap={8}>
<Header level={1}>Static Content Dwells Here</Header>
<Paragraph>
Other pages direct you down specific paths to the content that resides here
</Paragraph>
<HStack className="w-full" justify="between">
<span>
<Link href={`mailto:${AUTHOR_EMAIL}`}>{AUTHOR_NAME}</Link>, {getCurrentYear()}
</span>
<span>
<Link href={SITE_URL}>ermnvldmr.com</Link>
</span>
</HStack>
</VStack>
</VStack>
</main>
);
},
{ title: SITE_TITLE, description: SITE_DESCRIPTION }
);
+1 -13
View File
@@ -1,14 +1,2 @@
@import '../../../packages/ui/src/styles/index.css';
@source "../../../packages/ui/src";
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
width: 100%;
}
@source "../../../packages/ui/src";
@@ -1,19 +1,7 @@
---
/**
* Base layout for static service pages
*/
export interface Props {
title: string;
description: string;
}
const { title, description } = Astro.props;
---
<!doctype html>
<html lang="en">
<head>
<script is:inline>
<script>
const getThemePreference = () => {
if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
return localStorage.getItem('theme');
@@ -34,16 +22,11 @@ const { title, description } = Astro.props;
});
}
</script>
<meta charset="utf-8" />
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="robots" content="noindex,nofollow" />
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={Astro.url.href} />
<title>Vladimir Eremin</title>
</head>
<body>
<slot />
<div id="root"></div>
</body>
</html>
+38
View File
@@ -0,0 +1,38 @@
import React from 'react';
import { createRoot } from 'react-dom/client';
import '../global.css';
/**
* Options for page creation
*/
export interface PageOptions {
title?: string;
description?: string;
}
/**
* Creates a React page component with hydration support.
*
* @param Component - The React component to render.
* @param options - Page options like title.
*
* @example
* ```tsx
* createPage(App, { title: 'My Page' });
* ```
*/
export function createPage(Component: React.ComponentType, options: PageOptions = {}): void {
const rootElement = document.getElementById('root');
if (options.title) {
document.title = options.title;
}
if (rootElement) {
createRoot(rootElement).render(
<React.StrictMode>
<Component />
</React.StrictMode>
);
}
}
-56
View File
@@ -1,56 +0,0 @@
---
import { VStack, HStack } from '@ermnvldmr/ui';
import StaticLayout from '#layouts/StaticLayout/StaticLayout.astro';
import {
AUTHOR_EMAIL,
AUTHOR_NAME,
SITE_URL,
ERROR_TITLE,
ERROR_DESCRIPTION,
} from '#shared/constants';
import { getCurrentYear } from '#shared/utils';
import '#global.css';
---
<StaticLayout title={ERROR_TITLE} description={ERROR_DESCRIPTION}>
<main class="h-screen w-screen">
<VStack className="w-full h-full" align="center" justify="center">
<VStack align="start" gap={8}>
<h1 id="title">Exceptional Situation</h1>
<p id="message">
This location is unavailable at the moment — static content does not dwell here
</p>
<HStack justify="between" className="w-full">
<span>
<a href={`mailto:${AUTHOR_EMAIL}`}>{AUTHOR_NAME}</a>, {getCurrentYear()}
</span>
<span>
<a href={SITE_URL}>ermnvldmr.com</a>
</span>
</HStack>
</VStack>
</VStack>
</main>
<script>
import { getHttpStatusUrl } from '#shared/utils';
function isNavigationTiming(
entry: PerformanceEntry,
): entry is PerformanceNavigationTiming {
return entry.entryType === 'navigation';
}
const navigationData = window.performance.getEntries().find(isNavigationTiming);
if (navigationData?.responseStatus) {
const { responseStatus } = navigationData;
const link = document.createElement('a');
link.href = getHttpStatusUrl(responseStatus);
link.textContent = `#${responseStatus}`;
document.getElementById('title')?.append(' ', link);
}
</script>
</StaticLayout>
-35
View File
@@ -1,35 +0,0 @@
---
import { VStack, HStack } from '@ermnvldmr/ui';
import StaticLayout from '#layouts/StaticLayout/StaticLayout.astro';
import {
AUTHOR_EMAIL,
AUTHOR_NAME,
SITE_DESCRIPTION,
SITE_TITLE,
SITE_URL,
} from '#shared/constants';
import { getCurrentYear } from '#shared/utils';
import '#global.css';
---
<StaticLayout title={SITE_TITLE} description={SITE_DESCRIPTION}>
<main class="h-screen w-screen">
<VStack className="w-full h-full" align="center" justify="center">
<VStack align="start" gap={8}>
<h1>Static Content Dwells Here</h1>
<p>
Other pages direct you down specific paths to the content that resides here
</p>
<HStack justify="between" className="w-full">
<span>
<a href={`mailto:${AUTHOR_EMAIL}`}>{AUTHOR_NAME}</a>, {getCurrentYear()}
</span>
<span>
<a href={SITE_URL}>ermnvldmr.com</a>
</span>
</HStack>
</VStack>
</VStack>
</main>
</StaticLayout>