diff --git a/blocksuite/playground/examples/renderer/editor.ts b/blocksuite/playground/examples/renderer/editor.ts
deleted file mode 100644
index 02a577ce0c..0000000000
--- a/blocksuite/playground/examples/renderer/editor.ts
+++ /dev/null
@@ -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';
diff --git a/blocksuite/playground/examples/renderer/index.html b/blocksuite/playground/examples/renderer/index.html
deleted file mode 100644
index 2cc387fc4b..0000000000
--- a/blocksuite/playground/examples/renderer/index.html
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
- Renderer Example
-
-
-
-
-
-
-
diff --git a/blocksuite/playground/examples/renderer/main.ts b/blocksuite/playground/examples/renderer/main.ts
deleted file mode 100644
index 399bc75777..0000000000
--- a/blocksuite/playground/examples/renderer/main.ts
+++ /dev/null
@@ -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);
diff --git a/blocksuite/playground/vite.config.ts b/blocksuite/playground/vite.config.ts
index 4d051ba4d1..7ae0542ba0 100644
--- a/blocksuite/playground/vite.config.ts
+++ b/blocksuite/playground/vite.config.ts
@@ -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: {
diff --git a/blocksuite/presets/package.json b/blocksuite/presets/package.json
index bfd4809c3c..a61cf7559b 100644
--- a/blocksuite/presets/package.json
+++ b/blocksuite/presets/package.json
@@ -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"
diff --git a/blocksuite/presets/renderer.html b/blocksuite/presets/renderer.html
new file mode 100644
index 0000000000..45a5dff8d3
--- /dev/null
+++ b/blocksuite/presets/renderer.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+ Debug Entry
+
+
+
+
+
diff --git a/blocksuite/presets/src/__tests__/edgeless/viewport-renderer.spec.ts b/blocksuite/presets/src/__tests__/edgeless/viewport-renderer.spec.ts
new file mode 100644
index 0000000000..75f3a996a2
--- /dev/null
+++ b/blocksuite/presets/src/__tests__/edgeless/viewport-renderer.spec.ts
@@ -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);
+ });
+});
diff --git a/blocksuite/playground/examples/renderer/doc-generator.ts b/blocksuite/presets/src/__tests__/utils/doc-generator.ts
similarity index 64%
rename from blocksuite/playground/examples/renderer/doc-generator.ts
rename to blocksuite/presets/src/__tests__/utils/doc-generator.ts
index 551b579455..159a4e2eeb 100644
--- a/blocksuite/playground/examples/renderer/doc-generator.ts
+++ b/blocksuite/presets/src/__tests__/utils/doc-generator.ts
@@ -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);
}
}
diff --git a/blocksuite/presets/src/__tests__/utils/renderer-entry.ts b/blocksuite/presets/src/__tests__/utils/renderer-entry.ts
new file mode 100644
index 0000000000..a208d683c8
--- /dev/null
+++ b/blocksuite/presets/src/__tests__/utils/renderer-entry.ts
@@ -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();
diff --git a/blocksuite/presets/src/__tests__/utils/setup.ts b/blocksuite/presets/src/__tests__/utils/setup.ts
index b39150050f..d59d3a10a0 100644
--- a/blocksuite/presets/src/__tests__/utils/setup.ts
+++ b/blocksuite/presets/src/__tests__/utils/setup.ts
@@ -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();
diff --git a/blocksuite/presets/vite.config.ts b/blocksuite/presets/vite.config.ts
new file mode 100644
index 0000000000..ddeccc083b
--- /dev/null
+++ b/blocksuite/presets/vite.config.ts
@@ -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,
+ },
+ },
+ };
+});
diff --git a/yarn.lock b/yarn.lock
index d5ec44d7c8..b2f78da2f5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4106,6 +4106,9 @@ __metadata:
"@vanilla-extract/css": "npm:^1.17.0"
"@vanilla-extract/vite-plugin": "npm:^5.0.0"
lit: "npm:^3.2.0"
+ vite: "npm:^6.1.0"
+ vite-plugin-istanbul: "npm:^6.0.2"
+ vite-plugin-wasm: "npm:^3.4.1"
vitest: "npm:^3.0.0"
yjs: "npm:^13.6.21"
zod: "npm:^3.23.8"
@@ -33794,7 +33797,7 @@ __metadata:
languageName: node
linkType: hard
-"vite-plugin-wasm@npm:^3.3.0":
+"vite-plugin-wasm@npm:^3.3.0, vite-plugin-wasm@npm:^3.4.1":
version: 3.4.1
resolution: "vite-plugin-wasm@npm:3.4.1"
peerDependencies:
@@ -33818,7 +33821,7 @@ __metadata:
languageName: node
linkType: hard
-"vite@npm:^5.0.0 || ^6.0.0, vite@npm:^6.0.3":
+"vite@npm:^5.0.0 || ^6.0.0, vite@npm:^6.0.3, vite@npm:^6.1.0":
version: 6.1.0
resolution: "vite@npm:6.1.0"
dependencies: