From b1213d2dde100d892c38bb54b4d915ad1b97da01 Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Thu, 8 Jun 2023 08:12:38 +0300 Subject: [PATCH] Add Nuxt 3 migration Implementation Plan --- ...08-implementation_plan_nuxt_3_migration.md | 278 ++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 documentation/projects/proposals/nuxt_3_migration/20230608-implementation_plan_nuxt_3_migration.md diff --git a/documentation/projects/proposals/nuxt_3_migration/20230608-implementation_plan_nuxt_3_migration.md b/documentation/projects/proposals/nuxt_3_migration/20230608-implementation_plan_nuxt_3_migration.md new file mode 100644 index 00000000000..0431acfa454 --- /dev/null +++ b/documentation/projects/proposals/nuxt_3_migration/20230608-implementation_plan_nuxt_3_migration.md @@ -0,0 +1,278 @@ +# 2023-06-01 Implementation Plan: Nuxt 3 Migration + +**Author**: @obulat + + + + +## Reviewers + + + +- [ ] @sarayourfriend - for extensive experience with JS +- [ ] @zackkrida - for extensive frontend experience and the previous migration + to Nuxt + +## Project links + + + +- [Project Thread](https://github.com/WordPress/openverse/issues/411) +- [Project Proposal](https://docs.openverse.org/projects/proposals/nuxt_3_migration/20230604-project_proposal_nuxt_3_migration.html) + +## Overview + + + +Nuxt team has created Nuxt bridge to facilitate the migration from Nuxt 2. +However, there seems to be +[no support for Nuxt Bridge in Nuxt i18n](https://github.com/nuxt-modules/i18n/discussions/1334#discussioncomment-1967220), +so the best way forward is to migrate directly to Nuxt 3. + +Nuxt 3 migration will require a lot of changes split into several PRs. + +One set of changes is required for Nuxt 3, but can also work in the current Nuxt +2 app. An example of such change is the conversion of `onBeforeRouteEnter` to +`middleware`: both work well in Nuxt 2, but only `middleware` can access `store` +in Nuxt 3. These changes are described in the "Changes to main" section below, +should be merged directly into `main` branch. + +The other changes like actually updating the `nuxt` version would break the +current app. To make sure that we can split these changes into several distinct +steps without breaking the production app, we should use a separate branch, +`nuxt3`, that would gradually get more and more features re-enabled. + +### Nuxt 3 / Vue 3 features in Openverse: discussion + +#### Autoimports + +Nuxt 3 auto imports composables and components. Unlike the usual global imports, +these imports are handled in such a way that only the imports that are actually +used are left in the production files. The Nuxt team have optimized the way they +work both in the working app and in the IDEs, so I think we _should_ use the +auto import feature and not go against the framework and disable it. In the +current setup, our test suite throws warnings when a child component is not +imported. We would need to make sure that this does not happen with Nuxt 3. + +#### `script setup` + +The new way of writing components in Vue 3 is using `script setup` which reduces +the number of code lines by automatically exporting the variables for use in the +components. While we can eventually move to using `script setup` throughout the +app, this conversion is out of scope for this project. We can, however, convert +some components if they need extensive code changes anyways, or if the behavior +within them changes significantly and the `script setup` simplifies the +component. The decision wether to convert components to `script setup` would be +at the discretion of the PR implementer. + +#### Testing + +Vue 3 recommends to use Vitest for better performance and integration with +`vite` (which will replace `webpack` in our setup). I have not had an +opportunity to test it out, but I think it would make sense to convert our unit +tests to `Vitest`. The decision on whether to keep using the current +dependencies or convert to `Vitest` should be based on the ease of conversion. + +## Expected Outcomes + + + +Openverse frontend uses Nuxt 3, and all current features (including i18n, +sitemaps, SEO) work. + +## Outlined Steps + + + +This section describes the known steps that need to be taken to migrate to +Nuxt 3. However, it is possible that there will be some unknown steps that will +be discovered during the implementation. + +- [ ] Add changes that can be done in Nuxt 2 (see "Changes to main") +- [ ] Create a `nuxt3` branch with the first PR as described in the "Nuxt 3 + branch" +- [ ] Add all other Nuxt 3 changes, as described in the "Nuxt 3 branch" +- [ ] Re-enable Playwright tests +- [ ] Make all unit tests pass + +### Changes to main + +- Deprecation of CJS modules (the ones that use `require` and `module.exports`): + - `case` package that we use for `kebab-case`, `title` case and `camelCase` + function is CJS. We can either find replacements that use `ESM` modules, + vendor in these functions, or use a workaround that `vite` suggests (instead + of `const { kebab } = require "case"` use + `import casePkg; const { kebab } = casePkg;`) + - home gallery uses `require` when importing the images dynamically. There is + a small number of them, so we should just move them to `static` folder (or + `public` in Nuxt 3) and use static `import`s. + - [ ] #2342 Tailwind config should be converted to TypeScript. +- Moving functionality inside the `setup` function would make it easier to + handle with Vue 3/Nuxt 3: + - Refactor `search.vue` page: move the route watcher and `fetchMedia` + functions to `setup` +- Refactor image and audio single result pages to show the skeleton page when + the "image"/"audio" is `null`. This is required because the way data is + fetched changes, and _is_ the correct way it _should_ be set up (instead of + not handling the case of `image` being `null` and instead relying on the error + page redirect) +- [x] #2234 Replace `onBeforeRouteEnter` router guards that don't have access to + `pinia` stores with router `middleware` that does +- [x] #2233 Remove `@nuxtjs/style-resources` - this module was used to + auto-import `scss` variables into all components. We don't use `scss` + anymore + +### Changes in Nuxt 3 branch + +- The first PR should update the bare minimum to get the app working with Nuxt + 3: + - update `nuxt` itself and `i18n`, `tailwind` and `svg-sprite` modules (and + the way they are set up). Remove/comment out other modules, plugins, + middleware. + - update the Typescript config and node version. + - Move the functions that are called at the app set up from + `middleware`/`layout`s to `app.vue`. + - Convert the layouts and pages to use `NuxtPage` instead of `NuxtChild` and + `slot` instead of `Nuxt`. For other necessary changes, look up the Nuxt 3 + docs. + - Use the new way of declaring `async components` + - Remove `Vue.set` + - Move `key` from items inside a `v-for` to the surrounding `template`. This + PR would produce an app version that can be run with the `pnpm dev` or + `pnpm build && pnpm start` commands, but would have significantly less + functionality and many console errors/warnings, so it would probably be + pushed using `--no-verify` git flag. +- Set up unit tests and add `.skip` to all the tests that are failing. + Temporarily remove the setting that disallows error logs in the test console. +- Correctly set up the head using `useHead` and `i18n` +- Remove the `@nuxtjs/composition-api` imports, replacing them with the + corresponding `useNuxtApp` or `i18n` import. If not yet possible, comment out + the import and the functionality that uses it. +- Remove all `v-on="$listeners"`, making sure that the `on` handlers are still + passed to the correct component/element. +- Remove the `.native` modifiers, and convert `VLink` to use `NuxtLink`. The + `VButton` that has `as="VLink"` can be tricky here, so we would need to make + sure it works. +- Rewrite data fetching to use the new `useAsyncFetch` composable. +- Re-add the modules listed in the "Modules" section. + +## Dependencies + +### Infrastructure + + + +There should be no changes to infrastructure. + +### Tools & packages + + + +### Tools & packages + + + +Nuxt uses `module`s for adding functionality. The table below describes the +changes that need to be made to the modules we use. + +### Nuxt module changes + +| Module name | Change needed | Links | +| ---------------------------------- | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `"@nuxt/typescript-build"` | Delete as TypeScript is natively supported by Nuxt 3 | | +| `"@nuxtjs/composition-api/module"` | Delete - natively supported by Nuxt 3 | | +| `"portal-vue/nuxt"` | Delete - natively supported by Vue 3 / Nuxt 3 | | +| `"cookie-universal-nuxt"` | Delete - natively supported by Nuxt 3, [useCookie](https://nuxt.com/docs/api/composables/use-cookie) | | +| `"@nuxtjs/svg-sprite"` | Update to current that supports Nuxt 3 | | +| `"@nuxtjs/eslint-module"` | Update to current that supports Nuxt 3 | https://github.com/nuxt-modules/eslint | +| `"@pinia/nuxt"` | Update to current version that supports Nuxt 3 | | +| `"@nuxtjs/proxy"` | Replace with Nitro routeRules or use `proxyRequest` | https://stackoverflow.com/questions/76120894/how-do-i-set-proxy-with-baseurl-with-nuxt3-and-nitro-config, https://github.com/nuxt/nuxt/discussions/15907 | +| `"@nuxtjs/redirect-module"` | Define Nitro routeRules in `nuxt.config` | https://nitro.unjs.io/config/#routerules | +| `"@nuxtjs/sentry"` | No official support | Workaround in https://github.com/nuxt-community/sentry-module/issues/530 | +| `"vue-plausible"` | Update to current version that supports Nuxt 3 or https://github.com/nuxt-modules/plausible | Note: enabling outbound tracking breaks links with target blank in `vue-plausible` | +| `"@nuxtjs/sitemap"` | Replace with `nuxt-simple-sitemap` | https://github.com/harlan-zw/nuxt-simple-sitemap | + +We should probably add [`nuxt-vitest`](https://github.com/danielroe/nuxt-vitest) +for testing in Nuxt. The package is under active development, so we should pin +to the patch version + +The migration to Nuxt 3 also means migration from Vue 2 (with added composition +API) to Vue 3. Below is a list of breaking changes that need to be addressed in +Openverse. + +#### Vue 3 breaking changes + +- [ ] `v-model` + [changes](https://v3-migration.vuejs.org/breaking-changes/v-model.html) +- [ ] `key` usage on `template v-for` instead of the components inside that + `template` +- [ ] [`v-on:event.native` removed](https://v3-migration.vuejs.org/breaking-changes/v-on-native-modifier-removed.html) - + after removing `.native`, check that links work as expected, sending the + analytics events +- [ ] [`$listeners` has been removed / merged into `$attrs`](https://v3-migration.vuejs.org/breaking-changes/listeners-removed)- + remove the `$listeners` everywhere and make sure that we have + `v-bind="$attrs"` everywhere we had `$listeners` before +- [ ] [`$attrs` includes `class` & `style`](https://v3-migration.vuejs.org/breaking-changes/attrs-includes-class-style.html) - + remove `v-bind="$attrs"` from the root element in components where + `inheritAttrs="false"` +- [ ] `Vue.set` is not necessary anymore to keep array/object reactivity +- [ ] [async components change of syntax](https://v3-migration.vuejs.org/breaking-changes/async-components.html) + (for components that use `Comp = () => import("component.vue")`) +- [ ] [`emits` option](https://v3-migration.vuejs.org/breaking-changes/emits-option.html) - + replace the `defineEvents` custom implementation + +#### Nuxt 3 breaking changes + +- [ ] `NuxtLink` is now a wrapper around both external and internal links, so we + can replace our custom `VLink` component with it. +- [ ] `app.vue` is a single place where we can put the code that needs to run + once when the app starts up. Currently, we have some layout code that is + duplicated, and `middleware` code that is run before the first load. We + should move it to `app.vue` +- [ ] [Pages and layouts changes](https://nuxt.com/docs/migration/pages-and-layouts) + +## Alternatives + + + +Migrate to a non-Nuxt SSR solution for Vue. This would require significant +changes to code for an unclear benefit. + +## Design + + + +The designs should stay exactly the same. + +## Parallelizable streams + + + +The Nuxt 2 changes can be worked on immediately. The changes to Nuxt 3 branch +can be parallellized after the initial PR. + +## Blockers + + + +## Accessibility + + + +## Rollback + + + +Since Nuxt 3 specific features will be in a separate branch, if there is a need +to roll back after merging `nuxt3` branch, we can revert the merge commit. + +## Risks + + + +Nuxt 3 is ready for production, but several modules that we need are still in +beta. We might need to patch them ourselves if we find bugs. + +## Prior art + +