[nextjs]SNS Server-48(myapp58)Β 

πŸ‘‰πŸ» myapp58 은 nextjsμ„œλ²„ μ‹€ν–‰μ‹œ(nextjs16) λ°œμƒν•˜λŠ” tailwind 였λ₯˜μ™€ μ•‘ν‹°λΈŒ ν…Œλ§ˆ λ””λ ‰ν† λ¦¬λ‚˜ νŒŒμΌμ΄λ¦„ λ³€κ²½μ‹œ μ—λŸ¬λ‘œκ·Έ λ°œμƒ λΆ€λΆ„μ˜ 버그λ₯Ό μˆ˜μ •ν•©λ‹ˆλ‹€.
myapp58 fixes bugs related to Tailwind errors occurring when running the Next.js server(Nextjs16) and error logs generated when changing the active theme directory or file names.

πŸ‘‰πŸ» 전체 μ½”λ“œλŠ” κΉƒν—ˆλΈŒμ—μ„œ 확인 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
You can find the full code on GitHub.

https://github.com/gideonslife01/flm-nextjs

πŸ“ 전체 ν”„λ‘œμ νŠΈ ꡬ쑰 / Overall Project Structure

myapp project/  
β”œβ”€β”€ app/  (Next.js App Router)
β”‚   β”œβ”€β”€ .well-known/webfinger/route.ts  -> webfinger
β”‚   β”œβ”€β”€ api/follow/route.ts    -> Follow API(temporary)
β”‚   β”œβ”€β”€ api/announce/route.ts  -> Boost(Announcement)
β”‚   β”œβ”€β”€ api/like/route.ts.     -> Like API
β”‚   β”œβ”€β”€ api/posts/route.ts     -> Writing API(deprecated)
β”‚   β”œβ”€β”€ api/timeline/route.ts  -> Timeline API
β”‚   β”œβ”€β”€ api/followinglist/route.ts  -> followinglist API
β”‚   β”œβ”€β”€ api/followerslist/route.ts  -> followerslist API
β”‚   β”œβ”€β”€ api/v1/instance/route.ts -> auth
β”‚   β”œβ”€β”€ api/v1/apps/route.ts.    -> auth
β”‚   β”œβ”€β”€ api/v1/accounts/verify_credentials/route.ts -> auth
β”‚   β”œβ”€β”€ api/v1/statuses/route.ts -> Write Post
β”‚   β”œβ”€β”€ api/v1/timelines/home/route.ts -> timeline
β”‚   β”œβ”€β”€ api/v1/media/route.ts -> Image upload
β”‚   β”œβ”€β”€ api/v1/media/[id]/route.ts  -> Image Delete 
β”‚   β”œβ”€β”€ api/v1/instance/rules/route.ts -> Feature not implemented.
β”‚   β”œβ”€β”€ api/v1/instance/domain_blocks/route.ts -> Feature not implemented.
β”‚   β”œβ”€β”€ api/v1/filters/route.ts -> Feature not implemented.
β”‚   β”œβ”€β”€ api/v1/lists/route.ts -> Feature not implemented.
β”‚   β”œβ”€β”€ api/v1/announcements/route.ts -> Feature not implemented.
β”‚   β”œβ”€β”€ api/v1/timelines/public/route.ts -> Feature not implemented.
β”‚   β”œβ”€β”€ api/v1/statuses/[id]/context/route.ts -> Post Check,Delete
β”‚   β”œβ”€β”€ oauth/authorize/route.ts -> auth
β”‚   β”œβ”€β”€ oauth/token/route.ts -> auth
β”‚   β”œβ”€β”€ oauth/login-and-authorize/route.ts -> Tursky,Pinafore login processing
β”‚   β”œβ”€β”€ oauth/revoke/route.ts -> Feature not implemented.
β”‚   β”œβ”€β”€ api/v1/search/home/route.ts -> search
β”‚   β”œβ”€β”€ api/v2/search/home/route.ts -> search
β”‚   β”œβ”€β”€ api/v2/notifications/policy/route.ts-> Feature not implemented.
β”‚   β”œβ”€β”€ api/v1/accounts/[id]/followers/route.ts -> followers
β”‚   β”œβ”€β”€ api/v1/accounts/[id]/following/route.ts -> following
β”‚   β”œβ”€β”€ api/v1/statuses/[id]/route.ts -> -> Post delete(pinafore)
β”‚   β”œβ”€β”€ api/auth/signup/route.ts        -> Website Signup
β”‚   β”œβ”€β”€ api/auth/login/route.ts         -> Website Login
β”‚   β”œβ”€β”€ api/auth/logout/route.ts        -> Website Logout
β”‚   β”œβ”€β”€ api/auth/refresh/route.ts       -> Refresh Token
β”‚   β”œβ”€β”€ api/cleanup-orphan/route.ts     -> post,outbox clean up
β”‚   β”œβ”€β”€ api/auth/me/route.tsx           -> Login Check
β”‚   β”œβ”€β”€ auth/signup/page.tsx            -> Signup UI
β”‚   β”œβ”€β”€ auth/signup/page.tsx            -> Login UI        
β”‚   β”œβ”€β”€ users/[username]/
β”‚   β”‚   β”œβ”€β”€ statuses/[id]/route.ts -> Indivisual Post
β”‚   β”‚   β”œβ”€β”€ route.ts               -> Acotr Information
β”‚   β”‚   β”œβ”€β”€ followers/route.ts     -> Followers List
β”‚   β”‚   β”œβ”€β”€ following/route.ts     -> Following List
β”‚   β”‚   β”œβ”€β”€ inbox/route.ts         -> Inbox
β”‚   β”‚   └── outbox/route.ts        -> outbox
β”‚   β”œβ”€β”€ usersui/[username]/
β”‚   β”‚   β”œβ”€β”€ page.tsx               -> Timeline UI(Server, 404)
β”‚   β”‚   β”œβ”€β”€ ClientPage.tsx.        -> Timeline UI(Client,Call Active Themes)
β”‚   β”‚   └── _components/themes/
β”‚   β”‚       β”œβ”€β”€ themeex/ThemeexTheme.tsx   -> Example Theme
β”‚   β”‚       β”œβ”€β”€ pinafore/PinaforeTheme.tsx -> Theme 1
β”‚   β”‚       β”œβ”€β”€ pinafore/FollowersList.tsx -> Theme 1, FollowersList
β”‚   β”‚       β”œβ”€β”€ pinafore/FollowingList.tsx -> Theme 1, FollowingList
β”‚   β”‚       β”œβ”€β”€ pinafore/NotificationsList.tsx -> Theme 1, NotificationsList
β”‚   β”‚       β”œβ”€β”€ pinafore/TimelineList.tsx  -> Theme 1, TimelineList
β”‚   β”‚       β”œβ”€β”€ mastodon/MastodonTheme.tsx -> Theme 2
β”‚   β”‚       └── minimal/MinimaltTheme.tsx  -> Theme 3
β”‚   β”œβ”€β”€ layout.tsx, page.tsx, globals.css
β”‚   └── favicon.ico
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ theme.tsx              -> Theme Provider
β”‚   β”œβ”€β”€ watchThemes.ts         -> Check real-time theme changes
β”‚   β”œβ”€β”€ auth.ts                -> Authentication, User Management
β”‚   β”œβ”€β”€ ap.ts                  -> Follow,Undo,Create,Likes,Announce
β”‚   β”œβ”€β”€ visibility.ts          -> Visibility(Public,Unlisted,Private,Direct)
β”‚   └── db.ts                  -> DB connection
β”œβ”€β”€ data/
β”‚   β”œβ”€β”€ keys/userIDs/          -> private.pem, public.pem(New)
β”‚   └── keys/                  -> private.pem, public.pem(legacy)
β”œβ”€β”€ data.sqlite                -> Database(1/3)
β”œβ”€β”€ data.sqlite-wal            -> Database(2/3)
β”œβ”€β”€ data.sqlite-shm            -> Database(3/3)
β”œβ”€β”€ Caddyfile                  -> https 
β”œβ”€β”€ instrumentation.ts         -> Background Server
β”œβ”€β”€ proxy.ts                   -> middleware.ts - >proxy.ts(for Nextjs16)
β”œβ”€β”€ postcss.config.mjs         -> for Nextjs16
└── package.json

