张好球 發表於 2024-9-13 13:02:00

Build Lightweight AI SaaS: Next.js + Tailwind CSS

<blockquote>
<p>前端框架:<strong>Next.js</strong><br>
UI 组件:<strong>Tailwind CSS, Shadcn UI</strong><br>
AI 集成:<strong>Anthropic Claude API</strong>, <strong>Anthropic Claude API Keys</strong></p>
</blockquote>
<p><img src="https://img2024.cnblogs.com/blog/2872556/202504/2872556-20250420125025433-1260072050.png" alt="image" loading="lazy"></p>
<h2 id="11-initialization">1.1 Initialization</h2>
<p><strong>1. For the installation, you can refer https://ui.shadcn.com/docs/installation/next</strong></p>
<pre><code class="language-Powershell"># Choose the path to build your new project
cd your_path_to_put_your_new_project_folder

# Initialize the project by shadcn ui (default setting: New York/Zinc/Yes)
npx shadcn@latest init -d

# Select the options
/Yes
/my-app
</code></pre>
<p><strong>2. Initialize the <code>app/layout.tsx</code> and <code>app/page.tsx</code></strong><br>
layout.tsx</p>
<pre><code class="language-javascript">import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
title: "Cactus AI",
description: "Generated by create next app",
};

export default function RootLayout({
children,
}: Readonly&lt;{
children: React.ReactNode;
}&gt;) {
return (
    &lt;html lang="en"&gt;
      &lt;body className={inter.className}&gt;{children}&lt;/body&gt;
    &lt;/html&gt;
);
}
</code></pre>
<p>page.tsx</p>
<pre><code class="language-javascript">export default function RootPage = () =&gt; {
    return (
      &lt;div className="h-screen"&gt;
            Hello World!
      &lt;/div&gt;
   );
}
</code></pre>
<p><strong>3. Add components(e.g. Button) in the <code>/components/ui/</code>, follow this step:</strong></p>
<pre><code class="language-shell">npx shadcn@latest add button
</code></pre>
<p><strong>4. Run the Next.js server</strong></p>
<pre><code class="language-Powershell">cd your_app_name
npm run dev
</code></pre>
<h2 id="12-project-structure">1.2 Project Structure</h2>
<p>A Next.js project example</p>
<pre><code class="language-shell">your_app_name/
├── app/                                    # "/"
│   ├── api/                              # "/api" for the backend logic
│   │   ├── hanyuxinjie/
│   │   │   ├── route.ts                  # Handles AI requests for "/api/hanyuxinjie/"
│   │   ├── social-card/
│   │   │   ├── route.ts                  # Handles AI requests for "/api/social-card/"
│   ├── social-card/                        # "/social-card"
│   │   ├── page.tsx
│   ├── fonts/                              # Custom fonts for typography
│   │   ├── GeistMonoVF.woff
│   │   ├── GeistVF.woff
│   ├── favicon.ico
│   ├── globals.css
│   ├── layout.tsx
│   ├── page.tsx
├── components/                           # Usable global components
│   ├── ui/
│   │   ├── button.tsx
│   │   ├── card.tsx
│   │   ├── input.tsx
│   │   ├── sonner.tsx
│   ├── footer.tsx
│   ├── header.tsx
│   ├── word-rotate.tsx
│   ├── icons.tsx
│   ├── hero-typewriter.tsx
│   ├── PresetTemplateGrid.tsx
│   ├── social-card-generator.tsx
│   ├── svg-generator.tsx
├── lib/                                     # Helper files and constants.
│   ├── constants.ts
│   ├── utils.ts
├── public/                                  # Static assets (e.g., images).
│   ├── logo.png
├── .env.example                           # Environment variables template.
├── .eslintrc.json
├── .gitignore
├── README.md
├── components.json                        # Component configuration or mappings.
├── next.config.mjs
├── .nixpacks.toml
├── package.json
├── pnpm-lock.yaml
├── postcss.config.mjs
├── tailwind.config.ts
├── tsconfig.json
├── Dockerfile                               # Dockerfile for containerizing the app.
├── docker-compose.yml                     # Docker Compose file for managing services.
</code></pre>
<h2 id="13-app-router">1.3 App Router</h2>
<blockquote>
<p>https://nextjs.org/docs/app/building-your-application/routing/defining-routes</p>
</blockquote>
<ul>
<li>Dynamic Routes</li>
<li>Nested Routes</li>
<li>Group Routes</li>
</ul>
<h2 id="14-docker">1.4 Docker</h2>
<blockquote>
<p>To containerize your Next.js project using Docker, you can create a <code>Dockerfile</code> and a <code>docker-compose.yml</code>. Here's how to set it up:</p>
</blockquote>
<p><strong>1. Create a <code>Dockerfile</code></strong><br>
In the root of your project, create a <code>Dockerfile</code>. Here's an example:</p>
<pre><code class="language-Dockerfile"># Stage 1: Build Stage
FROM node:18-alpine AS builder

