Add asset sync script

This commit is contained in:
2025-11-19 17:31:18 +08:00
parent 0d5fc93b30
commit 7ca7655e40
5 changed files with 46 additions and 6 deletions

3
.gitignore vendored
View File

@@ -34,5 +34,8 @@ pnpm-debug.log*
# Vercel # Vercel
.vercel .vercel
# Generated assets mirror
/public/assets
# TypeScript # TypeScript
*.tsbuildinfo *.tsbuildinfo

View File

@@ -39,7 +39,7 @@ Recent iterations focused on migrating every image to `next/image`, refreshing t
- `posts/` Blog posts (`.md`) - `posts/` Blog posts (`.md`)
- `pages/` Static pages (`.md`) - `pages/` Static pages (`.md`)
- `assets/` Images referenced from markdown - `assets/` Images referenced from markdown
- `public/assets` Symlink to `content/assets` for serving images at `/assets/...` - `public/assets` Copy of `content/assets` that is refreshed via `npm run sync-assets` (and automatically before `npm run build`) so Next.js can serve `/assets/...` without relying on symlinks.
- `contentlayer.config.ts` Contentlayer document types and markdown pipeline - `contentlayer.config.ts` Contentlayer document types and markdown pipeline
## UI Overview ## UI Overview
@@ -201,7 +201,15 @@ Recent iterations focused on migrating every image to `next/image`, refreshing t
echo -n 'your-email@example.com' | md5sum | cut -d' ' -f1 # Linux echo -n 'your-email@example.com' | md5sum | cut -d' ' -f1 # Linux
``` ```
5. **Run the development server** 5. **Mirror markdown assets**
```bash
npm run sync-assets
```
This copies `content/assets` into `public/assets` so `/assets/...` continues to work; the build script already runs it before `next build`, but running it locally keeps your previews in sync.
6. **Run the development server**
```bash ```bash
npm run dev npm run dev
@@ -242,7 +250,7 @@ Contentlayer is configured in `contentlayer.config.ts` to read from the `content
``` ```
- At build time, a rehype plugin rewrites these to `/assets/my-image.jpg`. - At build time, a rehype plugin rewrites these to `/assets/my-image.jpg`.
- `public/assets` is a symlink to `content/assets`, so Next.js serves them as static files. - `public/assets` is populated from `content/assets` before each build (and via `npm run sync-assets`) so `/assets/...` stays available without symlinks.
- `feature_image` fields are also mapped from `../assets/...` → `/assets/...` and rendered above the article content via `next/image`. - `feature_image` fields are also mapped from `../assets/...` → `/assets/...` and rendered above the article content via `next/image`.
- All component-level imagery (list thumbnails, related posts, sidebar avatar, about page hero, etc.) now uses `next/image` for responsive sizing, blur placeholders, and better LCP. - All component-level imagery (list thumbnails, related posts, sidebar avatar, about page hero, etc.) now uses `next/image` for responsive sizing, blur placeholders, and better LCP.

View File

@@ -5,7 +5,8 @@
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
"build": "next build", "sync-assets": "node scripts/sync-assets.mjs",
"build": "npm run sync-assets && next build",
"start": "next start", "start": "next start",
"lint": "next lint", "lint": "next lint",
"contentlayer": "contentlayer build" "contentlayer": "contentlayer build"
@@ -20,6 +21,7 @@
"@fortawesome/react-fontawesome": "^3.1.0", "@fortawesome/react-fontawesome": "^3.1.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"contentlayer": "^0.3.4", "contentlayer": "^0.3.4",
"framer-motion": "^12.23.24",
"gray-matter": "^4.0.3", "gray-matter": "^4.0.3",
"markdown-wasm": "^1.2.0", "markdown-wasm": "^1.2.0",
"next": "^13.5.11", "next": "^13.5.11",
@@ -30,6 +32,7 @@
"rehype-autolink-headings": "^7.1.0", "rehype-autolink-headings": "^7.1.0",
"rehype-slug": "^6.0.0", "rehype-slug": "^6.0.0",
"remark-gfm": "^4.0.1", "remark-gfm": "^4.0.1",
"tailwind-merge": "^3.4.0",
"unist-util-visit": "^5.0.0" "unist-util-visit": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -1 +0,0 @@
../content/assets

27
scripts/sync-assets.mjs Normal file
View File

@@ -0,0 +1,27 @@
import { cp, mkdir, rm, stat } from 'node:fs/promises';
import path from 'node:path';
async function syncAssets() {
const root = process.cwd();
const sourceDir = path.join(root, 'content', 'assets');
const targetDir = path.join(root, 'public', 'assets');
await rm(targetDir, { recursive: true, force: true });
await mkdir(targetDir, { recursive: true });
try {
await stat(sourceDir);
} catch {
// Nothing to copy yet; leave the empty directory in place.
console.info('sync-assets: no content/assets directory found yet.');
return;
}
await cp(sourceDir, targetDir, { recursive: true, force: true });
console.info('sync-assets: copied content/assets → public/assets.');
}
syncAssets().catch((error) => {
console.error('sync-assets: failed to mirror assets.', error);
process.exit(1);
});