@sgiehl opened this Pull Request on July 22nd 2021 Member

Description:

This is a POC of using Vue.js 3 to replace AngularJS directives & components in Matomo step by step.

It migrates most parts of the SitesManager admin interface, as well as some basic components like enriched-headline, content-block or alert and various related directives and filters.

Current State:

The SitesManager admin should be quite fully migrated, at least some small functional tests were working and also the UI tests are passing (apart from slight UI changes). All main directives of the SitesManager are converted, but some directives like the piwik-fields/piwik-form-fields, are still used and compiled with Angular S, once they are shown.

Making it possible to communicate between piwik-fields in AngularJS and a outer Vue.js component wasn't possible directly, as you can't pass a Vue.js variable into a AngularJS model with a two way data binding. I used a workaround by listening to the native change event, that is triggered when the field's value changes. The value can then be received in Vue.js by directly accessing the AngularJS scope of that element. Similar workarounds might be needed if we don't migrate all directives that are used on one page at once.

I have also changed the content-block to use a Vue.js component instead of the previous AngularJS implementation. This currently breaks most of the pages, as it causes problems on pages using twig templates containing other AngularJS directives within that component. But in general this should work when a page uses only Vue.js components.

Core Concepts

In Vue.js there are actually mainly components.
Besides those components there are also directives, that are meant in another way than in AngularJS. Those can be used to register additional "attribute keywords" like v-model and could be used to implement something like the focus-anywhere-but-here directive.

Other than AngularJS directives it's not possible to let Vue.js components parse by attribute. So something like <div piwik-form-field ...> would need to be converted to <matomo-form-field> for Vue.

Vue.js does not provide any special implementation for controller, model or service. Those can be implemented with native javascript objects if they need to be used in a global way. But there are also Vue.js extensions like https://vuemc.io/ that provide some kind of model feature or https://vuex.vuejs.org/, which provides some kind of state management.

Routing is actually not provided by Vue.js core, but it can be implemented in Vue.js using the official Vue Router (https://next.router.vuejs.org/) or even a custom implementation if needed, or it can be done using some other libraries.

Note: Currently I'm using jQuery within the Vue.js components. If at any point we want to get rid of jQuery as well, we could consider using VueQuery (https://github.com/phanan/vuequery) instead.

Modularization

Modularization is achieved in a way similar to the current AngularJS implementation. New VueJs Components or Methods can be placed in a plugin and need to be loaded using the AssetManager.getJavaScriptFiles event. VueJs 3 is actually meant to build real single page apps, that only have one Vue.js app element containing everything else. As we can't do that at least until AngularJS is removed we need to register the components and functions to all Vue.js elements we want to parse. To achieve that, there is a global matomo javascript class that allows to register components and functions and serves a createVue method that automatically parses an element with Vue.js and registers all known components and methods.

Migration Path

Smaller components can be converted quite simple and we can use the angular directives to render Vue.js components, which will not require any changes in the templates.
I guess the best strategy would be to convert components page by page. Once the page is done we can add a vue-app css-class to the parent element, which will then be parsed with Vue.js after the page is loaded.

Pros & Cons

  • Pros

    • Coding with VueJS is quite fast and simple as it is plain Javascript (might be easier for contributors than TypeScript)
    • We can simply use our current structure and asset management
    • Possibility to switch & use TypeScript in the future if we want to
    • Having templates in twig files is not a problem, as long as the full page uses Vue.js components (mixing them up might cause problems)
  • Cons

    • Mixing Angular JS & Vue.js components does not work when using twig templates. Vue.js can't parse an element within an element that has been parsed as AngularJS directive before.
    • Binding data does not work between the frameworks. This is only possible using native javascript events
@github-actions[bot] commented on August 6th 2021 Contributor

If you don't want this PR to be closed automatically in 28 days then you need to assign the label 'Do not close'.

@sgiehl commented on February 14th 2022 Member

closing this one, as the migration is already in progress and the changes here are meanwhile outdated.

This Pull Request was closed on February 14th 2022
Powered by GitHub Issue Mirror