-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Move component registration #42
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 27 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
728e5a7
feat: started component basics
7c67b7d
feat: add button-counter example
89774c7
feat: moved component props
64847f5
feat: reworked events on components
b68d5db
Added v-model on components
ceb3aaa
feat: added slots to components basic
ee9757e
feat: added dynamic components
047ccfc
fix: fixed config
6f53955
fix: replaced fiddles with codesandboxes
22292da
Merge branch 'master' into move-component-basics
NataliaTepluhina 72cf025
Merge branch 'master' into move-component-basics
NataliaTepluhina 9e017f4
Update src/guide/component-basics.md
NataliaTepluhina bd6906c
fix: removed new Vue reminiscenses
7408763
Merge branch 'move-component-basics' of github.com:vuejs/docs-next in…
480d069
fix: fixed createApp reference
a0daafd
fix: fixed update events names
65fb43c
fix: fixed createApp
3d1d7f4
fix: changed modelValue to be camelCase
f03509a
fix: fixed prop name
caf4de5
Update src/guide/component-basics.md
NataliaTepluhina ba7519f
Update src/guide/component-basics.md
NataliaTepluhina ba6221d
feat: added a note on case-insensitiveness
dc085e5
feat: moved component registration
23d76af
Merge branch 'master' into move-component-registration
64a76e3
Update src/guide/component-registration.md
NataliaTepluhina 28a0d99
Update src/guide/component-registration.md
NataliaTepluhina 20a0324
Update src/guide/component-registration.md
NataliaTepluhina 41284fe
fix: removed global base registration recipe
01c8c47
Merge branch 'move-component-registration' of github.com:vuejs/docs-n…
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,252 @@ | ||
# Component Registration | ||
|
||
> This page assumes you've already read the [Components Basics](component-basics.md). Read that first if you are new to components. | ||
|
||
<div class="vueschool"><a href="https://vueschool.io/lessons/global-vs-local-components?friend=vuejs" target="_blank" rel="sponsored noopener" title="Free Vue.js Component Registration lesson">Watch a free video lesson on Vue School</a></div> | ||
|
||
## Component Names | ||
|
||
When registering a component, it will always be given a name. For example, in the global registration we've seen so far: | ||
|
||
```js | ||
const app = createApp({...}) | ||
|
||
app.component('my-component-name', { | ||
/* ... */ | ||
}) | ||
``` | ||
|
||
The component's name is the first argument of `app.component`. In the example above, the component's name is "my-component-name". | ||
|
||
The name you give a component may depend on where you intend to use it. When using a component directly in the DOM (as opposed to in a string template or [single-file component](TODO: single-file-components.html)), we strongly recommend following the [W3C rules](https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name) for custom tag names: | ||
|
||
1. All lowercase | ||
2. Contains a hyphen (i.e., has multiple words connected with the hyphen symbol) | ||
|
||
By doing so, this will help you avoid conflicts with current and future HTML elements. | ||
|
||
You can see other recommendations for component names in the [Style Guide](TODO:../style-guide/#Base-component-names-strongly-recommended). | ||
|
||
### Name Casing | ||
|
||
When defining components in a string template or a single-file component, you have two options when defining component names: | ||
|
||
#### With kebab-case | ||
|
||
```js | ||
app.component('my-component-name', { | ||
/* ... */ | ||
}) | ||
``` | ||
|
||
When defining a component with kebab-case, you must also use kebab-case when referencing its custom element, such as in `<my-component-name>`. | ||
|
||
#### With PascalCase | ||
|
||
```js | ||
app.component('MyComponentName', { | ||
/* ... */ | ||
}) | ||
``` | ||
|
||
When defining a component with PascalCase, you can use either case when referencing its custom element. That means both `<my-component-name>` and `<MyComponentName>` are acceptable. Note, however, that only kebab-case names are valid directly in the DOM (i.e. non-string templates). | ||
|
||
## Global Registration | ||
|
||
So far, we've only created components using `Vue.component`: | ||
|
||
```js | ||
Vue.createApp({...}).component('my-component-name', { | ||
// ... options ... | ||
}) | ||
``` | ||
|
||
These components are **globally registered**. That means they can be used in the template of any root Vue instance created after registration. For example: | ||
|
||
```js | ||
const app = Vue.createApp({}) | ||
|
||
app.component('component-a', { | ||
/* ... */ | ||
}) | ||
app.component('component-b', { | ||
/* ... */ | ||
}) | ||
app.component('component-c', { | ||
/* ... */ | ||
}) | ||
|
||
app.mount('#app') | ||
``` | ||
|
||
```html | ||
<div id="app"> | ||
<component-a></component-a> | ||
<component-b></component-b> | ||
<component-c></component-c> | ||
</div> | ||
``` | ||
|
||
This even applies to all subcomponents, meaning all three of these components will also be available _inside each other_. | ||
|
||
## Local Registration | ||
|
||
Global registration often isn't ideal. For example, if you're using a build system like Webpack, globally registering all components means that even if you stop using a component, it could still be included in your final build. This unnecessarily increases the amount of JavaScript your users have to download. | ||
|
||
In these cases, you can define your components as plain JavaScript objects: | ||
|
||
```js | ||
const ComponentA = { | ||
/* ... */ | ||
} | ||
const ComponentB = { | ||
/* ... */ | ||
} | ||
const ComponentC = { | ||
/* ... */ | ||
} | ||
``` | ||
|
||
Then define the components you'd like to use in a `components` option: | ||
|
||
```js | ||
const app = Vue.createApp({ | ||
components: { | ||
'component-a': ComponentA, | ||
'component-b': ComponentB | ||
} | ||
}) | ||
``` | ||
|
||
For each property in the `components` object, the key will be the name of the custom element, while the value will contain the options object for the component. | ||
|
||
Note that **locally registered components are _not_ also available in subcomponents**. For example, if you wanted `ComponentA` to be available in `ComponentB`, you'd have to use: | ||
|
||
```js | ||
const ComponentA = { | ||
/* ... */ | ||
} | ||
|
||
const ComponentB = { | ||
components: { | ||
'component-a': ComponentA | ||
} | ||
// ... | ||
} | ||
``` | ||
|
||
Or if you're using ES2015 modules, such as through Babel and Webpack, that might look more like: | ||
|
||
```js | ||
import ComponentA from './ComponentA.vue' | ||
|
||
export default { | ||
components: { | ||
ComponentA | ||
} | ||
// ... | ||
} | ||
``` | ||
|
||
Note that in ES2015+, placing a variable name like `ComponentA` inside an object is shorthand for `ComponentA: ComponentA`, meaning the name of the variable is both: | ||
|
||
- the custom element name to use in the template, and | ||
- the name of the variable containing the component options | ||
|
||
## Module Systems | ||
|
||
If you're not using a module system with `import`/`require`, you can probably skip this section for now. If you are, we have some special instructions and tips just for you. | ||
|
||
### Local Registration in a Module System | ||
|
||
If you're still here, then it's likely you're using a module system, such as with Babel and Webpack. In these cases, we recommend creating a `components` directory, with each component in its own file. | ||
|
||
Then you'll need to import each component you'd like to use, before you locally register it. For example, in a hypothetical `ComponentB.js` or `ComponentB.vue` file: | ||
|
||
```js | ||
import ComponentA from './ComponentA' | ||
import ComponentC from './ComponentC' | ||
|
||
export default { | ||
components: { | ||
ComponentA, | ||
ComponentC | ||
} | ||
// ... | ||
} | ||
``` | ||
|
||
Now both `ComponentA` and `ComponentC` can be used inside `ComponentB`'s template. | ||
|
||
### Automatic Global Registration of Base Components | ||
|
||
Many of your components will be relatively generic, possibly only wrapping an element like an input or a button. We sometimes refer to these as [base components](TODO:../style-guide/#Base-component-names-strongly-recommended) and they tend to be used very frequently across your components. | ||
|
||
The result is that many components may include long lists of base components: | ||
|
||
```js | ||
import BaseButton from './BaseButton.vue' | ||
import BaseIcon from './BaseIcon.vue' | ||
import BaseInput from './BaseInput.vue' | ||
|
||
export default { | ||
components: { | ||
BaseButton, | ||
BaseIcon, | ||
BaseInput | ||
} | ||
} | ||
``` | ||
|
||
Just to support relatively little markup in a template: | ||
|
||
```html | ||
<BaseInput v-model="searchText" v-on:keydown.enter="search" /> | ||
<BaseButton v-on:click="search"> | ||
<BaseIcon name="search" /> | ||
</BaseButton> | ||
``` | ||
|
||
Fortunately, if you're using Webpack (or [Vue CLI](https://github.com/vuejs/vue-cli), which uses Webpack internally), you can use `require.context` to globally register only these very common base components. Here's an example of the code you might use to globally import base components in your app's entry file (e.g. `src/main.js`): | ||
|
||
```js | ||
import Vue from 'vue' | ||
import upperFirst from 'lodash/upperFirst' | ||
import camelCase from 'lodash/camelCase' | ||
|
||
const requireComponent = require.context( | ||
// The relative path of the components folder | ||
'./components', | ||
// Whether or not to look in subfolders | ||
false, | ||
// The regular expression used to match base component filenames | ||
/Base[A-Z]\w+\.(vue|js)$/ | ||
) | ||
|
||
requireComponent.keys().forEach(fileName => { | ||
// Get component config | ||
const componentConfig = requireComponent(fileName) | ||
|
||
// Get PascalCase name of component | ||
const componentName = upperFirst( | ||
camelCase( | ||
// Gets the file name regardless of folder depth | ||
fileName | ||
.split('/') | ||
.pop() | ||
.replace(/\.\w+$/, '') | ||
) | ||
) | ||
|
||
// Register component globally | ||
const app = Vue.createApp({}) | ||
|
||
app.component( | ||
componentName, | ||
// Look for the component options on `.default`, which will | ||
// exist if the component was exported with `export default`, | ||
// otherwise fall back to module's root. | ||
componentConfig.default || componentConfig | ||
) | ||
}) | ||
``` |
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.
Uh oh!
There was an error while loading. Please reload this page.