Movable Type 至 Next.js 遷移指南(日本公司適用)
將Movable Type遷移至Next.js:日本公司完整指南
如果您長期從事日本企業網站工作,您幾乎肯定接觸過Movable Type。Six Apart的CMS自2000年代中期以來對日本市場的控制力異常強大,為從主要製造商的企業網站到政府入口網站和大學網站的一切提供支援。但這裡是關鍵 -- 現在是2026年,網路已經向前發展。您的Movable Type安裝可能沒有。
在過去兩年中,我幫助遷移了幾個日本企業網站以離開Movable Type,我會坦誠相告:這不是一個瑣碎的項目。字符編碼、日本企業網站特有的內容結構和組織問題方面存在怪癖,這使得這些遷移與典型的WordPress到Next.js遷移不同。本指南涵蓋我以艱難方式學到的一切。

目錄
- 為什麼日本公司正在離開Movable Type
- 理解Movable Type的架構
- 選擇您的無頭CMS後端
- 內容審計和資料提取
- 處理日文內容細節
- 構建Next.js前端
- 日本搜索的SEO遷移策略
- 部署和基礎設施
- 時程表和預算規劃
- 常見問題
為什麼日本公司正在離開Movable Type
讓我們先講明顯的事情:Movable Type並未消亡。Six Apart Japan仍在維護它,Movable Type 8(2024年末發佈)添加了一些現代功能。但由於幾個原因,牆上的字跡很清楚。
性能問題
Movable Type使用靜態發佈模型 -- 當內容更改時它會重建HTML文件。這聽起來很棒,直到您有一個包含15,000個頁面的網站,內容編輯器在等著重建完成需要20分鐘。我見過日本企業網站編輯會在晚上安排重建,因為這個過程太慢了。
具有ISR(增量靜態再生成)或按需重新驗證的Next.js完全解決了這個問題。頁面在毫秒內單獨重新生成。
所有權成本
截至2026年,日本Movable Type企業版許可費用大約為每年¥600,000-¥1,200,000。僅CMS許可就是每年$4,000-$8,000 USD,更不用說托管、插件或自定義開發。將其與流行的日本無頭CMS microCMS(業務計劃從¥4,900/月開始)配對,再加上Vercel上的Next.js,數字看起來完全不同。
開發者短缺
這是沒有人公開談論的重要問題。找到知道Perl(Movable Type的語言)並願意從事MT模板工作的開發者變得非常困難。我遇過有MT經驗的開發者的平均年齡超過45歲。與此同時,Next.js開發者無處不在 -- 這是2026年日本科技公司招聘的框架。
安全和合規性
Movable Type多年來遭遇過幾個嚴重的CVE,包括臭名昭著的XMLRPC漏洞(CVE-2021-20837),曾被積極地針對日本網站進行利用。隨著日本修訂的APPI(個人信息保護法案)要求在2025-2026年期間趨緊,公司正在重新評估其安全態勢。
理解Movable Type的架構
在您遷移之前,您需要理解您正在遷移什麼。Movable Type的資料模型與WordPress或大多數現代CMS不同。
核心資料結構
| MT概念 | 描述 | Next.js/無頭等效項 |
|---|---|---|
| Blog | 頂級內容容器 | 網站或工作區 |
| Entry | 博客文章或文章 | 內容項目(博客類型) |
| Page | 靜態頁面 | 內容項目(頁面類型) |
| Category | 層級分類法 | 類別/標籤系統 |
| Template | 帶有MT標籤的HTML模板 | React組件+佈局 |
| Custom Field | 擴展的條目字段 | 內容模型字段 |
| Asset | 上傳的媒體文件 | 媒體/資產庫 |
| Website | 博客的父容器 | 多網站配置 |
Movable Type的模板語言使用<mt:EntryTitle>和<mt:Entries>之類的標籤。這些與現代堆棧中的任何內容都不是1:1映射 -- 您將從頭開始重建表示層。
資料庫層
MT支持MySQL、PostgreSQL和SQLite。大多數日本企業安裝使用MySQL。資料庫架構文檔完整,但...古怪。自定義字段使用鍵值模式存儲在單獨的mt_entry_meta表中,這使得提取非平凡。
以下是條目表的樣子:
SELECT
entry_id,
entry_title,
entry_text,
entry_text_more,
entry_excerpt,
entry_created_on,
entry_modified_on,
entry_basename,
entry_status
FROM mt_entry
WHERE entry_blog_id = 1
AND entry_status = 2 -- 2 = published
ORDER BY entry_created_on DESC;
注意entry_text和entry_text_more的分割。MT將正文內容分為兩個字段 -- 這是早期博客時代的模式,您需要在遷移期間連接。

