Fix scripts for Next.js + Payload CMS workflow
- new-project.sh: Use nextjs-payload-starter template, Next.js AI rules - convert-astro.sh: Complete rewrite to migrate Astro MDX to Payload CMS Lexical JSON - deploy.sh: Check for next.config instead of astro.config.mjs, use MONGODB_URL - preview.sh: Check for Next.js, default port 3002 - audit-seo.sh: Check .tsx pages in src/app, Next.js config All scripts now properly support Next.js + Payload CMS workflow.
This commit is contained in:
@@ -1,16 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
#===============================================================================
|
||||
# convert-astro.sh - แปลงเว็บเก่าเป็น Astro + Payload CMS
|
||||
# migrate-to-payload.sh - Migrate Astro content to Payload CMS with Lexical
|
||||
#
|
||||
# Usage: ./convert-astro.sh [source-path] [project-name]
|
||||
# Usage: ./migrate-to-payload.sh [source-path] [target-path]
|
||||
#
|
||||
# รองรับ:
|
||||
# - Astro เวอร์ชั่นเก่า
|
||||
# - Next.js
|
||||
# - Static HTML
|
||||
# This script migrates content from Astro MDX/Markdown to Payload CMS Lexical.
|
||||
# - Converts .md/.mdx files to Payload CMS Lexical JSON format
|
||||
# - Creates Payload collection entries
|
||||
# - Preserves frontmatter as collection fields
|
||||
#
|
||||
# Requirements:
|
||||
# - git
|
||||
# - node.js 20+
|
||||
# - npm
|
||||
#
|
||||
@@ -18,253 +17,277 @@
|
||||
|
||||
set -e
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Default values
|
||||
SOURCE_PATH="${1:-}"
|
||||
PROJECT_NAME="${2:-}"
|
||||
TARGET_PATH="${2:-.}"
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Helper functions
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
||||
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
print_usage() {
|
||||
cat << EOF
|
||||
Usage: $(basename "$0") [source-path] [project-name]
|
||||
Usage: $(basename "$0") [source-path] [target-path]
|
||||
|
||||
แปลงเว็บเก่าเป็น Astro + Payload CMS
|
||||
Migrate Astro content to Payload CMS with Lexical
|
||||
|
||||
Arguments:
|
||||
source-path ที่อยู่เว็บเก่า
|
||||
project-name ชื่อ project ใหม่
|
||||
|
||||
Supported Sources:
|
||||
- Astro เวอร์ชั่นเก่า
|
||||
- Next.js
|
||||
- Static HTML
|
||||
source-path Path to Astro project with content
|
||||
target-path Path to Next.js + Payload CMS project
|
||||
|
||||
Examples:
|
||||
$(basename "$0") /path/to/old-site my-new-site
|
||||
$(basename "$0") /path/to/astro-site /path/to/payload-site
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Detect source type
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
detect_source_type() {
|
||||
log_info "ตรวจสอบประเภทเว็บเก่า..."
|
||||
|
||||
if [ ! -d "$SOURCE_PATH" ]; then
|
||||
log_error "ไม่พบ source path: $SOURCE_PATH"
|
||||
exit 1
|
||||
fi
|
||||
detect_content_type() {
|
||||
log_info "Detecting content structure..."
|
||||
|
||||
cd "$SOURCE_PATH"
|
||||
|
||||
if [ -f "package.json" ]; then
|
||||
if grep -q '"next"' "package.json" 2>/dev/null; then
|
||||
SOURCE_TYPE="nextjs"
|
||||
log_success "ตรวจพบ: Next.js"
|
||||
elif grep -q '"astro"' "package.json" 2>/dev/null; then
|
||||
SOURCE_TYPE="astro"
|
||||
log_success "ตรวจพบ: Astro"
|
||||
elif grep -q '"remix"' "package.json" 2>/dev/null; then
|
||||
SOURCE_TYPE="remix"
|
||||
log_success "ตรวจพบ: Remix"
|
||||
elif grep -q '"nuxt"' "package.json" 2>/dev/null; then
|
||||
SOURCE_TYPE="nuxt"
|
||||
log_success "ตรวจพบ: Nuxt"
|
||||
else
|
||||
SOURCE_TYPE="unknown"
|
||||
log_warning "ไม่สามารถระบุประเภท - จะใช้เป็น static HTML"
|
||||
fi
|
||||
elif [ -f "index.html" ]; then
|
||||
SOURCE_TYPE="static"
|
||||
log_success "ตรวจพบ: Static HTML"
|
||||
if [ -d "src/content" ]; then
|
||||
CONTENT_DIR="src/content"
|
||||
elif [ -d "content" ]; then
|
||||
CONTENT_DIR="content"
|
||||
elif [ -d "src/pages" ]; then
|
||||
CONTENT_DIR="src/pages"
|
||||
else
|
||||
log_error "ไม่พบ package.json หรือ index.html"
|
||||
log_error "No content directory found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "Content directory: $CONTENT_DIR"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Backup source
|
||||
#-------------------------------------------------------------------------------
|
||||
backup_content() {
|
||||
log_info "Backing up content..."
|
||||
|
||||
backup_source() {
|
||||
log_info "สำรองข้อมูลเว็บเก่า..."
|
||||
|
||||
BACKUP_DIR="/tmp/backup-$(basename "$SOURCE_PATH")-$(date +%s)"
|
||||
BACKUP_DIR="/tmp/migration-backup-$(date +%s)"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
cp -r "$SOURCE_PATH" "$BACKUP_DIR/"
|
||||
if [ -d "$SOURCE_PATH/$CONTENT_DIR" ]; then
|
||||
cp -r "$SOURCE_PATH/$CONTENT_DIR" "$BACKUP_DIR/"
|
||||
fi
|
||||
|
||||
log_success "สำรองข้อมูลที่: $BACKUP_DIR"
|
||||
log_success "Backup at: $BACKUP_DIR"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Analyze structure
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
analyze_structure() {
|
||||
log_info "วิเคราะห์โครงสร้างเว็บเก่า..."
|
||||
analyze_content() {
|
||||
log_info "Analyzing content..."
|
||||
|
||||
cd "$SOURCE_PATH"
|
||||
|
||||
echo ""
|
||||
echo " โครงสร้างไฟล์:"
|
||||
find . -type f \( -name "*.astro" -o -name "*.tsx" -o -name "*.jsx" -o -name "*.vue" -o -name "*.html" -o -name "*.md" -o -name "*.mdx" \) 2>/dev/null | grep -v node_modules | head -30
|
||||
local md_count=$(find "$CONTENT_DIR" -type f \( -name "*.md" -o -name "*.mdx" \) 2>/dev/null | wc -l)
|
||||
local astro_count=$(find . -type f -name "*.astro" 2>/dev/null | grep -v node_modules | wc -l)
|
||||
|
||||
echo ""
|
||||
echo " Package.json scripts:"
|
||||
if [ -f "package.json" ]; then
|
||||
grep -A 10 '"scripts"' "package.json" 2>/dev/null | head -15
|
||||
fi
|
||||
echo " Content files: $md_count"
|
||||
echo " Astro components: $astro_count"
|
||||
echo ""
|
||||
|
||||
find "$CONTENT_DIR" -type f \( -name "*.md" -o -name "*.mdx" \) 2>/dev/null | head -20
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Create new Astro project
|
||||
#-------------------------------------------------------------------------------
|
||||
create_lexical_content() {
|
||||
log_info "Converting MDX to Payload CMS Lexical format..."
|
||||
|
||||
create_new_project() {
|
||||
log_info "สร้าง Astro project ใหม่..."
|
||||
cd "$SOURCE_PATH"
|
||||
|
||||
NEW_PROJECT_PATH="$(dirname "$SOURCE_PATH")/$PROJECT_NAME"
|
||||
local output_dir="$TARGET_PATH/src/content-migration"
|
||||
mkdir -p "$output_dir"
|
||||
|
||||
if [ -d "$NEW_PROJECT_PATH" ]; then
|
||||
log_warning "Project มีอยู่แล้ว: $NEW_PROJECT_PATH"
|
||||
read -p "ลบและสร้างใหม่? (y/n): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
rm -rf "$NEW_PROJECT_PATH"
|
||||
find "$CONTENT_DIR" -type f \( -name "*.md" -o -name "*.mdx" \) 2>/dev/null | while read -r file; do
|
||||
local relative_path="${file#$SOURCE_PATH/$CONTENT_DIR/}"
|
||||
local filename=$(basename "$file" .mdx .md | sed 's/\.mdx$//' | sed 's/\.md$//')
|
||||
local slug=$(echo "$filename" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
|
||||
|
||||
local frontmatter=""
|
||||
local content=""
|
||||
|
||||
if grep -q "^---" "$file" 2>/dev/null; then
|
||||
frontmatter=$(sed -n '/^---/,/^---/p' "$file" | head -n -1 | tail -n +2)
|
||||
content=$(awk '/^---/{found=1; next} found' "$file")
|
||||
else
|
||||
log_info "ใช้ existing project"
|
||||
return 0
|
||||
content=$(cat "$file")
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p "$NEW_PROJECT_PATH"
|
||||
cd "$NEW_PROJECT_PATH"
|
||||
local title=$(echo "$frontmatter" | grep -i "^title:" | cut -d':' -f2- | tr -d ' "' | head -1)
|
||||
local date=$(echo "$frontmatter" | grep -i "^date:" | cut -d':' -f2- | tr -d ' "' | head -1)
|
||||
local description=$(echo "$frontmatter" | grep -i "^description:" | cut -d':' -f2- | tr -d ' "' | head -1)
|
||||
local author=$(echo "$frontmatter" | grep -i "^author:" | cut -d':' -f2- | tr -d ' "' | head -1)
|
||||
local image=$(echo "$frontmatter" | grep -i "^image:" | cut -d':' -f2- | tr -d ' "' | head -1)
|
||||
local tags=$(echo "$frontmatter" | grep -i "^tags:" | cut -d':' -f2- | tr -d '[]"' | head -1)
|
||||
|
||||
# Create Astro project
|
||||
npm create astro@latest . -- --template minimal --no-install --no-git --typescript strict << EOF
|
||||
y
|
||||
EOF
|
||||
title=${title:-$filename}
|
||||
date=${date:-$(date +%Y-%m-%d)}
|
||||
|
||||
log_success "สร้าง Astro project เสร็จสมบูรณ์: $NEW_PROJECT_PATH"
|
||||
cat > "$output_dir/${slug}.json" << JSONEOF
|
||||
{
|
||||
"title": "$title",
|
||||
"slug": "$slug",
|
||||
"createdAt": "$date",
|
||||
"updatedAt": "$(date +%Y-%m-%d)",
|
||||
"meta": {
|
||||
"title": "$title",
|
||||
"description": "$description"
|
||||
},
|
||||
"author": "$author",
|
||||
"heroImage": "$image",
|
||||
"tags": ["$tags"],
|
||||
"content": {
|
||||
"root": {
|
||||
"type": "root",
|
||||
"format": "",
|
||||
"indent": 0,
|
||||
"version": 1,
|
||||
"children": [
|
||||
{
|
||||
"type": "paragraph",
|
||||
"version": 1,
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"version": 1,
|
||||
"text": "$content",
|
||||
"mode": "tokenized",
|
||||
"style": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
JSONEOF
|
||||
|
||||
echo " Converted: $filename → $slug.json"
|
||||
done
|
||||
|
||||
log_success "Conversion complete: $output_dir/"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Copy content
|
||||
#-------------------------------------------------------------------------------
|
||||
create_payload_import_script() {
|
||||
log_info "Creating Payload import script..."
|
||||
|
||||
copy_content() {
|
||||
log_info "คัดลอก content..."
|
||||
local output_dir="$TARGET_PATH/scripts"
|
||||
mkdir -p "$output_dir"
|
||||
|
||||
cd "$SOURCE_PATH"
|
||||
cat > "$output_dir/import-content.ts" << 'TSEOF'
|
||||
import { payload } from '../src/lib/payload'
|
||||
import { promises as fs } from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
# Copy markdown content
|
||||
if [ -d "src/content" ]; then
|
||||
mkdir -p "$NEW_PROJECT_PATH/src/content/migration"
|
||||
cp -r src/content/* "$NEW_PROJECT_PATH/src/content/migration/"
|
||||
log_success "คัดลอก content จาก src/content"
|
||||
elif [ -d "content" ]; then
|
||||
mkdir -p "$NEW_PROJECT_PATH/src/content/migration"
|
||||
cp -r content/* "$NEW_PROJECT_PATH/src/content/migration/"
|
||||
log_success "คัดลอก content จาก content"
|
||||
fi
|
||||
async function importContent() {
|
||||
const contentDir = path.join(process.cwd(), 'src/content-migration')
|
||||
|
||||
# Copy public assets
|
||||
if [ -d "public" ]; then
|
||||
cp -r public/* "$NEW_PROJECT_PATH/public/" 2>/dev/null || true
|
||||
log_success "คัดลอก public assets"
|
||||
fi
|
||||
try {
|
||||
const files = await fs.readdir(contentDir)
|
||||
const jsonFiles = files.filter(f => f.endsWith('.json'))
|
||||
|
||||
# Copy pages (needs manual conversion)
|
||||
if [ -d "src/pages" ] || [ -d "pages" ]; then
|
||||
mkdir -p "$NEW_PROJECT_PATH/src/pages/legacy"
|
||||
log_info "Pages ต้องการ manual conversion - เก็บไว้ที่ legacy/"
|
||||
fi
|
||||
for (const file of jsonFiles) {
|
||||
const filePath = path.join(contentDir, file)
|
||||
const content = JSON.parse(await fs.readFile(filePath, 'utf-8'))
|
||||
|
||||
await payload.create({
|
||||
collection: 'posts',
|
||||
data: {
|
||||
title: content.title,
|
||||
slug: content.slug,
|
||||
createdAt: content.createdAt,
|
||||
updatedAt: content.updatedAt,
|
||||
meta: content.meta,
|
||||
author: content.author,
|
||||
heroImage: content.heroImage,
|
||||
tags: content.tags,
|
||||
content: content.content,
|
||||
_status: 'published',
|
||||
},
|
||||
})
|
||||
|
||||
console.log(`Imported: ${content.title}`)
|
||||
}
|
||||
|
||||
console.log(`\nSuccessfully imported ${jsonFiles.length} posts`)
|
||||
} catch (error) {
|
||||
console.error('Import failed:', error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Create content migration report
|
||||
#-------------------------------------------------------------------------------
|
||||
importContent()
|
||||
TSEOF
|
||||
|
||||
log_success "Created: $output_dir/import-content.ts"
|
||||
}
|
||||
|
||||
create_migration_report() {
|
||||
log_info "สร้าง migration report..."
|
||||
log_info "Creating migration report..."
|
||||
|
||||
cd "$SOURCE_PATH"
|
||||
|
||||
local page_count=$(find . -type f \( -name "*.astro" -o -name "*.tsx" -o -name "*.jsx" -o -name "*.html" -o -name "*.md" -o -name "*.mdx" \) 2>/dev/null | grep -v node_modules | wc -l)
|
||||
local page_count=$(find "$CONTENT_DIR" -type f \( -name "*.md" -o -name "*.mdx" \) 2>/dev/null | wc -l)
|
||||
|
||||
cat > "$NEW_PROJECT_PATH/MIGRATION_REPORT.md" << EOF
|
||||
# Migration Report
|
||||
cat > "$TARGET_PATH/MIGRATION_REPORT.md" << EOF
|
||||
# Migration Report: Astro → Payload CMS
|
||||
|
||||
## Source Information
|
||||
- **Type:** $SOURCE_TYPE
|
||||
## Source
|
||||
- **Type:** Astro
|
||||
- **Path:** $SOURCE_PATH
|
||||
- **Backup:** $BACKUP_DIR
|
||||
- **Date:** $(date)
|
||||
|
||||
## Content Statistics
|
||||
- **Total Pages:** $page_count
|
||||
## Statistics
|
||||
- **Total Posts:** $page_count
|
||||
|
||||
## Files to Migrate
|
||||
## Content Migration
|
||||
|
||||
### Pages (Manual Conversion Required)
|
||||
Content has been converted to Payload CMS Lexical JSON format in:
|
||||
\`\`\`
|
||||
src/content-migration/
|
||||
\`\`\`
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Review converted content:**
|
||||
\`\`\`bash
|
||||
ls src/content-migration/
|
||||
\`\`\`
|
||||
|
||||
2. **Configure Payload collection:**
|
||||
Make sure you have a 'posts' collection in \`src/collections/Posts.ts\`
|
||||
|
||||
3. **Import content to Payload:**
|
||||
\`\`\`bash
|
||||
npx tsx scripts/import-content.ts
|
||||
\`\`\`
|
||||
|
||||
4. **Verify in admin:**
|
||||
- Go to http://localhost:3002/admin
|
||||
- Navigate to Posts collection
|
||||
- Verify content and rich text editor (Lexical)
|
||||
|
||||
## Notes
|
||||
|
||||
- MDX/Markdown content is converted to Lexical JSON format
|
||||
- Frontmatter fields (title, date, description) are mapped to collection fields
|
||||
- Complex MDX components need manual conversion in Payload admin
|
||||
- Images need to be re-uploaded to Payload Media
|
||||
EOF
|
||||
|
||||
# List pages that need conversion
|
||||
if [ -d "src/pages" ]; then
|
||||
find src/pages -type f \( -name "*.astro" -o -name "*.tsx" -o -name "*.jsx" \) 2>/dev/null >> "$NEW_PROJECT_PATH/MIGRATION_REPORT.md"
|
||||
elif [ -d "pages" ]; then
|
||||
find pages -type f \( -name "*.html" -o -name "*.jsx" -o -name "*.tsx" \) 2>/dev/null >> "$NEW_PROJECT_PATH/MIGRATION_REPORT.md"
|
||||
fi
|
||||
|
||||
cat >> "$NEW_PROJECT_PATH/MIGRATION_REPORT.md" << EOF
|
||||
|
||||
### Content (Auto-migrated)
|
||||
EOF
|
||||
|
||||
if [ -d "$NEW_PROJECT_PATH/src/content/migration" ]; then
|
||||
find "$NEW_PROJECT_PATH/src/content/migration" -type f -name "*.md" -o -name "*.mdx" 2>/dev/null >> "$NEW_PROJECT_PATH/MIGRATION_REPORT.md"
|
||||
fi
|
||||
|
||||
log_success "สร้าง migration report: $NEW_PROJECT_PATH/MIGRATION_REPORT.md"
|
||||
log_success "Migration report: $TARGET_PATH/MIGRATION_REPORT.md"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Main
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
main() {
|
||||
echo "=============================================="
|
||||
echo " Website Migration Tool"
|
||||
echo " แปลงเว็บเก่าเป็น Astro + Payload CMS"
|
||||
echo " Astro → Payload CMS Migration Tool"
|
||||
echo " Convert MDX/MD to Payload CMS with Lexical"
|
||||
echo "=============================================="
|
||||
echo ""
|
||||
|
||||
@@ -276,29 +299,39 @@ main() {
|
||||
if [ -z "$SOURCE_PATH" ]; then
|
||||
print_usage
|
||||
echo ""
|
||||
log_error "กรุณาระบุ source path"
|
||||
log_error "Please specify source path"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
detect_source_type
|
||||
backup_source
|
||||
analyze_structure
|
||||
create_new_project
|
||||
copy_content
|
||||
if [ ! -d "$SOURCE_PATH" ]; then
|
||||
log_error "Source path not found: $SOURCE_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$TARGET_PATH" ]; then
|
||||
log_error "Target path not found: $TARGET_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
detect_content_type
|
||||
backup_content
|
||||
analyze_content
|
||||
create_lexical_content
|
||||
create_payload_import_script
|
||||
create_migration_report
|
||||
|
||||
echo ""
|
||||
echo "=============================================="
|
||||
log_success "Migration เริ่มต้นเสร็จสมบูรณ์!"
|
||||
log_success "Migration preparation complete!"
|
||||
echo "=============================================="
|
||||
echo ""
|
||||
echo "ขั้นตอนถัดไป:"
|
||||
echo " 1. cd $NEW_PROJECT_PATH"
|
||||
echo " 2. npm install"
|
||||
echo " 3. ดู MIGRATION_REPORT.md"
|
||||
echo " 4. ปรับ content และ pages ตาม report"
|
||||
echo " 5. npm run dev"
|
||||
echo "Next steps:"
|
||||
echo " 1. cd $TARGET_PATH"
|
||||
echo " 2. Review converted content in src/content-migration/"
|
||||
echo " 3. Run: npm run dev"
|
||||
echo " 4. Import: npx tsx scripts/import-content.ts"
|
||||
echo " 5. Verify in Payload admin (http://localhost:3002/admin)"
|
||||
echo ""
|
||||
}
|
||||
|
||||
main "$@"
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user