feat(editor): migrate typst mermaid to native (#14499)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Native/WASM Mermaid and Typst SVG preview rendering on desktop and
mobile, plus cross-platform Preview plugin integrations.

* **Improvements**
* Centralized, sanitized rendering bridge with automatic Typst
font-directory handling and configurable native renderer selection.
* More consistent and robust error serialization and worker-backed
preview flows for improved stability and performance.

* **Tests**
* Extensive unit and integration tests for preview rendering, font
discovery, sanitization, and error serialization.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-03-20 04:04:40 +08:00
committed by GitHub
parent 16a8f17717
commit 7ac8b14b65
85 changed files with 4926 additions and 835 deletions
+49 -6
View File
@@ -27,6 +27,9 @@ import {
type WorkerConfig = { name: string };
type CreateWorkerTargetConfig = (pkg: Package, entry: string) => WorkerConfig;
type BaseWorkerOptions = {
includeMermaidAndTypst?: boolean;
};
function assertRspackSupportedPackage(pkg: Package) {
assertRspackSupportedPackageName(pkg.name);
@@ -49,11 +52,13 @@ async function uploadAssetsForPackage(pkg: Package, logger: Logger) {
function getBaseWorkerConfigs(
pkg: Package,
createWorkerTargetConfig: CreateWorkerTargetConfig
createWorkerTargetConfig: CreateWorkerTargetConfig,
options: BaseWorkerOptions = {}
) {
const core = new Package('@affine/core');
const includeMermaidAndTypst = options.includeMermaidAndTypst ?? true;
return [
const workerConfigs = [
createWorkerTargetConfig(
pkg,
core.srcPath.join(
@@ -71,6 +76,21 @@ function getBaseWorkerConfigs(
).value
),
];
if (includeMermaidAndTypst) {
workerConfigs.push(
createWorkerTargetConfig(
pkg,
core.srcPath.join('modules/mermaid/renderer/mermaid.worker.ts').value
),
createWorkerTargetConfig(
pkg,
core.srcPath.join('modules/typst/renderer/typst.worker.ts').value
)
);
}
return workerConfigs;
}
function getRspackBundleConfigs(pkg: Package): MultiRspackOptions {
@@ -85,9 +105,7 @@ function getRspackBundleConfigs(pkg: Package): MultiRspackOptions {
] as MultiRspackOptions;
}
case '@affine/web':
case '@affine/mobile':
case '@affine/ios':
case '@affine/android': {
case '@affine/mobile': {
const workerConfigs = getBaseWorkerConfigs(
pkg,
createRspackWorkerTargetConfig
@@ -109,10 +127,35 @@ function getRspackBundleConfigs(pkg: Package): MultiRspackOptions {
...workerConfigs,
] as MultiRspackOptions;
}
case '@affine/ios':
case '@affine/android': {
const workerConfigs = getBaseWorkerConfigs(
pkg,
createRspackWorkerTargetConfig,
{ includeMermaidAndTypst: false }
);
workerConfigs.push(
createRspackWorkerTargetConfig(
pkg,
pkg.srcPath.join('nbstore.worker.ts').value
)
);
return [
createRspackHTMLTargetConfig(
pkg,
pkg.srcPath.join('index.tsx').value,
{},
workerConfigs.map(config => config.name)
),
...workerConfigs,
] as MultiRspackOptions;
}
case '@affine/electron-renderer': {
const workerConfigs = getBaseWorkerConfigs(
pkg,
createRspackWorkerTargetConfig
createRspackWorkerTargetConfig,
{ includeMermaidAndTypst: false }
);
return [
+18
View File
@@ -90,6 +90,22 @@ export function createHTMLTargetConfig(
);
const buildConfig = getBuildConfigFromEnv(pkg);
const codeBlockPreviewBackendFile =
buildConfig.distribution === 'desktop'
? 'platform-backend.desktop.ts'
: buildConfig.distribution === 'ios' ||
buildConfig.distribution === 'android'
? 'platform-backend.mobile.ts'
: 'platform-backend.ts';
const codeBlockPreviewBackendAlias = ProjectRoot.join(
'packages',
'frontend',
'core',
'src',
'modules',
'code-block-preview-renderer',
codeBlockPreviewBackendFile
).value;
console.log(
`Building [${pkg.name}] for [${buildConfig.appBuildType}] channel in [${buildConfig.debug ? 'development' : 'production'}] mode.`
@@ -145,6 +161,8 @@ export function createHTMLTargetConfig(
'@preact',
'signals-core'
).value,
'@affine/core/modules/code-block-preview-renderer/platform-backend':
codeBlockPreviewBackendAlias,
},
},
//#endregion