# Set working directory
WORKDIR /app

# Copy package.json and pnpm lock file
COPY package.json pnpm-lock.yaml ./

# Install pnpm and project dependencies
RUN npm install -g pnpm &amp;&amp; pnpm install --frozen-lockfile

# Copy all files to the working directory
COPY . .

# Build the Next.js project
RUN pnpm run build

# Stage 2: Production Image
FROM node:18-alpine AS runner

WORKDIR /app

# Copy only necessary files for production
COPY --from=builder /app/package.json ./
COPY --from=builder /app/pnpm-lock.yaml ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next

# Set environment variables
ENV NODE_ENV=production

# Expose the Next.js port
EXPOSE 3000

# Run the Next.js application
CMD ["pnpm", "start"]
</code></pre>
<p><strong>2. Create a <code>docker-compose.yml</code></strong><br>
If you want to use Docker Compose to manage your development setup, you can create a <code>docker-compose.yml</code> in the root directory.</p>
<pre><code class="language-yaml">version: '3'
services:
web:
    build: .
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: development
    volumes:
      - .:/app
      - /app/node_modules
    command: pnpm run dev
</code></pre>
<p><strong>3. Update <code>next.config.mjs</code> for Production</strong><br>
Ensure your <code>next.config.mjs</code> is optimized for a production environment. For example, it should enable compression and other optimizations.</p>
<pre><code class="language-javascript">const isProd = process.env.NODE_ENV === 'production';

