Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Dockerfile
build/
.dockerignore
node_modules
npm-debug.log
Expand Down
61 changes: 13 additions & 48 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,55 +1,20 @@
# Use Node.js 18 Alpine as base image
FROM node:18-alpine AS base

# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install dependencies (include devDependencies so build works)
COPY package.json package-lock.json* ./
RUN npm ci

# Rebuild the source code only when needed
FROM base AS builder
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
ENV NEXT_TELEMETRY_DISABLED 1

RUN npm install
RUN npm run build

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public

# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs
# Production stage
FROM nginx:alpine
WORKDIR /usr/share/nginx/html
RUN mkdir blog
COPY --from=builder /app/build ./blog

EXPOSE 3000
# Replace default.conf with our own
RUN rm -rf /etc/nginx/conf.d/*
COPY default.conf /etc/nginx/conf.d/default.conf

ENV PORT 3000
ENV HOSTNAME "0.0.0.0"
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

# server.js is created by next build from the standalone output
CMD ["node", "server.js"]
55 changes: 55 additions & 0 deletions default.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
server {
listen 80;
listen [::]:80;
server_name localhost;

#access_log /var/log/nginx/host.access.log main;

location / {
root /usr/share/nginx/html;
index index.html index.htm;
}

location /blog {
alias /usr/share/nginx/html/blog;
try_files $uri $uri/ /blog/index.html;

# Handle static assets (images, CSS, JS)
location ~* \.(png|jpg|jpeg|gif|svg|ico|css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}

#error_page 404 /404.html;

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}

# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
2 changes: 1 addition & 1 deletion nexlayer-update.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ application:
- name: blog
image: ghcr.io/nexlayer/nexlayer-blog:latest
path: "/"
servicePorts: [3000]
servicePorts: [80]
vars:
NODE_ENV: "production"
NEXT_TELEMETRY_DISABLED: "1"
4 changes: 2 additions & 2 deletions nexlayer.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ application:
pods:
- name: blog
image: ghcr.io/nexlayer/nexlayer-blog:latest
path: "/blog"
servicePorts: [3000]
path: "/"
servicePorts: [80]
vars:
NODE_ENV: "production"
NEXT_TELEMETRY_DISABLED: "1"
16 changes: 6 additions & 10 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@ import { NextConfig } from 'next'
import createMDX from '@next/mdx'
const nextConfig: NextConfig = {
pageExtensions: ['js', 'jsx', 'mdx', 'ts', 'tsx'],
output: 'standalone',
async redirects() {
return [
{
source: '/',
destination: '/blog',
permanent: true,
},
]
},
output: 'export', // Enable static export
distDir: 'build', // Output directory
basePath: '/blog',
images: {
unoptimized: true
}
}
const withMDX = createMDX({
extension: /\.mdx?$/,
Expand Down
28 changes: 20 additions & 8 deletions src/app/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import React from "react";
import Image from "next/image";
import Link from "next/link";
import BlogMdxContent from "../../components/BlogMdxContent";
import SimpleMdxRenderer from "@/components/SimpleMdxRenderer";
import fs from "fs";
import { ArrowLeft } from "lucide-react";
import path from "path";
import matter from "gray-matter";
import NotFound from "@/app/not-found";

import { serialize } from "next-mdx-remote/serialize";
// Generate static params for all blog posts
export async function generateStaticParams() {
const contentDir = path.join(process.cwd(), "src", "content");
try {
const files = fs.readdirSync(contentDir).filter((f) => f.endsWith(".mdx"));
return files.map((filename) => ({
slug: filename.replace(/\.mdx$/, ""),
}));
} catch (err) {
return [];
}
}

interface BlogPostProps {
params: Promise<{ slug: string }>;
Expand All @@ -20,15 +31,14 @@ async function getPostBySlug(slug: string) {
if (!fs.existsSync(filePath)) return null;
const source = fs.readFileSync(filePath, "utf-8");
const { data, content } = matter(source);
const mdxSource = await serialize(content, { scope: data });

return {
title: data.title || slug,
description: data.description || "",
author: data.author || "Unknown",
avatar: data.avatar || "/placeholder.svg",
readTime: data.readTime || "",
date: data.date || "",
mdxSource,
content,
};
}
Expand All @@ -41,6 +51,8 @@ const BlogPost = async ({ params }: BlogPostProps) => {
return <NotFound />;
}



return (
<div className="min-h-screen bg-black">
<main className="pt-16">
Expand All @@ -61,7 +73,7 @@ const BlogPost = async ({ params }: BlogPostProps) => {

<div className="flex items-center gap-3 mb-12 pb-8 border-b border-gray-800">
<Image
src={post.avatar && post.avatar.startsWith('/') ? post.avatar : '/placeholder.svg'}
src={post.avatar || '/placeholder.svg'}
alt={post.author}
width={40}
height={40}
Expand All @@ -75,9 +87,9 @@ const BlogPost = async ({ params }: BlogPostProps) => {
</div>
</div>

<div className="prose prose-invert prose-lg max-w-none">
<BlogMdxContent source={post.mdxSource} />
</div>
<div className="prose prose-invert prose-lg max-w-none">
<SimpleMdxRenderer content={post.content} />
</div>
</div>
</main>
</div>
Expand Down
88 changes: 0 additions & 88 deletions src/app/blog/[slug]/page.tsx

This file was deleted.

Loading