From b7e29e6bd14563e96e88227710ca8b80fa3d8e22 Mon Sep 17 00:00:00 2001 From: bh0fer Date: Fri, 4 Sep 2026 20:27:07 +0200 Subject: [PATCH 1/9] chore: support stackblitz --- docusaurus.config.ts | 2 ++ .../plugin-stackblitz-rspack-target/index.ts | 17 +++++++++++++++++ src/siteConfig/pluginConfigs.ts | 3 +++ 3 files changed, 22 insertions(+) create mode 100644 src/plugins/plugin-stackblitz-rspack-target/index.ts diff --git a/docusaurus.config.ts b/docusaurus.config.ts index f82db99f4..158cd2718 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -29,6 +29,7 @@ import { withSiteConfig } from './src/siteConfig/withSiteConfig'; import { sassPluginConfig, dynamicRouterPluginConfig, + stackblitzRspackTargetPluginConfig, rsDoctorPluginConfig, sentryPluginConfig, socketIoNoDepWarningsPluginConfig, @@ -381,6 +382,7 @@ const docusaurusConfig = withSiteConfig().then(async (siteConfig) => { plugins: [ sassPluginConfig, dynamicRouterPluginConfig(siteConfig), + stackblitzRspackTargetPluginConfig(), rsDoctorPluginConfig, [ aliasConfigurationPlugin, diff --git a/src/plugins/plugin-stackblitz-rspack-target/index.ts b/src/plugins/plugin-stackblitz-rspack-target/index.ts new file mode 100644 index 000000000..86c22317d --- /dev/null +++ b/src/plugins/plugin-stackblitz-rspack-target/index.ts @@ -0,0 +1,17 @@ +import { PluginModule } from '@docusaurus/types'; + +const stackblitzRspackTarget: PluginModule = (context, options) => { + if (process.env.STACKBLITZ === 'true') { + return { + name: 'webpack-target-fix-plugin', + configureWebpack() { + return { + target: 'web' // bypass rspack's browserslist-based target inference + }; + } + }; + } + return null; +}; + +export default stackblitzRspackTarget; diff --git a/src/siteConfig/pluginConfigs.ts b/src/siteConfig/pluginConfigs.ts index cb6fc4498..d66cfad9e 100644 --- a/src/siteConfig/pluginConfigs.ts +++ b/src/siteConfig/pluginConfigs.ts @@ -1,4 +1,5 @@ import dynamicRouterPlugin, { Config as DynamicRouteConfig } from '../plugins/plugin-dynamic-routes'; +import stackblitzRspackTarget from '../plugins/plugin-stackblitz-rspack-target'; import aliasConfigurationPlugin from '../plugins/plugin-alias-configuration'; import type { PluginConfig } from '@docusaurus/types'; import { sentryWebpackPlugin } from '@sentry/webpack-plugin'; @@ -21,6 +22,8 @@ export const dynamicRouterPluginConfig: (siteConfig: SiteConfig) => PluginConfig } satisfies DynamicRouteConfig ]; +export const stackblitzRspackTargetPluginConfig: () => PluginConfig = () => stackblitzRspackTarget; + export const rsDoctorPluginConfig: PluginConfig = process.env.RSDOCTOR === 'true' && [ 'rsdoctor', { From 40875b39ed542efb797dfbdec108ad575f381920 Mon Sep 17 00:00:00 2001 From: bh0fer Date: Fri, 4 Sep 2026 21:19:06 +0200 Subject: [PATCH 2/9] skip better-sqlite3 import for stackblitz env --- packages/tdev/page-index/utils/exportDb.ts | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/tdev/page-index/utils/exportDb.ts b/packages/tdev/page-index/utils/exportDb.ts index 985c41aec..2d3d6a182 100644 --- a/packages/tdev/page-index/utils/exportDb.ts +++ b/packages/tdev/page-index/utils/exportDb.ts @@ -1,15 +1,32 @@ -import db from './db'; import { promises as fs } from 'fs'; import { pageIndexPath } from './options'; import { PageIndex } from '..'; +import type { Database, Statement } from 'better-sqlite3'; -const getDocumentRoots = db.prepare('SELECT * FROM document_roots ORDER BY path ASC, position ASC'); +let db: Database | null = null; +let getDocumentRoots: Statement | null = null; +const requireDb = async () => { + if (process.env.STACKBLITZ === 'true') { + // Stackblitz does not support better-sqlite3, so we skip the database export + return; + } + if (!db) { + db = (await import('./db')).default; + } + if (!getDocumentRoots) { + getDocumentRoots = db.prepare('SELECT * FROM document_roots ORDER BY path ASC, position ASC'); + } +}; export const getContent = () => { + if (!getDocumentRoots) { + return { documentRoots: [] as PageIndex[] }; + } const documentRoots = getDocumentRoots.all() as PageIndex[]; return { documentRoots }; }; export const exportDB = async () => { + await requireDb(); await fs.writeFile(pageIndexPath, JSON.stringify(getContent(), null, 2)); }; From 2aaa9d81f118d31dd18e00e6e91ec281312a3b25 Mon Sep 17 00:00:00 2001 From: lebalz Date: Fri, 4 Sep 2026 21:35:43 +0200 Subject: [PATCH 3/9] add stackblitz start command --- package.json | 1 + .../tdev/page-index/remark-plugin/index.ts | 66 +++++++++++++------ 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index ca0d54527..5e9ef5e45 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "scripts": { "docusaurus": "docusaurus", "start": "concurrently --raw --kill-others 'PACKAGE_SRC=packages PACKAGE_DEST=docs/Packages docusaurus start' 'sleep 1s && tsx updateSync/packageDocsSync/watch.ts --src packages --dest tdev-website/docs/packages'", + "stackblitz": "YARN_IGNORE_ENGINES=true PACKAGE_SRC=packages PACKAGE_DEST=docs/Packages docusaurus start", "prebuild": "yarn workspace @tdev/material-sync sync && tsx updateSync/packageDocsSync/preBuild.ts --src packages --dest tdev-website/docs/packages", "build": "docusaurus build", "swizzle": "docusaurus swizzle", diff --git a/packages/tdev/page-index/remark-plugin/index.ts b/packages/tdev/page-index/remark-plugin/index.ts index 744a09701..e20d35907 100644 --- a/packages/tdev/page-index/remark-plugin/index.ts +++ b/packages/tdev/page-index/remark-plugin/index.ts @@ -2,37 +2,59 @@ import type { Plugin, Transformer } from 'unified'; import type { Code, Root } from 'mdast'; import type { MdxJsxFlowElement, MdxJsxTextElement } from 'mdast-util-mdx'; import path from 'path'; -import db from '../utils/db'; import { exportDB } from '../utils/exportDb'; import { debounce } from 'es-toolkit/function'; import { tdevRoot } from '../utils/options'; import { TypeModelMapping } from '@tdev-api/document'; +import type { Database, Statement } from 'better-sqlite3'; + const TdevRoot = `${tdevRoot === '' ? '' : '/'}${tdevRoot}`; const TdevRootRegex = new RegExp(`^${TdevRoot}`); const projectRoot = process.cwd(); const isDev = process.env.NODE_ENV !== 'production'; -const insertDocRoot = db.prepare( - `INSERT INTO document_roots ( - id, - type, - page_id, - path, - position - ) VALUES ( - @id, - @type, - @page_id, - @path, - @position - ) ON CONFLICT(id, path) DO NOTHING` -); +let _cachedImport: { + insertDocRoot: Statement, + cleanupPage: Statement +} | null = null; + +const requireDb = async () => { + if (process.env.STACKBLITZ === 'true') { + return Promise.resolve({}); + } + if (_cachedImport) { + return Promise.resolve(_cachedImport); + } + const db = (await import('../utils/db')).default; + + const insertDocRoot = db.prepare( + `INSERT INTO document_roots ( + id, + type, + page_id, + path, + position + ) VALUES ( + @id, + @type, + @page_id, + @path, + @position + ) ON CONFLICT(id, path) DO NOTHING` + ); + + const cleanupPage = db.prepare( + `DELETE FROM document_roots + WHERE path = ? AND page_id = ?;` + ); + _cachedImport = { + insertDocRoot, + cleanupPage + } + return _cachedImport; +} -const cleanupPage = db.prepare( - `DELETE FROM document_roots - WHERE path = ? AND page_id = ?;` -); interface JsxConfig { /** @@ -67,6 +89,10 @@ const remarkPlugin: Plugin = function plugin( const { components } = options; const mdxJsxComponents = new Map(components.map((c) => [c.name, c])); return async (root, file) => { + const { insertDocRoot, cleanupPage } = await requireDb(); + if (!insertDocRoot) { + return null; + } const { page_id } = (file.data?.frontMatter || {}) as { page_id?: string }; if (components.length < 1 || !page_id) { return; From 688b9db76e8cc6b545b43fdca667fe5c820b2b19 Mon Sep 17 00:00:00 2001 From: bh0fer Date: Sun, 6 Sep 2026 18:50:18 +0200 Subject: [PATCH 4/9] set stackblitz start command and streamline cache import --- .stackblitzrc | 2 +- packages/tdev/page-index/utils/exportDb.ts | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.stackblitzrc b/.stackblitzrc index cecca9411..a9fe8e09d 100644 --- a/.stackblitzrc +++ b/.stackblitzrc @@ -1,6 +1,6 @@ { "installDependencies": true, - "startCommand": "yarn run start", + "startCommand": "yarn run stackblitz", "env": { "NODE_ENV": "development", "OFFLINE_API": "indexedDB", diff --git a/packages/tdev/page-index/utils/exportDb.ts b/packages/tdev/page-index/utils/exportDb.ts index 2d3d6a182..269643085 100644 --- a/packages/tdev/page-index/utils/exportDb.ts +++ b/packages/tdev/page-index/utils/exportDb.ts @@ -3,22 +3,21 @@ import { pageIndexPath } from './options'; import { PageIndex } from '..'; import type { Database, Statement } from 'better-sqlite3'; -let db: Database | null = null; -let getDocumentRoots: Statement | null = null; +const _cachedImport = { + getDocumentRoots: null as Statement | null +}; const requireDb = async () => { if (process.env.STACKBLITZ === 'true') { // Stackblitz does not support better-sqlite3, so we skip the database export - return; - } - if (!db) { - db = (await import('./db')).default; - } - if (!getDocumentRoots) { - getDocumentRoots = db.prepare('SELECT * FROM document_roots ORDER BY path ASC, position ASC'); + return Promise.resolve(); } + const db = (await import('./db')).default; + const getDocumentRoots = db.prepare('SELECT * FROM document_roots ORDER BY path ASC, position ASC'); + _cachedImport.getDocumentRoots = getDocumentRoots; }; export const getContent = () => { + const { getDocumentRoots } = _cachedImport; if (!getDocumentRoots) { return { documentRoots: [] as PageIndex[] }; } From acb864a55b424df675e4a0fa108f81796b220768 Mon Sep 17 00:00:00 2001 From: bh0fer Date: Sun, 6 Sep 2026 19:04:50 +0200 Subject: [PATCH 5/9] fix type issues --- .../tdev/page-index/remark-plugin/index.ts | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/packages/tdev/page-index/remark-plugin/index.ts b/packages/tdev/page-index/remark-plugin/index.ts index e20d35907..7f5549645 100644 --- a/packages/tdev/page-index/remark-plugin/index.ts +++ b/packages/tdev/page-index/remark-plugin/index.ts @@ -6,24 +6,23 @@ import { exportDB } from '../utils/exportDb'; import { debounce } from 'es-toolkit/function'; import { tdevRoot } from '../utils/options'; import { TypeModelMapping } from '@tdev-api/document'; -import type { Database, Statement } from 'better-sqlite3'; - +import type { Statement } from 'better-sqlite3'; const TdevRoot = `${tdevRoot === '' ? '' : '/'}${tdevRoot}`; const TdevRootRegex = new RegExp(`^${TdevRoot}`); const projectRoot = process.cwd(); const isDev = process.env.NODE_ENV !== 'production'; -let _cachedImport: { - insertDocRoot: Statement, - cleanupPage: Statement -} | null = null; +const _cachedImport: Partial<{ + insertDocRoot: Statement; + cleanupPage: Statement; +}> = {}; -const requireDb = async () => { +const requireDb = async (): Promise => { if (process.env.STACKBLITZ === 'true') { return Promise.resolve({}); } - if (_cachedImport) { + if (!_cachedImport.cleanupPage || !_cachedImport.insertDocRoot) { return Promise.resolve(_cachedImport); } const db = (await import('../utils/db')).default; @@ -43,18 +42,15 @@ const requireDb = async () => { @position ) ON CONFLICT(id, path) DO NOTHING` ); - + const cleanupPage = db.prepare( `DELETE FROM document_roots WHERE path = ? AND page_id = ?;` ); - _cachedImport = { - insertDocRoot, - cleanupPage - } + _cachedImport.insertDocRoot = insertDocRoot; + _cachedImport.cleanupPage = cleanupPage; return _cachedImport; -} - +}; interface JsxConfig { /** @@ -90,8 +86,8 @@ const remarkPlugin: Plugin = function plugin( const mdxJsxComponents = new Map(components.map((c) => [c.name, c])); return async (root, file) => { const { insertDocRoot, cleanupPage } = await requireDb(); - if (!insertDocRoot) { - return null; + if (!insertDocRoot || !cleanupPage) { + return; } const { page_id } = (file.data?.frontMatter || {}) as { page_id?: string }; if (components.length < 1 || !page_id) { From 3da4c5bfee330493b8a74aa1c722a4d084e9f09a Mon Sep 17 00:00:00 2001 From: bh0fer Date: Sun, 6 Sep 2026 19:07:58 +0200 Subject: [PATCH 6/9] add vite extension --- .vscode/extensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 1058a23bc..c60c27832 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,7 @@ { "recommendations": [ - "pomdtr.excalidraw-editor", "zhuangtongfa.Material-theme", + "betterplace.betterplace-vscode-vitest-runner", "mhutchie.git-graph", "esbenp.prettier-vscode", "dbaeumer.vscode-eslint", From 752c4a3426eccd9fd3f817507a0ae1ab65c51d10 Mon Sep 17 00:00:00 2001 From: bh0fer Date: Sun, 6 Sep 2026 19:16:25 +0200 Subject: [PATCH 7/9] update stackblitz rc --- .stackblitzrc | 7 +++++-- package.json | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.stackblitzrc b/.stackblitzrc index a9fe8e09d..90f2b35c7 100644 --- a/.stackblitzrc +++ b/.stackblitzrc @@ -1,9 +1,12 @@ { "installDependencies": true, - "startCommand": "yarn run stackblitz", + "startCommand": "yarn run docusaurus start", "env": { "NODE_ENV": "development", "OFFLINE_API": "indexedDB", - "STACKBLITZ": "true" + "STACKBLITZ": "true", + "YARN_IGNORE_ENGINES": "true", + "PACKAGE_SRC": "packages", + "PACKAGE_DEST": "docs/Packages" } } \ No newline at end of file diff --git a/package.json b/package.json index 5e9ef5e45..ca0d54527 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,6 @@ "scripts": { "docusaurus": "docusaurus", "start": "concurrently --raw --kill-others 'PACKAGE_SRC=packages PACKAGE_DEST=docs/Packages docusaurus start' 'sleep 1s && tsx updateSync/packageDocsSync/watch.ts --src packages --dest tdev-website/docs/packages'", - "stackblitz": "YARN_IGNORE_ENGINES=true PACKAGE_SRC=packages PACKAGE_DEST=docs/Packages docusaurus start", "prebuild": "yarn workspace @tdev/material-sync sync && tsx updateSync/packageDocsSync/preBuild.ts --src packages --dest tdev-website/docs/packages", "build": "docusaurus build", "swizzle": "docusaurus swizzle", From 3a21854df715af0558186867fa5c85cd7ff0eb2c Mon Sep 17 00:00:00 2001 From: bh0fer Date: Sun, 6 Sep 2026 19:28:34 +0200 Subject: [PATCH 8/9] fix is cached check --- packages/tdev/page-index/remark-plugin/index.ts | 2 +- packages/tdev/page-index/utils/exportDb.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/tdev/page-index/remark-plugin/index.ts b/packages/tdev/page-index/remark-plugin/index.ts index 7f5549645..195c13d68 100644 --- a/packages/tdev/page-index/remark-plugin/index.ts +++ b/packages/tdev/page-index/remark-plugin/index.ts @@ -22,7 +22,7 @@ const requireDb = async (): Promise => { if (process.env.STACKBLITZ === 'true') { return Promise.resolve({}); } - if (!_cachedImport.cleanupPage || !_cachedImport.insertDocRoot) { + if (_cachedImport.cleanupPage && _cachedImport.insertDocRoot) { return Promise.resolve(_cachedImport); } const db = (await import('../utils/db')).default; diff --git a/packages/tdev/page-index/utils/exportDb.ts b/packages/tdev/page-index/utils/exportDb.ts index 269643085..f18378dcc 100644 --- a/packages/tdev/page-index/utils/exportDb.ts +++ b/packages/tdev/page-index/utils/exportDb.ts @@ -1,7 +1,7 @@ import { promises as fs } from 'fs'; import { pageIndexPath } from './options'; import { PageIndex } from '..'; -import type { Database, Statement } from 'better-sqlite3'; +import type { Statement } from 'better-sqlite3'; const _cachedImport = { getDocumentRoots: null as Statement | null @@ -16,7 +16,7 @@ const requireDb = async () => { _cachedImport.getDocumentRoots = getDocumentRoots; }; -export const getContent = () => { +const getContent = () => { const { getDocumentRoots } = _cachedImport; if (!getDocumentRoots) { return { documentRoots: [] as PageIndex[] }; From 5598c731bd6e3c65fe19b2415d8f740b8906a05d Mon Sep 17 00:00:00 2001 From: bh0fer Date: Sun, 6 Sep 2026 19:33:50 +0200 Subject: [PATCH 9/9] update readme --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 580ded534..a1c352c45 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ -# Website +# Teaching Dev -This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator. +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/GBSL-Informatik/teaching-dev) -> [!NOTE] -> Compatible with @docusaurus/faster (rspack and swc). +Diese Seite basiert auf [Docusaurus](https://docusaurus.io/), einem modernen statischen Website-Generator. Sie fügt viele hilfreiche Funktionalität für den Einsatz im Unterricht hinzu. ## TDEV-Website