πŸ“ ν”„λ‘œμ νŠΈ μ‹œμž‘ / Project Start


πŸ“ Nextj16 middleware.ts -> proxy.ts

βœ”οΈ μ•„λž˜μ™€ 같은 κ²½κ³  문ꡬ가 λ‚˜μ˜€λ©΄ 기쑴의 middleware.tsνŒŒμΌμ„ proxy.ts파일둜 이름을 λ°”κΏ‰λ‹ˆλ‹€.
If a warning message like the one below appears, rename the existing middleware.ts file to proxy.ts.

— next.js16 middleware κ²½κ³  / Next.js 16 middleware warning

β–² Next.js 16.4.0 (Turbopack)
- Local:         http://localhost:3000
- Network:       http://192.168.0.10:3000
- Environments: .env.local
βœ“ Ready in 172ms
βœ“ Running next.config.ts took 14ms
⚠️ The "middleware" file convention is deprecated. Please use "proxy" instead.

  To migrate automatically, run:
  npx @next/codemod@canary middleware-to-proxy .

  Learn more: https://nextjs.org/docs/messages/middleware-to-proxy
βœ… themes: [ 'mastodon', 'minimal', 'pinafore', 'themeex' ]
πŸ‘€ Theme watcher started in background

— μ½”λ“œ μˆ˜μ • / Code Modification

