Skip to content

第三方平台

跳转在线代码编辑平台

vitepress-demo-plugin 支持跳转至流行的在线代码编辑平台,如 Stackblitz,Codesandbox 等,有局部开启和全局开启两种方式。

局部开启

<demo /> 组件中添加 stackblitz/codesandbox 属性,可对单个 <demo /> 组件生效。例如:

html
<demo vue="../demos/demo.vue" stackblitz="true" codesandbox="true" />

渲染效果如下:

全局开启

.vitepress/config.ts 中添加如下配置,可对所有 <demo /> 组件生效。

ts
import { defineConfig } from 'vitepress';
import { vitepressDemoPlugin } from 'vitepress-demo-plugin';

export default defineConfig({
  // other configs...
  markdown: {
    config(md) {
      md.use(vitepressDemoPlugin, {
        stackblitz: { 
          show: true, 
        }, 
        codesandbox: { 
          show: true, 
        }, 
      });
    },
  },
});

预设文件及代码

vitepress-demo-plugin 预设了一些文件配置,让你多数情况下不需要单独配置文件就能够打开 stackblitz/codesandbox 等平台去预览你的 <demo />。不同平台及 demo 类型预设的文件及代码如下:

展开查看 stackblitz 平台 Vue 预设文件及代码
html
<!-- 会动态替换为你的 demo 代码 -->
ts
import { createApp } from "vue";
import Demo from "./Demo.vue";

const app = createApp(Demo);
app.mount("#app");
json
{
  "installDependencies": false,
  "startCommand": "npm install && npm run dev"
}
html
<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>
json
{
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "serve": "vite preview"
  },
  "dependencies": {
    "vue": "latest",
    // 会根据你 demo 中的 import 依赖自动添加
  },
  "devDependencies": {
    "vite": "latest",
    "typescript": "latest",
    "@vitejs/plugin-vue": "latest",
    "@vitejs/plugin-vue-jsx": "latest"
  }
}
json
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowImportingTsExtensions": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true
  },
  "include": [
    "src"
  ]
}
ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
export default defineConfig({
  plugins: [vue(), vueJsx()],
});
展开查看 stackblitz 平台 React 预设文件及代码
html
<!-- 会动态替换为你的 demo 代码 -->
ts
import React from "react";
import { createRoot } from "react-dom/client";
import Demo from "./Demo.tsx";

const root = createRoot(document.querySelector("#app"));
root.render(<Demo />);
json
{
  "installDependencies": false,
  "startCommand": "npm install && npm run dev"
}
html
<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>
json
{
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "serve": "vite preview"
  },
  "dependencies": {
    "react": "latest",
    "@emotion/styled": "latest",
    "react-dom": "latest",
    "@emotion/react": "latest"
  },
  "devDependencies": {
    "typescript": "latest",
    "vite": "latest",
    "@vitejs/plugin-react": "latest",
    "@types/react": "latest",
    "@types/react-dom": "latest"
  }
}
json
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowImportingTsExtensions": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react"
  },
  "include": [
    "src"
  ]
}
ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
  plugins: [react()],
});
展开查看 stackblitz 平台 Html 预设文件及代码
html
<!-- 会动态替换为你的 demo 代码 -->
展开查看 codesandbox 平台 Vue 预设文件及代码
html
<!-- 会动态替换为你的 demo 代码 -->
ts
import { createApp } from "vue";
import Demo from "./Demo.vue";

const app = createApp(Demo);
app.mount("#app");
html
<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <div id="app"></div>
  </body>
</html>
json
{
  "version": "0.0.0",
  "private": true,
  "dependencies": {
    "vue": "latest"
  },
  "devDependencies": {
    "typescript": "latest",
    "@vue/cli-plugin-babel": "latest"
  }
}
json
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowImportingTsExtensions": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true
  },
  "include": [
    "src"
  ]
}
展开查看 codesandbox 平台 React 预设文件及代码
html
<!-- 会动态替换为你的 demo 代码 -->
ts
import React from "react";
import { createRoot } from "react-dom/client";
import Demo from "./Demo.tsx";

const root = createRoot(document.querySelector("#app"));
root.render(<Demo />);
html
<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <div id="app"></div>
  </body>
