Skip to content

Commit f71abab

Browse files
committed
different headers for comp/options apis
1 parent c7d1ac9 commit f71abab

File tree

8 files changed

+111
-44
lines changed

8 files changed

+111
-44
lines changed

src/.vitepress/config.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const fs = require('fs')
33
const path = require('path')
44
const { genApiIndex } = require('../../scripts/genApiIndex')
55
const { genExamplesData } = require('../../scripts/genExamplesData')
6+
const { headerPlugin } = require('./header')
67

78
const nav = [
89
{
@@ -521,6 +522,12 @@ module.exports = {
521522
]
522523
],
523524

525+
markdown: {
526+
config(md) {
527+
md.use(headerPlugin)
528+
}
529+
},
530+
524531
themeConfig: {
525532
logo: '/logo.svg',
526533
repo: 'vuejs/docs',

src/.vitepress/header.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* A markdown-it plugin to support custom header metadata
3+
* Headers that end with * are Options API only
4+
* Headers that end with ** are Composition API only
5+
* This plugin strips the markers and augments the extracted header data,
6+
* which can be then used by the theme to filter headers.
7+
*
8+
* TODO: we will likely also need special syntax for preserving the same anchor
9+
* links across translations similar to the one at
10+
* https://github.com/vitejs/docs-cn/tree/main/.vitepress/markdown-it-custom-anchor
11+
*/
12+
13+
exports.headerPlugin = (md) => {
14+
const originalOpen = md.renderer.rules.heading_open
15+
md.renderer.rules.heading_open = (tokens, i, ...rest) => {
16+
for (const child of tokens[i + 1].children) {
17+
if (child.type === 'text' && child.content.endsWith('*')) {
18+
child.content = child.content.replace(/\s*\*+$/, '')
19+
}
20+
}
21+
return originalOpen.call(null, tokens, i, ...rest)
22+
}
23+
24+
md.renderer.rules.heading_close = (tokens, i, options, env, self) => {
25+
const headers = md.__data?.headers
26+
if (headers) {
27+
const last = headers[headers.length - 1]
28+
if (last.title.endsWith('*')) {
29+
if (last.title.endsWith('**')) {
30+
last.compositionOnly = true
31+
} else {
32+
last.optionsOnly = true
33+
}
34+
last.title = last.title.replace(/\s*\*+$/, '')
35+
}
36+
}
37+
return self.renderToken(tokens, i, options)
38+
}
39+
}

src/.vitepress/theme/components/preferences.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Header } from 'vitepress'
12
import { ref } from 'vue'
23

34
const hasStorage = typeof localStorage !== 'undefined'
@@ -11,3 +12,16 @@ export const preferComposition = ref(get(preferCompositionKey))
1112

1213
export const preferSFCKey = 'vue-docs-prefer-sfc'
1314
export const preferSFC = ref(get(preferSFCKey, true))
15+
16+
// headers are augmented via the md plugin in ../header.js
17+
type AugmentedHeader = Header & {
18+
compositionOnly?: boolean
19+
optionsOnly?: boolean
20+
}
21+
22+
export function filterHeadersByPreference(headers: AugmentedHeader[]) {
23+
const enableComp = preferComposition.value
24+
return headers.filter((h) => {
25+
return enableComp ? !h.optionsOnly : !h.compositionOnly
26+
})
27+
}

src/.vitepress/theme/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { h } from 'vue'
22
import { VPTheme, VTBadge } from '@vue/theme'
33
import PreferenceSwitch from './components/PreferenceSwitch.vue'
4-
import { preferComposition, preferSFC } from './components/preferences'
4+
import {
5+
preferComposition,
6+
preferSFC,
7+
filterHeadersByPreference
8+
} from './components/preferences'
59
import './styles/inline-demo.css'
610
import './styles/options-boxes.css'
711

@@ -15,5 +19,6 @@ export default Object.assign({}, VPTheme, {
1519
app.component('Badge', VTBadge)
1620
app.provide('prefer-composition', preferComposition)
1721
app.provide('prefer-sfc', preferSFC)
22+
app.provide('filter-headers', filterHeadersByPreference)
1823
}
1924
})

src/guide/advanced/reactivity-in-depth.md

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -313,33 +313,3 @@ A `render` function is conceptually very similar to a `computed` property. Vue d
313313
<div class="reactivecontent">
314314
<!-- <common-codepen-snippet title="Second Reactivity with Proxies in Vue 3 Explainer" slug="wvgqyJK" tab="result" theme="light" :height="500" :editable="false" :preview="false" /> -->
315315
</div>
316-
317-
## Additional Details
318-
319-
### Computed amd Watcher Debugging
320-
321-
It's great that a computed property automatically tracks its reactive dependencies, but in some cases we may want to figure out exactly what is being tracked, or what is causing it to re-compute. We can do that by passing `computed()` a second options object with `onTrack` and `onTrigger` callbacks:
322-
323-
- `onTrack` will be called when a reactive property or ref is tracked as a dependency.
324-
- `onTrigger` will be called when the watcher callback is triggered by the mutation of a dependency.
325-
326-
Both callbacks will receive a debugger event which contains information on the dependency in question. It is recommended to place a `debugger` statement in these callbacks to interactively inspect the dependency:
327-
328-
```js
329-
const plusOne = computed(() => count.value + 1, {
330-
onTrack(e) {
331-
// triggered when count.value is tracked as a dependency
332-
debugger
333-
},
334-
onTrigger(e) {
335-
// triggered when count.value is mutated
336-
debugger
337-
}
338-
})
339-
340-
// access plusOne, should trigger onTrack
341-
console.log(plusOne.value)
342-
343-
// mutate count.value, should trigger onTrigger
344-
count.value++
345-
```

src/guide/essentials/computed.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,38 @@ In comparison, a method invocation will **always** run the function whenever a r
188188

189189
Why do we need caching? Imagine we have an expensive computed property `list`, which requires looping through a huge array and doing a lot of computations. Then we may have other computed properties that in turn depend on `list`. Without caching, we would be executing `list`’s getter many more times than necessary! In cases where you do not want caching, use a method call instead.
190190

191+
<div class="composition-api">
192+
193+
## Computed Debugging **
194+
195+
It's great that a computed property automatically tracks its reactive dependencies, but in some cases we may want to figure out exactly what is being tracked, or what is causing it to re-compute. We can do that by passing `computed()` a second options object with `onTrack` and `onTrigger` callbacks:
196+
197+
- `onTrack` will be called when a reactive property or ref is tracked as a dependency.
198+
- `onTrigger` will be called when the watcher callback is triggered by the mutation of a dependency.
199+
200+
Both callbacks will receive a debugger event which contains information on the dependency in question. It is recommended to place a `debugger` statement in these callbacks to interactively inspect the dependency:
201+
202+
```js
203+
const plusOne = computed(() => count.value + 1, {
204+
onTrack(e) {
205+
// triggered when count.value is tracked as a dependency
206+
debugger
207+
},
208+
onTrigger(e) {
209+
// triggered when count.value is mutated
210+
debugger
211+
}
212+
})
213+
214+
// access plusOne, should trigger onTrack
215+
console.log(plusOne.value)
216+
217+
// mutate count.value, should trigger onTrigger
218+
count.value++
219+
```
220+
221+
</div>
222+
191223
## Writable Computed
192224

193225
Computed properties are by default getter-only. When you attempt to mutate a computed property, you will receive a runtime warning. In the rare cases where you need a "writable" computed property, you can create one by providing both a getter and a setter:

src/guide/essentials/reactivity-fundamentals.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
This section contains different content for Options API and Composition API. Your current preference is <span class="options-api">Options API</span><span class="composition-api">Composition API</span>. You can toggle between the API styles using the "API Preference" switches at the top of the left sidebar.
55
:::
66

7-
## Declaring State
8-
97
<div class="options-api">
108

