├── .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 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
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 |
41 |
42 |
49 |
Latest Commits
50 |
51 |
52 | {{ branch }}
53 |
54 |
{{ repoName }}@{{ currentBranch }}
55 |
Request loading...
56 |
57 |
Error: {{ errMsg }}.
58 |
Found the repository is no commit.
59 |
72 |
73 |
74 |
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 |
24 |
25 |
86 |
87 | Double-click to edit a todo
88 |
89 | Written by
90 | Evan You
91 |
92 |
93 | Part of
94 | TodoMVC
95 |
96 |
97 |
98 |
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 |
669 | Primary
670 | Danger
671 |
672 | Button
673 |
674 |
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 |
684 | Primary
685 | Danger
686 |
687 | Button
688 |
689 |
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 |
698 |
699 |
700 |
701 | Dropdown
702 |
703 |
704 | 1st menu item
705 |
706 |
707 | 2nd menu item
708 |
709 |
710 | 3rd item
711 |
712 |
713 |
714 |
715 | Dropdown
716 |
717 |
718 | 1st menu item
719 |
720 |
721 | 2nd menu item
722 |
723 |
724 | 3rd item
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 | Link something
740 |
741 |
742 |
743 |
744 | Display normal message
745 | Confirm
746 | Delete
747 | Modal
748 |
749 | Bla bla ...
750 | Bla bla ...
751 | Bla bla ...
752 |
753 |
754 |
755 |
756 |
757 | Large
758 | Default
759 | Small
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
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 |
34 |
35 |
Description
36 |
37 | Example
38 |
39 | Source Code
40 |
41 |
42 |
43 | ```
44 |
45 | After the Demo Container is rendered, only the main structure of the rendering is retained below.
46 |
47 | ```html
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
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 |
48 |
49 |
{{ message }}
50 |
51 |
52 |
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 |
77 |
78 |
{{ message }}
79 |
80 |
81 |
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 |
41 |
42 |
49 |
Latest Commits
50 |
51 |
52 | {{ branch }}
53 |
54 |
{{ repoName }}@{{ currentBranch }}
55 |
Request loading...
56 |
57 |
Error: {{ errMsg }}.
58 |
Found the repository is no commit.
59 |
72 |
73 |
74 |
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 |
24 |
25 |
86 |
87 | Double-click to edit a todo
88 |
89 | Written by
90 | Evan You
91 |
92 |
93 | Part of
94 | TodoMVC
95 |
96 |
97 |
98 |
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 |
669 | Primary
670 | Danger
671 |
672 | 按钮
673 |
674 |
675 | ` ` ` <= 删除左侧空格
676 | :::
677 | ```
678 |
679 | 渲染结果如下所示
680 |
681 | ::: demo `AntDesignVue` xxx组件示例,**请注意xxx**
682 | ```html
683 |
684 | Primary
685 | Danger
686 |
687 | 按钮
688 |
689 |
690 | ```
691 | :::
692 |
693 | **以下是基于组件库更全面的一个示例**
694 |
695 | ::: demo 注意,目前编写示例代码时 `import` 语法是无法被 `demo-container` 成功编译的,请避免在示例中使用这种语法
696 | ```html
697 |
698 |
699 |
700 |
701 | Dropdown
702 |
703 |
704 | 1st menu item
705 |
706 |
707 | 2nd menu item
708 |
709 |
710 | 3rd item
711 |
712 |
713 |
714 |
715 | Dropdown
716 |
717 |
718 | 1st menu item
719 |
720 |
721 | 2nd menu item
722 |
723 |
724 | 3rd item
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 | Link something
740 |
741 |
742 |
743 |
744 | Display normal message
745 | Confirm
746 | Delete
747 | Modal
748 |
749 | Bla bla ...
750 | Bla bla ...
751 | Bla bla ...
752 |
753 |
754 |
755 |
756 |
757 | Large
758 | Default
759 | Small
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
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 |
34 |
35 |
Description
36 |
37 | Example
38 |
39 | Source Code
40 |
41 |
42 |
43 | ```
44 |
45 | 经过 Demo Container 渲染后,下方只保留了渲染的主体结构
46 |
47 | ```html
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
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 |
49 |
50 |
{{ message }}
51 |
52 |
53 |
54 |
63 |
69 | ` ` ` <= 删除左侧空格
70 | :::
71 | ```
72 |
73 | 运行效果如下
74 |
75 | ::: demo 此处放置代码示例的描述信息,支持 `Markdown` 语法,**描述信息只支持单行**
76 | ```html
77 |
78 |
79 |
{{ message }}
80 |
81 |
82 |
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 |
2 |
8 |
9 |
10 |
11 |
19 |
26 |
27 |
28 |
29 |
30 | {{ controlText }}
31 |
32 | {{ copiedText }}
37 |
38 | {{ copiedText }}
39 |
40 |
41 |
42 |
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 |
25 | `;
26 | }
27 | return ` ${componentName}>`;
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 `${md.utils.escapeHtml(token.content)}
`;
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(`<${demoComponentName} /> `);
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 | }
--------------------------------------------------------------------------------