Skip to content

Commit

Permalink
feat: snippets compatibility with the Monaco Runner (#1512)
Browse files Browse the repository at this point in the history
Co-authored-by: _Kerman <kermanx@qq.com>
  • Loading branch information
kamuiiiii and KermanX committed Apr 11, 2024
1 parent bd441f1 commit 4342037
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 21 deletions.
15 changes: 6 additions & 9 deletions demo/starter/slides.md
Expand Up @@ -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<number>(10).reduce(fib => [...fib, fib.at(-1)! + fib.at(-2)!], [1, 1]))
```

---
Expand Down
9 changes: 6 additions & 3 deletions 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<T>(length: number) {
return Array.from<T>({ length })
}
// #endregion snippet

export default hello
export function sayHello() {
console.log('Hello from snippets/external.ts')
}
11 changes: 7 additions & 4 deletions packages/client/setup/code-runners.ts
Expand Up @@ -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()
Expand Down Expand Up @@ -85,7 +85,10 @@ async function runJavaScript(code: string): Promise<CodeRunnerOutputs> {
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)
}
Expand Down
12 changes: 7 additions & 5 deletions 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'
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit 4342037

Please sign in to comment.