feat: no more vercel, next. now vite and nix

This commit is contained in:
Jet Pham 2026-03-04 22:00:53 -08:00
parent fc80ead81e
commit bf5900edbb
No known key found for this signature in database
28 changed files with 4099 additions and 1554 deletions

View file

@ -1,14 +0,0 @@
# Since the ".env" file is gitignored, you can use the ".env.example" file to
# build a new ".env" file when you clone the repo. Keep this file up-to-date
# when you add new variables to `.env`.
# This file will be committed to version control, so make sure not to have any
# secrets in it. If you are cloning this repo, create a copy of this file named
# ".env" and populate it with your secrets.
# When adding additional environment variables, the schema in "/src/env.js"
# should be updated accordingly.
# Prisma
# https://www.prisma.io/docs/reference/database-reference/connection-urls#env
DATABASE_URL="postgresql://postgres:password@localhost:5432/website"

25
.gitignore vendored
View file

@ -1,25 +1,11 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# database
/prisma/db.sqlite
/prisma/db.sqlite-journal
db.sqlite
# next.js
/.next/
/out/
next-env.d.ts
# production
/build
# vite
/dist
# misc
.DS_Store
@ -31,14 +17,10 @@ yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
# do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables
# env files
.env
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
@ -46,4 +28,3 @@ yarn-error.log*
.idea
/.direnv
/generated

