Integrate Vue 3
Make sure that you place all JS modules in the bundle’s public folder. If the bundle does not exist, create one following the instruction in the Create a Bundle topic.
Keep in mind that if you create a new bundle or fail to create symlinks when installing the application, you need to run the following command bin/console assets:install --symlink
. For more information, please see OroAssetBundle documentation.
Declarative Rendering
The example below illustrates creating a simple component, such as the one shown in the screenshot, using the standard Vue 3 approach.
Install dependencies. Navigate to the root folder and modify the
composer.json
(ordev.json
if you use the developer mode) file with the code below. After updating the composer config file, execute thecomposer install
command."extra": { "npm": { "vue": "^3.2.20" } }
Note
To learn how to add dependencies to Composer, see Managing NPM dependencies with Composer.
Create a template for the Vue component.
<template v-if="editMode"> <form class="grid"> <div class="grid__row"> <label for="name">Title</label> <input type="text" id="name" class="input" name="title" v-model="title"> </div> <div class="grid__row"> <label for="content">Content</label> <textarea class="input" id="content" name="content" v-model="content"></textarea> </div> <div class="grid__row"> <button type="submit" class="btn btn-primary" @click.prevent="exitEditMode">Update</button> </div> </form> </template> <template v-else> <h1>{{ title }}</h1> <p>{{ content }}</p> <button class="btn edit-mode" @click.prevent="enterEditMode">Edit</button> </template>
Important
In all code examples, the bundle’s name is set to
AcmeBundle
. When copying, remember to correct the name of the bundle in the paths according to your bundle.Create a Vue component and copy the code below:
import template from 'text-loader!./App.html'; const App = { props: { initialTitle: { type: String, required: true }, initialContent: { type: String, required: true } }, template, data() { return { title: this.initialTitle, content: this.initialContent, editMode: false } }, methods: { enterEditMode() { this.editMode = true; }, exitEditMode() { this.editMode = false; } } } export default App;
To provide a runtime rendering template, create an alias for the Vue import. Since Vue is not the base framework for Oro, enable Page Component to start the Vue application, which will ensure proper integration into the Oro application lifecycle. Next, add the path for page component to
dynamic-imports:
, create a file, and insert the code below:aliases: vue: vue/dist/vue.esm-bundler app-modules: - oroui/js/app/modules/vue-module dynamic-imports: acmevueapp: - oroui/js/app/components/vue-app-component - acmevueapp/js/vue-app/App
To build the application after changes, run the
npm run build
command. To rebuild the application automatically, run thenpm run watch
command.In the Twig template, define where our Vue app will be displayed with a specific Page component using the
data-page-component-vue-app
shortcut. Copy and paste the code below:{% block _vue_app_block_widget %} {% set attr = layout_attr_defaults(attr, { 'data-page-component-vue-app': { vueApp: 'acmevueapp/js/vue-app/App', initialTitle: 'Vue demo', initialContent: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' } }) %} <div {{ block('block_attributes') }}> {{ block_widget(block) }} </div> {% endblock %}
Register your new widget and append it to the page container in layout. Create a file for this. For more information on the layout update, see the Layout topic.
layout: actions: - '@setBlockTheme': themes: 'layout.html.twig' - '@add': id: vue_app_block parentId: page_container prepend: true blockType: block
Single File Components
Vue makes it possible to use one file for the component. For more information, see the official Single File Components documentation.
The webpack config does not support the vue-loader
out-of-the-box. You need to modify the webpack.config.js
file at the root of your application.
The example below implements the same functionality discussed above but uses the Single File Component in Vue3.
Install the
vue-loader
by running the commandnpm install vue-loader@next -D
.Open your
webpack.config.js
and replace the code with the one below:const { VueLoaderPlugin } = require('vue-loader'); const OroConfig = require('@oroinc/oro-webpack-config-builder'); OroConfig .enableLayoutThemes() .setPublicPath('public/') .setCachePath('var/cache'); module.exports = () => { const webpackConfigs = OroConfig.getWebpackConfig()(); webpackConfigs.forEach(webpackConfig => { webpackConfig.module.rules = [ { test: /\.vue$/, loader: 'vue-loader' }, ...webpackConfig.module.rules ]; webpackConfig.plugins = [ ...webpackConfig.plugins, new VueLoaderPlugin() ]; }); return webpackConfigs; }
Create a Vue component and copy the code below:
<template> <template v-if="editMode"> <form class="grid"> <div class="grid__row"> <label for="name">Title</label> <input type="text" id="name" class="input" name="title" v-model="title"> </div> <div class="grid__row"> <label for="content">Content</label> <textarea class="input" id="content" name="content" v-model="content"></textarea> </div> <div class="grid__row"> <button type="submit" class="btn btn-primary" @click.prevent="exitEditMode">Update</button> </div> </form> </template> <template v-else> <h1>{{ title }}</h1> <p>{{ content }}</p> <button class="btn edit-mode" @click.prevent="enterEditMode">Edit</button> </template> </template> <script> export default { props: { initialTitle: { type: String, required: true }, initialContent: { type: String, required: true } }, data() { return { title: this.initialTitle, content: this.initialContent, editMode: false } }, methods: { enterEditMode() { this.editMode = true; }, exitEditMode() { this.editMode = false; } } } </script>
To provide a runtime rendering template, create an alias for the Vue import. Since Vue is not the base framework for Oro, enable Page Component to start the Vue application, which will ensure proper integration into the Oro application lifecycle. Next, add the path for page component to
dynamic-imports:
, create a file, and insert the code below:app-modules: - oroui/js/app/modules/vue-module dynamic-imports: acmevuesfcapp: - oroui/js/app/components/vue-app-component - acmevuesfcapp/js/vue-app/App.vue
To build the application after changes, run the
npm run build
command. To rebuild the application automatically, run thenpm run watch
command.Once the page component with Vue instance is created, declare it in the template of the required page. Copy and paste the code below:
{% block _vue_sfc_app_block_widget %} {% set attr = layout_attr_defaults(attr, { 'data-page-component-vue-app': { vueApp: 'acmevuesfcapp/js/vue-app/App.vue', initialTitle: 'Vue SFC demo', initialContent: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' } }) %} <div {{ block('block_attributes') }}> {{ block_widget(block) }} </div> {% endblock %}
Register your new widget and append it to the page container in the layout. Create a file for this. For more information on the layout update, see the Layout topic.
layout: actions: - '@setBlockTheme': themes: 'layout.html.twig' - '@add': id: vue_sfc_app_block parentId: page_container prepend: true blockType: block