Skip to content

Commit c825a40

Browse files
authored
Start working on Migration Guide (#50)
* start bringing over the writing guide * start working on 3 migration guide * work through the FAQ, put in TODOs where applicable * add the pages to the sidebar/config * more clear migration to vue 3 title * start working on built in modifiers * add in v-bind sync and graphic * add in more of the custom directive part * formatting * add in gitignore and remove ds_store
1 parent 0ca411f commit c825a40

File tree

5 files changed

+404
-2
lines changed

5 files changed

+404
-2
lines changed

.gitignore

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,103 @@
1-
node_modules
2-
dist
1+
### OSX ###
2+
# General
3+
.DS_Store
4+
.AppleDouble
5+
.LSOverride
6+
7+
# Thumbnails
8+
._*
9+
10+
# Files that might appear in the root of a volume
11+
.DocumentRevisions-V100
12+
.fseventsd
13+
.Spotlight-V100
14+
.TemporaryItems
15+
.Trashes
16+
.VolumeIcon.icns
17+
.com.apple.timemachine.donotpresent
18+
19+
# Directories potentially created on remote AFP share
20+
.AppleDB
21+
.AppleDesktop
22+
Network Trash Folder
23+
Temporary Items
24+
.apdisk
25+
26+
### Node ###
27+
# Logs
28+
logs
29+
*.log
30+
npm-debug.log*
31+
yarn-debug.log*
32+
yarn-error.log*
33+
lerna-debug.log*
34+
35+
# Diagnostic reports (https://nodejs.org/api/report.html)
36+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
37+
38+
# Runtime data
39+
pids
40+
*.pid
41+
*.seed
42+
*.pid.lock
43+
44+
# Directory for instrumented libs generated by jscoverage/JSCover
45+
lib-cov
46+
47+
# Coverage directory used by tools like istanbul
48+
coverage
49+
*.lcov
50+
51+
# nyc test coverage
52+
.nyc_output
53+
54+
# node-waf configuration
55+
.lock-wscript
56+
57+
# Compiled binary addons (https://nodejs.org/api/addons.html)
58+
build/Release
59+
60+
# Dependency directories
61+
node_modules/
62+
jspm_packages/
63+
64+
# TypeScript v1 declaration files
65+
typings/
66+
67+
# TypeScript cache
68+
*.tsbuildinfo
69+
70+
# Optional npm cache directory
71+
.npm
72+
73+
# Optional eslint cache
74+
.eslintcache
75+
76+
# Optional REPL history
77+
.node_repl_history
78+
79+
# Output of 'npm pack'
80+
*.tgz
81+
82+
# Yarn Integrity file
83+
.yarn-integrity
84+
85+
# dotenv environment variables file
86+
.env
87+
.env.test
88+
89+
# parcel-bundler cache (https://parceljs.org/)
90+
.cache
91+
92+
# rollup.js default build output
93+
dist/
94+
95+
# vuepress build output
96+
.vuepress/dist
97+
98+
# Serverless directories
99+
.serverless/
100+
101+
# Temporary folders
102+
tmp/
103+
temp/

src/.vuepress/config.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ const sidebar = {
2727
'/guide/component-slots',
2828
'/guide/component-provide-inject'
2929
]
30+
},
31+
{
32+
title: 'Migration to Vue 3',
33+
collapsable: true,
34+
children: ['migration']
35+
},
36+
{
37+
title: 'Contribute to the Docs',
38+
collapsable: true,
39+
children: ['writing-guide']
3040
}
3141
]
3242
}
Loading

src/guide/migration.md

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# Migration
2+
3+
> There's so much here! Does that mean 3.0 is completely different, I'll have to learn the basics all over again, and migrating will be practically impossible?
4+
5+
We're glad you asked! The answer is no. We've gone to great lengths to ensure most of the API is the same and the core concepts haven't changed. It's long because we like to offer very detailed explanations and include a lot of examples. Rest assured, **this is not something you have to read from top to bottom!**
6+
7+
[//]: # 'TODO: update composition API with a link'
8+
9+
Possibly the biggest change is our new Composition API, which is entirely additive- the previous Options API will continue to be supported, as the Composition API is an advanced feature.
10+
11+
## FAQ
12+
13+
> Where should I start in a migration?
14+
15+
[//]: # 'TODO: update this link when we have a migration helper'
16+
17+
1. Start by running the [migration helper](https://github.com/vuejs/vue-migration-helper) on a current project. We've carefully minified and compressed a senior Vue dev into a simple command line interface. Whenever they recognize an obsolete feature, they'll let you know, offer suggestions, and provide links to more info.
18+
19+
2. After that, browse through the table of contents for this page in the sidebar. If you see a topic you may be affected by, but the migration helper didn't catch, check it out.
20+
21+
3. If you have any tests, run them and see what still fails. If you don't have tests, just open the app in your browser and keep an eye out for warnings or errors as you navigate around.
22+
23+
4. By now, your app should be fully migrated. If you're still hungry for more though, you can read the rest of this page - or dive in to the new and improved guide from [the beginning](index.html). Many parts will be skimmable, since you're already familiar with the core concepts.
24+
25+
> How long will it take to migrate a Vue 2.x app to 3.0?
26+
27+
It depends on a few factors:
28+
29+
- The size of your app (small to medium-sized apps will probably be less than a day)
30+
31+
- How many times you get distracted and start playing with a cool new feature. 😉  Not judging, it also happened to us while building 3.0!
32+
33+
[//]: # 'TODO: update this with link to styleguide'
34+
35+
- Which obsolete features you're using. Most can be upgraded with find-and-replace, but others might take a few minutes. If you're not currently following best practices according to our styleguide, Vue 3.0 will also try harder to force you to. This is a good thing in the long run, but could also mean a significant (though possibly overdue) refactor.
36+
37+
> If I upgrade to Vue 3, will I also have to upgrade Vuex and Vue Router?
38+
39+
[//]: # 'TODO: still need to see where this lands'
40+
41+
## Built-in Directives
42+
43+
### `v-model` API Change
44+
45+
In Vue 2, the `v-model` directive required developers to always use the `value` prop. And if developers required different props for different purposes, they would have to resort to using `v-bind.sync`. In addition, this hard-coded relationship between `v-model` and `value` led to issues with how native elements and custom elements were handled.
46+
47+
However, with Vue 3, the API for two-way data binding is being standardized in order to reduce confusion and to allow developers more flexibility with the `v-model` directive.
48+
49+
Using v-model in Vue 3
50+
In Vue 3, by detaching the `v-model` from the `value` prop, developers now have the ability to pass arguments to `v-model` which will allow them to create multiple `v-model` bindings on a single component.
51+
52+
```html
53+
<SignupForm v-model:name="”userName”" v-model:email="”userEmail”" />
54+
```
55+
56+
#### Modifiers
57+
58+
In Vue 2.x, hard-coded modifiers such as `.trim` on `v-model` were introduced to provide an intuitive way to solve common scenarios. However,
59+
60+
[//]: # 'TODO: still need to finish, and perhaps add in caveats'
61+
62+
### `v-model.sync` Replaced with `v-model` Argument
63+
64+
In Vue 2, the `.sync` modifier was created in order to offer a shorthand way to create two-way data binding for a prop. For example, in the event we want a child component to update its own title property, we would have done something like this:
65+
66+
**ChildComponent.vue**
67+
68+
```html
69+
this.$emit('onUpdate:title', newTitle)
70+
```
71+
72+
**ParentComponent.vue**
73+
74+
```html
75+
<child-component v-bind:title.sync="pageTitle"></child-component>
76+
```
77+
78+
However, this led to some confusion since two-way data flow is closely tied to the `v-model` directive, whereas `v-bind` is normally used for one-way data flow for props.
79+
80+
#### How to Sync Props in Vue 3
81+
82+
In Vue 3, we no longer need the `.sync` modifier anymore. Similar to how we can listen for changes to a form input value, Vue 3 allows us to perform "two way data binding" on props by allowing you to pass the prop as an argument to `v-model`.
83+
84+
![v-bind anatomy](/images/v-bind-instead-of-sync.png)
85+
86+
Using the example from before, it can now be simplified to:
87+
88+
**ParentComponent.vue**
89+
90+
```html
91+
<child-component v-model:title="pageTitle"></child-component>
92+
```
93+
94+
By passing our prop title to the `v-model` directive, Vue will listen for an `onUpdate:title` event that will be emitted from the child component in order to update the data accordingly.
95+
96+
## Custom Directives
97+
98+
### Custom Directive Lifecycle API
99+
100+
Abstractions can be incredibly powerful to development, but they tend to break down when there is no escape hatch or extension beyond the original implementation. Custom directives allow us to create directives that are unique to our application.
101+
102+
Previously, we constructed these directives by using the hooks listed below to target an element’s lifecycle, all of which are optional:
103+
104+
- **bind** - Occurs once the directive is bound to the element. Occurs only once.
105+
- **inserted** - Occurs once the element is inserted into the parent DOM.
106+
- **update** - This hook is called when the element updates, but children haven't been updated yet.
107+
- **componentUpdated** - This hook is called once the component and the children have been updated.
108+
- **unbind** - This hook is called once the directive is removed. Also called only once.
109+
110+
Here’s an example of this:
111+
112+
```html
113+
<p v-highlight="yellow">Highlight this text bright yellow</p>
114+
```
115+
116+
```js
117+
Vue.directive('highlight', {
118+
bind(el, binding, vnode) {
119+
el.style.background = binding.value
120+
}
121+
})
122+
```
123+
124+
Here, in the initial setup for this element, the directive binds a style by passing in a value, that can be updated to different values through the application.
125+
126+
In Vue 3, however, we’ve created a more cohesive API for custom directives. As you can see, they differ greatly from our component lifecycle methods even though we’re hooking into similar events. We’ve now unified them like so:
127+
128+
- bind → **beforeMount**
129+
- inserted → **mounted**
130+
- **beforeUpdate**: new! this is called before the element itself is updated, much like the component lifecycle hooks.
131+
- update → removed! There were too many similarities to updated, so this is redundant. Please use updated instead.
132+
- componentUpdated → **updated**
133+
- **beforeUnmount** new! similar to component lifecycle hooks, this will be called right before an element is unmounted.
134+
- unbind -> **unmounted**
135+
136+
The final API is as follows:
137+
138+
```js
139+
const MyDirective = {
140+
beforeMount(el, binding, vnode, prevVnode) {},
141+
mounted() {},
142+
beforeUpdate() {},
143+
updated() {},
144+
beforeUnmount() {}, // new
145+
unmounted() {}
146+
}
147+
```
148+
149+
The resulting API could be used like this, mirroring the example from earlier:
150+
151+
```html
152+
<p v-highlight="yellow">Highlight this text bright yellow</p>
153+
```
154+
155+
```js
156+
Vue.directive('highlight', {
157+
beforeMount(el, binding, vnode) {
158+
el.style.background = binding.value
159+
}
160+
})
161+
```
162+
163+
Now that the custom directive lifecycle hooks mirror those of the components themselves, they become easier to reason about and remember!
164+
165+
#### Implementation Details
166+
167+
In Vue 3, we’re now supporting fragments, which allow us to return more than one DOM node per component. You can imagine how handy that is for something like a component with multiple lis or the children elements of a table:
168+
169+
```html
170+
<>
171+
<li>Hello</li>
172+
<li>Vue</li>
173+
<li>Devs!</li>
174+
</>
175+
```
176+
177+
As wonderfully flexible as this is, we can potentially encounter a problem with a custom directive that could potentially have multiple root nodes.
178+
179+
As a result, custom directives are included as part of a virtual DOM node’s data. When a custom directive is used on a component, hooks are passed down to the component as extraneous props and end up in this.\$attrs.
180+
181+
[//]: # 'TODO: add in a better example'
182+
183+
[example]
184+
185+
This also means it's possible to directly hook into an element's lifecycle like this in the template, which can be handy when a custom directive is too involved:
186+
187+
[write a better example with more text when it’s implemented]
188+
189+
```html
190+
<div @vnodeMounted="myHook" />
191+
```
192+
193+
[//]: # 'TODO: add in link'
194+
195+
This is consistent with the attribute fallthrough behavior, so when a child component uses `v-bind="$attrs"` on an inner element, it will apply any custom directives used on it as well.

0 commit comments

Comments
 (0)