feat(infra): migrate to rsbuild
This commit is contained in:
95 files changed
+5582
-11282
No files matched your search
@@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export default {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
};
|
||||
@@ -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',
|
||||
},
|
||||
});
|
||||
@@ -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 }
|
||||
);
|
||||
@@ -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,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";
|
||||
+4
-21
@@ -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>
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
Reference in new issue
Block a user