Frontend Demo
About 2234 wordsAbout 7 min
2025-01-08
Legacy Frontend Code Demo Deprecated - Please Migrate to New Solution
The legacy solution was provided by vuepress-plugin-md-enhance. We appreciate its support for code demos in the past. The code demo functionality in vuepress-plugin-md-enhance
will be migrated to vuepress/ecosystem. For details, please refer to vuepress/ecosystem#293.
Why Redesign?
Frontend code demos are a highly useful feature, but the legacy implementation did not align with actual usage scenario expectations.
In the legacy solution, for example, vue-demo
only supported simple Vue component demonstrations and could not directly import dependencies from the project. It relied on loading external scripts for additional functionality and did not provide full support for Vue SFC, being limited to simple code demonstrations.
Furthermore, script code compilation occurred in the browser runtime. It required loading babel
from a CDN first, then performing the transformation via babel
, which introduced additional waiting time. Additionally, for internal enterprise projects within an intranet environment that cannot access external resources, the demos failed to display properly.
In the new solution, all demo code is compiled and transformed during the Node.js runtime. Therefore, demo code can be displayed directly in the browser runtime without extra waiting time. Leveraging Node.js's powerful capabilities, it fully supports all features of Vue SFC and allows direct import of project dependencies, enabling richer demonstrations that better match real-world usage scenarios.
Overview
This feature supports embedding code demonstration functionality within pages. A frontend code demo consists of two main areas: Render Area and Code Area.
The Render Area displays the execution results of the code, including UI rendering and interactions. The Code Area displays the source code and is collapsed by default.
The theme provides support for three different types of frontend code demos:
- Vue Component Demo: Supports demonstrations of
Vue
components. Write your demo code as you would aVue
component. It can be used to demonstrate external dependencies like component libraries orComposables API
. - Markdown Demo: Supports demonstrations of
Markdown
. - Normal Code Demo: Supports native
HTML
+JS/TS
+CSS/Less/Sass/Stylus
code demos. Write your demo code as you would a web page.
The theme also provides two different methods for writing demo code:
Embed Demo Code Files:
@[demo type](url)
Use simple embedding syntax to import demo code from files.
Inline Demo Code within Demo Container:
::: demo type ``` [lang] code ``` :::
Write demo code directly within the markdown file, wrapped in a
demo
container.
Configuration
Frontend code demos are powered by vuepress-plugin-md-power.
Frontend code demos are disabled by default. You can enable them via configuration.
export default defineUserConfig({
theme: plumeTheme({
markdown: {
demo: true,
},
})
})
Language Support
Code demos support the following languages:
- javascript
- typescript
- html
- css
- less
- sass
- stylus
For CSS preprocessor languages, you need to install the corresponding preprocessor in your project, such as less
, sass
, or stylus
.
Embed Syntax
Different code demos use the same embed syntax, allowing you to quickly grasp their usage.
<!-- Syntax -->
@[demo](url)
@[demo [type]](url)
@[demo [type] title="" desc="" expanded code-setting=""](url)
@[demo](url)
is a fixed syntax format.
[type]
indicates the type and supports three different values:
normal
: Normal code demo type. This is the default type when the[type]
parameter is omitted.vue
: Vue component demo type.markdown
: Markdown demo type.
url
indicates the path to the demo code file, which can be relative or absolute.
- Relative paths start with
./
or../
and are relative to the current markdown file's path. - Absolute paths start with
/
and are resolved from the VuePress source directory path.
<!-- Normal Code Demo -->
@[demo](./demo/normal.html)
@[demo normal](./demo/normal.html)
@[demo](/.vuepress/demo/normal.html)
<!-- Vue Component Demo -->
@[demo vue](./demo/Counter.vue)
@[demo vue](./demo/Counter.ts)
@[demo](/.vuepress/demo/Counter.vue)
<!-- Markdown Demo -->
@[demo markdown](./demo/example.md)
@[demo markdown](/.vuepress/demo/example.md)
Additional parameters:
title="xxx"
: Demo title.desc="xxx"
: Demo description.expanded
: Expand the code area.code-setting="xxx"
: Code settings. The value will be appended after ``` [lang]` and is used to add configurations to the code block.code-setting=":lines-number"
will add:lines-number
after the code block, enabling line numbers.code-setting=":collapsed-lines=10"
will add:collapsed-lines=10
after the code block, causing the code block to be collapsed starting from line 10.
@[demo vue expanded title="Title" desc="Description" code-setting=":collapsed-lines=10"](./demo/Counter.vue)
Demo Container Inline Demo
Demo container inline demos use the demo
container to wrap the demo code, allowing quick writing of demo code within the markdown file:
::: demo [type] title="" desc="" expanded
<!-- Code Block -->
:::
All parameters are the same as the @[demo](url)
syntax.
<!-- Normal Code Demo -->
::: demo
```html
<!-- html code -->
```
``` js
// js code
```
``` css
/* css code */
```
:::
<!-- Vue Component Demo -->
::: demo vue
``` vue
<!-- vue code -->
```
:::
<!-- Markdown Demo -->
::: demo markdown
``` md
<!-- markdown code -->
```
:::
You can also wrap code blocks with the ::: code-tabs
container within the ::: demo
container for better interactive presentation.
:::: demo
::: code-tabs
@tab HTML
```html
<!-- html code -->
```
@tab javascript
``` js
// js code
```
@tab css
``` css
/* css code */
```
:::
:::::
When using TypeScript or Less/Sass/Stylus
, simply modify the value of ``` [lang]
:
:::: demo
::: code-tabs
@tab HTML
```html
<!-- html code -->
```
@tab Typescript
``` ts
// ts code
```
@tab Scss
``` scss
/* scss code */
```
:::
:::::
Vue Component Demo
Vue component demo is a powerful feature with no restrictions on the demo code—it ultimately depends on the bundler
's support for Vue. You can directly import dependencies installed in your project within the demo code, just as you would when writing a component in a Vue project.
Therefore, you can use it directly to provide demonstration examples for your component library or for your Composables API
.
Embed Syntax
You can directly embed a Vue component demo in a page using the following method:
Input:
@[demo vue title="Counter" desc="Click the +1 button to increment the counter by 1"](./demo/Counter.vue)
View ./demo/Counter.vue
Code
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<div class="counter">
<p>
Counter: {{ count }}
</p>
<button type="button" class="btn" @click="count += 1">
+ 1
</button>
</div>
</template>
<style scoped>
.btn {
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
}
</style>
Output:
Counter
Click the +1 button to increment the counter by 1
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<div class="counter">
<p>
Counter: {{ count }}
</p>
<button type="button" class="btn" @click="count += 1">
+ 1
</button>
</div>
</template>
<style scoped>
.btn {
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
}
</style>
You can also embed a Vue component written in .ts
:
Input:
@[demo vue title="Counter" desc="Click the +1 button to increment the counter by 1"](./demo/Counter.ts)
View ./demo/Counter.ts
Code
import { defineComponent, h, ref } from 'vue'
import styles from './Counter.module.css'
export default defineComponent({
setup() {
const count = ref(0)
return () => h('div', {
class: 'counter',
}, [
h('p', `Counter: ${count.value}`),
h('button', {
type: 'button',
class: styles.btn,
onClick: () => count.value += 1,
}, '+ 1'),
])
},
})
.btn {
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
}
Output:
Counter
Click the +1 button to increment the counter by 1
import { defineComponent, h, ref } from 'vue'
import styles from './Counter.module.css'
export default defineComponent({
setup() {
const count = ref(0)
return () => h('div', {
class: 'counter',
}, [
h('p', `Counter: ${count.value}`),
h('button', {
type: 'button',
class: styles.btn,
onClick: () => count.value += 1,
}, '+ 1'),
])
},
})
For components written in .js/.ts
, use CSS Module
to write styles for style isolation.
You can import external dependencies in the demo code. Example using useToggle()
from @vueuse/core
:
Input:
@[demo vue title="useToggle" desc="useToggle() Demo"](./demo/Toggle.vue)
./demo/Toggle.vue
<script setup lang="ts">
import { useToggle } from '@vueuse/core'
const [value, toggle] = useToggle()
</script>
<template>
<div>
<p>Value: {{ value ? 'ON' : 'OFF' }}</p>
<div style="display: flex;gap: 16px;">
<button class="btn" @click="toggle()">
Toggle
</button>
<button class="btn" @click="value = true">
Set On
</button>
<button class="btn" @click="value = false">
Set Off
</button>
</div>
</div>
</template>
<style scoped>
.btn {
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
}
</style>
Output:
useToggle
useToggle() Demo
<script setup lang="ts">
import { useToggle } from '@vueuse/core'
const [value, toggle] = useToggle()
</script>
<template>
<div>
<p>Value: {{ value ? 'ON' : 'OFF' }}</p>
<div style="display: flex;gap: 16px;">
<button class="btn" @click="toggle()">
Toggle
</button>
<button class="btn" @click="value = true">
Set On
</button>
<button class="btn" @click="value = false">
Set Off
</button>
</div>
</div>
</template>
<style scoped>
.btn {
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
}
</style>
Container Syntax
Using the demo
container to wrap demo code in a markdown file allows for quick demo code writing:
Input:
Expand to view full code
::: demo vue title="Counter" desc="Click the +1 button to increment the counter by 1"
```vue
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<div class="counter">
<p>Counter: {{ count }}</p>
<button type="button" class="btn" @click="count += 1">
+ 1
</button>
</div>
</template>
<style scoped>
.btn {
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
}
</style>
```
:::
Output:
Counter
Click the +1 button to increment the counter by 1
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<div class="counter">
<p>Counter: {{ count }}</p>
<button type="button" class="btn" @click="count += 1">
+ 1
</button>
</div>
</template>
<style scoped>
.btn {
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
}
</style>
Warning
The Vue demo container syntax also supports embedding demo code using the .js/ts + css
approach, but this is not recommended by the theme. Styles cannot be isolated, which may lead to style pollution.
Reference Example
:::: demo vue title="Title" desc="Description"
::: code-tabs
@tab Counter.ts
```ts
import { defineComponent, ref } from 'vue'
export default defineComponent({
// code
})
```
@tab Counter.css
```css
/* css code */
```
:::
::::
Normal Code Demo
Normal code demos support html
, css/less/sass/stylus
, and js/ts
languages.
They are suitable for relatively simple code demonstrations, such as a style rendering effect, an interaction effect, or a functionality.
Normal code demos also support jumping to CodePen
and jsFiddle
for viewing.
Additionally, they support importing third-party libraries via external links, such as jQuery
or dayjs
.
Overly complex demonstrations are not recommended.
Embed Syntax
When using the embed syntax, use .html
as the file suffix for the imported demo code file. In the .html
file, you can write the demo code as you would an HTML page:
<!-- html code -->
<div id="app">
Demo Content
<div>
<!-- Script content, use lang attribute to set language, defaults to js -->
<script lang="ts">
</script>
<!-- Style content, use lang attribute to set language, defaults to css -->
<style lang="css">
</style>
<!-- Optional configuration file in json format -->
<script type="config">
{
"jsLib": [],
"cssLib": []
}
</script>
Each section is optional. However, note that multiple identical sections are not supported. The order of sections does not matter. Content outside of <script>
and <style>
is considered HTML code.
You can declare additional dependency resources to load using JSON format within <script type="config"></script>
.
For example, loading jQuery
and normalize.css
:
<div>xxxx</div>
<script type="config">
{
"jsLib": [
"https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"
],
"cssLib": [
"https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.min.css"
]
}
</script>
A conventional example:
Input:
@[demo title="Example" desc="This is a conventional demo"](./demo/normal.html)
View ./demo/normal.html
Code
<div id="app">
<h3>vuepress-theme-plume</h3>
</div>
<script lang="ts">
const a = 'So Awesome!'
const app = document.querySelector('#app')
app.appendChild(document.createElement('small')).textContent = a
</script>
<style lang="css">
#app {
font-size: 2em;
text-align: center;
}
</style>
Output:
Example
This is a conventional demo
<div id="app">
<h3>vuepress-theme-plume</h3>
</div>
const a = 'So Awesome!'
const app = document.querySelector('#app')
app.appendChild(document.createElement('small')).textContent = a
#app {
font-size: 2em;
text-align: center;
}
Example introducing jQuery
, dayjs
, and normalize.css
:
Input:
@[demo title="Example" desc="This is a conventional demo"](./demo/normal-lib.html)
View ./demo/normal-lib.html
Code
<div id="app">
<h3>vuepress-theme-plume</h3>
<p id="message"></p>
<datetime id="datetime"></datetime>
</div>
<script>
$('#message').text('So Awesome!')
const datetime = $('#datetime')
setInterval(() => {
datetime.text(dayjs().format('YYYY-MM-DD HH:mm:ss'))
}, 1000)
</script>
<style lang="css">
#app {
font-size: 2em;
text-align: center;
}
</style>
<script type="config">
{
"jsLib": [
"https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js",
"https://cdn.jsdelivr.net/npm/dayjs@1.11.13/dayjs.min.js"
],
"cssLib": ["https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.min.css"]
}
</script>
Output:
Example
This is a conventional demo
<div id="app">
<h3>vuepress-theme-plume</h3>
<p id="message"></p>
<datetime id="datetime"></datetime>
</div>
$('#message').text('So Awesome!')
const datetime = $('#datetime')
setInterval(() => {
datetime.text(dayjs().format('YYYY-MM-DD HH:mm:ss'))
}, 1000)
#app {
font-size: 2em;
text-align: center;
}
Container Syntax
Using the demo container to wrap demo code in a markdown file allows for quick demo code writing:
Expand to view full example code
::: demo title="Example" desc="Description" expanded
```json
{
"jsLib": [],
"cssLib": []
}
```
```html
<!-- html code -->
```
```js
// js code
```
```css
/* css code */
```
:::
```
You can also wrap ::: code-tabs
within ::: demo
for better code block presentation:
Expand to view full example code
:::: demo title="Example" desc="Description" expanded
```json
{
"jsLib": [],
"cssLib": []
}
```
::: code-tabs
@tab HTML
```html
<!-- html code -->
```
@tab Javascript
```js
// js code
```
@tab CSS
```css
/* css code */
```
:::
::::
```
A conventional container example:
Input:
Expand to view full example code
:::: demo title="Conventional Example" desc="A conventional example"
::: code-tabs
@tab HTML
```html
<div id="app">
<h3>vuepress-theme-plume</h3>
</div>
```
@tab Javascript
```js
const a = 'So Awesome!'
const app = document.querySelector('#app')
app.appendChild(document.createElement('small')).textContent = a
```
@tab CSS
```css
#app {
font-size: 2em;
text-align: center;
}
```
:::
::::
Output:
Conventional Example
A conventional example
<div id="app">
<h3>vuepress-theme-plume</h3>
</div>
const a = 'So Awesome!'
const app = document.querySelector('#app')
app.appendChild(document.createElement('small')).textContent = a
#app {
font-size: 2em;
text-align: center;
}
Example introducing jQuery, dayjs, and normalize.css:
Input:
Expand to view full example code
:::: demo title="Conventional Example" desc="A conventional example"
```json
{
"jsLib": [
"https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js",
"https://cdn.jsdelivr.net/npm/dayjs@1.11.13/dayjs.min.js"
],
"cssLib": ["https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.min.css"]
}
```
::: code-tabs
@tab HTML
```html
<div id="app">
<h3>vuepress-theme-plume</h3>
<p id="message"></p>
<datetime id="datetime"></datetime>
</div>
```
@tab Javascript
```js
$('#message').text('So Awesome!')
const datetime = $('#datetime')
setInterval(() => {
datetime.text(dayjs().format('YYYY-MM-DD HH:mm:ss'))
}, 1000)
```
@tab CSS
```css
#app {
font-size: 2em;
text-align: center;
}
```
:::
::::
Output:
Conventional Example
A conventional example
<div id="app">
<h3>vuepress-theme-plume</h3>
<p id="message"></p>
<datetime id="datetime"></datetime>
</div>
$('#message').text('So Awesome!')
const datetime = $('#datetime')
setInterval(() => {
datetime.text(dayjs().format('YYYY-MM-DD HH:mm:ss'))
}, 1000)
#app {
font-size: 2em;
text-align: center;
}
Markdown Demo
Demonstrate markdown source code and rendering results within a page.
Embed Syntax
Input:
@[demo markdown title="Bulletin Board" desc="Bulletin Board Code Example"](/.vuepress/bulletin.md)
Expand to view /.vuepress/bulletin.md
Code
::: center
**QQ 交流群:** [792882761](https://qm.qq.com/q/FbPPoOIscE)
{width="618" height="616" style="width: 200px"}
您在使用过程中遇到任何问题,欢迎通过 [issue](https://github.com/pengzhanbo/vuepress-theme-plume/issues/new/choose) 反馈。也欢迎加入我们的 QQ 交流群一起讨论。
:::
Output:
Bulletin Board
Bulletin Board Code Example
::: center
**QQ 交流群:** [792882761](https://qm.qq.com/q/FbPPoOIscE)
{width="618" height="616" style="width: 200px"}
您在使用过程中遇到任何问题,欢迎通过 [issue](https://github.com/pengzhanbo/vuepress-theme-plume/issues/new/choose) 反馈。也欢迎加入我们的 QQ 交流群一起讨论。
:::
Container Syntax
Input:
Expand to view full code
:::: demo markdown title="Bulletin Board" desc="Bulletin Board Code Example"
```md
::: center
**QQ Group:** [792882761](https://qm.qq.com/q/FbPPoOIscE)
{width="618" height="616" style="width: 200px"}
If you encounter any issues during use, please feel free to provide feedback via [issue](https://github.com/pengzhanbo/vuepress-theme-plume/issues/new/choose). You are also welcome to join our QQ group for discussion.
:::
```
::::
Output:
Bulletin Board
Bulletin Board Code Example
::: center
**QQ Group:** [792882761](https://qm.qq.com/q/FbPPoOIscE)
{width="618" height="616" style="width: 200px"}
If you encounter any issues during use, please feel free to provide feedback via [issue](https://github.com/pengzhanbo/vuepress-theme-plume/issues/new/choose). You are also welcome to join our QQ group for discussion.
:::