Skip to content
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

Global API updates: more details on mounting behavior + replacement for Vue.prototype #117

Merged
merged 2 commits into from
Mar 25, 2020
Merged
Changes from 1 commit
Commits
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
31 changes: 31 additions & 0 deletions active-rfcs/0009-global-api-change.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Vue.mixin(/* ... */)
Vue.component(/* ... */)
Vue.directive(/* ... */)

Vue.prototype.customProperty = () => {}

new Vue({
render: h => h(App)
}).$mount('#app')
Expand All @@ -44,6 +46,8 @@ app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)

app.config.globalProperties.customProperty = () => {}
Copy link
Member

Choose a reason for hiding this comment

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

Is there an interface that can be extended to type new properties?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'd say just don't use this if using TS.

Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't this be better for people migrating TS projects using libraries that are not adapted yet (or that may never completely adapt) to the inject/provide?

Copy link
Member Author

Choose a reason for hiding this comment

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

There's no way to make this work in TS though. If users insist on using this with TS they'd have to shim the types themselves.

Copy link
Member

Choose a reason for hiding this comment

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

If users insist on using this with TS they'd have to shim the types themselves

Oh yeah, I just thinking of exposing an interface that can be extended by users to add their own typings


app.mount(App, '#app')
```

Expand Down Expand Up @@ -112,6 +116,18 @@ app.mount(App, '#app', {
})
```

### Mounting Behavior Difference from 2.x

When using the compiler-included build and mounting a root component with no template of its own, Vue will attempt to use the mount target element's content as template. Note the differences between the 3.x behavior and 2.x:

- In 2.x, the root instance uses target element's `outerHTML` as template and replaces target element itself.

- In 3.x, the root instance uses target element's `innerHTML` as template and only replaces target element's children.

In most cases this should have no effect on how your app behaves, with the only side effect being that if the target element contains multiple children, the root instance will be mounted as a fragment and its `this.$el` will be pointing to the starting anchor node of the fragment (a DOM Comment node).

In Vue 3, due to the availability of Fragments, it is recommended to use template refs for direct access to DOM nodes instead of relying on `this.$el`.

## Provide / Inject

An app instance can also provide dependencies that can be injected by any component inside the app:
Expand Down Expand Up @@ -160,6 +176,21 @@ app.config.isCustomElement = tag => tag.startsWith('ion-')

- This will be a new top-level option in the Vue CLI config.

## Attaching Globally Shared Instance Properties

In 2.x, it was possible to inject globally shared instance properties by simply attaching them to `Vue.prototype`.

In Vue 3, since the global `Vue` is no longer a constructor, this is no longer supported. Instead, shared instance properties should be attached to an app instance's `config.globalProperties` instead:

``` js
// Before
Vue.prototype.$http = () => {}

// After
const app = createApp()
app.config.globalProperties.$http = () => {}
Copy link
Member

Choose a reason for hiding this comment

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

how would we access this inside the setup function?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is essentially a legacy escape hatch and not for setup function. You should just import things directly or use provide/inject in setup functions.

Copy link
Contributor

Choose a reason for hiding this comment

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

This won't work for legacy apps that use multiple instances and apply Vue.use globally since you'd have to run app.use in every one of them. If that's required only for legacy plugins shouldn't that be included only in the compatibility build with global registration on the prototype as usual? That way you won't have to rewrite that much and stay with global Vue.use. Why would you need that hack for anything but legacy plugins? (Assuming that the new strategy for plugins is to utilize provide\inject).

Copy link
Member Author

Choose a reason for hiding this comment

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

The "legacy" term I used was incorrect - it should be for "options/this-based usage". Even with setup function this can still be used to expose globally available properties to templates.

With the global API change there is no once-for-all global configs anymore. 2.x multi-root-instance apps will have to be updated to configure each root instance individually. If all root instances share the same config, then it can be extracted into a shared function.

```

# Drawbacks

## Plugin auto installation
Expand Down