Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@
"typescript": "^5.5.0",
"vite": "^5.4.0",
"vitest": "^2.0.0"
}
},
"packageManager": "pnpm@11.8.0+sha512.c1f5e7c4cb241c8f174b743851d82f42b802324afc8b0f116b96adb15aa06664948dde36960a3ba1079ba5b4b29dd0140135b94b5b5f5263592249d68e555f26"
}
118 changes: 97 additions & 21 deletions scripts/build.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,29 @@
chcp 65001 >nul
setlocal enabledelayedexpansion

:: 先切到仓库根目录,避免相对路径问题
:: 先切到仓库根目录
cd /d "%~dp0.."

echo ========================================
echo MD++ 打包构建脚本
echo ========================================
echo.

:: 读取 package.json 中的版本号
for /f "tokens=2 delims=:," %%a in ('findstr "\"version\"" package.json') do (
set PKG_VER=%%~a
set PKG_VER=!PKG_VER:"=!
set PKG_VER=!PKG_VER: =!
)
:: 读取当前 package.json 版本号
for /f %%v in ('node -p "require('./package.json').version"') do set PKG_VER=%%v

echo 当前 package.json 版本: !PKG_VER!
echo Tauri/Cargo 版本会在构建前自动跟随 package.json
echo 当前版本: !PKG_VER!
echo.

:: 询问版本号
set /p INPUT_VER="请输入要发布的版本号 (直接回车使用 !PKG_VER!): "
if "!INPUT_VER!"=="" set INPUT_VER=!PKG_VER!

echo.
echo ========================================
echo 即将构建 MD++ v!INPUT_VER!
echo 目标: msi + nsis 安装包
echo ========================================
echo.

set /p CONFIRM="确认构建? (y/N): "
Expand All @@ -37,34 +34,113 @@ if /i not "!CONFIRM!"=="y" (
)

echo.
echo [1/3] 同步版本号到 package.json 和 Cargo.toml...
echo [1/4] 同步版本号...

:: 更新 package.json 版本号
powershell -NoProfile -Command ^
"$json = Get-Content 'package.json' -Raw | ConvertFrom-Json; $json.version = '!INPUT_VER!'; $json | ConvertTo-Json -Depth 10 | Set-Content 'package.json' -Encoding UTF8"
:: 用 node 更新版本号(避免 PowerShell ConvertTo-Json 破坏编码)
if not "!INPUT_VER!"=="!PKG_VER!" (
echo 更新 package.json: !PKG_VER! -^> !INPUT_VER!
node -e "const fs=require('fs'),p=JSON.parse(fs.readFileSync('package.json','utf8'));p.version='!INPUT_VER!';fs.writeFileSync('package.json',JSON.stringify(p,null,2)+'\r\n')"
)

:: 同步 tauri.conf.json 版本号
node -e "const fs=require('fs'),t=JSON.parse(fs.readFileSync('src-tauri/tauri.conf.json','utf8'));t.version='!INPUT_VER!';fs.writeFileSync('src-tauri/tauri.conf.json',JSON.stringify(t,null,2)+'\r\n')"
echo 已同步 tauri.conf.json 版本号: !INPUT_VER!

:: 同步 Cargo.toml 版本号
call pnpm sync-version
if %ERRORLEVEL% neq 0 (
echo.
echo 版本同步失败! 错误码: %ERRORLEVEL%
echo 版本同步失败! 错误码: %ERRORLEVEL%
exit /b %ERRORLEVEL%
)
echo 已同步 Cargo.toml 版本号: !INPUT_VER!

echo [2/4] 清理旧的构建产物...
if exist "src-tauri\target\release\bundle\msi" rmdir /s /q "src-tauri\target\release\bundle\msi" 2>nul
if exist "src-tauri\target\release\wix" rmdir /s /q "src-tauri\target\release\wix" 2>nul

echo [3/4] 编译 Rust 后端 + 前端...
call pnpm build
if %ERRORLEVEL% neq 0 (
echo 前端构建失败!
exit /b %ERRORLEVEL%
)
echo 前端构建成功。

echo 编译 Rust 后端 (release)...
cargo build --release --manifest-path src-tauri\Cargo.toml
if %ERRORLEVEL% neq 0 (
echo Rust 编译失败!
exit /b %ERRORLEVEL%
)
echo Rust 编译成功。

echo [2/3] 清理旧的构建产物...
if exist "src-tauri\target\release\bundle" rmdir /s /q "src-tauri\target\release\bundle"
echo [4/4] 打包 MSI 安装包...

:: 找到 WiX 工具路径
set WIX_DIR=%LOCALAPPDATA%\tauri\WixTools314
if not exist "%WIX_DIR%\light.exe" (
echo 错误: 找不到 WiX 工具! 请安装 Tauri CLI 后重试。
echo 路径: %WIX_DIR%\light.exe
exit /b 1
)

echo [3/3] 开始构建...
call pnpm tauri build
:: 生成 WiX 文件 (tauri bundler 的 candle/light 前置步骤)
:: 先用 tauri build --bundles 仅编译不打包
:: 然后手动运行 candle + light
set BUNDLE_DIR=src-tauri\target\release
set WIX_SRC=%BUNDLE_DIR%\wix\x64

echo 正在准备 WiX 源文件...
:: 调用 Tauri 生成 WiX 配置(candle + light 文件)
call pnpm tauri build --bundles msi 2>&1 | findstr /v "failed light.exe"

