-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Added custom components interop migration section #177
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
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
882e969
feat: added migration for custom components
NataliaTepluhina 5671b13
fix: fixed is attribute usage
NataliaTepluhina a7a4364
feat: added v-is to API reference
NataliaTepluhina 442edf7
fix: added nore about Vue templates
NataliaTepluhina b0d966c
Update src/guide/migration/custom-elements-interop.md
NataliaTepluhina File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
--- | ||
types: | ||
- breaking | ||
--- | ||
|
||
# Custom Elements Interop changes <span v-for="type in $frontmatter.types" class="badge" :key="`type-${type}`">{{ type }}</span> | ||
|
||
# Overview | ||
|
||
- **BREAKING:** Custom elements whitelisting is now performed during template compilation, and should be configured via compiler options instead of runtime config. | ||
- **BREAKING:** Special `is` prop usage is restricted to the reserved `<component>` tag only. | ||
- **NEW:** There is new `v-is` directive to support 2.x use cases where `is` was used on native elements to work around native HTML parsing restrictions. | ||
|
||
## Autonomous Custom Elements | ||
|
||
If we want to add a custom element defined outside of Vue (e.g. using the Web Components API), we need to 'instruct' Vue to treat it as a custom element. Let's use the following template as an example. | ||
|
||
```html | ||
<plastic-button></plastic-button> | ||
``` | ||
|
||
### 2.x Syntax | ||
|
||
In Vue 2.x, whitelisting tags as custom elements was done via `Vue.config.ignoredElements`: | ||
|
||
```js | ||
// This will make Vue ignore custom element defined outside of Vue | ||
// (e.g., using the Web Components APIs) | ||
|
||
Vue.config.ignoredElements = ['plastic-button'] | ||
``` | ||
|
||
### 3.x Syntax | ||
|
||
**In Vue 3.0, this check is performed during template compilation.** To instruct the compiler to treat `<plastic-button>` as a custom element: | ||
|
||
- If using a build step: pass the `isCustomElement` option to the Vue template compiler. If using `vue-loader`, this should be passed via `vue-loader`'s `compilerOptions` option: | ||
|
||
```js | ||
// in webpack config | ||
rules: [ | ||
{ | ||
test: /\.vue$/, | ||
use: 'vue-loader', | ||
options: { | ||
compilerOptions: { | ||
isCustomElement: tag => tag === 'plastic-button' | ||
} | ||
} | ||
} | ||
// ... | ||
] | ||
``` | ||
|
||
- If using on-the-fly template compilation, pass it via `app.config.isCustomElement`: | ||
|
||
```js | ||
const app = Vue.createApp({}) | ||
app.config.isCustomElement = tag => tag === 'plastic-button' | ||
``` | ||
|
||
It's important to note the runtime config only affects runtime template compilation - it won't affect pre-compiled templates. | ||
|
||
## Customized Built-in Elements | ||
|
||
The Custom Elements specification provides a way to use custom elements as [Customized Built-in Element](https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-customized-builtin-example) by adding the `is` attribute to a built-in element: | ||
|
||
```html | ||
<button is="plastic-button">Click Me!</button> | ||
``` | ||
|
||
Vue's usage of the `is` special prop was simulating what the native attribute does before it was made universally available in browsers. However, in 2.x it was interpreted as rendering a Vue component with the name `plastic-button`. This blocks the native usage of Customized Built-in Element mentioned above. | ||
|
||
In 3.0, we are limiting Vue's special treatment of the `is` prop to the `<component>` tag only. | ||
|
||
- When used on the reserved `<component>` tag, it will behave exactly the same as in 2.x; | ||
- When used on normal components, it will behave like a normal prop: | ||
|
||
```html | ||
<foo is="bar" /> | ||
``` | ||
|
||
- 2.x behavior: renders the `bar` component. | ||
- 3.x behavior: renders the `foo` component and passing the `is` prop. | ||
|
||
- When used on plain elements, it will be passed to the `createElement` call as the `is` option, and also rendered as a native attribute. This supports the usage of customized built-in elements. | ||
|
||
```html | ||
<button is="plastic-button">Click Me!</button> | ||
``` | ||
|
||
- 2.x behavior: renders the `plastic-button` component. | ||
- 3.x behavior: renders a native button by calling | ||
|
||
```js | ||
document.createElement('button', { is: 'plastic-button' }) | ||
``` | ||
|
||
## `v-is` for In-DOM Template Parsing Workarounds | ||
|
||
> Note: this section only affects cases where Vue templates are directly written in the page's HTML. | ||
> When using in-DOM templates, the template is subject to native HTML parsing rules. Some HTML elements, such as `<ul>`, `<ol>`, `<table>` and `<select>` have restrictions on what elements can appear inside them, and some elements such as `<li>`, `<tr>`, and `<option>` can only appear inside certain other elements. | ||
|
||
### 2x Syntax | ||
|
||
In Vue 2 we recommended working around with these restrictions by using the `is` prop on a native tag: | ||
|
||
```html | ||
<table> | ||
<tr is="blog-post-row"></tr> | ||
</table> | ||
``` | ||
|
||
### 3.x Syntax | ||
|
||
With the behavior change of `is`, we introduce a new directive `v-is` for working around these cases: | ||
|
||
```html | ||
<table> | ||
<tr v-is="'blog-post-row'"></tr> | ||
</table> | ||
``` | ||
|
||
:::warning | ||
`v-is` functions like a dynamic 2.x `:is` binding - so to render a component by its registered name, its value should be a JavaScript string literal: | ||
|
||
```html | ||
<!-- Incorrect, nothing will be rendered --> | ||
<tr v-is="blog-post-row"></tr> | ||
|
||
<!-- Correct --> | ||
<tr v-is="'blog-post-row'"></tr> | ||
``` | ||
|
||
::: | ||
|
||
## Migration Strategy | ||
|
||
- Replace `config.ignoredElements` with either `vue-loader`'s `compilerOptions` (with the build step) or `app.config.isCustomElement` (with on-the-fly template compilation) | ||
|
||
- Change all non-`<component>` tags with `is` usage to `<component is="...">` (for SFC templates) or `v-is` (for in-DOM templates). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is component more accurate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bencodezen ugh, it's complicated 😅 it's a custom element, not Vue component, that's why I used
template
word here