</html>
json
{
  "version": "0.0.0",
  "private": true,
  "dependencies": {
    "react": "latest",
    "@emotion/styled": "latest",
    "react-dom": "latest",
    "@emotion/react": "latest"
  },
  "devDependencies": {
    "typescript": "latest",
    "@types/react": "latest",
    "@types/react-dom": "latest"
  }
}
json
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowImportingTsExtensions": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react"
  },
  "include": [
    "src"
  ]
}
展开查看 codesandbox 平台 Html 预设文件及代码
html
<!-- 会动态替换为你的 demo 代码 -->

自定义文件及代码

vitepress-demo-plugin 支持自定义文件及代码,你可以在 .vitepress/config.ts 中添加 templates 配置,来替换预设文件的代码或者添加新的文件。templates 的类型如下:

ts
type Template = {
  scope: 'global' | 'vue' | 'react' | 'html' | string;
  files: {
    [filename: string]: string; // 代码内容
  };
}

type Templates = Template[];

全类别生效

当设置 scopeglobal 时,表示该模板对所有类型的 demo 组件都生效。以 stackblitz 平台为例:

ts
import { defineConfig } from 'vitepress';
import { vitepressDemoPlugin } from 'vitepress-demo-plugin';

export default defineConfig({
  // other configs...
  markdown: {
    config(md) {
      md.use(vitepressDemoPlugin, {
        stackblitz: {
          show: true,
          templates: [ 
            { 
              scope: 'global', // 针对所有类型的 demo 组件都生效
              files: { 
                // 新添加一个文件
                'print.js': `console.log("Hello!Vitepress Demo Plugin")`, 
                // 替换预设的 index.html 文件
                'index.html': `<!DOCTYPE html><html><body><div id="app"></div></body><script src="print.js"></script></html>`, 
              } 
            }, 
          ], 
        }
      });
    },
  }
});

单类别生效

当设置 scopevue/react/html 时,表示该模板仅对相应类型的 demo 组件生效。以下面的 demo 为例,仅对 Vue 类型的 demo 组件生效:

ts
import { defineConfig } from 'vitepress';
import { vitepressDemoPlugin } from 'vitepress-demo-plugin';

export default defineConfig({
  // other configs...
  markdown: {
    config(md) {
      md.use(vitepressDemoPlugin, {
        stackblitz: {
          show: true,
          templates: [
            {
              scope: 'global', // 针对所有类型的 demo 组件都生效
              files: {
                // 新添加一个文件
                'print.js': `console.log("Hello!Vitepress Demo Plugin")`,
                // 替换预设的 index.html 文件
                'index.html': `<!DOCTYPE html><html><body><div id="app"></div></body><script src="print.js"></script></html>`,
              },
            },
            { 
              scope: 'vue', // 仅针对 Vue 类型的 demo 组件生效
              files: { 
                // 替换预设的 main.ts 文件
                'main.ts': `import { createApp } from "vue";\nimport Demo from "./Demo.vue";\nconst app = createApp(Demo);\napp.mount("#app");`, 
              } 
            }, 
          ]
        }
      });
    },
  }
});

自定义 demo 生效范围

你也可以自定义 scope 的名称,表示该模板仅对相应类型的 demo 组件生效。例如:

ts
import { defineConfig } from 'vitepress';
import { vitepressDemoPlugin } from 'vitepress-demo-plugin';

export default defineConfig({
  // other configs...
  markdown: {
    config(md) {
      md.use(vitepressDemoPlugin, {
        stackblitz: {
          show: true,
          templates: [
            {
              scope: 'global', // 针对所有类型的 demo 组件都生效
              files: {
                // 新添加一个文件
                'print.js': `console.log("Hello!Vitepress Demo Plugin")`,
                // 替换预设的 index.html 文件
                'index.html': `<!DOCTYPE html><html><body><div id="app"></div></body><script src="print.js"></script></html>`,
              },
            },
            { 
              scope: 'vue', // 仅针对 Vue 类型的 demo 组件生效
              files: { 
                // 替换预设的 main.ts 文件
                'main.ts': `import { createApp } from "vue";\nimport Demo from "./Demo.vue";\nconst app = createApp(Demo);\napp.mount("#app");`, 
              } 
            },
            { 
              scope: 'myScope', // 仅针对 Vue 类型的 demo 组件生效
              files: { 
                // 替换预设的 main.ts 文件
                'main.ts': `console.log("this is a custom template")`, 
              } 
            }, 
          ]
        }
      });
    },
  }
});

现在你定义了一个名为 myScope 的模板,你可以通过 scope 属性来让该模版对特定的 demo 组件生效。

html
<demo vue="../demos/demo.vue" scope="myScope" />