├── .commitlintrc.js ├── .github └── workflows │ ├── deploy_docs.yml │ └── release_package.yml ├── .gitignore ├── .npmignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README.zh-CN.md ├── docs ├── .vuepress │ ├── CustomDemoBlock.vue │ ├── config.js │ ├── enhanceApp.js │ ├── public │ │ └── contributor.png │ └── styles │ │ └── index.styl ├── README.md ├── complex.md ├── options.md ├── started.md └── zh │ ├── README.md │ ├── complex.md │ ├── options.md │ └── started.md ├── package.json ├── src ├── DemoBlock.vue ├── common │ ├── containers.js │ ├── fence.js │ ├── render.js │ └── util.js ├── enhanceAppFile.js ├── i18n │ └── default_lang.json └── index.js └── yarn.lock /.commitlintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | '@commitlint/config-conventional' 4 | ], 5 | rules: { 6 | } 7 | }; -------------------------------------------------------------------------------- /.github/workflows/deploy_docs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy plugin docs 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | build-and-deploy-docs: 8 | runs-on: ubuntu-18.04 9 | steps: 10 | - uses: actions/checkout@master 11 | 12 | - name: Setup Node 13 | uses: actions/setup-node@v1 14 | with: 15 | node-version: '12.x' 16 | 17 | - name: Build with vuepress 18 | run: | 19 | yarn --frozen-lockfile 20 | yarn docs:build 21 | 22 | - name: Deploy to gh-pages 23 | uses: peaceiris/actions-gh-pages@v3 24 | with: 25 | github_token: ${{ secrets.GITHUB_TOKEN }} 26 | publish_dir: docs/.vuepress/dist/vuepress-plugin-demo-container/ 27 | 28 | - name: Deploy to server 29 | uses: easingthemes/ssh-deploy@v2.1.1 30 | env: 31 | SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }} 32 | ARGS: "-rltgoDzvO --delete" 33 | SOURCE: "docs/.vuepress/dist/vuepress-plugin-demo-container/" 34 | REMOTE_HOST: ${{ secrets.REMOTE_HOST }} 35 | REMOTE_USER: ${{ secrets.REMOTE_USER }} 36 | TARGET: ${{ secrets.REMOTE_TARGET }} -------------------------------------------------------------------------------- /.github/workflows/release_package.yml: -------------------------------------------------------------------------------- 1 | name: Node.js Package 2 | on: 3 | push: 4 | tags: 5 | - v* 6 | jobs: 7 | publish-plugin: 8 | runs-on: ubuntu-18.04 9 | steps: 10 | - uses: actions/checkout@master 11 | # Setup .npmrc file to publish to npm 12 | - name: Setup Node 13 | uses: actions/setup-node@v1 14 | with: 15 | node-version: '12.x' 16 | registry-url: 'https://registry.npmjs.org' 17 | 18 | - run: npm install 19 | - run: npm publish 20 | env: 21 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | docs/.vuepress 2 | .commitlintrc.js 3 | *.sh -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ## [0.2.0](https://github.com/calebman/vuepress-plugin-demo-container/compare/v0.1.1...v0.2.0) (2020-08-19) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * **demoblick:** solve the problem of code line number style ([675666e](https://github.com/calebman/vuepress-plugin-demo-container/commit/675666eac7c20bc853be8b328b4b1134d91fa1af)), closes [#4](https://github.com/calebman/vuepress-plugin-demo-container/issues/4) 11 | 12 | ### [0.1.1](https://github.com/calebman/vuepress-plugin-demo-container/compare/v0.1.0...v0.1.1) (2020-07-06) 13 | 14 | 15 | ### Bug Fixes 16 | 17 | * **demoblock.vue:** fix plugin usage bug ([2d8ded9](https://github.com/calebman/vuepress-plugin-demo-container/commit/2d8ded99d7cd1c9f8e345ff07a6ad66650d02182)), closes [#3](https://github.com/calebman/vuepress-plugin-demo-container/issues/3) 18 | 19 | ## [0.1.0](https://github.com/calebman/vuepress-plugin-demo-container/compare/v0.0.1...v0.1.0) (2020-06-01) 20 | 21 | 22 | ### Features 23 | 24 | * support custom demo component, use demo、description、source slots ([6cc2ec4](https://github.com/calebman/vuepress-plugin-demo-container/commit/6cc2ec44afc44e0d69660f47b903cfda4c69ca29)) 25 | * support multi-language configuration ([6805af5](https://github.com/calebman/vuepress-plugin-demo-container/commit/6805af5bc607d645931270b21efa647fd542156f)) 26 | 27 | ### 0.0.1 (2020-05-30) 28 | 29 | 30 | ### Features 31 | 32 | * **core:** initialize the plugin code ([7b6581b](https://github.com/calebman/vuepress-plugin-demo-container/commit/7b6581b3877c0c8afecb4ac5ab73c898269827d6)) 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018-present, Yuxi (Evan) You 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | [点此查看中文简介](https://github.com/calebman/vuepress-plugin-demo-container/blob/master/README.zh-CN.md) 4 | 5 | `Demo Container` is a `Vuepress-based` plug-in, which can help you add `Vue` examples when writing documents. Its original intention is to reduce the difficulty of adding some related examples when writing component documents. 6 | 7 | Using Vuepress to write component examples has the following embarrassment: 8 | 1. Component examples and sample code are essentially the same, but need to be written twice; 9 | 2. Vuepress cannot render the `export default {}` code block in Markdown; 10 | 11 | The Demo Container refers to Element UI's document rendering and implements the same syntax as it can be used to write sample syntax directly in Markdown. 12 | * Element UI ColorPicker component **documentation example**, [click here to view](https://github.com/ElemeFE/element/blob/dev/examples/docs/en-US/color-picker.md) 13 | * Element UI ColorPicker component **document sample preview**, [click here to view](https://element.eleme.cn/2.0/#/en-US/component/color-picker)。 14 | 15 | [Click here for examples and documentation](https://calebman.github.io/vuepress-plugin-demo-container/) -------------------------------------------------------------------------------- /README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | `Demo Container` 是一个基于 `Vuepress` 的插件,它可以帮助你在编写文档的时候增加 `Vue` 示例,它的诞生初衷是为了降低编写组件文档时增加一些相关示例的难度。 4 | 5 | 使用 Vuepress 编写组件示例有以下尴尬之处: 6 | 1. 组件示例和示例代码本质上一样,却需要写两遍; 7 | 2. Vuepress 无法渲染 Markdown 中的 `export default {}` 代码块; 8 | 9 | Demo Container 参考了 Element UI 的文档渲染,实现了和它一样的,可在 Markdown 中直接编写示例的语法。 10 | * Element UI ColorPicker 组件的**文档编写示例**,[点此查看](https://github.com/ElemeFE/element/blob/dev/examples/docs/zh-CN/color-picker.md) 11 | * Element UI ColorPicker 组件的**文档示例预览**,[点此查看](https://element.eleme.cn/2.0/#/zh-CN/component/color-picker) 12 | 13 | [点此查看示例与使用文档](https://docs.chenjianhui.site/vuepress-plugin-demo-container/zh/) -------------------------------------------------------------------------------- /docs/.vuepress/CustomDemoBlock.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 30 | 31 | 34 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const isProd = process.env.NODE_ENV === 'production' 3 | module.exports = { 4 | base: isProd ? '/vuepress-plugin-demo-container/' : '/', 5 | port: '6700', 6 | dest: 'docs/.vuepress/dist/vuepress-plugin-demo-container/', 7 | markdown: { 8 | lineNumbers: false 9 | }, 10 | locales: { 11 | '/': { 12 | lang: 'en-US', 13 | title: 'Demo Container', 14 | description: 'plugin for vuepress to display vue demo' 15 | }, 16 | '/zh/': { 17 | lang: 'zh-CN', 18 | title: 'Demo Container', 19 | description: '用于编写 vue 组件示例的 vuepress 插件' 20 | } 21 | }, 22 | themeConfig: { 23 | repo: 'calebman/vuepress-plugin-demo-container', 24 | editLinks: false, 25 | docsDir: 'docs', 26 | locales: { 27 | '/': { 28 | label: 'English', 29 | selectText: 'Languages', 30 | editLinkText: 'Edit this page on GitHub', 31 | lastUpdated: 'Last Updated', 32 | sidebar: { 33 | '/': genSidebarConfig('Guide') 34 | } 35 | }, 36 | '/zh/': { 37 | label: '简体中文', 38 | selectText: '选择语言', 39 | editLinkText: '在 GitHub 上编辑此页', 40 | lastUpdated: '上次更新', 41 | sidebar: { 42 | '/zh/': genSidebarConfig('指南') 43 | } 44 | } 45 | } 46 | }, 47 | plugins: [ 48 | [ 49 | require('../../src'), 50 | { 51 | component: 'DemoBlock', 52 | locales: [ 53 | { 54 | "lang": "zh-CN", 55 | "demo-block": { 56 | "hide-text": "隐藏", 57 | "show-text": "显示", 58 | "copy-text": "复制", 59 | "copy-success": "成功" 60 | } 61 | }, 62 | { 63 | "lang": "en-US", 64 | "demo-block": { 65 | "hide-text": "Hide", 66 | "show-text": "Expand", 67 | "copy-text": "Copy", 68 | "copy-success": "Successful" 69 | } 70 | } 71 | ] 72 | } 73 | ] 74 | ], 75 | configureWebpack: { 76 | resolve: { 77 | alias: { 78 | '@assets': path.resolve(__dirname, './public/assets') 79 | } 80 | } 81 | } 82 | } 83 | 84 | function genSidebarConfig (title) { 85 | return [ 86 | { 87 | title, 88 | collapsable: false, 89 | children: [ 90 | '', 91 | 'started', 92 | 'options', 93 | 'complex', 94 | ] 95 | } 96 | ] 97 | } -------------------------------------------------------------------------------- /docs/.vuepress/enhanceApp.js: -------------------------------------------------------------------------------- 1 | import Antd from 'ant-design-vue' 2 | import CustomDemoBlock from './CustomDemoBlock.vue' 3 | import 'ant-design-vue/dist/antd.css' 4 | export default ({ 5 | Vue 6 | }) => { 7 | Vue.component('CustomDemoBlock', CustomDemoBlock) 8 | Vue.use(Antd) 9 | } -------------------------------------------------------------------------------- /docs/.vuepress/public/contributor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calebman/vuepress-plugin-demo-container/d049d005f1012565e78fefa81d85faef2d5e81c8/docs/.vuepress/public/contributor.png -------------------------------------------------------------------------------- /docs/.vuepress/styles/index.styl: -------------------------------------------------------------------------------- 1 | p { 2 | margin-top: 16px !important; 3 | } 4 | 5 | .theme-default-content ul { 6 | margin-top: 16px !important; 7 | } -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | `Demo Container` is a `Vuepress-based` plug-in, which can help you add `Vue` examples when writing documents. Its original intention is to reduce the difficulty of adding some related examples when writing component documents. 4 | 5 | ::: warning Using Vuepress to write component examples has the following embarrassment: 6 | Component examples and sample code are essentially the same, but need to be written twice; 7 | 8 | Vuepress cannot render multiple `export default {}` code blocks in Markdown; 9 | ::: 10 | 11 | The Demo Container refers to Element UI's document rendering and implements the same syntax as it can be used to write sample syntax directly in Markdown. 12 | * Element UI ColorPicker component **documentation example**,[click here to view](https://github.com/ElemeFE/element/blob/dev/examples/docs/en-US/color-picker.md) 13 | * Element UI ColorPicker component **document sample preview**,[click here to view](https://element.eleme.cn/2.0/#/en-US/component/color-picker)。 14 | 15 | 16 | ## How does it work? 17 | 18 | The Demo Container uses Vuepress's [chainMarkdown, extendMarkdown API](https://vuepress.vuejs.org/plugin/option-api.html#extendmarkdown) to expand its internal markdown object and does the following: 19 | 20 | 1. Based on [markdown-it-container](https://github.com/markdown-it/markdown-it-container), a plug-in that recognizes the following code blocks is built 21 | ``` 22 | :::demo xxx 23 | xxx 24 | ::: 25 | ``` 26 | Wrap the ` ` component for it, and pick up the sample code using `` comments Cache mode, wait for subsequent reading, specific implementation [click here to view](https://github.com/calebman/vuepress-plugin-demo-container/blob/master/src/common/container.js); 27 | 28 | 2. Expand the markdown.render method, based on its rendering results, read the sample code annotated by `pre-render-demo` and use [vue-template-compiler](https://github.com/vuejs/vue/tree/dev/packages/vue-template-compiler) compile it into a Redner Function and introduce it as a subcomponent of the entire sample page. The output of the expanded method is a code block that conforms to Vue Template syntax, specific implementation [click here to view](https://github.com/calebman/vuepress-plugin-demo-container/blob/master/src/common/render.js); 29 | 30 | 3. The sample page code will be processed by [vue-loader](https://vue-loader.vuejs.org/guide/) and compiled into the final document 31 | 32 | ## What is the rendering effect? 33 | 34 | ::: tip The following is an example of a component rendered using the Demo Container plugin 35 | The display effect refers to the implementation of Element UI document component [demo-block.vue](https://github.com/ElemeFE/element/blob/dev/examples/components/demo-block.vue) 36 | ::: 37 | 38 | ::: demo This example refers to the [GitHub submission](https://vuejs.org/v2/examples/commits.html) implementation in the example of the `Vue` official document, uses the Github API to get the latest submission data of the repository, and displays them in a list. 39 | ```html 40 | 75 | 76 | 136 | 137 | 170 | ``` 171 | ::: 172 | 173 | ## Why not...? 174 | 175 | ::: tip Are there any other options 176 | Before I created the Demo Container, I searched for plug-ins that meet the above requirements as much as possible, and found some useful plugins. If there are other available plug-ins that have been omitted by the author, I can add it by mentioning [Issus](https://github.com/calebman/vuepress-plugin-demo-container/issues). Thank you very much. 177 | ::: 178 | 179 | ### vuepress-plugin-demo-block 180 | 181 | Repository [click here to view](https://github.com/xiguaxigua/vuepress-plugin-demo-block),the **use of this plugin is exactly the same as the author's ideal way**, and its implementation principle is 182 | 183 | Through [Vuepress clientRootMixin API](https://vuepress.vuejs.org/plugin/option-api.html#clientrootmixin) mixed into the mounted and updated life cycle of the page, read the sample code to separate the `template`,` script`, `style` code blocks: 184 | * The code block wrapped by the template is inserted directly into the example node; 185 | * The code block wrapped by script compiles the Vue object through Vue.extend, and then calls its $ mount () method to mount it to the sample dom; 186 | * The code block wrapped in style is inserted directly into the document; 187 | 188 | The problem with this is that **template code blocks cannot contain globally registered components in Vuepress**, and writing component library examples will necessarily rely on globally registered components. 189 | 190 | ### vuepress-plugin-demo-code 191 | 192 | Repository [click here to view](https://github.com/BuptStEve/vuepress-plugin-demo-code),The plug-in's **use method is the same as the demo-block**. The workflow of the plugin is similar to the Demo Container. Its implementation principle is: 193 | 194 | Extend the internal markdown object through [Vuepress extendMarkdown API](https://vuepress.vuejs.org/plugin/option-api.html#extendMarkdown), and then identify the `::: demo xxx :::` code block, and insert the wrapped sample code directly into the Markdown document to be processed by vue-loader. 195 | 196 | The problem with this is that **only the `export default {}` block of the first example will be successfully recognized**, because vue-loader will only process the first match to the package when compiling a single file `` Code block. 197 | 198 | ### vuepress-plugin-extract-code 199 | 200 | Repository [click here to view](https://github.com/vuepress-reco/vuepress-plugin-extract-code),The usage of this plugin is not consistent with the author's ideal way, but it **resolves the problem that component examples and code need to be written twice**, and its implementation principle is: 201 | 202 | Provide a RecoDemo component for constructing sample pages in Markdown, and add a plug-in to Vuepress's internal markdown through [Vuepress chainMarkdown API](https://vuepress.vuejs.org/plugin/option-api.html#chainmarkdown). This plug-in is responsible for manually parsing `<<< @/docs/.vuepress/demo/demo.vue?template` syntax, identify the code block and add it to the sample code description, if you do n’t know the syntax, you can click [click here to view the description](https://vuepress.vuejs.org/guide/markdown.html#%E5%AF%BC%E5%85%A5%E4%BB%A3%E7%A0%81%E6%AE%B5). 203 | 204 | This takes advantage of the features of Vuepress's ability to compile Vue components, and there is no problem in use, but if a component usage document contains multiple examples, even if the single example code is very small, you have to create a file for it and register it globally. Vuepress, **The problem is troublesome maintenance**. 205 | 206 | ## Contributor 207 | 208 |