選擇您的無頭CMS後端
Next.js是您的前端框架。但您需要在某處管理內容。對於日本公司,我將其縮小到四個現實選項。
microCMS
這是日本公司的預設選擇,理由充分。它由日本公司構建,具有原生日文UI、日語客戶支持和日本資料駐留。定價從¥4,900/月開始(業餘愛好版本對於小項目是免費的)。API很乾淨,webhook支持與Next.js ISR配合良好,您的內容編輯者無需英文技能。
Newt
另一個日本製造的無頭CMS,正在獲得關注。它比microCMS對開發者更友好,並且具有更好的內容建模靈活性。如果您的網站具有複雜的內容結構,這是一個不錯的選擇。
Contentful
全球企業選擇。強大的本地化支持、出色的API和成熟的生態系統。對於日本公司的缺點:支持是英文的,UI是英文的,定價是美元。在2026年定價中,團隊計劃為$300/月,價格比日本替代方案高得多。
Sanity
我提及Sanity是因為它在技術上是出色的,其可自定義的Studio可以配置日文標籤。但學習曲線更陡峭,您找不到許多有Sanity經驗的日本開發者。
| CMS | 日文UI | 日本資料駐留 | 起始價格 | 最適合 |
|---|---|---|---|---|
| microCMS | ✅ | ✅ | ¥4,900/月 | 大多數日本企業網站 |
| Newt | ✅ | ✅ | ¥3,300/月 | 複雜內容模型 |
| Contentful | ❌ | ❌ (EU/US) | ~$300/月 | 全球企業 |
| Sanity | 部分 | ❌ | $99/月 (Team) | 開發者重的團隊 |
對於大多數從Movable Type遷移的日本公司,我推薦microCMS或Newt。擁有全日文環境的摩擦減少值得超過您預期的。我們通過我們的無頭CMS開發實踐廣泛與所有這些合作過。
內容審計和資料提取
這是真正工作開始的地方。不要跳過審計階段 -- 我見過遷移失敗,因為團隊在沒有理解他們實際擁有什麼的情況下直接跳到提取。
步驟1:清點一切
連接到您的MT資料庫並運行計數:
-- Count entries by blog
SELECT
b.blog_name,
COUNT(e.entry_id) as entry_count
FROM mt_entry e
JOIN mt_blog b ON e.entry_blog_id = b.blog_id
WHERE e.entry_status = 2
GROUP BY b.blog_name;
-- Count custom fields per blog
SELECT
b.blog_name,
em.entry_meta_type,
COUNT(*) as field_count
FROM mt_entry_meta em
JOIN mt_entry e ON em.entry_meta_entry_id = e.entry_id
JOIN mt_blog b ON e.entry_blog_id = b.blog_id
GROUP BY b.blog_name, em.entry_meta_type;
步驟2:匯出內容
MT具有內置匯出格式,但它是受限的。我更喜歡使用Python指令碼進行直接資料庫提取:
import mysql.connector
import json
import html
def extract_mt_entries(config):
conn = mysql.connector.connect(**config)
cursor = conn.cursor(dictionary=True)
cursor.execute("""
SELECT
e.entry_id,
e.entry_title,
e.entry_text,
e.entry_text_more,
e.entry_excerpt,
e.entry_basename,
e.entry_created_on,
e.entry_modified_on,
GROUP_CONCAT(c.category_label) as categories
FROM mt_entry e
LEFT JOIN mt_placement p ON e.entry_id = p.placement_entry_id
LEFT JOIN mt_category c ON p.placement_category_id = c.category_id
WHERE e.entry_status = 2
GROUP BY e.entry_id
""")
entries = cursor.fetchall()
for entry in entries:
# Combine text and text_more
body = (entry['entry_text'] or '') + (entry['entry_text_more'] or '')
entry['full_body'] = body
# Handle encoding
entry['entry_title'] = entry['entry_title']
with open('mt_export.json', 'w', encoding='utf-8') as f:
json.dump(entries, f, ensure_ascii=False, default=str, indent=2)
return entries
步驟3:媒體資產遷移
MT在文件系統上存儲資產,通常在/path/to/mt/support/uploads/下。您需要:
- 清點所有文件並將其與
mt_asset資料庫記錄匹配 - 重新上傳到您的新CMS或CDN(Cloudinary、imgix或您的CMS的內置存儲)
- 更新內容正文HTML中的所有參考
這很繁瑣。為此分配時間。
處理日文內容細節
本節是我寫這篇文章的原因。通用遷移指南不涵蓋這些問題。
字符編碼
較舊的Movable Type安裝(MT5之前)有時存儲EUC-JP或Shift_JIS編碼的內容,即使資料庫名義上是UTF-8。檢查您的實際資料:
# Detect encoding issues
import chardet
def check_encoding(text_bytes):
result = chardet.detect(text_bytes)
if result['encoding'] != 'utf-8':
print(f"Warning: detected {result['encoding']} "
f"with {result['confidence']:.0%} confidence")
return result
如果您發現編碼不匹配,在導入到新CMS之前將所有內容轉換為UTF-8。企業網站上的損壞文字化け(文字化け)是職業限制事件。
紅色文本(假名音註)
日本企業網站經常使用紅色註釋 -- 在漢字字符上方的小讀音輔助。MT模板經常使用自定義標籤來處理這些。在Next.js中,您將使用標準HTML <ruby> 元素:
// components/RubyText.tsx
export function RubyText({ base, reading }: { base: string; reading: string }) {
return (
<ruby>
{base}
<rp>(</rp>
<rt>{reading}</rt>
<rp>)</rp>
</ruby>
);
}
確保您的內容遷移指令碼保留任何現有的紅色標記。
日文日期格式
日本企業網站經常以和暦(日本時代格式)顯示日期:令和8年1月15日 而不是 2026-01-15。在您的Next.js組件中處理此問題:
function formatJapaneseDate(dateString: string): string {
const date = new Date(dateString);
return date.toLocaleDateString('ja-JP-u-ca-japanese', {
era: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
});
}
縱向文本佈局
某些日本網站,特別是在出版或傳統行業中,使用縱向文本(縱書き)。CSS處理此問題:
.vertical-text {
writing-mode: vertical-rl;
text-orientation: mixed;
}
Next.js可以很好地處理此問題,但在瀏覽器中進行徹底測試。
構建Next.js前端
通過提取內容和選擇CMS,是時候構建了。以下是我為日本企業網站推薦的架構。
應用程式路由器與靜態生成
使用Next.js 15的App Router進行大多數頁面的靜態生成。日本企業網站通常是內容繁重的,更新不頻繁 -- 非常適合靜態生成,具有按需重新驗證。
// app/news/[slug]/page.tsx
import { getArticle, getAllArticleSlugs } from '@/lib/cms';
export async function generateStaticParams() {
const slugs = await getAllArticleSlugs();
return slugs.map((slug) => ({ slug }));
}
export default async function NewsArticle({
params
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params;
const article = await getArticle(slug);
return (
<article>
<h1>{article.title}</h1>
<time dateTime={article.publishedAt}>
{formatJapaneseDate(article.publishedAt)}
</time>
<div dangerouslySetInnerHTML={{ __html: article.body }} />
</article>
);
}
i18n配置
許多日本企業網站需要日文和英文版本。Next.js App Router通過路由組或基於中間件的語言環境檢測來處理此問題:
// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
export function middleware(request: NextRequest) {
const pathname = request.nextUrl.pathname;
const locale = pathname.startsWith('/en') ? 'en' : 'ja';
request.headers.set('x-locale', locale);
return NextResponse.next();
}
我們使用Next.js構建了數十個雙語日本企業網站 -- 我們的Next.js開發團隊可以帶您了解細微差別。
日本搜索的SEO遷移策略
這是非協商的。日本公司靠他們的Google搜索排名生活和死亡(雅虎日本自2010年以來一直使用Google的搜索引擎,所以實際上只是Google)。拙劣的遷移可能會在數月內導致有機流量下降。
URL映射
Movable Type使用可配置的模式生成URL。我在日本網站上看到的常見模式:
/blog/2024/01/entry-basename.html/news/category/entry_basename.html/archives/000123.html(最舊的模式)
在構建任何內容之前創建完整的URL映射:
// scripts/generate-redirects.ts
interface RedirectMap {
source: string;
destination: string;
permanent: boolean;
}
function generateRedirects(mtEntries: MTEntry[]): RedirectMap[] {
return mtEntries.map(entry => ({
source: buildMTUrl(entry), // Old MT URL pattern
destination: `/news/${entry.entry_basename}`, // New Next.js URL
permanent: true, // 301 redirect
}));
}
將這些放在您的next.config.ts中:
const nextConfig = {
async redirects() {
const redirects = await import('./redirects.json');
return redirects.default;
},
};
對於具有數千個重定向的網站,改為使用中間件 -- next.config.ts重定向有實際限制。
結構化資料
日本Google結果大量展示豐富片段。為文章、常見問題和組織信息添加JSON-LD:
function ArticleJsonLd({ article }: { article: Article }) {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: article.title,
datePublished: article.publishedAt,
dateModified: article.updatedAt,
author: {
'@type': 'Organization',
name: article.companyName,
},
inLanguage: 'ja',
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
);
}
部署和基礎設施
對於日本受眾,延遲很重要。以下是有效的方法:
| 平台 | 日本邊緣節點 | 最適合 | 典型月成本 |
|---|---|---|---|
| Vercel | Tokyo | 大多數Next.js網站 | $20-150/月 |
| AWS (CloudFront + Lambda@Edge) | Tokyo, Osaka | 企業合規性 | $100-500/月 |
| Google Cloud Run + Cloud CDN | Tokyo | 原生GCP團隊 | $50-200/月 |
| Cloudflare Pages | Tokyo + many | 簡單靜態網站 | 免費-$25/月 |
Vercel是我的預設建議。它是為Next.js設計的,具有東京邊緣節點,DX無可比擬。對於具有嚴格資料駐留要求的公司(政府、財務),AWS在ap-northeast-1(東京)是安全的選擇。
如果您考慮為一個內容繁重、互動性最小的網站選擇Astro而不是Next.js,那是一個有效的選擇 -- 檢查我們的Astro開發能力。
時程表和預算規劃
基於我完成的實際遷移,以下是您可以期待的:
| 階段 | 持續時間 | 關鍵活動 |
|---|---|---|
| 發現與審計 | 2-3週 | 內容清單、利益相關者訪談、URL映射 |
| CMS設置與內容建模 | 2-4週 | 架構設計、內容遷移指令碼 |
| 內容遷移 | 3-6週 | 資料傳輸、媒體遷移、QA |
| 前端開發 | 6-10週 | Next.js構建、組件庫、i18n |
| SEO與QA | 2-3週 | 重定向測試、性能調整、跨瀏覽器QA |
| 分階段推出 | 1-2週 | DNS轉換、監控、快速修復 |
總計:16-28週 對於具有1,000-10,000個頁面的典型日本企業網站。
預算方面,根據複雜性,您看在¥5,000,000-¥15,000,000($33,000-$100,000 USD)。這看起來可能很多,但請考慮:您可能已經為MT許可證和專業開發支付超過¥1,000,000/年。遷移通過降低運營成本和改進開發者速度在2-3年內自我支付。
需要針對您特定情況的詳細估計嗎?與我們聯繫或查看我們的定價頁面了解參與模型。
常見問題
我們可以將Movable Type作為無頭CMS與Next.js一起使用嗎? 在技術上是的 -- Movable Type 7+具有可以向前端提供內容的資料API。但它很慢、文檔不完善,缺乏用於重新驗證的webhook。我在一個項目上嘗試了這種方法,不會推薦它。您將花費更多時間解決MT的API限制問題,而不是遷移到適當的無頭CMS。
我們如何處理MT重建模型與Next.js ISR? 它們從根本上是不同的。MT一次重建整個網站部分(批量靜態生成)。Next.js ISR按需重新生成單個頁面。這意味著您的編輯者獲得即時發佈時間,而不是等待重建。心智模型轉變對編輯者來說實際上更容易 -- 他們只是點擊發佈,頁面在數秒內是實時的。
我們在遷移期間會發生什麼關於MT插件? 每個MT插件都需要替換或重新實施。常見的插件,如聯繫表格(基於MT的表格插件)會被替換為Next.js表格處理或Formspree之類的服務。搜索插件會被Algolia或CMS的內置搜索替換。在審計階段製作完整的插件清單。
我們的Google排名會在遷移期間下降嗎? 它們可能會,但不一定。關鍵因素是:針對每個URL的301重定向、保持相同或改進的頁面標題和元描述、保留內部鏈接結構以及提交更新的網站地圖。我見過排名實際上改進的遷移,因為新網站更快,具有更好的Core Web Vitals分數。
我們如何處理日本特定的SEO元素,如雅虎日本? 雅虎日本自2010年以來一直使用Google的搜索引擎,所以您的Google SEO策略涵蓋雅虎。唯一的例外是雅虎日本自己的屬性(雅虎新聞等),它們有單獨的提交流程。對於一般有機搜索,專注於Google,您會被涵蓋。
我們應該遷移所有內容還是以此為機會進行清理? 總是清理。在我做過的每個日本企業網站遷移中,30-50%的內容都是過期的、冗餘的或零流量的。遷移死內容浪費時間並稀釋您網站的主題權威。使用分析資料確定值得遷移的頁面,讓其餘的消失(帶有適當的410 Gone響應,而不是404)。
我們能否在遷移期間同時運行Movable Type和Next.js? 是的,我建議這樣做。使用子域或基於路徑的路由為已遷移的部分提供新的Next.js網站,同時MT處理其餘部分。這讓您可以分階段遷移,而不是進行風險的大爆炸轉換。nginx或Cloudflare Workers的反向代理配置使這變得簡單。
Movable Type的內置訪問控制和成員功能呢? 如果您的MT網站使用成員登錄、門控內容或基於角色的訪問,您需要在Next.js中實施身份驗證。NextAuth.js(現為Auth.js)在這方面運作良好,或者您可以使用Clerk或Auth0之類的服務。這增加了複雜性和成本 -- 從第一天起就在您的規劃中計算它。