9+
## Declaring Reactive State *
10+
1111
With Options API, we use the `data` option to declare reactive state of a component. The option value should be a function that returns an object. Vue will call the function when creating a new component instance, and wrap the returned object in its reactivity system. The wrapped object is stored on the component instance as `$data`. For convenience, any top-level properties of that object are also exposed directly on the component instance (`this` in methods and lifecycle hooks):
1212

1313
```js
@@ -45,7 +45,7 @@ Vue uses a `$` prefix when exposing its own built-in APIs via the component inst
4545

4646
<div class="composition-api">
4747

48-
### Reactive Variables with `ref`
48+
## Reactive Variables with `ref` **
4949

5050
The primary API for declaring reactive state when using Composition API is the [`ref()`](/api/reactivity-core.html#ref) method:
5151

@@ -106,7 +106,7 @@ There are two reasons why we need to wrap the value in an object:
106106

107107
This capability is quite important as it is frequently used when extracting logic into [Composable Functions](/guide/reusability/composables.html).
108108

109-
### Exposing State to Template
109+
## Exposing State to Template **
110110

111111
To use refs in a component's template, declare and return them from a component's `setup()` function:
112112

@@ -150,7 +150,7 @@ Top-level imports and variables declared in `<script setup>` are automatically u
150150

151151
> For the rest of the guide, we will be primarily using SFC + `<script setup>` syntax for Composition API code examples, as that is the most common usage for Vue developers.
152152
153-
### Reactive Objects with `reactive`
153+
## Reactive Objects with `reactive` **
154154

155155
It is also possible to directly create a reactive object or array with the [`reactive()`](/api/reactivity-core.html#reactive) method:
156156

@@ -274,7 +274,7 @@ In the example above, the method `increment` will be called when the `<button>`
274274

275275
<div class="composition-api">
276276

277-
To declare methods when using Composition API, simply declare functions in the same scope with the reactive state:
277+
We can declare functions that mutate reactive state in the same scope, and expose it as a method alongside the state:
278278

279279
```js
280280
import { ref } from 'vue'
@@ -297,7 +297,7 @@ export default {
297297
}
298298
```
299299

300-
Methods are typically used as event listeners:
300+
Exposed methods are typically used as event listeners:
301301

302302
```vue-html
303303
<button @click="increment">{{ count }}</button>
@@ -386,7 +386,7 @@ function mutateDeeply() {
386386

387387
</div>
388388

389-
It is also possible to explicitly create [shallow refs](<(/api/reactivity-advanced.html#shallowref)>) and [shallow reactive objects](/api/reactivity-advanced.html#shallowreactive) where the reactivity is only tracked at the root-level, however they are typically only needed in advanced use cases.
389+
It is also possible to explicitly create [shallow refs](/api/reactivity-advanced.html#shallowref) and [shallow reactive objects](/api/reactivity-advanced.html#shallowreactive) where the reactivity is only tracked at the root-level, however they are typically only needed in advanced use cases.
390390

391391
<div class="options-api">
392392

@@ -442,7 +442,7 @@ app.component('save-button', {
442442

443443
<div class="composition-api">
444444

445-
### Ref Transform <Badge type="warning" text="experimental" />
445+
## Ref Transform <Badge type="warning" text="experimental" /> **
446446

447447
Refs require the `.value` property due to the language constraints of JavaScript. However, with compile-time transforms we can improve the ergonomics by automatically appending `.value` in appropriate locations. The [ref transform](https://github.com/vuejs/vue-next/tree/master/packages/ref-transform) allows us to write the above example like this:
448448

src/guide/essentials/watchers.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,10 +319,10 @@ watchPostEffect(() => {
319319
})
320320
```
321321

322-
</div>
322+
## Side Effect Invalidation **
323323

324-
## Side Effect Invalidation
324+
## Stopping a Watcher **
325325

326-
## Stopping a Watcher
326+
## Watcher Debugging **
327327

328-
## Watcher Debugging
328+
</div>

0 commit comments

Comments
 (0)