209 | 210 | 211 | 212 | 213 | 214 |

-------------------------------------------------------------------------------- /docs/complex.md: -------------------------------------------------------------------------------- 1 | # Complex example 2 | 3 | Here are two examples of complex scenarios that Demo Container can support well. The specific effects are as follows: 4 | 5 | ## TodoMVC example 6 | 7 | `demo-container` provides good support for the example. This example is taken from the more complicated` TodoMVC` in the example of the `Vue` official document, and its display effect [Click here to view](https://vuejs.org/v2/examples/todomvc.html) 8 | 9 | After copying the official code and transforming it into `template`, use the following syntax to quote 10 | 11 | ```html 12 | ::: demo `TodoMVC` is an example provided in the official documentation of` Vue`, which covers many `API` calls such as` data, watch, computed, methods, directives`, etc. 13 | ```html 14 | // Omit TodoMVC related code... 15 | ` ` ` <= Remove the left space 16 | ::: 17 | ``` 18 | 19 | The rendering result is as follows 20 | 21 | ::: demo `TodoMVC` is an example provided in the official documentation of` Vue`, which covers many `API` calls such as` data, watch, computed, methods, directives`, etc. 22 | ```html 23 | 99 | 100 | 261 | 262 | 638 | ``` 639 | ::: 640 | 641 | ## Example of combined component library 642 | 643 | As a **component example plug-in**, most of its usage scenarios are used as component library document sample construction when developing a component library. Here we will demonstrate the document sample writing based on [AntDeisgnVue](https://www.antdv.com/docs/vue/introduce/) component library 644 | 645 | First we introduce the `AntDesignVue` component library in` Vuepress`: 646 | 647 | ```bash 648 | yarn add ant-design-vue 649 | ``` 650 | 651 | Then edit the `.vuepress/enhanceApp.js` file (create if it does not exist): 652 | 653 | ```js 654 | import Antd from 'ant-design-vue' 655 | import 'ant-design-vue/dist/antd.css' 656 | export default ({ 657 | Vue 658 | }) => { 659 | Vue.use(Antd) 660 | } 661 | ``` 662 | 663 | At this point, the introduction of the component library is completed. Now you can find a `Markdown` file and type the following code 664 | 665 | ```html 666 | ::: demo `AntDesignVue` xxx component example, **please note xxx** 667 | ```html 668 | 675 | ` ` ` <= Remove the left space 676 | ::: 677 | ``` 678 | 679 | The rendering result is shown below 680 | 681 | ::: demo `AntDesignVue` xxx component example, **please note xxx** 682 | ```html 683 | 690 | ``` 691 | ::: 692 | 693 | **The following is a more comprehensive example based on the component library** 694 | 695 | ::: demo Note that currently, the `import` syntax cannot be successfully compiled by` demo-container` when writing sample code, please avoid using this syntax in the example 696 | ```html 697 | 769 | 770 | 819 | 820 | 828 | ``` 829 | ::: -------------------------------------------------------------------------------- /docs/options.md: -------------------------------------------------------------------------------- 1 | # Options 2 | 3 | ## component 4 | 5 | - Type: `string` 6 | - Default: `demo-block` 7 | 8 | The component name of the warp code and example. 9 | 10 | Use this parameter to customize the **demo block** component inside the Demo Container. The customized component should support the following three slots: 11 | 12 | - Slot demo:Is rendered as an example 13 | - Slot description:Is rendered as example description information 14 | - Slot source:Source code rendered as an example 15 | 16 | ::: warning 17 | The configured component name must be registered globally in Vuepress, which can be registered using `Vue.component` in enhanceApp.js. 18 | ::: 19 | 20 | ```js 21 | module.exports = { 22 | plugins: { 23 | 'demo-container': { 24 | component: 'CustomDemoBlock' 25 | } 26 | } 27 | } 28 | ``` 29 | 30 | Set custom sample block component CustomDemoBlock.vue. 31 | 32 | ```html 33 | 43 | ``` 44 | 45 | After the Demo Container is rendered, only the main structure of the rendering is retained below. 46 | 47 | ```html 48 | 49 | 52 |
53 | 54 |
55 | 58 |
59 | ``` 60 | 61 | ## locales 62 | 63 | - Type: `Array` 64 | - Default 65 | 66 | <<< @/src/i18n/default_lang.json 67 | 68 | Use `locales` to customize the internationalization configuration, and the plugin will complete the language switching according to the [matching lang field in Vuepress](https://vuepress.vuejs.org/guide/i18n.html). -------------------------------------------------------------------------------- /docs/started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ## Installation 4 | 5 | ### Install VuePress 6 | 7 | Please refer to the official Vuepress documentation, [click here to view](https://vuepress.vuejs.org/guide/) 8 | 9 | ### Install the plugin 10 | 11 | Use `yarn` to install the` vuepress-plugin-demo-container` component: 12 | ```bash 13 | yarn add vuepress-plugin-demo-container -D 14 | ``` 15 | Or use `npm` to install it: 16 | ```bash 17 | npm i vuepress-plugin-demo-container --save-dev 18 | ``` 19 | 20 | ### Configure plugin 21 | 22 | Open the .vuepress/config.js file, and then reference the plugin in the appropriate location: 23 | 24 | ```js 25 | module.exports = { 26 | ... 27 | plugins: ['demo-container'] 28 | ... 29 | } 30 | ``` 31 | 32 | If you are not familiar with VuePress plugin configuration, please click here: [Use plugin](https://vuepress.vuejs.org/zh/plugin/using-a-plugin.html) 33 | 34 | After the configuration is complete, cd to the same level directory in the .vuepress folder, run `vuepress dev .` to start the document service 35 | 36 | ## Use plugin 37 | 38 | ::: warning 39 | In order to show how to write an example, the three points used to mark the end of the code part have been separated by spaces, and the spaces need to be removed when used. 40 | ::: 41 | 42 | Write the following code in the Markdown file: 43 | 44 | ```html 45 | ::: demo The description information of the code example is placed here, supporting the `Markdown` syntax, **the description information only supports a single line** 46 | ```html 47 | 53 | 62 | 68 | ` ` ` <= Remove the left space 69 | ::: 70 | ``` 71 | 72 | The running effect is as follows 73 | 74 | ::: demo The description information of the code example is placed here, supporting the `Markdown` syntax, **the description information only supports a single line** 75 | ```html 76 | 82 | 91 | 97 | ``` 98 | ::: -------------------------------------------------------------------------------- /docs/zh/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | `Demo Container` 是一个基于 `Vuepress` 的插件,它可以帮助你在编写文档的时候增加 `Vue` 示例,它的诞生初衷是为了降低编写组件文档时增加一些相关示例的难度。 4 | 5 | ::: warning 使用 Vuepress 编写组件示例有以下尴尬之处: 6 | 组件示例和示例代码本质上一样,却需要写两遍; 7 | 8 | Vuepress 无法渲染 Markdown 中多个 `export default {}` 代码块; 9 | ::: 10 | 11 | Demo Container 参考了 Element UI 的文档渲染,实现了和它一样的,可在 Markdown 中直接编写示例的语法。 12 | * Element UI ColorPicker 组件的**文档编写示例**,[点此查看](https://github.com/ElemeFE/element/blob/dev/examples/docs/zh-CN/color-picker.md) 13 | * Element UI ColorPicker 组件的**文档示例预览**,[点此查看](https://element.eleme.cn/2.0/#/zh-CN/component/color-picker)。 14 | 15 | 16 | ## 它是如何工作的? 17 | 18 | Demo Container 使用 Vuepress 的 [chainMarkdown、extendMarkdown API](https://vuepress.vuejs.org/zh/plugin/option-api.html#extendmarkdown) 拓展了其内部的 markdown 对象,并做了以下操作: 19 | 20 | 1. 基于 [markdown-it-container](https://github.com/markdown-it/markdown-it-container) 构建了一个识别以下代码块的插件 21 | ``` 22 | :::demo xxx 23 | xxx 24 | ::: 25 | ``` 26 | 为其包裹 `` 组件,并拾取示例代码使用 `` 注释的方式缓存,等待后续读取,具体实现 [点此查看](https://github.com/calebman/vuepress-plugin-demo-container/blob/master/src/common/container.js); 27 | 28 | 2. 拓展 markdown.render 方法,在其渲染结果的基础上,读取 `pre-render-demo` 注释的示例代码,使用 [vue-template-compiler](https://github.com/vuejs/vue/tree/dev/packages/vue-template-compiler) 将其编译成 Redner Function,并作为整个示例页面的子组件引入,拓展后的方法输出的内容为符合 Vue Template 语法的代码块,具体实现 [点此查看](https://github.com/calebman/vuepress-plugin-demo-container/blob/master/src/common/render.js); 29 | 30 | 3. 示例页面代码后续将被 [vue-loader](https://vue-loader.vuejs.org/zh/guide/) 处理,编译为最终文档。 31 | 32 | ## 渲染效果是? 33 | 34 | ::: tip 以下是使用 Demo Container 插件渲染的一个组件示例 35 | 其展示效果参照了 Element UI 文档组件 [demo-block.vue](https://github.com/ElemeFE/element/blob/dev/examples/components/demo-block.vue) 的实现 36 | ::: 37 | 38 | ::: demo 这个例子参考了 `Vue` 官方文档示例中 [GitHub 提交](https://cn.vuejs.org/v2/examples/commits.html) 实现,使用 Github API 获取仓库最新的提交数据,并且以列表形式将它们展示了出来。 39 | ```html 40 | 75 | 76 | 136 | 137 | 170 | ``` 171 | ::: 172 | 173 | ## 为什么不是...? 174 | 175 | ::: tip 有没有其他的选择 176 | 笔者在创造 Demo Container 之前尽可能的搜索了符合上述需求的插件,找到了以下几款有用的插件,如果有其他的可用插件被笔者遗漏了,可通过提 [Issus](https://github.com/calebman/vuepress-plugin-demo-container/issues) 的方式补充,十分感谢。 177 | ::: 178 | 179 | ### vuepress-plugin-demo-block 180 | 181 | 仓库地址 [点此查看](https://github.com/xiguaxigua/vuepress-plugin-demo-block),该插件的**使用方式和笔者理想方式完全一致**,其实现原理是: 182 | 183 | 通过 [Vuepress clientRootMixin API](https://vuepress.vuejs.org/zh/plugin/option-api.html#clientrootmixin) 混入页面的 mounted、updated 生命周期,读取示例代码分离 `template`、`script`、`style` 代码块: 184 | * template 包裹的代码块直接插入示例节点; 185 | * script 包裹的代码块通过 Vue.extend 编译出 Vue 对象,再调用其 $mount() 方法挂载到示例 dom; 186 | * style 包裹的代码块直接插入 document; 187 | 188 | 这么做的问题是 **template 代码块中不能包含 Vuepress 中全局注册的组件**,而编写组件库示例必然会依赖全局注册的组件。 189 | 190 | ### vuepress-plugin-demo-code 191 | 192 | 仓库地址 [点此查看](https://github.com/BuptStEve/vuepress-plugin-demo-code),该插件的**使用方式和 demo-block 一样属于理想方式**,插件的工作流程和 Demo Container 有相似之处,其实现原理是: 193 | 194 | 通过 [Vuepress extendMarkdown API](https://vuepress.vuejs.org/zh/plugin/option-api.html#extendMarkdown) 拓展内部 markdown 对象,进而识别 `::: demo xxx :::` 代码块,将其包裹的示例代码直接插入 Markdown 文档等待 vue-loader 处理。 195 | 196 | 这么做的问题是 **只有第一个示例的 `export default {}` 代码块会被成功识别**,因为 vue-loader 编译单个文件时只会处理首次匹配到包裹 `` 的代码块。 197 | 198 | ### vuepress-plugin-extract-code 199 | 200 | 仓库地址 [点此查看](https://github.com/vuepress-reco/vuepress-plugin-extract-code),该插件的使用方式和笔者理想方式不太一致,但是它**解决了组件示例和代码需要写两遍的问题**,其实现原理是: 201 | 202 | 提供了一个 RecoDemo 组件用于在 Markdown 中构造示例页面,并通过 [Vuepress chainMarkdown API](https://vuepress.vuejs.org/zh/plugin/option-api.html#chainmarkdown) 给 Vuepress 内部的 markdown 添加一个插件,该插件负责,手动解析RecoDemo中的`<<< @/docs/.vuepress/demo/demo.vue?template`语法,识别代码块并添加到示例代码说明中,不太清楚该语法的可以[点此查看说明](https://vuepress.vuejs.org/zh/guide/markdown.html#%E5%AF%BC%E5%85%A5%E4%BB%A3%E7%A0%81%E6%AE%B5)。 203 | 204 | 这么做利用了 Vuepress 可以编译 Vue 组件的特性,使用上没有啥问题,但是如果一个组件使用文档中包含多个示例的话,即使单个示例代码很少,你也得为它建立一个文件并全局注册到 Vuepress,**其产生的问题就是维护麻烦**。 205 | 206 | ## 贡献者 207 | 208 |

209 | 210 | 211 | 212 | 213 | 214 |

-------------------------------------------------------------------------------- /docs/zh/complex.md: -------------------------------------------------------------------------------- 1 | # 复杂示例 2 | 3 | 此处提供了两种复杂场景的示例,Demo Container 都能良好的支持,具体效果如下所示: 4 | 5 | ## TodoMVC 示例 6 | 7 | `demo-container` 对示例提供了良好的支持,本例子取自 `Vue` 官方文档示例中较为复杂的 `TodoMVC`,其展示效果 [点此查看](https://cn.vuejs.org/v2/examples/todomvc.html) 8 | 9 | 拷贝官方代码将其改造成 `template` 的写法后,通过以下语法引用 10 | 11 | ```html 12 | ::: demo `TodoMVC` 是 `Vue` 官方文档中提供的示例,其涵盖了 `data、watch、computed、methods、directives` 等较多 `API` 调用 13 | ```html 14 | // Omit TodoMVC related code... 15 | ` ` ` <= 删除左侧空格 16 | ::: 17 | ``` 18 | 19 | 其渲染结果如下所示 20 | 21 | ::: demo `TodoMVC` 是 `Vue` 官方文档中提供的示例,其涵盖了 `data、watch、computed、methods、directives` 等较多 `API` 调用 22 | ```html 23 | 99 | 100 | 261 | 262 | 638 | ``` 639 | ::: 640 | 641 | ## 结合组件库示例 642 | 643 | 作为一个**组件示例插件**,其使用场景大多是在开发组件库时,用作组件库的文档示例构建,在此将演示基于 [AntDeisgnVue](https://www.antdv.com/docs/vue/introduce-cn/) 组件库的文档示例编写 644 | 645 | 首先我们在 `Vuepress` 中 引入 `AntDesignVue` 组件库: 646 | 647 | ```bash 648 | yarn add ant-design-vue 649 | ``` 650 | 651 | 然后编辑 `.vuepress/enhanceApp.js` 文件(如不存在则创建): 652 | 653 | ```js 654 | import Antd from 'ant-design-vue' 655 | import 'ant-design-vue/dist/antd.css' 656 | export default ({ 657 | Vue 658 | }) => { 659 | Vue.use(Antd) 660 | } 661 | ``` 662 | 663 | 到这里就完成组件库的引入,现在可以找一个 `Markdown` 文件键入以下代码 664 | 665 | ```html 666 | ::: demo `AntDesignVue` xxx组件示例,**请注意xxx** 667 | ```html 668 | 675 | ` ` ` <= 删除左侧空格 676 | ::: 677 | ``` 678 | 679 | 渲染结果如下所示 680 | 681 | ::: demo `AntDesignVue` xxx组件示例,**请注意xxx** 682 | ```html 683 | 690 | ``` 691 | ::: 692 | 693 | **以下是基于组件库更全面的一个示例** 694 | 695 | ::: demo 注意,目前编写示例代码时 `import` 语法是无法被 `demo-container` 成功编译的,请避免在示例中使用这种语法 696 | ```html 697 | 769 | 770 | 819 | 820 | 828 | ``` 829 | ::: -------------------------------------------------------------------------------- /docs/zh/options.md: -------------------------------------------------------------------------------- 1 | # 配置 2 | 3 | ## component 4 | 5 | - 类型:`string` 6 | - 默认值:`demo-block` 7 | 8 | 包裹代码与示例的组件名称。 9 | 10 | 使用本参数自定义 Demo Container 内部的**示例块**组件,自定义的组件应当支持以下三个挂载点: 11 | 12 | - Slot demo:被渲染成示例 13 | - Slot description:被渲染成示例描述信息 14 | - Slot source:被渲染成示例的源代码 15 | 16 | ::: warning 注意 17 | 配置的组件名称必须在 Vuepress 全局注册,可在 enhanceApp.js 中使用 `Vue.component` 进行注册。 18 | ::: 19 | 20 | ```js 21 | module.exports = { 22 | plugins: { 23 | 'demo-container': { 24 | component: 'CustomDemoBlock' 25 | } 26 | } 27 | } 28 | ``` 29 | 30 | 设置自定义示例块组件 CustomDemoBlock.vue 31 | 32 | ```html 33 | 43 | ``` 44 | 45 | 经过 Demo Container 渲染后,下方只保留了渲染的主体结构 46 | 47 | ```html 48 | 49 | 52 |
53 | 54 |
55 | 58 |
59 | ``` 60 | 61 | ## locales 62 | 63 | - 类型:`Array` 64 | - 默认值 65 | 66 | <<< @/src/i18n/default_lang.json 67 | 68 | 使用 `locales` 自定义国际化配置,插件将根据 Vuepress 中匹配的 lang 字段完成语言切换,[点此查看 Vuepress 的多语言支持](https://vuepress.vuejs.org/zh/guide/i18n.html)。 -------------------------------------------------------------------------------- /docs/zh/started.md: -------------------------------------------------------------------------------- 1 | # 快速上手 2 | 3 | ## 安装 4 | 5 | ### 安装 VuePress 6 | 7 | 请参考 Vuepress 官方文档,[点此查看](https://vuepress.vuejs.org/zh/guide/) 8 | 9 | ### 安装插件 10 | 11 | 使用 `yarn` 安装 `vuepress-plugin-demo-container` 组件: 12 | ```bash 13 | yarn add vuepress-plugin-demo-container -D 14 | ``` 15 | 或者使用 `npm` 安装它: 16 | ```bash 17 | npm i vuepress-plugin-demo-container --save-dev 18 | ``` 19 | 如果你的网络环境不佳,推荐使用 [cnpm](https://github.com/cnpm/cnpm)。 20 | 21 | ### 配置插件 22 | 23 | 打开 .vuepress/config.js 文件,然后在合适的位置引用插件: 24 | 25 | ```js 26 | module.exports = { 27 | ... 28 | plugins: ['demo-container'] 29 | ... 30 | } 31 | ``` 32 | 33 | 如果你对 VuePress 插件配置不是很了解,请点这里:[使用插件](https://vuepress.vuejs.org/zh/plugin/using-a-plugin.html) 34 | 35 | 配置完毕后,cd 到 .vuepress 文件夹同级目录,运行 `vuepress dev .` 即可启动文档服务 36 | 37 | ## 使用 38 | 39 | ::: warning 注意 40 | 为了展示如何编写示例, 用于标记代码部分结束的三点增加了空格分隔,使用时需要将空格去除。 41 | ::: 42 | 43 | 在 Markdown 文件中编写以下代码: 44 | 45 | ```html 46 | ::: demo 此处放置代码示例的描述信息,支持 `Markdown` 语法,**描述信息只支持单行** 47 | ```html 48 | 54 | 63 | 69 | ` ` ` <= 删除左侧空格 70 | ::: 71 | ``` 72 | 73 | 运行效果如下 74 | 75 | ::: demo 此处放置代码示例的描述信息,支持 `Markdown` 语法,**描述信息只支持单行** 76 | ```html 77 | 83 | 92 | 98 | ``` 99 | ::: -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuepress-plugin-demo-container", 3 | "version": "0.2.0", 4 | "description": "Vuepress plugin for demo block.", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "release": "standard-version && git push --follow-tags origin master", 8 | "release:minor": "standard-version --release-as minor && git push --follow-tags origin master", 9 | "release:major": "standard-version --release-as major && git push --follow-tags origin master", 10 | "docs:dev": "vuepress dev docs --no-cache --debug", 11 | "docs:build": "vuepress build docs", 12 | "docs:build-preview": "vuepress build docs && anywhere -d docs/.vuepress/dist/" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/calebman/vuepress-plugin-demo-container.git" 17 | }, 18 | "devDependencies": { 19 | "@commitlint/cli": "^8.3.5", 20 | "@commitlint/config-conventional": "^8.3.4", 21 | "ant-design-vue": "^1.6.1", 22 | "conventional-changelog-cli": "^2.0.34", 23 | "conventional-changelog-lint-config-cz": "^0.3.0", 24 | "core-js": "^2.6.5", 25 | "cz-conventional-changelog": "^3.2.0", 26 | "husky": "^4.2.5", 27 | "less": "^3.8.1", 28 | "less-loader": "^4.1.0", 29 | "markdown-it-container": "^2.0.0", 30 | "vuepress": "1.5.3" 31 | }, 32 | "keywords": [ 33 | "documentation", 34 | "plugin", 35 | "vue", 36 | "vuepress", 37 | "demo", 38 | "block" 39 | ], 40 | "author": "JianhuiChen", 41 | "license": "MIT", 42 | "bugs": { 43 | "url": "https://github.com/calebman/vuepress-plugin-demo-container/issues" 44 | }, 45 | "homepage": "https://github.com/calebman/vuepress-plugin-demo-container#readme", 46 | "config": { 47 | "commitizen": { 48 | "path": "./node_modules/cz-conventional-changelog" 49 | } 50 | }, 51 | "husky": { 52 | "hooks": { 53 | "commit-msg": "commitlint -e $GIT_PARAMS" 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/DemoBlock.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 159 | -------------------------------------------------------------------------------- /src/common/containers.js: -------------------------------------------------------------------------------- 1 | const mdContainer = require('markdown-it-container'); 2 | 3 | module.exports = options => { 4 | const { 5 | component = 'demo-block' 6 | } = options; 7 | const componentName = component 8 | .replace(/^\S/, s => s.toLowerCase()) 9 | .replace(/([A-Z])/g, "-$1").toLowerCase(); 10 | return md => { 11 | md.use(mdContainer, 'demo', { 12 | validate(params) { 13 | return params.trim().match(/^demo\s*(.*)$/); 14 | }, 15 | render(tokens, idx) { 16 | const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/); 17 | if (tokens[idx].nesting === 1) { 18 | const description = m && m.length > 1 ? m[1] : ''; 19 | const content = tokens[idx + 1].type === 'fence' ? tokens[idx + 1].content : ''; 20 | const encodeOptionsStr = encodeURI(JSON.stringify(options)); 21 | return `<${componentName} :options="JSON.parse(decodeURI('${encodeOptionsStr}'))"> 22 | 23 | ${description ? `
${md.render(description).html}
` : ''} 24 | `; 28 | } 29 | }); 30 | }; 31 | } -------------------------------------------------------------------------------- /src/common/fence.js: -------------------------------------------------------------------------------- 1 | // 覆盖默认的 fence 渲染策略 2 | module.exports = md => { 3 | const defaultRender = md.renderer.rules.fence; 4 | md.renderer.rules.fence = (tokens, idx, options, env, self) => { 5 | const token = tokens[idx]; 6 | // 判断该 fence 是否在 :::demo 内 7 | const prevToken = tokens[idx - 1]; 8 | const isInDemoContainer = prevToken && prevToken.nesting === 1 && prevToken.info.trim().match(/^demo\s*(.*)$/); 9 | if (token.info === 'html' && isInDemoContainer) { 10 | return ``; 11 | } 12 | return defaultRender(tokens, idx, options, env, self); 13 | }; 14 | }; -------------------------------------------------------------------------------- /src/common/render.js: -------------------------------------------------------------------------------- 1 | const { 2 | stripScript, 3 | stripStyle, 4 | stripTemplate, 5 | genInlineComponentText 6 | } = require('./util.js'); 7 | 8 | module.exports = function (content) { 9 | if (!content) { 10 | return content 11 | } 12 | const startTag = ''; 15 | const endTagLen = endTag.length; 16 | 17 | let componenetsString = ''; // 组件引用代码 18 | let templateArr = []; // 模板输出内容 19 | let styleArr = []; // 样式输出内容 20 | let id = 0; // demo 的 id 21 | let start = 0; // 字符串开始位置 22 | let commentStart = content.indexOf(startTag); 23 | let commentEnd = content.indexOf(endTag, commentStart + startTagLen); 24 | while (commentStart !== -1 && commentEnd !== -1) { 25 | templateArr.push(content.slice(start, commentStart)); 26 | const commentContent = content.slice(commentStart + startTagLen, commentEnd); 27 | const html = stripTemplate(commentContent); 28 | const script = stripScript(commentContent); 29 | const style = stripStyle(commentContent); 30 | const demoComponentContent = genInlineComponentText(html, script); // 示例组件代码内容 31 | const demoComponentName = `render-demo-${id}`; // 示例代码组件名称 32 | templateArr.push(``); 33 | styleArr.push(style); 34 | componenetsString += `${JSON.stringify(demoComponentName)}: ${demoComponentContent},`; 35 | // 重新计算下一次的位置 36 | id++; 37 | start = commentEnd + endTagLen; 38 | commentStart = content.indexOf(startTag, start); 39 | commentEnd = content.indexOf(endTag, commentStart + startTagLen); 40 | } 41 | // 仅允许在 demo 不存在时,才可以在 Markdown 中写 script 标签 42 | // todo: 优化这段逻辑 43 | let pageScript = ''; 44 | if (componenetsString) { 45 | pageScript = ``; 53 | } else if (content.indexOf('') + ''.length; 55 | pageScript = content.slice(0, start); 56 | } 57 | // 合并 style 内容 58 | let styleString = ''; 59 | if(styleArr && styleArr.length > 0) { 60 | styleString = `` 61 | } else { 62 | styleString = `` 63 | } 64 | templateArr.push(content.slice(start)); 65 | return { 66 | template: templateArr.join(''), 67 | script: pageScript, 68 | style: styleString 69 | } 70 | }; -------------------------------------------------------------------------------- /src/common/util.js: -------------------------------------------------------------------------------- 1 | const { compileTemplate } = require('@vue/component-compiler-utils'); 2 | const compiler = require('vue-template-compiler'); 3 | 4 | function stripScript(content) { 5 | const result = content.match(/<(script)>([\s\S]+)<\/\1>/); 6 | return result && result[2] ? result[2].trim() : ''; 7 | } 8 | 9 | function stripStyle(content) { 10 | const result = content.match(/<(style)\s*>([\s\S]+)<\/\1>/); 11 | return result && result[2] ? result[2].trim() : ''; 12 | } 13 | 14 | // 编写例子时不一定有 template。所以采取的方案是剔除其他的内容 15 | function stripTemplate(content) { 16 | content = content.trim(); 17 | if (!content) { 18 | return content; 19 | } 20 | return content.replace(/<(script|style)[\s\S]+<\/\1>/g, '').trim(); 21 | } 22 | 23 | function pad(source) { 24 | return source 25 | .split(/\r?\n/) 26 | .map(line => ` ${line}`) 27 | .join('\n'); 28 | } 29 | 30 | function genInlineComponentText(template, script) { 31 | // https://github.com/vuejs/vue-loader/blob/423b8341ab368c2117931e909e2da9af74503635/lib/loaders/templateLoader.js#L46 32 | const finalOptions = { 33 | source: `
${template}
`, 34 | filename: 'inline-component', // TODO:这里有待调整 35 | compiler 36 | }; 37 | const compiled = compileTemplate(finalOptions); 38 | // tips 39 | if (compiled.tips && compiled.tips.length) { 40 | compiled.tips.forEach(tip => { 41 | console.warn(tip); 42 | }); 43 | } 44 | // errors 45 | if (compiled.errors && compiled.errors.length) { 46 | console.error( 47 | `\n Error compiling template:\n${pad(compiled.source)}\n` + 48 | compiled.errors.map(e => ` - ${e}`).join('\n') + 49 | '\n' 50 | ); 51 | } 52 | let demoComponentContent = ` 53 | ${compiled.code} 54 | `; 55 | // todo: 这里采用了硬编码有待改进 56 | script = script.trim(); 57 | if (script) { 58 | script = script.replace(/export\s+default/, 'const democomponentExport ='); 59 | } else { 60 | script = 'const democomponentExport = {}'; 61 | } 62 | demoComponentContent = `(function() { 63 | ${demoComponentContent} 64 | ${script} 65 | return { 66 | render, 67 | staticRenderFns, 68 | ...democomponentExport 69 | } 70 | })()`; 71 | return demoComponentContent; 72 | } 73 | 74 | module.exports = { 75 | stripScript, 76 | stripStyle, 77 | stripTemplate, 78 | genInlineComponentText 79 | }; -------------------------------------------------------------------------------- /src/enhanceAppFile.js: -------------------------------------------------------------------------------- 1 | import DemoBlock from './DemoBlock.vue' 2 | export default ({ Vue }) => { 3 | Vue.component('DemoBlock', DemoBlock) 4 | } 5 | -------------------------------------------------------------------------------- /src/i18n/default_lang.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "lang": "zh-CN", 4 | "demo-block": { 5 | "hide-text": "隐藏代码", 6 | "show-text": "显示代码", 7 | "copy-text": "复制代码", 8 | "copy-success": "复制成功" 9 | } 10 | }, 11 | { 12 | "lang": "en-US", 13 | "demo-block": { 14 | "hide-text": "Hide", 15 | "show-text": "Expand", 16 | "copy-text": "Copy", 17 | "copy-success": "Successful" 18 | } 19 | } 20 | ] -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 提供 ::: demo xxx ::: 语法,用于构建 markdown 中的示例 3 | */ 4 | const path = require('path') 5 | const renderDemoBlock = require('./common/render') 6 | const demoBlockContainers = require('./common/containers') 7 | module.exports = (options = {}, ctx) => { 8 | return { 9 | enhanceAppFiles: path.resolve(__dirname, './enhanceAppFile.js'), 10 | chainMarkdown(config) { 11 | config.plugin('containers') 12 | .use(demoBlockContainers(options)) 13 | .end(); 14 | }, 15 | extendMarkdown: md => { 16 | const id = setInterval(() => { 17 | const render = md.render; 18 | if (typeof render.call(md, '') === 'object') { 19 | md.render = (...args) => { 20 | let result = render.call(md, ...args); 21 | const { template, script, style } = renderDemoBlock(result.html); 22 | result.html = template; 23 | result.dataBlockString = `${script}\n${style}\n${result.dataBlockString}`; 24 | return result; 25 | } 26 | clearInterval(id); 27 | } 28 | }, 10); 29 | } 30 | } 31 | } --------------------------------------------------------------------------------