diff --git a/.vitepress/config.js b/.vitepress/config.js index 8e337bc..cbb921e 100644 --- a/.vitepress/config.js +++ b/.vitepress/config.js @@ -6,13 +6,14 @@ import locales from "./locales" export default { srcDir: 'src', locales: locales.vitepressConfig, - + themeConfig: { localeLinks: { items: [ {text: 'English', link: '/'}, - {text: '中文简体', link: '/zh/'} + {text: '中文简体', link: '/zh/'}, + {text: '日本語(翻訳中)', link: '/ja/'}, ] }, locales: locales.themeConfig diff --git a/.vitepress/locales/index.js b/.vitepress/locales/index.js index ff3ef3c..bdd2f4b 100644 --- a/.vitepress/locales/index.js +++ b/.vitepress/locales/index.js @@ -1,13 +1,16 @@ import en from './en' import zh from './zh' +import ja from './ja' export default { vitepressConfig: { '/': en.vitepressConfig, - '/zh/': zh.vitepressConfig + '/zh/': zh.vitepressConfig, + '/ja/': ja.vitepressConfig, }, themeConfig: { '/': en.themeConfig, - '/zh/': zh.themeConfig + '/zh/': zh.themeConfig, + '/ja/': ja.themeConfig, } -} \ No newline at end of file +} diff --git a/.vitepress/locales/ja.js b/.vitepress/locales/ja.js new file mode 100644 index 0000000..0372d60 --- /dev/null +++ b/.vitepress/locales/ja.js @@ -0,0 +1,164 @@ +export default { + vitepressConfig: { + title: 'Vue 3 移行ガイド', + description: 'Vue 2 から Vue 3 への移行に関するガイド', + lang: 'ja-JP', + }, + themeConfig: { + docFooter: { + prev: '前のページ', + next: '次のページ', + }, + outlineTitle: 'ページの内容', + nav: [ + { text: 'Vue 3 ドキュメント', link: 'https://ja.vuejs.org' }, + ], + + sidebar: [ + { + text: 'ガイド', + items: [ + { text: '概要', link: '/ja/' }, + { text: '新しい推奨事項', link: '/ja/recommendations' }, + { text: '移行ビルド', link: '/ja/migration-build' }, + { + text: '破壊的変更', + link: '/ja/breaking-changes/' + } + ] + }, + { + text: 'Global API', + items: [ + { + text: 'Global API Application Instance', + link: '/ja/breaking-changes/global-api' + }, + { + text: 'Global API Treeshaking', + link: '/ja/breaking-changes/global-api-treeshaking' + } + ] + }, + { + text: 'Template Directives', + items: [ + { text: 'v-model', link: '/ja/breaking-changes/v-model' }, + { + text: 'key Usage Change', + link: '/ja/breaking-changes/key-attribute' + }, + { + text: 'v-if vs. v-for Precedence', + link: '/ja/breaking-changes/v-if-v-for' + }, + { text: 'v-bind Merge Behavior', link: '/ja/breaking-changes/v-bind' }, + { + text: 'v-on.native modifier removed', + link: '/ja/breaking-changes/v-on-native-modifier-removed' + } + ] + }, + { + text: 'Components', + items: [ + { + text: 'Functional Components', + link: '/ja/breaking-changes/functional-components' + }, + { + text: 'Async Components', + link: '/ja/breaking-changes/async-components' + }, + { text: 'emits Option', link: '/ja/breaking-changes/emits-option' } + ] + }, + { + text: 'Render Function', + items: [ + { + text: 'Render Function API', + link: '/ja/breaking-changes/render-function-api' + }, + { + text: 'Slots Unification', + link: '/ja/breaking-changes/slots-unification' + }, + { + text: '$listeners merged into $attrs', + link: '/ja/breaking-changes/listeners-removed' + }, + { + text: '$attrs includes class & style', + link: '/ja/breaking-changes/attrs-includes-class-style' + } + ] + }, + { + text: 'Custom Elements', + items: [ + { + text: 'Custom Elements Interop Changes', + link: '/ja/breaking-changes/custom-elements-interop' + } + ] + }, + { + text: 'Removed APIs', + items: [ + { + text: 'v-on keyCode Modifiers', + link: '/ja/breaking-changes/keycode-modifiers' + }, + { text: 'Events API', link: '/ja/breaking-changes/events-api' }, + { text: 'Filters', link: '/ja/breaking-changes/filters' }, + { + text: 'inline-template', + link: '/ja/breaking-changes/inline-template-attribute' + }, + { text: '$children', link: '/ja/breaking-changes/children' }, + { text: 'propsData option', link: '/ja/breaking-changes/props-data' } + ] + }, + { + text: 'Other Minor Changes', + items: [ + { + text: 'Attribute Coercion Behavior', + link: '/ja/breaking-changes/attribute-coercion' + }, + { + text: 'Custom Directives', + link: '/ja/breaking-changes/custom-directives' + }, + { text: 'Data Option', link: '/ja/breaking-changes/data-option' }, + { + text: 'Mount API changes', + link: '/ja/breaking-changes/mount-changes' + }, + { + text: 'Props Default Function this Access', + link: '/ja/breaking-changes/props-default-this' + }, + { + text: 'Transition Class Change', + link: '/ja/breaking-changes/transition' + }, + { + text: 'Transition as Root', + link: '/ja/breaking-changes/transition-as-root' + }, + { + text: 'Transition Group Root Element', + link: '/ja/breaking-changes/transition-group' + }, + { + text: 'VNode lifecycle events', + link: '/ja/breaking-changes/vnode-lifecycle-events' + }, + { text: 'Watch on Arrays', link: '/ja/breaking-changes/watch' } + ] + } + ] + } +} diff --git a/src/ja/breaking-changes/async-components.md b/src/ja/breaking-changes/async-components.md new file mode 100644 index 0000000..c6c9981 --- /dev/null +++ b/src/ja/breaking-changes/async-components.md @@ -0,0 +1,98 @@ +--- +badges: + - new +--- + +# Async Components + +## Overview + +Here is a high level overview of what has changed: + +- New `defineAsyncComponent` helper method that explicitly defines async components +- `component` option renamed to `loader` +- Loader function does not inherently receive `resolve` and `reject` arguments and must return a Promise + +For a more in-depth explanation, read on! + +## Introduction + +Previously, async components were created by simply defining a component as a function that returned a promise, such as: + +```js +const asyncModal = () => import('./Modal.vue') +``` + +Or, for the more advanced component syntax with options: + +```js +const asyncModal = { + component: () => import('./Modal.vue'), + delay: 200, + timeout: 3000, + error: ErrorComponent, + loading: LoadingComponent +} +``` + +## 3.x Syntax + +Now, in Vue 3, since functional components are defined as pure functions, async components definitions need to be explicitly defined by wrapping it in a new `defineAsyncComponent` helper: + +```js +import { defineAsyncComponent } from 'vue' +import ErrorComponent from './components/ErrorComponent.vue' +import LoadingComponent from './components/LoadingComponent.vue' + +// Async component without options +const asyncModal = defineAsyncComponent(() => import('./Modal.vue')) + +// Async component with options +const asyncModalWithOptions = defineAsyncComponent({ + loader: () => import('./Modal.vue'), + delay: 200, + timeout: 3000, + errorComponent: ErrorComponent, + loadingComponent: LoadingComponent +}) +``` + +::: tip NOTE +Vue Router supports a similar mechanism for asynchronously loading route components, known as *lazy loading*. Despite the similarities, this feature is distinct from Vue's support for async components. You should **not** use `defineAsyncComponent` when configuring route components with Vue Router. You can read more about this in the [Lazy Loading Routes](https://router.vuejs.org/guide/advanced/lazy-loading.html) section of the Vue Router documentation. +::: + +Another change that has been made from 2.x is that the `component` option is now renamed to `loader` in order to accurately communicate that a component definition cannot be provided directly. + +```js{4} +import { defineAsyncComponent } from 'vue' + +const asyncModalWithOptions = defineAsyncComponent({ + loader: () => import('./Modal.vue'), + delay: 200, + timeout: 3000, + errorComponent: ErrorComponent, + loadingComponent: LoadingComponent +}) +``` + +In addition, unlike 2.x, the loader function no longer receives the `resolve` and `reject` arguments and must always return a Promise. + +```js +// 2.x version +const oldAsyncComponent = (resolve, reject) => { + /* ... */ +} + +// 3.x version +const asyncComponent = defineAsyncComponent( + () => + new Promise((resolve, reject) => { + /* ... */ + }) +) +``` + +For more information on the usage of async components, see: + +- [Guide: Async Components](https://ja.vuejs.org/guide/components/async.html) +- [Migration build flag: `COMPONENT_ASYNC`](../migration-build.html#compat-configuration) diff --git a/src/ja/breaking-changes/attribute-coercion.md b/src/ja/breaking-changes/attribute-coercion.md new file mode 100644 index 0000000..dcb9a7c --- /dev/null +++ b/src/ja/breaking-changes/attribute-coercion.md @@ -0,0 +1,144 @@ +--- +badges: + - breaking +--- + +# Attribute Coercion Behavior + +::: info Info +This is a low-level internal API change and does not affect most developers. +::: + +## Overview + +Here is a high level summary of the changes: + +- Drop the internal concept of enumerated attributes and treat those attributes the same as normal non-boolean attributes +- **BREAKING**: No longer removes attribute if the value is boolean `false`. Instead, it's set as attr="false". To remove the attribute, use `null` or `undefined`. + +For more information, read on! + +## 2.x Syntax + +In 2.x, we had the following strategies for coercing `v-bind` values: + +- For some attribute/element pairs, Vue is always using the corresponding IDL attribute (property): [like `value` of ``, ` + +``` + +## 3.x Behavior + +`$attrs` contains _all_ attributes, which makes it easier to apply all of them to a different element. The example from above now generates the following HTML: + +```html + +``` + +## Migration Strategy + +In components that use `inheritAttrs: false`, make sure that styling still works as intended. If you previously relied on the special behavior of `class` and `style`, some visuals might be broken as these attributes might now be applied to another element. + +[Migration build flag: `INSTANCE_ATTRS_CLASS_STYLE`](../migration-build.html#compat-configuration) + +## See also + +- [Relevant RFC](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0031-attr-fallthrough.md) +- [Migration guide - `$listeners` removed](./listeners-removed.md) +- [Migration guide - New Emits Option](./emits-option.md) +- [Migration guide - `.native` modifier removed](./v-on-native-modifier-removed.md) +- [Migration guide - Changes in the Render Functions API](./render-function-api.md) diff --git a/src/ja/breaking-changes/children.md b/src/ja/breaking-changes/children.md new file mode 100644 index 0000000..57d1901 --- /dev/null +++ b/src/ja/breaking-changes/children.md @@ -0,0 +1,44 @@ +--- +badges: + - removed +--- + +# $children + +## Overview + +The `$children` instance property has been removed from Vue 3.0 and is no longer supported. + +## 2.x Syntax + +In 2.x, developers could access direct child components of the current instance with `this.$children`: + +```vue + + + +``` + +## 3.x Update + +In 3.x, the `$children` property is removed and no longer supported. Instead, if you need to access a child component instance, we recommend using [template refs](https://ja.vuejs.org/guide/essentials/template-refs.html#template-refs). + +## Migration Strategy + +[Migration build flag: `INSTANCE_CHILDREN`](../migration-build.html#compat-configuration) diff --git a/src/ja/breaking-changes/custom-directives.md b/src/ja/breaking-changes/custom-directives.md new file mode 100644 index 0000000..d8e6eea --- /dev/null +++ b/src/ja/breaking-changes/custom-directives.md @@ -0,0 +1,111 @@ +--- +badges: + - breaking +--- + +# Custom Directives + +## Overview + +The hook functions for directives have been renamed to better align with the component lifecycle. + +Additionally, the `expression` string is no longer passed as part of the `binding` object. + +## 2.x Syntax + +In Vue 2, custom directives were created by using the hooks listed below to target an element’s lifecycle, all of which are optional: + +- **bind** - Called once the directive is bound to the element. Called only once. +- **inserted** - Called once the element is inserted into the parent DOM. +- **update** - This hook is called when the element updates, but children haven't been updated yet. +- **componentUpdated** - This hook is called once the component and the children have been updated. +- **unbind** - This hook is called once the directive is removed. Also called only once. + +Here’s an example of this: + +```html +

Highlight this text bright yellow

+``` + +```js +Vue.directive('highlight', { + bind(el, binding, vnode) { + el.style.background = binding.value + } +}) +``` + +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. + +## 3.x Syntax + +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: + +- **created** - new! This is called before the element's attributes or event listeners are applied. +- bind → **beforeMount** +- inserted → **mounted** +- **beforeUpdate**: new! This is called before the element itself is updated, much like the component lifecycle hooks. +- update → removed! There were too many similarities to `updated`, so this is redundant. Please use `updated` instead. +- componentUpdated → **updated** +- **beforeUnmount**: new! Similar to component lifecycle hooks, this will be called right before an element is unmounted. +- unbind -> **unmounted** + +The final API is as follows: + +```js +const MyDirective = { + created(el, binding, vnode, prevVnode) {}, // new + beforeMount() {}, + mounted() {}, + beforeUpdate() {}, // new + updated() {}, + beforeUnmount() {}, // new + unmounted() {} +} +``` + +The resulting API could be used like this, mirroring the example from earlier: + +```html +

Highlight this text bright yellow

+``` + +```js +const app = Vue.createApp({}) + +app.directive('highlight', { + beforeMount(el, binding, vnode) { + el.style.background = binding.value + } +}) +``` + +Now that the custom directive lifecycle hooks mirror those of the components themselves, they become easier to reason about and remember! + +### Edge Case: Accessing the component instance + +It's generally recommended to keep directives independent of the component instance they are used in. Accessing the instance from within a custom directive is often a sign that the directive should rather be a component itself. However, there are situations where this actually makes sense. + +In Vue 2, the component instance had to be accessed through the `vnode` argument: + +```js +bind(el, binding, vnode) { + const vm = vnode.context +} +``` + +In Vue 3, the instance is now part of the `binding`: + +```js +mounted(el, binding, vnode) { + const vm = binding.instance +} +``` + +:::warning +With [fragments](../new/fragments.html#overview) support, components can potentially have more than one root node. When applied to a multi-root component, a custom directive will be ignored and a warning will be logged. +::: + +## Migration Strategy + +[Migration build flag: `CUSTOM_DIR`](../migration-build.html#compat-configuration) diff --git a/src/ja/breaking-changes/custom-elements-interop.md b/src/ja/breaking-changes/custom-elements-interop.md new file mode 100644 index 0000000..69e145d --- /dev/null +++ b/src/ja/breaking-changes/custom-elements-interop.md @@ -0,0 +1,134 @@ +--- +badges: + - breaking +--- + +# Custom Elements Interop + +## Overview + +- **BREAKING:** The checks to determine whether tags should be treated as custom elements are now performed during template compilation, and should be configured via compiler options instead of runtime config. +- **BREAKING:** Special `is` attribute usage is restricted to the reserved `` tag only. +- **NEW:** To support 2.x use cases where `is` was used on native elements to work around native HTML parsing restrictions, prefix the value with `vue:` to resolve it as a Vue component. + +## 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 + +``` + +### 2.x Syntax + +In Vue 2.x, configuring 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 `` 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.compilerOptions.isCustomElement`: + + ```js + const app = Vue.createApp({}) + app.config.compilerOptions.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 {#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 + +``` + +Vue's usage of the `is` special attribute 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` attribute to the `` tag only. + +- When used on the reserved `` tag, it will behave exactly the same as in 2.x; +- When used on normal components, it will behave like a normal attribute: + + ```html + + ``` + + - 2.x behavior: renders the `bar` component. + - 3.x behavior: renders the `foo` component and passing the `is` attribute. + +- When used on plain elements, it will be passed to the `createElement` call as the `is` attribute, and also rendered as a native attribute. This supports the usage of customized built-in elements. + + ```html + + ``` + + - 2.x behavior: renders the `plastic-button` component. + - 3.x behavior: renders a native button by calling + + ```js + document.createElement('button', { is: 'plastic-button' }) + ``` + +[Migration build flag: `COMPILER_IS_ON_ELEMENT`](../migration-build.html#compat-configuration) + +## `vue:` Prefix 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 `
    `, `
      `, `` and ``, and `
      + +
      +``` + +### 3.x Syntax + +With the behavior change of `is`, a `vue:` prefix is now required to resolve the element as a Vue component: + +```html + + +
      +``` + +## Migration Strategy + +- Replace `config.ignoredElements` with either `vue-loader`'s `compilerOptions` (with the build step) or `app.config.compilerOptions.isCustomElement` (with on-the-fly template compilation) + +- Change all non-`` tags with `is` usage to `` (for SFC templates) or prefix it with `vue:` (for in-DOM templates). + +## See Also + +- [Guide - Vue and Web Components](https://ja.vuejs.org/guide/extras/web-components.html) diff --git a/src/ja/breaking-changes/data-option.md b/src/ja/breaking-changes/data-option.md new file mode 100644 index 0000000..d21170b --- /dev/null +++ b/src/ja/breaking-changes/data-option.md @@ -0,0 +1,128 @@ +--- +title: Data Option +badges: + - breaking +--- + +# {{ $frontmatter.title }} + +## Overview + +- **BREAKING**: `data` component option declaration no longer accepts a plain JavaScript `object` and expects a `function` declaration. + +- **BREAKING**: when merging multiple `data` return values from mixins or extends, the merge is now shallow instead of deep (only root-level properties are merged). + +## 2.x Syntax + +In 2.x, developers could define the `data` option with either an `object` or a `function`. + +For example: + +```html + + + + + +``` + +Though this provided some convenience in terms of root instances having a shared state, this has led to confusion due to the fact that its only possible on the root instance. + +## 3.x Update + +In 3.x, the `data` option has been standardized to only accept a `function` that returns an `object`. + +Using the example above, there would only be one possible implementation of the code: + +```html + +``` + +## Mixin Merge Behavior Change {#mixin-merge-behavior-change} + +In addition, when `data()` from a component and its mixins or extends base are merged, the merge is now performed *shallowly*: + +```js +const Mixin = { + data() { + return { + user: { + name: 'Jack', + id: 1 + } + } + } +} + +const CompA = { + mixins: [Mixin], + data() { + return { + user: { + id: 2 + } + } + } +} +``` + +In Vue 2.x, the resulting `$data` is: + +```json +{ + "user": { + "id": 2, + "name": "Jack" + } +} +``` + +In 3.0, the result will be: + +```json +{ + "user": { + "id": 2 + } +} +``` + +[Migration build flag: `OPTIONS_DATA_FN`](../migration-build.html#compat-configuration) + +## Migration Strategy + +For users relying on the object declaration, we recommend: + +- Extracting the shared data into an external object and using it as a property in `data` +- Rewrite references to the shared data to point to a new shared object + +For users relying on the deep merge behavior from mixins, we recommend refactoring your code to avoid such reliance altogether, since deep merges from mixins are very implicit and can make the code logic more difficult to understand and debug. + +[Migration build flags:](../migration-build.html#compat-configuration) + +- `OPTIONS_DATA_FN` +- `OPTIONS_DATA_MERGE` diff --git a/src/ja/breaking-changes/emits-option.md b/src/ja/breaking-changes/emits-option.md new file mode 100644 index 0000000..01add6c --- /dev/null +++ b/src/ja/breaking-changes/emits-option.md @@ -0,0 +1,97 @@ +--- +title: emits Option +badges: + - new +--- + +# `emits` Option + +## Overview + +Vue 3 now offers an `emits` option, similar to the existing `props` option. This option can be used to define the events that a component can emit to its parent. + +## 2.x Behavior + +In Vue 2, you can define the props that a component receives, but you can't declare which events it can emit: + +```vue + + +``` + +## 3.x Behavior + +Similar to props, the events that the component emits can now be defined with the `emits` option: + +```vue + + +``` + +The option also accepts an object, which allows the developer to define validators for the arguments that are passed with the emitted event, similar to validators in `props` definitions. + +For more information on this, please read the [API documentation for this feature](https://ja.vuejs.org/api/options-state.html#emits). + +## Migration Strategy + +It is highly recommended that you document all the events emitted by each of your components using `emits`. + +This is especially important because of [the removal of the `.native` modifier](./v-on-native-modifier-removed.md). Any listeners for events that aren't declared with `emits` will now be included in the component's `$attrs`, which by default will be bound to the component's root node. + +### Example + +For components that re-emit native events to their parent, this would now lead to two events being fired: + +```vue + + +``` + +When a parent listens for the `click` event on the component: + +```html + +``` + +it would now be triggered _twice_: + +- Once from `$emit()`. +- Once from a native event listener applied to the root element. + +Here you have two options: + +1. Properly declare the `click` event. This is useful if you actually do add some logic to that event handler in ``. +2. Remove the re-emitting of the event, since the parent can now listen for the native event easily, without adding `.native`. Suitable when you really only re-emit the event anyway. + +## See also + +- [Relevant RFC](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0030-emits-option.md) +- [Migration guide - `.native` modifier removed](./v-on-native-modifier-removed.md) +- [Migration guide - `$listeners` removed](./listeners-removed.md) +- [Migration guide - `$attrs` includes `class` & `style`](./attrs-includes-class-style.md) +- [Migration guide - Changes in the Render Functions API](./render-function-api.md) diff --git a/src/ja/breaking-changes/events-api.md b/src/ja/breaking-changes/events-api.md new file mode 100644 index 0000000..9376423 --- /dev/null +++ b/src/ja/breaking-changes/events-api.md @@ -0,0 +1,104 @@ +--- +badges: + - breaking +--- + +# Events API + +## Overview + +`$on`, `$off` and `$once` instance methods are removed. Component instances no longer implement the event emitter interface. + +## 2.x Syntax + +In 2.x, a Vue instance could be used to trigger handlers attached imperatively via the event emitter API (`$on`, `$off` and `$once`). This could be used to create an _event bus_ to create global event listeners used across the whole application: + +```js +// eventBus.js + +const eventBus = new Vue() + +export default eventBus +``` + +```js +// ChildComponent.vue +import eventBus from './eventBus' + +export default { + mounted() { + // adding eventBus listener + eventBus.$on('custom-event', () => { + console.log('Custom event triggered!') + }) + }, + beforeDestroy() { + // removing eventBus listener + eventBus.$off('custom-event') + } +} +``` + +```js +// ParentComponent.vue +import eventBus from './eventBus' + +export default { + methods: { + callGlobalCustomEvent() { + eventBus.$emit('custom-event') // if ChildComponent is mounted, we will have a message in the console + } + } +} +``` + +## 3.x Update + +We removed `$on`, `$off` and `$once` methods from the instance completely. `$emit` is still a part of the existing API as it's used to trigger event handlers declaratively attached by a parent component. + +## Migration Strategy + +[Migration build flag: `INSTANCE_EVENT_EMITTER`](../migration-build.html#compat-configuration) + +In Vue 3, it is no longer possible to use these APIs to listen to a component's own emitted events from within a component. There is no migration path for that use case. + +### Root Component Events + +Static event listeners can be added to the root component by passing them as props to `createApp`: + +```js +createApp(App, { + // Listen for the 'expand' event + onExpand() { + console.log('expand') + } +}) +``` + +### Event Bus + +The event bus pattern can be replaced by using an external library implementing the event emitter interface, for example [mitt](https://github.com/developit/mitt) or [tiny-emitter](https://github.com/scottcorgan/tiny-emitter). + +Example: + +```js +// eventBus.js +import emitter from 'tiny-emitter/instance' + +export default { + $on: (...args) => emitter.on(...args), + $once: (...args) => emitter.once(...args), + $off: (...args) => emitter.off(...args), + $emit: (...args) => emitter.emit(...args) +} +``` + +This provides the same event emitter API as in Vue 2. + +In most circumstances, using a global event bus for communicating between components is discouraged. While it is often the simplest solution in the short term, it almost invariably proves to be a maintenance headache in the long term. Depending on the circumstances, there are various alternatives to using an event bus: + +* Props and events should be your first choice for parent-child communication. Siblings can communicate via their parent. +* Provide / inject allow a component to communicate with its slot contents. This is useful for tightly-coupled components that are always used together. +* Provide / inject can also be used for long-distance communication between components. It can help to avoid 'prop drilling', where props need to be passed down through many levels of components that don't need those props themselves. +* Prop drilling can also be avoided by refactoring to use slots. If an interim component doesn't need the props then it might indicate a problem with separation of concerns. Introducing a slot in that component allows the parent to create the content directly, so that props can be passed without the interim component needing to get involved. +* [Global state management](https://ja.vuejs.org/guide/scaling-up/state-management.html), such as [Pinia](https://pinia.vuejs.org/). diff --git a/src/ja/breaking-changes/filters.md b/src/ja/breaking-changes/filters.md new file mode 100644 index 0000000..4dcccb0 --- /dev/null +++ b/src/ja/breaking-changes/filters.md @@ -0,0 +1,107 @@ +--- +badges: + - removed +--- + +# Filters + +## Overview + +Filters are removed from Vue 3.0 and no longer supported. + +## 2.x Syntax + +In 2.x, developers could use filters in order to apply common text formatting. + +For example: + +```html + + + +``` + +While this seems like a convenience, it requires a custom syntax that breaks the assumption of expressions inside curly braces being "just JavaScript," which has both learning and implementation costs. + +## 3.x Update + +In 3.x, filters are removed and no longer supported. Instead, we recommend replacing them with method calls or computed properties. + +Using the example above, here is one example of how it could be implemented. + +```html + + + +``` + +## Migration Strategy + +Instead of using filters, we recommend replacing them with computed properties or methods. + +[Migration build flags:](../migration-build.html#compat-configuration) + +- `FILTERS` +- `COMPILER_FILTERS` + +### Global Filters + +If you are using filters that were globally registered and then used throughout your app, it's likely not convenient to replace them with computed properties or methods in each individual component. + +Instead, you can make your global filters available to all components through [globalProperties](https://ja.vuejs.org/api/application.html#app-config-globalproperties): + +```js +// main.js +const app = createApp(App) + +app.config.globalProperties.$filters = { + currencyUSD(value) { + return '$' + value + } +} +``` + +Then you can fix all templates using this `$filters` object like this: + +```html + +``` + +Note that with this approach, you can only use methods, not computed properties, as the latter only make sense when defined in the context of an individual component. diff --git a/src/ja/breaking-changes/functional-components.md b/src/ja/breaking-changes/functional-components.md new file mode 100644 index 0000000..953431d --- /dev/null +++ b/src/ja/breaking-changes/functional-components.md @@ -0,0 +1,120 @@ +--- +badges: + - breaking +--- + +# Functional Components + +## Overview + +In terms of what has changed, at a high level: + +- Performance gains from 2.x for functional components are now negligible in 3.x, so we recommend just using stateful components +- Functional components can only be created using a plain function that receives `props` and `context` (i.e., `slots`, `attrs`, `emit`) +- **BREAKING:** `functional` attribute on single-file component (SFC) `