From 4342037d4d2d646bad060aa415a142e40fa15ad7 Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 12 Apr 2024 00:25:18 +0800 Subject: [PATCH] feat: snippets compatibility with the Monaco Runner (#1512) Co-authored-by: _Kerman --- demo/starter/slides.md | 15 ++++++--------- demo/starter/snippets/external.ts | 9 ++++++--- packages/client/setup/code-runners.ts | 11 +++++++---- packages/slidev/node/vite/loaders.ts | 12 +++++++----- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/demo/starter/slides.md b/demo/starter/slides.md index ecb9643a0c..b9d655eb36 100644 --- a/demo/starter/slides.md +++ b/demo/starter/slides.md @@ -611,23 +611,20 @@ Add `{monaco}` to the code block to turn it into an editor: ```ts {monaco} import { ref } from 'vue' -import hello from './external' +import { emptyArray } from './external' -const code = ref(hello()) +const arr = ref(emptyArray(10)) ``` Use `{monaco-run}` to create an editor that can execute the code directly in the slide: ```ts {monaco-run} import { version } from 'vue' +import { emptyArray, sayHello } from './external' -function fibonacci(n: number): number { - return n <= 1 - ? n - : fibonacci(n - 1) + fibonacci(n - 2) // you know, this is NOT the best way to do it :P -} - -console.log(version, Array.from({ length: 10 }, (_, i) => fibonacci(i + 1))) +sayHello() +console.log(`vue ${version}`) +console.log(emptyArray(10).reduce(fib => [...fib, fib.at(-1)! + fib.at(-2)!], [1, 1])) ``` --- diff --git a/demo/starter/snippets/external.ts b/demo/starter/snippets/external.ts index 96774892ea..40c109bc44 100644 --- a/demo/starter/snippets/external.ts +++ b/demo/starter/snippets/external.ts @@ -1,9 +1,12 @@ /* eslint-disable no-console */ // #region snippet -function hello() { - console.log('Hello from snippets/external.ts') +// Inside ./snippets/external.ts +export function emptyArray(length: number) { + return Array.from({ length }) } // #endregion snippet -export default hello +export function sayHello() { + console.log('Hello from snippets/external.ts') +} diff --git a/packages/client/setup/code-runners.ts b/packages/client/setup/code-runners.ts index f6f4457384..f297353936 100644 --- a/packages/client/setup/code-runners.ts +++ b/packages/client/setup/code-runners.ts @@ -26,9 +26,9 @@ export default createSingletonPromise(async () => { }) const resolveId = async (specifier: string) => { - if (!/^(@[^\/:]+?\/)?[^\/:]+$/.test(specifier)) - return specifier - const res = await fetch(`/@slidev/resolve-id/${specifier}`) + if (!'./'.includes(specifier[0]) && !/^(@[^\/:]+?\/)?[^\/:]+$/.test(specifier)) + return specifier // this might be a url or something else + const res = await fetch(`/@slidev/resolve-id?specifier=${specifier}`) if (!res.ok) return null const id = await res.text() @@ -85,7 +85,10 @@ async function runJavaScript(code: string): Promise { replace.clear = () => allLogs.length = 0 const vmConsole = Object.assign({}, console, replace) try { - const safeJS = `return async (console) => {${sanitizeJS(code)}}` + const safeJS = `return async (console) => { + window.console = console + ${sanitizeJS(code)} + }` // eslint-disable-next-line no-new-func await (new Function(safeJS)())(vmConsole) } diff --git a/packages/slidev/node/vite/loaders.ts b/packages/slidev/node/vite/loaders.ts index 2b2467df86..ac3d7d09d8 100644 --- a/packages/slidev/node/vite/loaders.ts +++ b/packages/slidev/node/vite/loaders.ts @@ -1,4 +1,4 @@ -import { basename } from 'node:path' +import path from 'node:path' import type { Connect, HtmlTagDescriptor, ModuleNode, Plugin, Update, ViteDevServer } from 'vite' import { isString, isTruthy, notNullish, range } from '@antfu/utils' import fg from 'fast-glob' @@ -106,7 +106,7 @@ export function createSlidesLoader( let skipHmr: { filePath: string, fileContent: string } | null = null - const { data, clientRoot, roots, mode } = options + const { data, clientRoot, userRoot, roots, mode } = options const templateCtx: VirtualModuleTempalteContext = { md, @@ -125,7 +125,7 @@ export function createSlidesLoader( }) for (const layoutPath of layoutPaths) { - const layout = basename(layoutPath).replace(/\.\w+$/, '') + const layout = path.basename(layoutPath).replace(/\.\w+$/, '') if (layouts[layout]) continue layouts[layout] = layoutPath @@ -198,13 +198,15 @@ export function createSlidesLoader( next() }) + const snippetsPath = path.resolve(userRoot, 'snippets/__importer__.ts') + server.middlewares.use(async (req, res, next) => { - const match = req.url?.match(/^\/\@slidev\/resolve-id\/(.*)$/) + const match = req.url?.match(/^\/\@slidev\/resolve-id\?specifier=(.*)$/) if (!match) return next() const [, specifier] = match - const resolved = await server!.pluginContainer.resolveId(specifier) + const resolved = await server!.pluginContainer.resolveId(specifier, snippetsPath) res.statusCode = 200 res.write(resolved?.id ?? '') return res.end()