markbind icon indicating copy to clipboard operation
markbind copied to clipboard

Investigate and list what needs to be done for Vue 3 migration

Open ang-zeyu opened this issue 2 years ago • 11 comments

Please confirm that you have searched existing issues in the repo

Yes, I have searched the existing issues

Any related issues?

No response

What is the area that this feature belongs to?

No response

Is your feature request related to a problem? Please describe.

This is a hard ticket as it requires fairly comprehensive understanding of the entire codebase, but would be nice to have soon. With SSR, things are a tad bit more complex as well.

Describe the solution you'd like

The request here is to comprehensively investigate and document what needs to be done for vue v3 migration into a separate issue as a checklist of items.

If any, link said items to other tickets in the repository as well.

Describe alternatives you've considered

No response

Additional context

  • Slightly related to https://github.com/MarkBind/markbind/issues/1702 when we discussed Bootstrap-vue

ang-zeyu avatar Jan 15 '23 06:01 ang-zeyu

@MarkBind/active-devs, if you're interested as well this is very nice to have.

ang-zeyu avatar Jan 15 '23 06:01 ang-zeyu

I will give this a try.

EltonGohJH avatar Mar 06 '23 12:03 EltonGohJH

@MarkBind/active-devs

  • [ ] Remove/update vue2 plugins. While removing we need to refactor too (portal-vue is no longer used and replace with teleport which is native to vue) (Related to the list below)
  • [ ] Refactor all components to vue 3. (A lot of stuff is deprecated and we would need to refactored every vue components. Github co-pilot helps so if anyone is helping in the future can try that. I think our goal is to remove all vue-warnings for all currently working components.
    • [ ] Box.vue
    • [ ] Navbar.vue
    • [ ] PageNavButton.vue
    • [ ] Popover.vue
    • [ ] Searchbar.vue
    • [ ] SiteNavButton.vue
    • [ ] TabGroup.vue
    • [ ] Tooltip.vue
    • [ ] Dropdown.vue
    • [ ] Overlay.vue
    • [ ] Panel.vue
    • [ ] Retriever.vue
    • [ ] SearchbarPageItem.vue
    • [ ] Submenu.vue
    • [ ] Tabset.vue
    • [ ] Thumbnail.vue
    • [ ] Modal.vue
    • [ ] OverlaySource.vue
    • [ ] Pic.vue
    • [ ] ScrollTopButton.vue
    • [ ] SiteNav.vue
    • [ ] Annotate.vue
    • [ ] AnnotatePoint.vue
    • [ ] MinimalPanel.vue
    • [ ] NestedPanel.vue
    • [ ] QOption.vue
    • [ ] Question.vue
    • [ ] Quiz.vue
  • [ ] Update testcases. Will update once all components have been refactored. vue-jes updated to vue3-jest so we will probably need to refactor testcases too.

I dun think there is any need to change anything with regards to webpack. I updated some components to vue3 on my end. But there are still vue-warnings so they are not marked as checked here. Some components have dependencies from one another and I think it would be better to resolve those together so that it can be tested.

EltonGohJH avatar Mar 12 '23 17:03 EltonGohJH

Just as a side note, #1536 should be important to keep in mind :)

lhw-1 avatar Mar 13 '23 04:03 lhw-1

  • [ ] Remove/update vue2 plugins. While removing we need to refactor too (portal-vue is no longer used and replace with teleport which is native to vue) (Related to the list below)
  • [ ] Refactor all components to vue 3. (A lot of stuff is deprecated and we would need to refactored every vue components. Github co-pilot helps so if anyone is helping in the future can try that. I think our goal is to remove all vue-warnings for all currently working components.

@EltonGohJH could you elaborate on what you mean by "refactor"? What will we need to change when refactoring from Vue 2 to Vue 3? Will we need to change any libraries (that don't support Vue 3)?

jovyntls avatar Mar 20 '23 14:03 jovyntls

@jovyntls SFLR. I guess refactor might be the wrong word to use here. Maybe update and fix warning would be more apt. I think that library wise only portal-vue is affected since it is now supported by vue 3 natively. For components non affected by library changes, one would need to fix the vue warnings. There are a lot of it. image

EltonGohJH avatar Mar 25 '23 04:03 EltonGohJH

@MarkBind/active-devs

Current Approach to Migrate to Vue 3:

  1. Disabled SSR (Server Side Rendering) - Will be explained in detail later.
  2. Removed usage of Vue through CDN and switched to using Vue 3 from node modules - Will be explained in detail later.
  3. The current workflow:
    1. Process the Markdown file and generate the HTML text (stored in a variable through javascript in page.njk for client-side use).
    2. SSR is intended to process the HTML file (not fully functional) and place it in the HTML as content (page.njk). Since SSR is disabled, a <div id="app"></div> is used for now.
    3. The client-side creates a Vue app using the variable from page.njk (mentioned in 3a).

Current Issues:

  1. SSR is not fully functional.

    1. It does not work for importing components in Vue components (e.g., Navbar.vue using Button.vue), causing a resolveComponent can only be used in render() or setup() error.
    2. This error is misleading and occurs due to multiple Vue instances.
    3. In CSR (Client Side Rendering), the issue is resolved by using the Vue instance from node_modules rather than using both vue in CDN and node_modules.
    4. For SSR, the issue persists because two different Vue files are used (runtime-core.cjs.js and runtime-core.esm-bundler.js). This makes it non-trivial to solve, so SSR has been disabled for now.
      1. This is probably due to the fact that we are using runtime-core.cjs.js for our core and runtime-core.esm-bundler.js for vue-components.
      2. This is not trivial to debug.
  2. Removed usage of Vue through CDN and switched to using Vue 3 from node modules.

    1. Multiple Vue instances resulted in the resolveComponent can only be used in render() or setup() error.
    2. Using Vue solely through CDN seems non-trivial.
    3. Using Vue from node modules simplifies the process.
    4. The advantages of importing Vue through CDN do not justify the cost of getting it to work.

Future Steps:

  1. Fix SSR to make it fully functional.
  2. Continue migrating all components to Vue 3, with CSR working as intended.
    1. SSR not working does not hinder our migration since they are supposed to generate the same output.
  3. Additional considerations:
    1. Investigate the possibility of reducing DOM manipulation in Vue.
    2. Consider using solely CSR and addressing the root cause of FOUC (Flash of Unstyled Content) to simplify the codebase.

How to migrate:

  1. Choose a component that you want to migrate
  2. For components that are using other components, you should migrate all of them together. Eg. Navbar is using SiteNavButton. So, you should migrate everything so that components are working as intended when used together.
  3. Enable the testcases in vue (by removing skip). Make sure that the testcases (non snapshot testcases) are working. After that, you can update testcases.

Tips to migrate:

  1. Main problem with migration is the usage of this.$el that is deprecated. You will need to define $el as the root of the component with ref.
  2. Calling methods in setup. You will need to call methods through currentInstance instead of this.

What inputs do I require?

  1. I think I require sanity to check to ensure that what I am doing so far is okay before we do a mass conversion to vue 3 components.

EltonGohJH avatar Apr 20 '23 14:04 EltonGohJH

For those who are interested to see why there is an issue with SSR, can look at this branch

https://github.com/EltonGohJH/markbind/tree/elton/test-SSR

If you attempt to Markbind Serve with Navbar you would get,

[Vue warn]: resolveComponent can only be used in render() or setup(). [Vue warn]: resolveComponent can only be used in render() or setup(). [Vue warn]: Component <Anonymous> is missing template or render function. [Vue warn]: Component <Anonymous> is missing template or render function.

4 errors because in Navbar there are two imported components.

EltonGohJH avatar Apr 20 '23 16:04 EltonGohJH

Removing SSR and hydration and then reintroducing it later will postpone and enlarge the effort required, and degrade UX in the meantime. I don't think it is the right direction.

  • Is the shift to composition API (e.g. setup()) necessary? Speaking from experience, for a large migration, try to aim to make the minimal set of changes to reduce the room for error and initial effort. (stick to the still highly relevant and recommended vue v2 option apis) The code readibility benefit in our case is sometimes very debatable as well from what I see in the PR. We can stash the changes and bring up another issue to discuss and work on it more closely. (e.g. maybe mixins in particular?)

  • It seems kinda redundant to pass (the html code) to the client side for client to hydrate. So, I was thinking can we do with no hydration. It seems that there are some parts that are preventing us from going full SSR with client side hydration.

    I'd recommend taking a look at https://www.npmjs.com/package/@vue/compiler-sfc (vue-template-compiler equivalent for v3).

  • On the above package, we should not be shipping the uncompiled template (even if doing just CSR), the performance impact is far from negligible. We had some specific work to address its impact https://github.com/MarkBind/markbind/pull/1512

  • Removing hydration is not a trivial UX decision https://blog.angular.io/whats-next-for-server-side-rendering-in-angular-2a6f27662b67

  • Consider using solely CSR and addressing the root cause of FOUC (Flash of Unstyled Content) to simplify the codebase.

    There can be many causes of fouc, are you thinking of any specific one? Removing SSR would only increase the page load time (CSR with an empty template) and/or introduce more FOUC (we used to do CSR + ship the raw, uncompiled template which took very long to render). AOT template compilation + SSR should be complementary/necessary in any scenario to fix fouc arising from an uncompiled template or unrendered application.

  • runtime-core.cjs.js and runtime-core.esm-bundler.js

    From where are they transitively imported?

  • This is probably due to the fact that we are using runtime-core.cjs.js for our core and runtime-core.esm-bundler.js for vue-components.

    Is this not due to the draft PR's changes? (import ... from 'vue') We are only importing it server side for doing the SSR. The requireFromString-ed bundle (webpack.server.config.js) should not be importing any parts of the Vue bundle currently.

  • This is not trivial to debug.

    I added Vue to the externals configuration for the server webpack config on your branch, which seems to fix this on a surface level for a start. (should redirect and remove the requireFromString's Vue to use the CLI app's Vue) I haven't considered carefully if this will properly make Vue available to all references inside the requireFromString-ed bundle however. We can further investigate in the direction of bundling options to fix this if needed.

    Alternatively, restructuring how we import bundles (e.g. do the reverse, export and use Vue from the requireFromString-ed bundle) (probably safer than the above option)

  • Be careful with relying on bundling vue as well as some features we rely on that are not detected at bundling time may be absent from the bundle. (e.g. template compilation for panel src)

  • Choose a component that you want to migrate

    If you feel the overall level of effort is small for all components, I'd personally prefer doing it in one go to reduce the repeated change merging and need for a feature branch. But I think either way is ok.

The advantages of importing Vue through CDN

Just to be clear on the wording in case I don't think we are using it for any of those benefits; It is served only directly from CDN only when using markbind s -d mode. We are bundling a CDN/pre-built asset directly into the site build output however.

ang-zeyu avatar Apr 28 '23 14:04 ang-zeyu

I recently closed an old PR that had been pending for some time. After considerable reflection and discussions, I've come to believe that a more effective approach might be to support both Vue 2 and Vue 3 simultaneously as we transition away from Vue 2.

Upon reviewing my code and taking into account the insights from discussions and @ang-zeyu's comments, it's become evident that my understanding of the intricate details involved in our current SSR system is limited. (There are a lot of like implementation that I do not understand why and is not well documented.) Undertaking a comprehensive migration single-handedly seems overly ambitious, and the complexity of the task might pose a barrier for others who wish to contribute.

In light of these considerations, and following discussions with Yongliang, I propose that we maintain support for both Vue 2 and Vue 3 concurrently. This approach would allow for a more gradual and meticulous migration from the old component system to the new one. Eventually, this would lead to a complete phase-out of the Vue 2 system once the migration is fully accomplished.

I have been exploring Astro as a potential model for this approach. Given that Astro supports SSR for multiple frameworks simultaneously, it might offer valuable insights or strategies that we could adapt for our project.

EltonGohJH avatar Jan 31 '24 13:01 EltonGohJH

In light of these considerations, and following discussions with Yongliang, I propose that we maintain support for both Vue 2 and Vue 3 concurrently. This approach would allow for a more gradual and meticulous migration from the old component system to the new one. Eventually, this would lead to a complete phase-out of the Vue 2 system once the migration is fully accomplished.

Just to add: I didn't research into whether vue 2 and vue 3 can co-exist so that needs to be explored :). Googling "is it possible to run vue 2 and vue 3 together" seems to yield interesting results that could be useful... including folks who share their experience migrating from vue 2 to vue 3, which might provide potential learning/lessons that can help us.

Overall I think coming up with a proper plan (plus some proof of concept) is a good first step.

tlylt avatar Jan 31 '24 14:01 tlylt

Vue Migration Vue 2 to Vue 3

Vue Migration Guide here

Issues that typically come up are related to both breaking Vue framework API changes and dependencies used in Vue 2 vs Vue 3.

Compilation and SSR of Vue (Core):

  • [ ] Page/PageVueServerRenderer.ts needs to be updated
  1. 'vue-template-compiler' has been replaced by '@vue/compiler-sfc', hencecompileVuePageAndCreateScript method which compiles page into Vue Application to get the render function must be updated.

  2. renderVuePage: Method that Renders Vue page app into html string (Vue SSR). Ensure that it works during migration process.

Webpack bundling (Core-Web)

  • [ ] core-web library needs to be updated
  1. Update core-web/src/index.js setup process. Ensure setup functions for mounting Vue apps are not affected.

Issue I currently face here:

  • pageVueServerRenderer attaches the render function
  • core-web source uses the render function for Vue 3, the way the render function is created and consumed is different. I noticed that @\EltonGohJH 's old PR didnt manage to resolve this and hence disabled SSR - trying to resolve this.

Relevant Changelog:

Global Mounting: Vue.js 2: The global Vue instance is used to mount the root component. Vue.js 3: Introduces createApp for creating the application instance and makes the mounting process more explicit.

Feature Vue 2 Vue 3
Instance Creation new Vue() createApp()
Global Configuration On Vue constructor On app instance
Global APIs Attached to Vue Instance methods on app
Reactivity System Object.defineProperty Proxy
Composition API Not available Available
Fragments Single root element required Multiple root elements allowed
Teleport Not available Built-in <teleport> support
  • In Vue 2, plugins add global level functionality. In Vue 3, each createApp call creates completely isolated app instance with its own config and global properties. Due to differences, the Vue instance is setup differently.
  • Migrating from new Vue to createSSRApp(): case study here on using render function
  • In Vue2, static render functions explicitly separated from main render function, but in Vue3, it is not. Hence, only one render function. (compileVuePageAndCreateScript)
  • package vue-server-renderer is for Vue 2.0. Corresponding functionality for Vue 3 is in @vue/server-renderer, which is actually a dependency of the main vue package.
  1. VueCommonAppFactory.js.The appFactory helps create the Vue app instances needed for each page, to set up the necessary configurations. Configure it if necessary for Vue 3, and dependencies used if any.

Vue Components SFCs

  • [ ] Vue-Components Library needs to be updated

  • Update vue-components library where needed. Note: Vue 2 Options API -> Vue 3 Options API should not have too many changes. Should be the most straightforward process. However, a lot of dependencies have to be updated such as floating vue, etc. Not too sure yet. Working on vue rendering first.

Plugins:

  • [ ] Update necessary plugins
  1. Ensure usability and non-regression of dataTable and Mermaid plugins as they use Vue Directives.

Relevant Changelog:

Custom Directives: Vue.js 2: Custom directives are registered globally using Vue.directive. Vue.js 3: Custom directives are registered using the app.directive method, making it more modular and scoped to the app instance.

Others:

  • Why Migrate to Vue 3? Vue2 has reached EOL, (end-2023) and will not receive any type of support. Packages supporting Vue2 used may not be maintained by extension. Vue3 has TypeScript support, noticeable performance improvements and more responsive application. Also has smaller bundle size. However, Vue 3 does not support IE13 (internet explorer). Migration is a time intensive process with codebase understanding required.

  • What about considering letting vue2 and vue3 co-exist? We can use a migration build (Vue 2.7) that allows both Vue 2 & 3 code in a single codebase. Once done, migrate over to Vue 3. However, I faced some issues with getting @vue/compat to work.

Sources:

Issues faced:

  • No documentation in most packages, most just specify 'For detailed API references and options, check out the source type definitions in GitHub Repo' 🤕 🙃

Will open a draft PR soon regarding work done on this.

gerteck avatar Feb 05 '25 06:02 gerteck