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 分钟才能完成重建。我见过日本企业网站,编辑们会安排在夜间进行重建,因为这个过程非常缓慢。
Next.js 配合 ISR(增量静态再生成)或按需重新验证可以完全解决这个问题。页面在毫秒级别内单独再生成。
所有权成本
截至 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/无头 CMS 等效物 |
|---|---|---|
| Blog | 顶级内容容器 | 网站或工作区 |
| Entry | 博客文章或文章 | 内容项(博客类型) |
| Page | 静态页面 | 内容项(页面类型) |
| Category | 分层分类法 | 分类/标签系统 |
| Template | 带有 MT 标签的 HTML 模板 | React 组件 + 布局 |
| Custom Field | 扩展条目字段 | 内容模型字段 |
| Asset | 上传的媒体文件 | 媒体/资源库 |
| Website | 博客的父容器 | 多站点配置 |
Movable Type 的模板语言使用诸如 <mt:EntryTitle> 和 <mt:Entries> 之类的标签。这些与现代堆栈中的任何内容都不一一对应——您将从头开始重建演示层。
数据库层
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/月(Hobby 对小项目免费)开始。API 简洁,webhook 支持适用于 Next.js ISR,您的内容编辑不需要英语技能。
Newt
另一个日本开发的无头 CMS,已获得越来越多的关注。它比 microCMS 稍微对开发人员更友好,并且具有更好的内容建模灵活性。如果您的网站具有复杂的内容结构,这是一个不错的选择。
Contentful
全球企业的选择。强大的本地化支持、出色的 API 和成熟的生态系统。对日本企业的缺点:支持仅提供英文、UI 为英文、定价以美元计价。按照 2026 年的定价,Team 计划每月 $300,比日本替代品昂贵得多。
Sanity
我提及 Sanity 是因为它在技术上很出色,其可定制的 Studio 可以配置日语标签。但学习曲线更陡峭,您找不到那么多拥有 Sanity 经验的日本开发人员。
| CMS | 日语 UI | 日本数据驻留 | 起价 | 最适合 |
|---|---|---|---|---|
| microCMS | ✅ | ✅ | ¥4,900/月 | 大多数日本企业网站 |
| Newt | ✅ | ✅ | ¥3,300/月 | 复杂的内容模型 |
| Contentful | ❌ | ❌ (欧盟/美国) | ~$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>
);
}
确保您的内容迁移脚本保留任何现有的 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 已选择,现在是构建的时候。以下是我为日本企业网站推荐的架构。
App Router 配合静态生成
对大多数页面使用 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 迁移策略
这是不可协商的。日本企业的生死取决于他们的谷歌搜索排名(Yahoo! Japan 自 2010 年以来一直使用谷歌的搜索引擎,所以实际上只是谷歌)。迁移失败可能会在几个月内摧毁您的有机流量。
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 重定向有实际的限制。
结构化数据
日本谷歌结果广泛展示丰富片段。为文章、常见问题和组织信息添加 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 + 许多 | 简单静态网站 | 免费-$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 的内置搜索。在审计阶段制作完整的插件清单。
我们的谷歌排名在迁移期间会下降吗? 可能会,但不一定非要这样。关键因素是:为每个 URL 执行 301 重定向、维护相同或改进的页面标题和元描述、保留内部链接结构以及提交更新的站点地图。我见过一些迁移,其中排名实际上改善了,因为新网站更快,并且具有更好的 Core Web Vitals 分数。
我们如何处理日本特有的 SEO 元素,如 Yahoo! Japan? Yahoo! Japan 自 2010 年以来一直使用谷歌的搜索引擎,所以您的谷歌 SEO 策略也涵盖了 Yahoo!。唯一的例外是 Yahoo! Japan 自己的属性(Yahoo! News 等),它们拥有单独的提交流程。对于一般的有机搜索,关注谷歌,您就涵盖了。
我们应该迁移所有内容还是将其用作清理的机会? 始终进行清理。在我完成的每一个日本企业网站迁移中,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 之类的服务。这增加了复杂性和成本——从第一天起就将其纳入您的规划中。