markbind
markbind copied to clipboard
Investigate and list what needs to be done for Vue 3 migration
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
@MarkBind/active-devs, if you're interested as well this is very nice to have.
I will give this a try.
@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.
Just as a side note, #1536 should be important to keep in mind :)
- [ ] 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
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.
@MarkBind/active-devs
Current Approach to Migrate to Vue 3:
- Disabled SSR (Server Side Rendering) - Will be explained in detail later.
- Removed usage of Vue through CDN and switched to using Vue 3 from node modules - Will be explained in detail later.
- The current workflow:
- Process the Markdown file and generate the HTML text (stored in a variable through javascript in page.njk for client-side use).
- 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. - The client-side creates a Vue app using the variable from page.njk (mentioned in 3a).
Current Issues:
-
SSR is not fully functional.
- 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. - This error is misleading and occurs due to multiple Vue instances.
- 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.
- 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.
- 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.
- This is not trivial to debug.
- It does not work for importing components in Vue components (e.g., Navbar.vue using Button.vue), causing a
-
Removed usage of Vue through CDN and switched to using Vue 3 from node modules.
- Multiple Vue instances resulted in the
resolveComponent can only be used in render() or setup()
error. - Using Vue solely through CDN seems non-trivial.
- Using Vue from node modules simplifies the process.
- The advantages of importing Vue through CDN do not justify the cost of getting it to work.
- Multiple Vue instances resulted in the
Future Steps:
- Fix SSR to make it fully functional.
- Continue migrating all components to Vue 3, with CSR working as intended.
- SSR not working does not hinder our migration since they are supposed to generate the same output.
- Additional considerations:
- Investigate the possibility of reducing DOM manipulation in Vue.
- Consider using solely CSR and addressing the root cause of FOUC (Flash of Unstyled Content) to simplify the codebase.
How to migrate:
- Choose a component that you want to migrate
- 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.
- 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:
- 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.
- Calling methods in setup. You will need to call methods through currentInstance instead of this.
What inputs do I require?
- 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.
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.
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. TherequireFromString
-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 theexternals
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 therequireFromString
's Vue to use the CLI app's Vue) I haven't considered carefully if this will properly makeVue
available to all references inside therequireFromString
-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 therequireFromString
-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.
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.
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.
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
-
'vue-template-compiler' has been replaced by '@vue/compiler-sfc', hence
compileVuePageAndCreateScript
method which compiles page into Vue Application to get the render function must be updated. -
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
- 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 mainvue
package.
-
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
- Ensure usability and non-regression of
dataTable
andMermaid
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.