10 KiB
Headless Mode
import LiveCodes from '../../src/components/LiveCodes.tsx';
The LiveCodes SDK can be used to create playgrounds in headless mode. In this mode, no visible output is displayed in the embedding web page. However, all SDK methods#sdk-methods) are accessible (e.g. for updating code#setconfig), getting compiled code#getcode), console output, result HTML#getcode), shareable URLs#getshareurl), formatting code#format), running tests#runtests), etc).
This provides the power of leveraging the wide range of features and language support offered by LiveCodes, while retaining full control over the UI.
Usage
To create a headless playground, set the embed option#embed-options) headless#headless) to true.
Please note that in headless mode, the first parameter (container) of the function createPlayground#createplayground) is optional and can be omitted.
Example:
import { createPlayground } from 'livecodes';
createPlayground({
view: 'headless',
config: {
markup: {
language: 'markdown',
content: '# Hello World!',
},
},
}).then(async (playground) => {
const code = await playground.getCode();
console.log(code.markup.compiled); // "<h1>Hello World!</h1>"
console.log(code.result); // (result page HTML)
});
Examples
The following examples show how to use the headless mode to make a Markdown editor, an MDX editor and a Python interpreter.
:::tip
You may want to view the following playgrounds in full screen (using the full screen button in the top right of each playground).
:::
Markdown Editor
In this demo, code changes are watched using the SDK method watch('code', callback)#watch). The callback function accepts an argument which is an object with the properties code and config (see getCode#getcode) and getConfig#getconfig)). The compiled code is obtained as code.markup.compiled.
export const mdDemo = { markup: { language: 'html', content: <textarea id="editor" style="display: none;"></textarea>\n<div id="output">Loading...</div>\n\n\x3Cscript type="module">\n import { createPlayground } from "https://cdn.jsdelivr.net/npm/livecodes@0.2.0";\n import debounce from "https://jspm.dev/debounce";\n\n const initialCode = "# Hello, LiveCodes!\\n\\n";\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById("editor"), {\n lineNumbers: true,\n mode: "markdown",\n });\n editor.setSize("100%", 200);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: "headless",\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const compile = async () => {\n await livecodes.setConfig({\n autoupdate: false,\n markup: {\n language: "markdown",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on("change", debounce(compile, 1000));\n livecodes.watch("code", ({ code, config }) => {\n createSandbox(document.querySelector("#output"), code.markup.compiled);\n });\n\n await compile();\n\n // create a sandbox for safe execution of compiled code\n function createSandbox (container, html) {\n const iframe = document.createElement("iframe");\n iframe.src = "https://livecodes-sandbox.pages.dev/v7/";\n iframe.sandbox =\n "allow-same-origin allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-presentation allow-scripts";\n iframe.onload = () => {\n iframe.contentWindow.postMessage({ html }, "*");\n };\n container.innerHTML = "";\n container.appendChild(iframe);\n return iframe;\n };\n\x3C/script>\n\n<link rel="stylesheet" href="https://unpkg.com/codemirror@5.65.15/lib/codemirror.css" />\n\x3Cscript src="https://unpkg.com/codemirror@5.65.15/lib/codemirror.js">\x3C/script>\n\x3Cscript src="https://unpkg.com/codemirror@5.65.15/mode/markdown/markdown.js">\x3C/script>\n\n<style>\n * {\n margin: 0;\n padding: 0;\n }\n body {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n }\n #output {\n flex: 1;\n }\n #output iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n</style>\n }}
MDX Editor
In this demo, code changes are watched using the SDK method watch('code', callback)#watch). The callback function accepts an argument which is an object with the properties code and config (see getCode#getcode) and getConfig#getconfig)). The result HTML is obtained as code.result.
:::tip
If you do not want to run the result page in the headless playground and only want to get the generated result HTML, you can set the configuration option [autoupdate](../configuration/configuration-object.html.md)#autoupdate) to false`.
:::
export const mdxDemo = { markup: { language: 'html', content: <textarea id="editor" style="display: none;"></textarea>\n<div id="output">Loading...</div>\n\n\x3Cscript type="module">\n import { createPlayground } from "https://cdn.jsdelivr.net/npm/livecodes@0.2.0";\n import debounce from "https://jspm.dev/debounce";\n\n const initialCode = \import { useState, useEffect } from 'react';\n\nexport const Hello = ({name}) => {\n const [count, setCount] = useState(0);\n return (\n <>\n
Hello, {name}!
\nYou clicked {count} times.
\n <button onClick={() => setCount(count + 1)}>Click me\n </>\n );\n};\n\n\n\n## MDX in short\n\n- ❤️ Powerful\n- 💻 Everything is a component\n- 🔧 Customizable\n- 📚 Markdown-based\n- 🔥 Blazingly blazing fast\n\n> from mdxjs.com\n`;\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById("editor"), {\n lineNumbers: true,\n mode: "markdown",\n });\n editor.setSize("100%", 200);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: "headless",\n config: { autoupdate: false },\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const compile = async () => {\n await livecodes.setConfig({\n autoupdate: false,\n markup: {\n language: "mdx",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on("change", debounce(compile, 1000));\n livecodes.watch("code", ({ code, config }) => {\n createSandbox(document.querySelector("#output"), code.result);\n });\n\n await compile();\n\n // create a sandbox for safe execution of compiled code\n function createSandbox (container, html) {\n const iframe = document.createElement("iframe");\n iframe.src = "https://livecodes-sandbox.pages.dev/v7/";\n iframe.sandbox =\n "allow-same-origin allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-presentation allow-scripts";\n iframe.onload = () => {\n iframe.contentWindow.postMessage({ html }, "*");\n };\n container.innerHTML = "";\n container.appendChild(iframe);\n return iframe;\n };\n\x3C/script>\n\n\n\x3Cscript src="https://unpkg.com/codemirror@5.65.15/lib/codemirror.js">\x3C/script>\n\x3Cscript src="https://unpkg.com/codemirror@5.65.15/mode/markdown/markdown.js">\x3C/script>\n\n\n` }}Python Interpreter
In this demo, console output is obtained using the SDK method watch('code', callback)#watch). The callback function accepts an argument which is an object with the properties method and args indicating the console method and the arguments that were passed (as an array).
export const pyDemo = { markup: { language: 'html', content: <textarea id="editor" style="display: none"></textarea>\n<div id="output">Loading...</div>\n\n\x3Cscript type="module">\n import { createPlayground } from "https://cdn.jsdelivr.net/npm/livecodes@0.2.0";\n import debounce from "https://jspm.dev/debounce";\n\n const initialCode = \def say_hello(name):\n return f"Hello, {name}!"\n\nprint(say_hello("LiveCodes"))\n`;\n\n // the code editor\n const editor = CodeMirror.fromTextArea(document.getElementById("editor"), {\n lineNumbers: true,\n mode: "python",\n });\n editor.setSize("100%", 250);\n editor.setValue(initialCode);\n\n // the playground\n const options = {\n view: "headless",\n };\n\n const livecodes = await createPlayground(options);\n await livecodes.load();\n\n const run = async () => {\n await livecodes.setConfig({\n autoupdate: true,\n script: {\n language: "python",\n content: editor.doc.getValue(),\n },\n });\n };\n\n // watch for changes\n editor.on("change", debounce(run, 1000));\n livecodes.watch("console", ({ method, args }) => {\n const output = document.querySelector("#output");\n output.innerHTML = args.join("\n");\n if (method === "error") {\n output.style.color = "red";\n } else {\n output.style.color = "unset";\n }\n });\n\n await run();\n\x3C/script>\n\n\n\x3Cscript src="https://unpkg.com/codemirror@5.65.15/lib/codemirror.js">\x3C/script>\n\x3Cscript src="https://unpkg.com/codemirror@5.65.15/mode/python/python.js">\x3C/script>\n\n\n` }}