(Part1)一行代码不写完全用 AI IDE 实现 VSCode 插件系列:VSCode 内无缝预览 Mintlify 项目站点
·
开头介绍
Mintlify 作为下一代技术文档平台,以其现代化的 MDX 支持和简洁易用的界面,深受技术写作者的喜爱。
我在写作的过程中面临的一个关键痛点:需要频繁在编辑器和浏览器之间切换来预览文档效果。这些琐碎的操作严重影响了写作流畅度。
为了解决这个问题,我在 FlashMintlify 插件中实现了一个强大的功能:VSCode 内预览 Mintlify 项目站点。这个功能让技术写作真正回归本质——专注于思考如何进行内容架构,而不是被技术细节打断写作思路。
演示和下载
- 功能演示:
- 插件功能完全演示
一行代码不写完全用 AI 实现 VSCode 插件:FlashMintlify
- VSCode 插件市场下载:FlashMintlify
- GitHub 仓库:https://github.com/Match-Yang/FlashMintlify
功能点详解
用户痛点分析
在使用 Mintlify 进行技术写作时,开发者通常需要:
- 在终端运行
mint dev
启动本地开发服务器 - 在浏览器中打开
localhost:3000
查看效果 - 每次修改文档后切换到浏览器查看变化
这种工作流程不仅效率低下,还容易打断写作思路。
功能设计思路
FlashMintlify 的预览功能设计围绕以下核心原则:
- 一键预览:通过编辑器标题栏的预览按钮,一键打开当前文档的预览
- 多种预览模式:支持编辑器内预览、全屏预览和浏览器预览三种模式
- 智能路径解析:自动将 MDX 文件路径转换为 Mintlify 的路由路径
- 实时同步:文档内容变化时自动刷新预览
- 可视化配置:提供友好的配置界面管理预览选项
架构图解
整体架构流程
时序交互图
类设计架构
代码实现
核心预览命令实现
const openPreviewCommand = vscode.commands.registerCommand('flashMintlify.preview.open', async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showErrorMessage('No active editor found');
return;
}
const doc = editor.document;
const filePath = doc.uri.fsPath;
// 构建内部路径
const root = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
if (!root) {
vscode.window.showErrorMessage('No workspace folder found');
return;
}
// 将文件路径转换为 Mintlify 路由路径
const rel = path.relative(root, filePath)
.replace(/\\/g, '/')
.replace(/\.(md|mdx)$/i, '');
// 特殊处理:根目录的 index.mdx 应该渲染为 /,而不是 /index
const internalPath = rel === 'index' ? '/' : '/' + rel;
// 读取预览配置
const cfg = vscode.workspace.getConfiguration('flashMintlify');
const configuredPort = cfg.get<number>('preview.port', 3000);
const mode = cfg.get<'beside' | 'fullscreen' | 'browser'>('preview.mode', 'browser');
const targetUrl = `http://localhost:${configuredPort}${internalPath}`;
// 根据模式选择预览方式
if (mode === 'beside') {
PreviewPanel.createOrShow(context.extensionUri, targetUrl, vscode.ViewColumn.Beside);
} else if (mode === 'fullscreen') {
PreviewPanel.createOrShow(context.extensionUri, targetUrl, vscode.ViewColumn.Active);
} else {
vscode.env.openExternal(vscode.Uri.parse(targetUrl));
}
});
PreviewPanel 核心实现
export class PreviewPanel {
public static currentPanel: PreviewPanel | undefined;
private readonly _panel: vscode.WebviewPanel;
private readonly _extensionUri: vscode.Uri;
public static createOrShow(
extensionUri: vscode.Uri,
url: string,
viewColumn: vscode.ViewColumn = vscode.ViewColumn.Two
) {
if (PreviewPanel.currentPanel) {
// 如果已经有预览面板,只更新内容,避免位置变化
PreviewPanel.currentPanel.update(url);
return;
}
const panel = new PreviewPanel(extensionUri, url, viewColumn);
PreviewPanel.currentPanel = panel;
}
private constructor(extensionUri: vscode.Uri, url: string, viewColumn: vscode.ViewColumn) {
this._extensionUri = extensionUri;
// 根据 viewColumn 决定标题和图标
const isFullscreen = viewColumn === vscode.ViewColumn.Active;
const title = isFullscreen ? 'Mintlify Preview (Fullscreen)' : 'Mintlify Preview';
this._panel = vscode.window.createWebviewPanel(
'flashMintlifyPreview',
title,
{ viewColumn, preserveFocus: !isFullscreen },
{
enableScripts: true,
retainContextWhenHidden: true,
localResourceRoots: [
vscode.Uri.joinPath(extensionUri, 'media'),
vscode.Uri.joinPath(extensionUri, 'out', 'webview')
]
}
);
this._panel.onDidDispose(() => this.dispose());
this.update(url);
}
public update(url: string) {
const nonce = String(Date.now());
const csp = `default-src 'none'; img-src vscode-resource: https: data:; script-src 'nonce-${nonce}'; style-src 'unsafe-inline'; frame-src ${url};`;
// 使用 iframe 嵌入 Mintlify 预览页面
this._panel.webview.html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="${csp}">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mintlify Preview</title>
<style>
html, body, iframe { height: 100%; width: 100%; padding: 0; margin: 0; }
body { background: var(--vscode-editor-background); }
iframe { border: 0; }
</style>
</head>
<body>
<iframe src="${url}" allow="clipboard-read; clipboard-write"></iframe>
</body>
</html>`;
}
}
预览设置面板实现
export class PreviewSettingsPanel extends SettingsPanel {
protected async handleSave(data: SettingsData): Promise<void> {
const cfg = vscode.workspace.getConfiguration('flashMintlify');
const portValue = Number(data['preview.port']?.value ?? 3000);
const modeValue = (data['preview.mode']?.value ?? 'browser') as 'beside' | 'fullscreen' | 'browser';
// 验证端口值
if (isNaN(portValue) || portValue <= 0 || portValue > 65535) {
vscode.window.showErrorMessage(`Invalid port number: ${portValue}`);
return;
}
try {
// 保存配置到工作区
await cfg.update('preview.port', portValue, vscode.ConfigurationTarget.Workspace);
await cfg.update('preview.mode', modeValue, vscode.ConfigurationTarget.Workspace);
const action = await vscode.window.showInformationMessage(
'Preview options saved successfully!',
'OK',
'Reload Window'
);
if (action === 'Reload Window') {
vscode.commands.executeCommand('workbench.action.reloadWindow');
}
} catch (error) {
vscode.window.showErrorMessage('Failed to save preview options: ' + error);
}
}
protected getFields(): SettingsField[] {
const cfg = vscode.workspace.getConfiguration('flashMintlify');
const port = cfg.get<number>('preview.port', 3000);
const mode = cfg.get<string>('preview.mode', 'browser');
return [
{
name: 'preview.port',
type: 'number',
label: 'Preview port',
description: "Port where 'mint dev' is running",
defaultValue: String(port),
currentValue: String(port),
placeholder: '3000'
},
{
name: 'preview.mode',
type: 'select',
label: 'Preview mode',
description: 'Choose how to open the preview',
options: ['beside', 'fullscreen', 'browser'],
defaultValue: mode,
currentValue: mode
}
];
}
}
实现要点和注意事项
- 路径转换逻辑:需要正确处理 Windows 和 Unix 路径分隔符,并将
.md
和.mdx
扩展名移除 - 特殊路径处理:根目录的
index.mdx
文件应该映射到/
路径,而不是/index
- 面板管理:使用单例模式确保同一时间只有一个预览面板,避免资源浪费
- 安全策略:正确配置 Content Security Policy,允许 iframe 加载本地开发服务器内容
- 错误处理:对无效端口号、文件路径等进行适当的验证和错误提示
简单总结
VSCode 内预览功能极大地提升了使用 Mintlify 进行技术写作的效率和体验:
- 无缝集成:在编辑器内直接预览,无需切换窗口
- 多种模式:支持分屏、全屏和浏览器三种预览方式,满足不同场景需求
- 智能路径:自动处理文件路径到 URL 路径的转换
- 配置友好:可视化的设置界面,轻松配置端口和预览模式
- 实时同步:文档变化时自动更新预览内容
这个功能让技术写作者能够真正专注于内容创作,而不是被技术细节分散注意力。它体现了 FlashMintlify 的核心理念:让写作回归本质,把重心放在内容架构和核心价值传达上。
后续改进方向
- 智能端口检测:自动检测
mint dev
运行的端口 - 预览状态同步:支持预览窗口和编辑器光标位置同步
- 快捷键支持:添加快捷键快速切换预览模式
- 错误页面优化:当服务器未启动时显示友好的提示页面
体验 FlashMintlify,让技术写作变得更加高效和愉悦!
更多推荐
所有评论(0)