refactor(editor): move worker renderer to presets with basic test (#10127)

This commit is contained in:
Yifeng Wang
2025-02-13 09:35:06 +08:00
committed by GitHub
parent 270d1754a3
commit fc77c7d41a
12 changed files with 124 additions and 82 deletions

View File

@@ -1,22 +0,0 @@
import '../../style.css';
import { ViewportTurboRendererExtension } from '@blocksuite/affine-shared/viewport-renderer';
import { effects as blocksEffects } from '@blocksuite/blocks/effects';
import { AffineEditorContainer } from '@blocksuite/presets';
import { effects as presetsEffects } from '@blocksuite/presets/effects';
import { createEmptyDoc } from '../../apps/_common/helper';
blocksEffects();
presetsEffects();
export const { doc } = createEmptyDoc();
export const editor = new AffineEditorContainer();
editor.edgelessSpecs = [
...editor.edgelessSpecs,
ViewportTurboRendererExtension,
];
editor.doc = doc;
editor.mode = 'edgeless';

View File

@@ -1,29 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Renderer Example</title>
<style>
html,
body {
height: 100%;
overflow: hidden;
margin: 0;
padding: 0;
background-color: var(--affine-white-90);
transition: background-color 0.3s;
}
#container {
position: relative;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="container"></div>
<script type="module" src="./main.ts"></script>
</body>
</html>

View File

@@ -1,10 +0,0 @@
import { addSampleNotes } from './doc-generator.js';
import { doc, editor } from './editor.js';
function main() {
doc.load();
addSampleNotes(6);
}
main();
document.querySelector('#container')?.append(editor);

View File

@@ -120,10 +120,6 @@ export default defineConfig(({ mode }) => {
'examples/multiple-editors/edgeless-edgeless/index.html'
),
'examples/inline': resolve(__dirname, 'examples/inline/index.html'),
'examples/renderer': resolve(
__dirname,
'examples/renderer/index.html'
),
},
treeshake: true,
output: {

View File

@@ -3,6 +3,7 @@
"description": "Prebuilt BlockSuite editors and opt-in additional UI components.",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc",
"test:unit": "vitest --browser.headless --run",
"test:debug": "PWDEBUG=1 npx vitest"
@@ -46,6 +47,9 @@
],
"devDependencies": {
"@vanilla-extract/vite-plugin": "^5.0.0",
"vite": "^6.1.0",
"vite-plugin-istanbul": "^6.0.2",
"vite-plugin-wasm": "^3.4.1",
"vitest": "^3.0.0"
},
"version": "0.19.0"

View File

@@ -0,0 +1,21 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Kalam&display=swap"
rel="stylesheet"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Debug Entry</title>
</head>
<body>
<script
type="module"
src="./src/__tests__/utils/renderer-entry.ts"
></script>
</body>
</html>

View File

@@ -0,0 +1,23 @@
import { ViewportTurboRendererExtension } from '@blocksuite/affine-shared/viewport-renderer';
import { beforeEach, describe, expect, test } from 'vitest';
import { wait } from '../utils/common.js';
import { addSampleNotes } from '../utils/doc-generator.js';
import { setupEditor } from '../utils/setup.js';
describe('viewport turbo renderer', () => {
beforeEach(async () => {
const cleanup = await setupEditor('edgeless', [
ViewportTurboRendererExtension,
]);
return cleanup;
});
test('should render 6 notes in viewport', async () => {
addSampleNotes(doc, 6);
await wait();
const notes = document.querySelectorAll('affine-edgeless-note');
expect(notes.length).toBe(6);
});
});

View File

@@ -1,33 +1,32 @@
import { Text } from '@blocksuite/store';
import { type Store, Text } from '@blocksuite/store';
import { doc } from './editor.js';
function addParagraph(noteId: string, content: string) {
function addParagraph(doc: Store, noteId: string, content: string) {
const props = { text: new Text(content) };
doc.addBlock('affine:paragraph', props, noteId);
}
function addSampleNote(noteId: string, i: number) {
addParagraph(noteId, `Note ${i + 1}`);
addParagraph(noteId, 'Hello World!');
function addSampleNote(doc: Store, noteId: string, i: number) {
addParagraph(doc, noteId, `Note ${i + 1}`);
addParagraph(doc, noteId, 'Hello World!');
addParagraph(
doc,
noteId,
'Hello World! Lorem ipsum dolor sit amet. Consectetur adipiscing elit. Sed do eiusmod tempor incididunt.'
);
addParagraph(
doc,
noteId,
'你好这是测试,这是一个为了换行而写的中文段落。这个段落会自动换行。'
);
}
export function addSampleNotes(n: number) {
export function addSampleNotes(doc: Store, n: number) {
const cols = Math.ceil(Math.sqrt(n));
const NOTE_WIDTH = 500;
const NOTE_HEIGHT = 250;
const SPACING = 50;
const rootId = doc.addBlock('affine:page', {});
doc.addBlock('affine:surface', {}, rootId);
const rootId = doc.getBlocksByFlavour('affine:page')[0]?.id;
for (let i = 0; i < n; i++) {
const row = Math.floor(i / cols);
@@ -37,6 +36,6 @@ export function addSampleNotes(n: number) {
const xywh = `[${x},${y},${NOTE_WIDTH},${NOTE_HEIGHT}]`;
const noteId = doc.addBlock('affine:note', { xywh }, rootId);
addSampleNote(noteId, i);
addSampleNote(doc, noteId, i);
}
}

View File

@@ -0,0 +1,12 @@
import { ViewportTurboRendererExtension } from '@blocksuite/affine-shared/viewport-renderer';
import { addSampleNotes } from './doc-generator.js';
import { setupEditor } from './setup.js';
async function init() {
setupEditor('edgeless', [ViewportTurboRendererExtension]);
addSampleNotes(doc, 6);
doc.load();
}
init();

View File

@@ -2,7 +2,7 @@ import '@toeverything/theme/style.css';
import '@toeverything/theme/fonts.css';
import { effects as blocksEffects } from '@blocksuite/blocks/effects';
import type { Store, Transformer } from '@blocksuite/store';
import type { ExtensionType, Store, Transformer } from '@blocksuite/store';
import { effects } from '../../effects.js';
@@ -59,7 +59,11 @@ function initCollection(collection: TestWorkspace) {
doc.resetHistory();
}
async function createEditor(collection: TestWorkspace, mode: DocMode = 'page') {
async function createEditor(
collection: TestWorkspace,
mode: DocMode = 'page',
extensions: ExtensionType[] = []
) {
const app = document.createElement('div');
const blockCollection = collection.docs.values().next().value;
assertExists(blockCollection, 'Need to create a doc first');
@@ -69,9 +73,11 @@ async function createEditor(collection: TestWorkspace, mode: DocMode = 'page') {
editor.mode = mode;
editor.pageSpecs = editor.pageSpecs.concat([
FontConfigExtension(CommunityCanvasTextFonts),
...extensions,
]);
editor.edgelessSpecs = editor.edgelessSpecs.concat([
FontConfigExtension(CommunityCanvasTextFonts),
...extensions,
]);
app.append(editor);
@@ -87,7 +93,10 @@ async function createEditor(collection: TestWorkspace, mode: DocMode = 'page') {
return app;
}
export async function setupEditor(mode: DocMode = 'page') {
export async function setupEditor(
mode: DocMode = 'page',
extensions: ExtensionType[] = []
) {
const collection = new TestWorkspace(createCollectionOptions());
collection.storeExtensions = StoreExtensions;
collection.meta.initialize();
@@ -95,7 +104,7 @@ export async function setupEditor(mode: DocMode = 'page') {
window.collection = collection;
initCollection(collection);
const appElement = await createEditor(collection, mode);
const appElement = await createEditor(collection, mode, extensions);
return () => {
appElement.remove();

View File

@@ -0,0 +1,36 @@
import { cpus } from 'node:os';
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
import { defineConfig } from 'vite';
import wasm from 'vite-plugin-wasm';
// https://vitejs.dev/config/
export default defineConfig(() => {
return {
plugins: [wasm(), vanillaExtractPlugin()],
esbuild: {
target: 'es2022',
},
resolve: {
extensions: ['.ts', '.js'],
},
build: {
target: 'es2022',
sourcemap: true,
rollupOptions: {
cache: false,
maxParallelFileOps: Math.max(1, cpus().length - 1),
onwarn(warning, defaultHandler) {
if (
warning.code &&
['EVAL', 'SOURCEMAP_ERROR'].includes(warning.code)
) {
return;
}
defaultHandler(warning);
},
treeshake: true,
},
},
};
});