Skip to content

feat: Vue components, mount options, global options, and v3 support #1409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 45 commits into from
Nov 23, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
35ad5c5
Add vueOptions and vueGlobalOptions
jhildenbiddle Oct 10, 2020
cd8f2d3
Fix vueGlobalOptions.data checks
jhildenbiddle Oct 10, 2020
ecd053b
Support functions in docsify configuration
jhildenbiddle Oct 15, 2020
5fa79eb
Fix Vue content detection and global options
jhildenbiddle Oct 15, 2020
a2386e5
Add vueComponents support
jhildenbiddle Oct 16, 2020
bc2e091
Ignore `el` property in Vue configs for Vue v2
jhildenbiddle Oct 16, 2020
1774ab8
Initial commit
jhildenbiddle Oct 17, 2020
6d152e2
Refactor regular expression usage
jhildenbiddle Oct 17, 2020
758538c
Add `<output>`. Refactor `<pre>` and `<code>`.
jhildenbiddle Oct 17, 2020
0193659
Update docs with new Vue features and usage
jhildenbiddle Oct 17, 2020
8a56f72
Fix directive detection
jhildenbiddle Oct 18, 2020
5a2dde1
Update docs
jhildenbiddle Oct 20, 2020
1a52e97
Update docs
jhildenbiddle Oct 21, 2020
86dae61
Rename `vueOptions` to `vueMountOptions`
jhildenbiddle Oct 21, 2020
2946c06
Update test
jhildenbiddle Oct 21, 2020
871e48f
Update default waitForSelector value
jhildenbiddle Oct 21, 2020
131aae5
Fix waitForText() timeout and reject messages
jhildenbiddle Oct 23, 2020
af7e713
Change default startPath for tests & manual start
jhildenbiddle Oct 23, 2020
25084f8
Update jest/docsify side-effect cleanup
jhildenbiddle Oct 23, 2020
6a5e84b
Update directive detection (data vs static)
jhildenbiddle Oct 23, 2020
febe7f8
Remove global event listeners beforeEach
jhildenbiddle Oct 25, 2020
b6d5407
Fix basePath
jhildenbiddle Oct 25, 2020
8362ed0
Remove unnecessary globals
jhildenbiddle Oct 26, 2020
f0a8d69
Fix basePath update when config is function
jhildenbiddle Oct 26, 2020
5ec2256
Fix basePath & update route URLs
jhildenbiddle Oct 26, 2020
a9be6f2
Merge branch 'develop' into feat/vue-options
jhildenbiddle Oct 26, 2020
3af1cfa
Add selector option to _logHTML
jhildenbiddle Oct 26, 2020
b33d750
Remove SRC_PATH global variable
jhildenbiddle Oct 26, 2020
cafdd62
Remove —runInBand flag from test script
jhildenbiddle Oct 26, 2020
d9e491a
Fix covepage test
jhildenbiddle Oct 26, 2020
a5a431f
Fix base element reset
jhildenbiddle Nov 7, 2020
4e5dae7
Squashed commit of the following:
jhildenbiddle Nov 11, 2020
eae3ad8
Remove markdownlint config
jhildenbiddle Nov 11, 2020
421ef1d
Update docs
jhildenbiddle Nov 11, 2020
52cce02
Delete unnecessary file
jhildenbiddle Nov 11, 2020
727ee8f
Rename `vueMountOptions` to `vueMounts`
jhildenbiddle Nov 11, 2020
69efae3
Fix typos
jhildenbiddle Nov 11, 2020
51451a4
Remove BLANK_URL global
jhildenbiddle Nov 11, 2020
a10fcbd
Update Vue-related descriptions
jhildenbiddle Nov 12, 2020
9a1935a
Add support for Vue shorthand directive syntax
jhildenbiddle Nov 15, 2020
43a73bb
Merge branch 'develop' into feat/vue-options
sy-records Nov 16, 2020
7cf1e7c
Update Vue-related descriptions and links
jhildenbiddle Nov 19, 2020
7878c60
Merge branch 'develop' into feat/vue-options
jhildenbiddle Nov 19, 2020
90b67e2
Merge branch 'develop' into feat/vue-options
sy-records Nov 23, 2020
ffa7c90
Fix Lint
sy-records Nov 23, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add support for Vue shorthand directive syntax
  • Loading branch information
