4 Commits

Author SHA1 Message Date
cbcf6a731b library version updates 2024-05-09 14:41:42 +10:00
9ad8e1aa9b move the assets to remote location and change blog cover to Next/Image 2024-03-13 14:23:11 +11:00
bea1c3aba3 updated dependency, standalone seems to work
updated pnpm version
added dockerignore
revert the standalone output
2024-02-23 14:56:19 +11:00
5c8a3f56dd WIP: build attempted 2024-02-22 23:42:04 +11:00
17 changed files with 3309 additions and 2185 deletions

5
.dockerignore Normal file
View File

@@ -0,0 +1,5 @@
**/node_modules
.git
.gitignore
.local
.env*

29
.idea/dataSources.local.xml generated Normal file
View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="dataSourceStorageLocal" created-in="WS-241.15989.105">
<data-source name="devblog@mysql-server" uuid="32913bc6-cafd-416c-b070-eee7c73cf755">
<database-info product="MySQL" version="8.3.0" jdbc-version="4.2" driver-name="MySQL Connector/J" driver-version="mysql-connector-java-8.0.25 (Revision: 08be9e9b4cba6aa115f9b27b215887af40b159e0)" dbms="MYSQL" exact-version="8.3.0" exact-driver-version="8.0">
<extra-name-characters>#@</extra-name-characters>
<identifier-quote-string>`</identifier-quote-string>
</database-info>
<case-sensitivity plain-identifiers="exact" quoted-identifiers="exact" />
<secret-storage>master_key</secret-storage>
<user-name>devblog</user-name>
<schema-mapping>
<introspection-scope>
<node kind="schema">
<name qname="@" />
<name qname="devblog" />
</node>
</introspection-scope>
</schema-mapping>
<ssl-config use-ide-store="true" use-java-store="true" use-system-store="true">
<ca-cert>$USER_HOME$/Documents/db-ssl/ca.crt</ca-cert>
<client-cert>$USER_HOME$/Documents/db-ssl/mbp.crt</client-cert>
<client-key>$USER_HOME$/Documents/db-ssl/mbp.key</client-key>
<enabled>true</enabled>
<mode>VERIFY_FULL</mode>
</ssl-config>
</data-source>
</component>
</project>

12
.idea/dataSources.xml generated Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="devblog@mysql-server" uuid="32913bc6-cafd-416c-b070-eee7c73cf755">
<driver-ref>mysql.8</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql://mysql-server.suyono.dev:13306/devblog</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

6
.idea/sqldialects.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SqlDialectMappings">
<file url="PROJECT" dialect="MySQL" />
</component>
</project>

View File

@@ -1,2 +1,2 @@
nodejs 20.8.1
pnpm 8.9.2
nodejs 20.12.2
pnpm 9.0.6

37
Dockerfile Normal file
View File

@@ -0,0 +1,37 @@
FROM node:lts-alpine as base
FROM base as builder
USER 1000:1000
ADD --chown=1000:1000 . /home/node/nextts
WORKDIR /home/node/nextts
RUN wget -qO- https://get.pnpm.io/install.sh | PNPM_VERSION="8.15.3" ENV="/home/node/.shrc" SHELL="$(which sh)" sh -
ENV PATH=/home/node/.local/share/pnpm:$PATH
RUN pnpm install && pnpm run build
FROM base as runtime
RUN npm install -g pm2
COPY --from=builder /home/node/nextts/public /home/node/nextts/public
COPY --from=builder /home/node/nextts/.next/standalone /home/node/nextts
COPY --from=builder /home/node/nextts/.next/static /home/node/nextts/.next/static
ADD --chown=1000:1000 pm2.config.js /home/node/nextts/
ADD --chown=1000:1000 dummies /home/node/nextts/dummies
RUN chown -R 1000:1000 /home/node/nextts
USER 1000:1000
WORKDIR /home/node/nextts
ENV PORT 3000
ENV NODE_ENV production
ENV HOME /home/node
ENV HOSTNAME "0.0.0.0"
RUN wget -qO- https://get.pnpm.io/install.sh | PNPM_VERSION="8.15.3" ENV="/home/node/.shrc" SHELL="$(which sh)" sh -
ENV PATH=/home/node/.local/share/pnpm:$PATH
RUN pnpm install
CMD ["pm2-runtime", "pm2.config.js"]
#CMD ["node", "server.js"]

View File

@@ -1,9 +1,9 @@
import { promisePool } from "@/backend/db";
import { getPromisePool } from "@/backend/db";
import {RowDataPacket} from "mysql2";
async function query() {
try {
const [rows, fields] = await promisePool.query<RowDataPacket[]>('select slug from post limit 1;')
const [rows, fields] = await getPromisePool().query<RowDataPacket[]>('select slug from post limit 1;')
return(rows[0]['slug'] as string)
} catch (e) {
console.log(e)
@@ -11,11 +11,18 @@ async function query() {
}
}
export default async function DbCheck() {
export default async function DbCheck({ searchParams }: { searchParams: { [key: string]: string | string[] | undefined }}) {
let flag = "empty";
if (typeof searchParams["flag"] === 'string') {
flag = searchParams["flag"]
}
return(
<div className={`flex flex-col`}>
<p>Env: { process.env.MYSQL_HOST }</p>
<p>Result: { await query() }</p>
<p>Flag: { flag }</p>
</div>
)
}

View File

@@ -5,8 +5,16 @@ import { raleway, syne, questrial } from "@/app/fonts";
export default function Home() {
return (
<div className={`flex flex-col`}>
<div className={`bg-cover bg-center flex flex-col-reverse bg-blog-cover`}>
<div className={`bg-neutral-100 bg-opacity-30 flex flex-col py-10`}>
<div className={`grid grid-rows-1 grid-cols-1 justify-items-center`}>
<Image
src={`https://assets.suyono.me/placeholder.webp`}
alt={`blog cover`}
className={`object-cover col-start-1 row-start-1 w-screen h-192 z-0`}
width={1581}
height={759}
/>
<div className={`flex flex-col-reverse col-start-1 row-start-1 w-screen`}>
<div className={`bg-neutral-100 bg-opacity-30 flex flex-col py-10 z-10`}>
<p className={`${raleway.className} text-white text-center text-7xl font-thin mb-6`}>
SUYONO
</p>
@@ -14,8 +22,7 @@ export default function Home() {
A Tech Archive
</p>
</div>
<div className={`h-64`}></div> {/* spacer */}
<div className={`h-64`}></div> {/* spacer */}
</div>
</div>
<div className={`flex flex-row justify-center my-8`}>
<div className={`border border-slate-100 flex flex-col`}>
@@ -24,7 +31,7 @@ export default function Home() {
className={`flex flex-row max-w-4xl items-center`}
>
<Image
src="/assets/pthumb.webp"
src="https://assets.suyono.me/pthumb.webp"
alt="post thumbnail"
width={454}
height={341}

View File

@@ -1,20 +1,13 @@
import mysql, { PoolOptions } from "mysql2";
import mysql, { PoolOptions, Pool } from "mysql2";
import { Pool as pPool } from "mysql2/promise"
import * as fs from 'fs';
import * as appEnv from "./env";
if (typeof process.env.MYSQL_SSL_CA === 'undefined') {
throw new Error("missing MYSQL_SSL_CA")
}
let pool: Pool | undefined;
let promisePool: pPool | undefined;
if (typeof process.env.MYSQL_SSL_KEY === 'undefined') {
throw new Error("missing MYSQL_SSL_KEY")
}
if (typeof process.env.MYSQL_SSL_CERT === 'undefined') {
throw new Error("missing MYSQL_SSL_CERT")
}
const access: PoolOptions = {
export function getPool(): Pool {
const access: PoolOptions = {
host: appEnv.getMysqlHost(),
port: appEnv.getMysqlPort(),
user: appEnv.getMysqlUser(),
@@ -32,8 +25,18 @@ const access: PoolOptions = {
key: fs.readFileSync(appEnv.getMysqlSslKeyFile()),
cert: fs.readFileSync(appEnv.getMysqlSslCertFile())
}
}
if (typeof pool === 'undefined') {
pool = mysql.createPool(access)
}
return pool
}
export const pool = mysql.createPool(access)
export const promisePool = pool.promise()
export function getPromisePool(): pPool {
if (typeof promisePool === 'undefined') {
promisePool = getPool().promise()
}
return promisePool
}

View File

@@ -1,9 +1,9 @@
import { RowDataPacket } from "mysql2";
import { promisePool } from "@/backend/db";
import { getPromisePool } from "@/backend/db";
export async function getPost(slug: string): Promise<string> {
try {
const [rows, fields] = await promisePool.query<RowDataPacket[]>(
const [rows, fields] = await getPromisePool().query<RowDataPacket[]>(
'select content from post where slug = ?', [slug])
return rows[0]['content']
} catch (e) {

View File

@@ -1,8 +1,18 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "standalone",
webpack: (config) => {
config.externals = [...config.externals, "jsdom"];
return config;
},
images: {
remotePatterns: [
{
protocol: "https",
hostname: "assets.suyono.me",
pathname: "/**"
},
]
}
}

View File

@@ -9,24 +9,25 @@
"lint": "next lint"
},
"dependencies": {
"@types/dompurify": "^3.0.3",
"@types/jsdom": "^21.1.3",
"@types/dompurify": "^3.0.5",
"@types/jsdom": "^21.1.6",
"@types/node": "20.6.5",
"@types/react": "18.2.22",
"@types/react-dom": "18.2.7",
"autoprefixer": "10.4.16",
"bright": "^0.8.4",
"dompurify": "^3.0.6",
"eslint": "8.50.0",
"eslint-config-next": "13.5.2",
"html-react-parser": "^4.2.2",
"bright": "^0.8.5",
"dompurify": "^3.1.2",
"eslint": "8.57.0",
"eslint-config-next": "14.2.3",
"html-react-parser": "^4.2.10",
"jsdom": "^22.1.0",
"mysql2": "^3.6.1",
"next": "13.5.2",
"mysql2": "^3.9.7",
"next": "14.2.3",
"postcss": "8.4.30",
"react": "18.2.0",
"react-dom": "18.2.0",
"redis": "^4.6.10",
"react": "18.3.1",
"react-dom": "18.3.1",
"redis": "^4.6.13",
"sharp": "^0.33.3",
"tailwindcss": "3.3.3",
"typescript": "5.2.2"
},

7
pm2.config.js Normal file
View File

@@ -0,0 +1,7 @@
module.exports = {
apps: [{
script: "server.js",
instances: 4,
exec_mode: "cluster"
}]
}

5076
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -12,10 +12,12 @@ const config: Config = {
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
'gradient-conic':
'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
'blog-cover': "url('/assets/placeholder.webp')"
},
width: {
'224': '56rem',
},
height: {
'192': '48rem',
}
},
},