:: 如果上面失败(WiX 步骤失败),我们手动构建 MSI
if not exist "%WIX_SRC%\main.wixobj" (
echo Tauri 未生成 .wixobj,尝试直接通过 cargo-bundle...

:: 使用 tauri-bundler 或手动 candle
if exist "%WIX_SRC%\main.wxs" (
echo 运行 candle.exe...
"%WIX_DIR%\candle.exe" -arch x64 -dBuildVersion="!INPUT_VER!" -out "%WIX_SRC%\" "%WIX_SRC%\main.wxs"
if %ERRORLEVEL% neq 0 (
echo candle 失败!
exit /b %ERRORLEVEL%
)
) else (
echo 错误: 找不到 main.wxs!
exit /b 1
)
)

:: 修复 locale.wxl 的 codepage(中文需要 936 而非 1252)
set WXL=%WIX_SRC%\locale.wxl
if exist "%WXL%" (
echo 修复 WiX locale codepage 为 936 (支持中文)...
powershell -NoProfile -Command ^
"$xml=[xml](Get-Content '%WXL%');$xml.WixLocalization.Codepage='936';$xml.WixLocalization.SelectSingleNode('//*[local-name()=""String"" and @Id=""TauriCodepage""]').InnerText='936';$xml.Save('%WXL%')"
)

:: 运行 light.exe 生成 MSI
echo 运行 light.exe 生成 MSI...
set OUT_MSI=%BUNDLE_DIR%\bundle\msi\md++_!INPUT_VER!_x64_en-US.msi
if not exist "%BUNDLE_DIR%\bundle\msi" mkdir "%BUNDLE_DIR%\bundle\msi"

"%WIX_DIR%\light.exe" ^
-ext "%WIX_DIR%\WixUIExtension.dll" ^
-loc "%WXL%" ^
-out "%OUT_MSI%" ^
"%WIX_SRC%\main.wixobj"

if %ERRORLEVEL% neq 0 (
echo.
echo 构建失败! 错误码: %ERRORLEVEL%
echo light.exe 打包失败! 错误码: %ERRORLEVEL%
exit /b %ERRORLEVEL%
)

echo.
echo ========================================
echo 构建完成! 版本: v!INPUT_VER!
echo 产物位于: src-tauri\target\release\bundle\
echo MSI: %OUT_MSI%
echo ========================================

endlocal
30 changes: 30 additions & 0 deletions scripts/sync-version.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { readFile, writeFile } from 'node:fs/promises';

const packageJsonPath = new URL('../package.json', import.meta.url);
const cargoTomlPath = new URL('../src-tauri/Cargo.toml', import.meta.url);
const tauriConfPath = new URL('../src-tauri/tauri.conf.json', import.meta.url);
const aboutModalPath = new URL('../src/components/AboutModal/AboutModal.tsx', import.meta.url);

const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'));
const version = packageJson.version;
Expand All @@ -10,6 +12,7 @@ if (typeof version !== 'string' || !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9
throw new Error(`package.json version must be semver-compatible, got: ${version}`);
}

// Sync Cargo.toml
const cargoToml = await readFile(cargoTomlPath, 'utf8');
const nextCargoToml = cargoToml.replace(
/^version = ".*"$/m,
Expand All @@ -22,3 +25,30 @@ if (nextCargoToml === cargoToml) {
await writeFile(cargoTomlPath, nextCargoToml);
console.log(`Synced src-tauri/Cargo.toml to package.json version ${version}`);
}

// Sync tauri.conf.json
const tauriConfRaw = await readFile(tauriConfPath, 'utf8');
const tauriConf = JSON.parse(tauriConfRaw);
tauriConf.version = version;
const nextTauriConf = JSON.stringify(tauriConf, null, 2) + '\n';

if (nextTauriConf === tauriConfRaw) {
console.log(`tauri.conf.json already matches package.json version ${version}`);
} else {
await writeFile(tauriConfPath, nextTauriConf);
console.log(`Synced src-tauri/tauri.conf.json to package.json version ${version}`);
}

// Sync AboutModal APP_VERSION
const aboutModalRaw = await readFile(aboutModalPath, 'utf8');
const nextAboutModal = aboutModalRaw.replace(
/^const APP_VERSION = '.*';$/m,
`const APP_VERSION = '${version}';`,
);

if (nextAboutModal === aboutModalRaw) {
console.log(`AboutModal already matches package.json version ${version}`);
} else {
await writeFile(aboutModalPath, nextAboutModal);
console.log(`Synced AboutModal APP_VERSION to package.json version ${version}`);
}
2 changes: 1 addition & 1 deletion src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "app"
version = "0.2.0"
version = "0.3.0"
description = "md++ — 轻量便捷的 Markdown 阅读器 (Windows / macOS)"
authors = ["leonan"]
license = "MIT"
Expand Down
12 changes: 9 additions & 3 deletions src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
"productName": "md++",
"version": "0.2.0",
"version": "0.3.0",
"identifier": "com.easymd.app",
"build": {
"frontendDist": "../dist",
Expand Down Expand Up @@ -31,7 +31,10 @@
},
"bundle": {
"active": true,
"targets": ["dmg", "msi"],
"targets": [
"dmg",
"msi"
],
"icon": [
"icons/32x32.png",
"icons/128x128.png",
Expand All @@ -45,7 +48,10 @@
},
"fileAssociations": [
{
"ext": ["md", "markdown"],
"ext": [
"md",
"markdown"
],
"mimeType": "text/markdown",
"description": "Markdown 文件"
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/AboutModal/AboutModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useTabsStore } from '../../stores/tabsStore';
import appIcon from '../../assets/app-icon.svg';
import featuresMd from '../../../features.md?raw';

const APP_VERSION = '0.1.0';
const APP_VERSION = '0.3.0';
const GITHUB_URL = 'https://github.com/Gitleonan/easy-md';

interface AboutModalProps {
Expand Down
Loading