module.exports = {
reactStrictMode: true,
swcMinify: true,
compress: isProd,
};
</code></pre>
<p><strong>4. Build and Run the Docker Image</strong><br>
To build the Docker image, run the following command in the root of your project:</p>
<pre><code class="language-shell">docker build -t my-nextjs-app .
</code></pre>
<p>If you're using <code>docker-compose</code>, simply run:</p>
<pre><code class="language-shell">docker-compose up
</code></pre>
<h1 id="2-tailwind-css">2 Tailwind CSS</h1>
<h2 id="21-docs">2.1 Docs</h2>
<blockquote>
<p>https://tailwindcss.com/docs/</p>
</blockquote>
<p>position-sticky top-0 bg-black<br>
flex justify-between<br>
container<br>
mx-auto<br>
text-white<br>
text-3xl<br>
font-bold<br>
p-8</p>
<h1 id="3-frontend-basics">3. Frontend Basics</h1>
<h2 id="31-html">3.1 HTML</h2>
<ul>
<li>按<code>tab</code>自动生成</li>
<li>按<code>ctrl + D</code>复制该行</li>
</ul>
<table>
<thead>
<tr>
<th style="text-align: center">Label</th>
<th style="text-align: center">Meaning</th>
<th style="text-align: center">Properties</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center"><code>&lt;div&gt;</code></td>
<td style="text-align: center">块状元素</td>
<td style="text-align: center"></td>
</tr>
<tr>
<td style="text-align: center"><code>&lt;span&gt;</code></td>
<td style="text-align: center">行间元素</td>
<td style="text-align: center"></td>
</tr>
<tr>
<td style="text-align: center"><code>&lt;h1&gt;</code> - <code>&lt;h6&gt;</code></td>
<td style="text-align: center">标题</td>
<td style="text-align: center"></td>
</tr>
<tr>
<td style="text-align: center"><code>&lt;i&gt;</code></td>
<td style="text-align: center">icon图标</td>
<td style="text-align: center"></td>
</tr>
<tr>
<td style="text-align: center"><code>&lt;strong&gt;</code></td>
<td style="text-align: center">字体加粗</td>
<td style="text-align: center"></td>
</tr>
<tr>
<td style="text-align: center"><code>&lt;a&gt;</code></td>
<td style="text-align: center">超链接</td>
<td style="text-align: center"></td>
</tr>
<tr>
<td style="text-align: center"><code>&lt;img&gt;</code></td>
<td style="text-align: center">插入图片</td>
<td style="text-align: center"></td>
</tr>
<tr>
<td style="text-align: center"><code>&lt;video&gt;</code></td>
<td style="text-align: center">插入视频</td>
<td style="text-align: center">controls</td>
</tr>
<tr>
<td style="text-align: center"><code>&lt;input&gt;</code></td>
<td style="text-align: center">表单(输入账号、密码的框)</td>
<td style="text-align: center">type='text'<br>type='password'</td>
</tr>
<tr>
<td style="text-align: center"><code>&lt;textarea&gt;</code></td>
<td style="text-align: center">表单(支持多行)</td>
<td style="text-align: center"></td>
</tr>
<tr>
<td style="text-align: center"><code>&lt;button&gt;</code></td>
<td style="text-align: center">按钮</td>
<td style="text-align: center"></td>
</tr>
</tbody>
</table>
<h2 id="32-css">3.2 CSS</h2>
<h3 id="321-css布局思路">3.2.1 CSS布局思路</h3>
<p><strong>(1) 盒子模型</strong></p>
<table>
<thead>
<tr>
<th style="text-align: center">Label</th>
<th style="text-align: center">Meaning</th>
<th>Properties</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center"><code>margin</code></td>
<td style="text-align: center">外边距</td>
<td></td>
</tr>
<tr>
<td style="text-align: center"><code>padding</code></td>
<td style="text-align: center">内边距</td>
<td></td>
</tr>
<tr>
<td style="text-align: center"><code>border</code></td>
<td style="text-align: center">边框</td>
<td></td>
</tr>
<tr>
<td style="text-align: center"><code>box-shadow</code></td>
<td style="text-align: center">阴影</td>
<td></td>
</tr>
<tr>
<td style="text-align: center"><code>box-redius</code></td>
<td style="text-align: center">边角</td>
<td></td>
</tr>
<tr>
<td style="text-align: center"><code>word-wrap: break-word</code></td>
<td style="text-align: center">内容</td>
<td></td>
</tr>
</tbody>
</table>
<p><strong>(2) flex布局</strong><br>
https://www.runoob.com/w3cnote/flex-grammar.html</p>
<table>
<thead>
<tr>
<th style="text-align: center">Label</th>
<th style="text-align: center">Meaning</th>
<th style="text-align: center">Properties</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center"><code>flex-direction</code></td>
<td style="text-align: center"></td>
<td style="text-align: center">row | column</td>
</tr>
<tr>
<td style="text-align: center"><code>flex-wrap</code></td>
<td style="text-align: center"></td>
<td style="text-align: center">wrap</td>
</tr>
<tr>
<td style="text-align: center"><code>justify-content</code></td>
<td style="text-align: center"></td>
<td style="text-align: center">flex-start | flex-end | center | space-between | space-around</td>
</tr>
<tr>
<td style="text-align: center"><code>align-items</code></td>
<td style="text-align: center"></td>
<td style="text-align: center">flex-start | flex-end | center | baseline | stretch</td>
</tr>
</tbody>
</table>
<h3 id="322-css布局元素">3.2.2 CSS布局元素</h3>
<p><strong>(1)宽度width</strong></p>
<ul>
<li>固定宽度 百分比宽度</li>
<li>最大宽度</li>
<li>最小宽度</li>
<li>水平居中 <code>margin: auto</code></li>
</ul>
<p><strong>(2)高度height</strong></p>
<ul>
<li>固定高度(必须)</li>
<li>最大高度</li>
<li>最小高度</li>
<li>行高对齐 <code>line-height</code></li>
</ul>
<p><strong>(3)字体</strong></p>
<ul>
<li>颜色 <code>color</code> 十六进制、rgb、英文</li>
<li>大小 <code>font-size</code></li>
<li>粗细 <code>font-weight: bold</code></li>
</ul>
<p><strong>(4)背景</strong></p>
<ul>
<li>https://tool.oschina.net/commons?type=3</li>
<li>颜色 <code>background-color</code></li>
<li>图片 <code>background-img: url(...)</code></li>
</ul>
<p><strong>(5)定位position</strong></p>
<ul>
<li><code>absolute</code> 生成绝对定位的元素,相对于static定位意外的第一个父元素进行定位</li>
<li><code>relative</code> 生成相对定位的元素,相对于其正常位置进行定位(上下移动行内元素最简单的方式)</li>
<li><code>Fixed</code> 生成固定定位的元素,相对于浏览器窗口进行定位</li>
</ul>
<p>(6)溢出</p>
<ul>
<li><code>overflow: hidden</code></li>
<li><code>overflow: scroll</code></li>
</ul><br><br>
来源:https://www.cnblogs.com/forhheart/p/18412006
頁: [1]
查看完整版本: Build Lightweight AI SaaS: Next.js + Tailwind CSS