# middleware.tsνŒŒμΌμ„ proxy.ts둜 이름을 λ°”κΎΈκ³  μ½”λ“œλ₯Ό μ•„λž˜μ²˜λŸΌ μˆ˜μ •
# Rename the `middleware.ts` file to `proxy.ts` and modify the code as shown below.

//export function middleware(req: NextRequest) {

// βœ… myapp58
export default function proxy(req: NextRequest) { ... ...}

πŸ“ Tailwind error

βœ”οΈ μ•„λž˜μ™€ 같은 였λ₯˜ λ°œμƒμ‹œ ν”„λ‘œμ νŠΈ λ£¨νŠΈμ— postcss.config.mjs νŒŒμΌμ„ λ§Œλ“€κ³  μ½”λ“œλ₯Ό μž…λ ₯ν•©λ‹ˆλ‹€.
If an error like the one below occurs, create a postcss.config.mjs file in the project root and enter the code.

— Error

Unknown at rule: @theme

Generated code of PostCSS transform of file content of app/globals.css:
./app/globals.css:8:7
   6 | }
   7 |
>  8 | @theme inline {
     |       ^
   9 |   --color-background: var(--background);
  10 |   --color-foreground: var(--foreground);
  11 |   --font-sans: var(--font-geist-sans);

Import trace:
  Client Component Browser:
    ./app/globals.css [Client Component Browser]
    ./app/layout.tsx [Server Component]

— μ½”λ“œ / Code

# postcss.config.mjs
const config = {
  plugins: {
    "@tailwindcss/postcss": {},
  },
};

export default config;

— λͺ¨λ“ˆ μ„€μΉ˜ / module install

npm install -D @tailwindcss/postcss
# or
npm install -D tailwindcss @tailwindcss/postcss

βœ”οΈ 곡식 λ¬Έμ„œ / Official Documentation (Tailwindcss for nextjs)

https://tailwindcss.com/docs/installation/framework-guides/nextjs
https://www.npmjs.com/package/@tailwindcss/postcss


πŸ“ ν…Œλ§ˆ λ””λ ‰ν† λ¦¬λ‚˜ νŒŒμΌμ΄λ¦„ λ³€κ²½μ‹œ μ„œλ²„λ‘œκ·Έμ— μ—λŸ¬ 둜그 좜λ ₯ 였λ₯˜ μˆ˜μ •
Fixed an issue where error logs were generated in the server logs when renaming theme directories or filenames.

βœ”οΈ 였λ₯˜ / Error

β¨― ./app/usersui/[username]/_components/themes/index.ts:4:1
Error: Module not found: Can't resolve './themeex/PinaforeTheme'

βœ”οΈ lib/watchThemes.ts

      for (const folderName of folders) {
        const folderPath = path.join(themesDir, folderName);
        try { 
... ...
          // βœ… myapp58 
          // -  pinaforeλŠ” _Fallback 
          if (folderName === 'pinafore') {
            registryLines += ` pinafore: { component: _Fallback, label: 'pinafore' },\n`;
          } else {
            // βœ… 정적 import μ•ˆν•¨, requireλ₯Ό try/catch + eval둜 κ°μ‹Έμ„œ λ²ˆλ“€λŸ¬κ°€ 파일 없어도 μ—λŸ¬ μ•ˆ λ‚΄κ²Œ
            registryLines += ` ${folderName}: { component: _load('./${folderName}/${fileBase}', '${exported}'), label: '${folderName}' },\n`;
          }
        } catch { continue; } // 폴더 읽기 μ‹€νŒ¨ν•˜λ©΄ μŠ€ν‚΅ / Skip if folder reading fails
      }

      // βœ… myapp58 - write code to index.ts themeName.ts files
      // λ””λ ‰ν† λ¦¬λ‚˜ 파일 인식 λͺ»ν•˜λ©΄ Pinaforeν…Œλ§ˆλ‘œ λŒ€μ²΄ / If directories or files are not recognized, replace with the Pinafore theme.
      const indexContent = `import { PinaforeTheme as _Fallback } from './pinafore/PinaforeTheme';

function _load(path: string, exportName: string) {
  try {
    const mod = eval('require')(path);
    return mod[exportName] || mod.default || _Fallback;
  } catch {
    return _Fallback;
  }
}

export const themeRegistry = {
${registryLines}} as const;
export type ThemeName = keyof typeof themeRegistry;
export function getThemeComponent(name: ThemeName) {
  return themeRegistry[name]?.component?? _Fallback;
}
`;
      const namesContent = `export const themeNames = ${JSON.stringify(validFolders)} as const;
export type ThemeName = typeof themeNames[number];
`;

βœ”οΈ app/usersui/[username]/_components/themes/index.ts – μžλ™μƒμ„± 파일 / Automatically generated file

— index.tsνŒŒμΌμ€ μ•„λž˜μ™€ 같은 ν˜•μ‹μœΌλ‘œμƒμ„± λ©λ‹ˆλ‹€.
The index.ts file is generated in the following format.

import { PinaforeTheme as _Fallback } from './pinafore/PinaforeTheme';

function _load(path: string, exportName: string) {
  try {
    
    const mod = eval('require')(path);
    return mod[exportName] || mod.default || _Fallback;
  } catch {
    return _Fallback;
  }
}

export const themeRegistry = {
 mastodon: { component: _load('./mastodon/MastodonTheme', 'MastodonTheme'), label: 'mastodon' },
 minimal: { component: _load('./minimal/MinimalTheme', 'MinimalTheme'), label: 'minimal' },
 pinafore: { component: _Fallback, label: 'pinafore' },
 themeex: { component: _load('./themeex/Themetheme', 'Theme'), label: 'themeex' },
} as const;
export type ThemeName = keyof typeof themeRegistry;
export function getThemeComponent(name: ThemeName) {
  return themeRegistry[name]?.component?? _Fallback;
}

πŸ“ ν…ŒμŠ€νŠΈ / Test

βœ”οΈ Tailwind

— μ„œλ²„μ‹œμž‘μ‹œ 였λ₯˜κ°€ λ°œμƒν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
No errors occur when starting the server.

Server Log

βœ”οΈ μ—‘ν‹°λΈŒ ν…Œλ§ˆ / Active Theme

— ν…Œλ§ˆ λ””λ ‰ν† λ¦¬λ‚˜ 파일이 μΆ”κ°€ μ‚­μ œ λ³€κ²½μ‹œ μ„œλ²„ 였λ₯˜ λ‘œκ·Έκ°€ λ°œμƒν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
No server error logs are generated when theme directories or files are added, deleted, or modified.

Server Log

— ν…Œλ§ˆ 리슀트 λ³€κ²½ 확인 / Check theme list changes

Theme

λ§ˆνƒœλ³΅μŒ 21μž₯ 22절 / Matthew 21: 22

“λ„ˆν¬κ°€ 기도할 λ•Œμ— 무엇이든지 λ―Ώκ³  κ΅¬ν•˜λŠ” 것은 λ‹€ λ°›μœΌλ¦¬λΌ ν•˜μ‹œλ‹ˆλΌ”

“And everything you ask in prayer, believing, you will receive.”

Leave a Reply