1220
bun.lock

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,8 @@
import { FlatCompat } from "@eslint/eslintrc";
import tseslint from 'typescript-eslint';
const compat = new FlatCompat({
baseDirectory: import.meta.dirname,
});
export default tseslint.config(
{
ignores: ['.next', 'cgol/pkg/**/*', 'next-env.d.ts']
ignores: ['dist', 'cgol/pkg/**/*']
},
{
files: ['**/*.ts', '**/*.tsx'],

12
flake.lock generated
View file

@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1771369470,
"narHash": "sha256-0NBlEBKkN3lufyvFegY4TYv5mCNHbi5OmBDrzihbBMQ=",
"lastModified": 1772542754,
"narHash": "sha256-WGV2hy+VIeQsYXpsLjdr4GvHv5eECMISX1zKLTedhdg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "0182a361324364ae3f436a63005877674cf45efb",
"rev": "8c809a146a140c5c8806f13399592dbcb1bb5dc4",
"type": "github"
},
"original": {
@ -62,11 +62,11 @@
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1771384185,
"narHash": "sha256-KvmjUeA7uODwzbcQoN/B8DCZIbhT/Q/uErF1BBMcYnw=",
"lastModified": 1772679930,
"narHash": "sha256-FxYmdacqrdDVeE9QqZKTIpNLjv2B8GSKssgwlZuTR98=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "23dd7fa91602a68bd04847ac41bc10af1e6e2fd2",
"rev": "9b741db17141331fdb26270a1b66b81be8be9edd",
"type": "github"
},
"original": {

View file

@ -1,63 +1,44 @@
{
description = "CTF Jet development environment (Bun)";
description = "Jet Pham's personal website";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
rust-overlay.url = "github:oxalica/rust-overlay";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, rust-overlay, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
(flake-utils.lib.eachDefaultSystem (system:
let
overlays = [ (import rust-overlay) ];
pkgs = import nixpkgs {
inherit system overlays;
};
bun = pkgs.bun;
# Prisma engines for NixOS
prismaEngines = pkgs.prisma-engines;
devTools = with pkgs; [
git
postgresql
curl
wget
typescript-language-server
pkg-config
wasm-pack
binaryen
(rust-bin.selectLatestNightlyWith (toolchain: toolchain.default.override {
pkgs = import nixpkgs { inherit system overlays; };
rustToolchain = pkgs.rust-bin.selectLatestNightlyWith (toolchain:
toolchain.default.override {
extensions = [ "rust-src" ];
targets = [ "wasm32-unknown-unknown" ];
}))
];
in {
devShells.default = pkgs.mkShell {
buildInputs = [
bun
prismaEngines
] ++ devTools;
NIXPKGS_ALLOW_UNFREE = "1";
PRISMA_QUERY_ENGINE_BINARY = "${prismaEngines}/bin/query-engine";
PRISMA_SCHEMA_ENGINE_BINARY = "${prismaEngines}/bin/schema-engine";
PRISMA_INTROSPECTION_ENGINE_BINARY = "${prismaEngines}/bin/introspection-engine";
PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING = "1";
});
website = pkgs.stdenv.mkDerivation {
pname = "jet-website";
version = "0.1.0";
src = pkgs.lib.cleanSource ./.;
nativeBuildInputs = [ pkgs.nodejs rustToolchain pkgs.wasm-pack pkgs.binaryen pkgs.pkg-config ];
buildPhase = ''
export HOME=$TMPDIR
cd cgol && wasm-pack build --release --target web && cd ..
npm ci
npm run build
'';
installPhase = ''
mkdir -p $out
cp -r dist/* $out/
'';
};
packages = {
inherit bun prismaEngines;
default = pkgs.symlinkJoin {
name = "ctfjet-dev-bun";
paths = [ bun prismaEngines ];
};
in {
packages = { default = website; };
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
nodejs git curl typescript-language-server
pkg-config wasm-pack binaryen rustToolchain
];
};
}
);
));
}

18
index.html Normal file
View file

@ -0,0 +1,18 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#000000" />
<meta name="apple-mobile-web-app-title" content="Jet Pham" />
<title>Jet Pham - Software Extremist</title>
<meta name="description" content="Jet Pham's personal website" />
<link rel="manifest" href="/manifest.json" />
<link rel="icon" href="/favicon.ico" />
<link rel="apple-touch-icon" href="/apple-icon.png" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View file

@ -1,37 +0,0 @@
#!/bin/bash
set -euo pipefail
# fix home issues
export HOME=/root
# Install Rustup
if ! command -v rustup
then
echo "Installing Rustup..."
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -t wasm32-unknown-unknown --profile minimal
source "$HOME/.cargo/env"
else
echo "Rustup already installed."
rustup target add wasm32-unknown-unknown
fi
# Install wasm-pack
if ! command -v wasm-pack
then
echo "Installing wasm-pack..."
curl https://drager.github.io/wasm-pack/installer/init.sh -sSf | sh
echo "wasm-pack installation complete."
else
echo "wasm-pack already installed."
fi
# Build cgol WASM package
echo "Building cgol WASM package..."
cd cgol
wasm-pack build --release --target web
cd ..
# Install Next.js dependencies with bun
echo "Installing Next.js dependencies with bun..."
bun install

View file

@ -1,100 +0,0 @@
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
* for Docker builds.
*/
/** @type {import("next").NextConfig} */
const config = {
webpack: (config, { isServer }) => {
config.module.rules.push({
test: /\.txt$/,
type: "asset/source",
});
config.experiments = {
...config.experiments,
asyncWebAssembly: true,
};
config.module.rules.push({
test: /\.wasm$/,
type: "asset/resource",
generator: {
filename: "static/wasm/[name].[hash][ext]",
},
});
// Ensure WASM files are properly handled
config.resolve.fallback = {
...config.resolve.fallback,
fs: false,
};
// Ensure WASM files are properly served
config.output.webassemblyModuleFilename = "static/wasm/[modulehash].wasm";
return config;
},
turbopack: {
rules: {
"*.txt": {
loaders: ["raw-loader"],
as: "*.js",
},
},
},
productionBrowserSourceMaps: false,
// Redirect /_not-found to /
async redirects() {
return [
{
source: '/_not-found',
destination: '/',
permanent: false,
},
];
},
// Ensure static files are properly served
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'Cross-Origin-Opener-Policy',
value: 'same-origin',
},
{
key: 'Cross-Origin-Resource-Policy',
value: 'cross-origin',
},
],
},
{
source: '/_next/static/:path*',
headers: [
{
key: 'Cross-Origin-Resource-Policy',
value: 'cross-origin',
},
],
},
{
source: '/_next/static/wasm/:path*',
headers: [
{
key: 'Cross-Origin-Resource-Policy',
value: 'cross-origin',
},
{
key: 'Content-Type',
value: 'application/wasm',
},
],
},
];
},
};
export default config;

3970
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -4,52 +4,40 @@
"private": true,
"type": "module",
"scripts": {
"build": "next build",
"build": "vite build",
"build:wasm": "cd cgol && wasm-pack build --release --target web",
"check": "bun run lint && tsc --noEmit",
"dev": "next dev --turbo",
"check": "npm run lint && tsc --noEmit",
"dev": "vite",
"format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,mdx}\" --cache",
"format:write": "prettier --write \"**/*.{ts,tsx,js,jsx,mdx}\" --cache",
"lint": "eslint .",
"lint:fix": "next lint --fix",
"preview": "next build && next start",
"start": "next start",
"lint:fix": "eslint . --fix",
"preview": "vite preview",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@tanstack/react-query": "^5.90.21",
"anser": "^2.3.5",
"cgol": "file:./cgol/pkg",
"escape-carriage": "^1.3.1",
"next": "^16.1.6",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"server-only": "^0.0.1",
"superjson": "^2.2.6"
"react-dom": "^19.2.4"
},
"devDependencies": {
"@eslint/eslintrc": "^3.3.3",
"@next/eslint-plugin-next": "^16.1.6",
"@tailwindcss/postcss": "^4.2.0",
"@types/node": "^25.3.0",
"@tailwindcss/vite": "^4.2.1",
"@types/node": "^25.3.3",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"eslint": "^9",
"eslint-config-next": "^16.1.6",
"postcss": "^8.5.6",
"@vitejs/plugin-react": "^5.1.4",
"eslint": "^10",
"prettier": "^3.8.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"raw-loader": "^4.0.2",
"react-doctor": "^0.0.21",
"tailwindcss": "^4.2.0",
"tailwindcss": "^4.2.1",
"typescript": "^5.9.3",
"typescript-eslint": "^8.56.0",
"webpack": "^5.105.2"
"typescript-eslint": "^8.56.1",
"vite": "^7.3.1",
"vite-plugin-top-level-await": "^1.6.0",
"vite-plugin-wasm": "^3.5.0"
},
"ct3aMetadata": {
"initVersion": "7.40.0"
},
"overrides": {},
"knip": {
"ignore": [
"cgol/pkg/**"

View file

@ -1,5 +0,0 @@
export default {
plugins: {
"@tailwindcss/postcss": {},
},
};

View file

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 979 KiB

After

Width:  |  Height:  |  Size: 979 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before After
Before After

View file

@ -1,17 +1,10 @@
import Link from "next/link";
import Image from "next/image";
import { BorderedBox } from "./_components/bordered-box";
import { FrostedBox } from "./_components/frosted-box";
import Header from "./_components/header";
import { CgolCanvas } from "./_components/cgol-canvas";
import FirstName from "~/assets/Jet.txt";
import { BorderedBox } from "~/components/bordered-box";
import { FrostedBox } from "~/components/frosted-box";
import Header from "~/components/header";
import { CgolCanvas } from "~/components/cgol-canvas";
import Jet from "~/assets/Jet.txt?raw";
export const metadata = {
title: "Jet Pham - Software Extremist",
description: "Personal website of Jet Pham, a software extremist.",
};
export default async function Home() {
export default function App() {
return (
<>
<CgolCanvas />
@ -20,58 +13,57 @@ export default async function Home() {
<FrostedBox className="my-[2ch] w-full max-w-[66.666667%] min-w-fit md:mt-[4ch]">
<div className="flex flex-col items-center justify-center gap-[2ch] md:flex-row">
<div className="order-1 flex flex-col items-center md:order-2">
<Header content={FirstName} />
<Header content={Jet} />
<div className="mt-[2ch]">Software Extremist</div>
</div>
<div className="order-2 shrink-0 md:order-1">
<Image
<img
src="/jet.svg"
alt="Jet"
width={250}
height={250}
className="aspect-square w-full max-w-[250px] object-cover md:h-[263px] md:w-[175px] md:max-w-none"
priority
/>
</div>
</div>
<BorderedBox label="Contact" className="mt-[2ch]">
<Link href="mailto:jet@extremist.software">
<a href="mailto:jet@extremist.software">
jet@extremist.software
</Link>
</a>
</BorderedBox>
<BorderedBox label="Links">
<ol>
<li>
<Link
<a
href="https://git.extremist.software"
className="inline-flex items-center"
>
Forgejo
</Link>
</a>
</li>
<li>
<Link
<a
href="https://github.com/jetpham"
className="inline-flex items-center"
>
GitHub
</Link>
</a>
</li>
<li>
<Link
<a
href="https://x.com/jetpham5"
className="inline-flex items-center"
>
X
</Link>
</a>
</li>
<li>
<Link
<a
href="https://bsky.app/profile/jetpham.com"
className="inline-flex items-center"
>
Bluesky
</Link>
</a>
</li>
</ol>
</BorderedBox>

View file

@ -1,29 +0,0 @@
import "~/styles/globals.css";
import { type Metadata, type Viewport } from "next";
export const metadata: Metadata = {
title: "Jet Pham",
description: "Jet Pham's personal website",
appleWebApp: {
title: "Jet Pham",
},
};
export const viewport: Viewport = {
width: "device-width",
initialScale: 1,
themeColor: "#000000",
};
export default function RootLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="en">
<body>
{children}
</body>
</html>
);
}

View file

@ -1,5 +1,3 @@
"use client";
import { useEffect, useRef, useCallback } from "react";
export function CgolCanvas() {

7
src/global.d.ts vendored
View file

@ -1,10 +1,11 @@
declare module "*.txt" {
/// <reference types="vite/client" />
declare module "*.txt?raw" {
const content: string;
export default content;
}
declare module "*.utf8ans" {
declare module "*.utf8ans?raw" {
const content: string;
export default content;
}

10
src/main.tsx Normal file
View file

@ -0,0 +1,10 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "~/styles/globals.css";
import App from "./App";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
</StrictMode>,
);

View file

@ -23,11 +23,6 @@
"module": "ESNext",
"moduleResolution": "Bundler",
"jsx": "react-jsx",
"plugins": [
{
"name": "next"
}
],
"incremental": true,
/* Path Aliases */
"baseUrl": ".",
@ -38,17 +33,15 @@
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
"**/*.cjs",
"**/*.js",
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
"vite.config.ts"
],
"exclude": [
"node_modules",
"generated",
"dist",
"cgol/pkg"
]
}

23
vite.config.ts Normal file
View file

@ -0,0 +1,23 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
import wasm from "vite-plugin-wasm";
import topLevelAwait from "vite-plugin-top-level-await";
export default defineConfig({
plugins: [react(), tailwindcss(), wasm(), topLevelAwait()],
resolve: {
alias: {
"~": "/src",
},
},
server: {
headers: {
"Cross-Origin-Opener-Policy": "same-origin",
"Cross-Origin-Embedder-Policy": "require-corp",
},
},
build: {
target: "esnext",
},
});