jhildenbiddle committed Nov 15, 2020
commit 9a1935ac644f55eb2d53e532b9f015b1ec3c40de
16 changes: 8 additions & 8 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -683,17 +683,17 @@ window.$docsify = {

```markdown
<p>
<button v-on:click="count -= 1">-</button>
<button @click="count -= 1">-</button>
{{ count }}
<button v-on:click="count += 1">+</button>
<button @click="count += 1">+</button>
</p>
```

<output data-lang="output">
<p>
<button v-on:click="count -= 1">-</button>
<button @click="count -= 1">-</button>
{{ count }}
<button v-on:click="count += 1">+</button>
<button @click="count += 1">+</button>
</p>
</output>

Expand All @@ -719,14 +719,14 @@ window.$docsify = {

```markdown
<div id="counter">
<button v-on:click="count -= 1">-</button>
<button @click="count -= 1">-</button>
{{ count }}
<button v-on:click="count += 1">+</button>
<button @click="count += 1">+</button>
</div>
```

<output id="counter">
<button v-on:click="count -= 1">-</button>
<button @click="count -= 1">-</button>
{{ count }}
<button v-on:click="count += 1">+</button>
<button @click="count += 1">+</button>
</output>
27 changes: 15 additions & 12 deletions docs/vue.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,12 @@ Good {{ timeOfDay }}!
}
```

```markdown
<button @click="hello">Say Hello</button>
```

<output data-lang="output">
<p><button v-on:click="hello">Say Hello</button></p>
<p><button @click="hello">Say Hello</button></p>
</output>

### Lifecycle Hooks
Expand Down Expand Up @@ -205,27 +209,27 @@ window.$docsify = {

```markdown
<p>
<button v-on:click="count -= 1">-</button>
<button @click="count -= 1">-</button>
{{ count }}
<button v-on:click="count += 1">+</button>
<button @click="count += 1">+</button>
</p>
```

<output data-lang="output">
<p>
<button v-on:click="count -= 1">-</button>
<button @click="count -= 1">-</button>
{{ count }}
<button v-on:click="count += 1">+</button>
<button @click="count += 1">+</button>
</p>
</output>

Notice the behavior when multiple global counters are rendered:

<output data-lang="output">
<p>
<button v-on:click="count -= 1">-</button>
<button @click="count -= 1">-</button>
{{ count }}
<button v-on:click="count += 1">+</button>
<button @click="count += 1">+</button>
</p>
</output>

Expand All @@ -251,16 +255,16 @@ window.$docsify = {

```markdown
<div id="counter">
<button v-on:click="count -= 1">-</button>
<button @click="count -= 1">-</button>
{{ count }}
<button v-on:click="count += 1">+</button>
<button @click="count += 1">+</button>
</div>
```

<output id="counter">
<button v-on:click="count -= 1">-</button>
<button @click="count -= 1">-</button>
{{ count }}
<button v-on:click="count += 1">+</button>
<button @click="count += 1">+</button>
</output>

## Components
Expand Down Expand Up @@ -331,4 +335,3 @@ Vue content can mounted using a `<script>` tag in your markdown pages.
- Docsify will not mount an existing Vue instance or an element that contains an existing Vue instance.
- Docsify will automatically destroy/unmount all Vue instances it creates before new page content is loaded.
- When processing `vueGlobalOptions`, docsify parses the child elements within the main content area (`#main`) and mounts the element if it contains Vue content. Docsify does not parse each individual node within the main content area.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not clear on the last bullet point. I guess if it'll start to explain this magic part, it might just need to go into more detail.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree this description could use some work. To be honest, I debated about even adding it. I've updated the description to (hopefully) make it more clear. At the end of the day, this text exists to help explain why this edge case won't work:

window.$docsify = {
  vueGlobalOptions: {
    data() {
      return {
        globalMsg: 'Hello from vueGlobalOptions!',
      };
    },
  },
  vueMounts: {
    '#test': {
      data() {
        return {
          mountMsg: 'Hello from vueMounts!'
        };
      },
    },
  },
};

Example 1: This will work

<!-- Source -->
<p>{{ globalMsg }}</p>
<p id="test">{{ mountMsg }}</p>
<!-- Output -->
<p>Hello from vueGlobalOptions!</p>
<p id="test">Hello from vueMounts!</p>

In this example, docsify first mounts the top-level <p id="test"> from vueMounts. Docsify then iterates over the top-level child elements (<p>), skips the ones that contain or are themselves Vue instances, detects Vue template syntax in the top-level <p> element, and mounts it using vueGlobalOptions. Great.

Example 2: This will not work

<!-- Source -->
<div>
  <p>{{ globalMsg }}</p>
  <p id="test">{{ mountMsg }}</p>
</div>
<!-- Output -->
<div>
  <p>{{ globalMsg }}</p>
  <p id="test">Hello from vueMounts!</p>
</div>

Like the previous example, docsify first mounts the top-level <p id="test"> from vueMounts. Docsify then iterates over the top-level child elements (<div>), detects that <div> contains a Vue instance (<p id="test">) and skips that element. This behavior is explained in the following "Technical Notes" bullet point:

  • Docsify will not mount an existing Vue instance or an element that contains an existing Vue instance.

I think it is highly unlikely that this will be an issue, but I added the related technical notes in hopes of making life easier for everyone if it does. The trick is how to do this succinctly without going into the same level of detail above. Hopefully the changes I've put in place are good enough for now. We can always revisit if/when needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jhildenbiddle The example of what works vs what doesn't will be very helpful to some people. I think it'd be worth pasting what you wrote into the docs.

- When processing `vueGlobalOptions`, docsify will only detect the full `v-` attribute syntax (e.g `v-bind:href` or `v-on:click`). For performance reasons, detection of Vue's [shorthand](https://vuejs.org/v2/guide/syntax.html#Shorthands) attribute syntax (e.g. `:href`or `@click`) is not supported. Shorthand syntax is supported when explicitly mounting Vue content via `vueComponents`, `vueMounts`, or a markdown `<script>`.
28 changes: 21 additions & 7 deletions src/core/render/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,25 @@ function renderMain(html) {
// Template syntax, vueComponents, vueGlobalOptions
if (docsifyConfig.vueGlobalOptions || vueComponentNames.length) {
const reHasBraces = /{{2}[^{}]*}{2}/;
const reHasDataDirective = /\sv-(bind:|cloak|html=|is=|model=|on:|slot=|text=)/;
const reHasStaticDirective = /\sv-(else|else-if=|for=|if=|once|pre|show=)/;
// Matches Vue full and shorthand syntax as attributes in HTML tags.
//
// Full syntax examples:
// v-foo, v-foo[bar], v-foo-bar, v-foo:bar-baz.prop
//
// Shorthand syntax examples:
// @foo, @foo.bar, @foo.bar.baz, @[foo], :foo, :[foo]
//
// Markup examples:
// <div v-html>{{ html }}</div>
// <div v-text="msg"></div>
// <div v-bind:text-content.prop="text">
// <button v-on:click="doThis"></button>
// <button v-on:click.once="doThis"></button>
// <button v-on:[event]="doThis"></button>
// <button @click.stop.prevent="doThis">
// <a :href="url">
// <a :[key]="url">
const reHasDirective = /<[^>/]+\s([@:]|v-)[\w-:.[\]]+[=>\s]/;

vueMountData.push(
...dom
Expand All @@ -145,11 +162,8 @@ function renderMain(html) {
elm.querySelector(vueComponentNames.join(',') || null) ||
// has curly braces
reHasBraces.test(elm.outerHTML) ||
// has data directive
(docsifyConfig.vueGlobalOptions &&
reHasDataDirective.test(elm.outerHTML)) ||
// has static content directive
reHasStaticDirective.test(elm.outerHTML);
// has content directive
reHasDirective.test(elm.outerHTML);

return isVueMount;
})
Expand Down
6 changes: 3 additions & 3 deletions test/e2e/vue.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,19 @@ describe('Vue.js Compatibility', function() {

<div id="vueglobaloptions">
<p v-text="msg">---</p>
<button v-on:click="counter += 1">+</button>
<button @click="counter += 1">+</button>
<span>{{ counter }}<span>
</div>

<div id="vuemounts">
<p v-text="msg">---</p>
<button v-on:click="counter += 1">+</button>
<button @click="counter += 1">+</button>
<span>{{ counter }}<span>
</div>

<div id="vuescript">
<p v-text="msg">---</p>
<button v-on:click="counter += 1">+</button>
<button @click="counter += 1">+</button>
<span>{{ counter }}<span>
</div>

Expand Down