Skip to content

Commit 6f3df43

Browse files
committed
Add Nuxt 3 migration Implementation Plan
1 parent 6363147 commit 6f3df43

File tree

1 file changed

+278
-0
lines changed

1 file changed

+278
-0
lines changed
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
# 2023-06-01 Implementation Plan: Nuxt 3 Migration
2+
3+
**Author**: @obulat
4+
5+
<!-- See the implementation plan guide for more information: https://github.com/WordPress/openverse/tree/19791f51c063d0979112f4b9f4eeace04c8cf5ff/docs/projects#implementation-plans-status-in-rfc -->
6+
<!-- This template is exhaustive and may include sections which aren't relevant to your project. Feel free to remove any sections which would not be useful to have. -->
7+
8+
## Reviewers
9+
10+
<!-- Choose two people at your discretion who make sense to review this based on their existing expertise. Check in to make sure folks aren't currently reviewing more than one other proposal or RFC. -->
11+
12+
- [ ] @sarayourfriend - for extensive experience with JS
13+
- [ ] @zackkrida - for extensive frontend experience and the previous migration
14+
to Nuxt
15+
16+
## Project links
17+
18+
<!-- Enumerate any references to other documents/pages, including milestones and other plans -->
19+
20+
- [Project Thread](https://github.com/WordPress/openverse/issues/411)
21+
- [Project Proposal](https://docs.openverse.org/projects/proposals/nuxt_3_migration/20230604-project_proposal_nuxt_3_migration.html)
22+
23+
## Overview
24+
25+
<!-- An overview of the implementation plan, if necessary. Save any specific steps for the section(s) below. -->
26+
27+
Nuxt team has created Nuxt bridge to facilitate the migration from Nuxt 2.
28+
However, there seems to be
29+
[no support for Nuxt Bridge in Nuxt i18n](https://github.com/nuxt-modules/i18n/discussions/1334#discussioncomment-1967220),
30+
so the best way forward is to migrate directly to Nuxt 3.
31+
32+
Nuxt 3 migration will require a lot of changes split into several PRs.
33+
34+
One set of changes is required for Nuxt 3, but can also work in the current Nuxt
35+
2 app. An example of such change is the conversion of `onBeforeRouteEnter` to
36+
`middleware`: both work well in Nuxt 2, but only `middleware` can access `store`
37+
in Nuxt 3. These changes are described in the "Changes to main" section below,
38+
should be merged directly into `main` branch.
39+
40+
The other changes like actually updating the `nuxt` version would break the
41+
current app. To make sure that we can split these changes into several distinct
42+
steps without breaking the production app, we should use a separate branch,
43+
`nuxt3`, that would gradually get more and more features re-enabled.
44+
45+
### Nuxt 3 / Vue 3 features in Openverse: discussion
46+
47+
#### Autoimports
48+
49+
Nuxt 3 auto imports composables and components. Unlike the usual global imports,
50+
these imports are handled in such a way that only the imports that are actually
51+
used are left in the production files. The Nuxt team have optimized the way they
52+
work both in the working app and in the IDEs, so I think we _should_ use the
53+
auto import feature and not go against the framework and disable it. In the
54+
current setup, our test suite throws warnings when a child component is not
55+
imported. We would need to make sure that this does not happen with Nuxt 3.
56+
57+
#### `script setup`
58+
59+
The new way of writing components in Vue 3 is using `script setup` which reduces
60+
the number of code lines by automatically exporting the variables for use in the
61+
components. While we can eventually move to using `script setup` throughout the
62+
app, this conversion is out of scope for this project. We can, however, convert
63+
some components if they need extensive code changes anyways, or if the behavior
64+
within them changes significantly and the `script setup` simplifies the
65+
component. The decision wether to convert components to `script setup` would be
66+
at the discretion of the PR implementer.
67+
68+
#### Testing
69+
70+
Vue 3 recommends to use Vitest for better performance and integration with
71+
`vite` (which will replace `webpack` in our setup). I have not had an
72+
opportunity to test it out, but I think it would make sense to convert our unit
73+
tests to `Vitest`. The decision on whether to keep using the current
74+
dependencies or convert to `Vitest` should be based on the ease of conversion.
75+
76+
## Expected Outcomes
77+
78+
<!-- List any succinct expected products from this implementation plan. -->
79+
80+
Openverse frontend uses Nuxt 3, and all current features (including i18n,
81+
sitemaps, SEO) work.
82+
83+
## Outlined Steps
84+
85+
<!-- Describe the implementation step necessary for completion. -->
86+
87+
This section describes the known steps that need to be taken to migrate to
88+
Nuxt 3. However, it is possible that there will be some unknown steps that will
89+
be discovered during the implementation.
90+
91+
- [ ] Add changes that can be done in Nuxt 2 (see "Changes to main")
92+
- [ ] Create a `nuxt3` branch with the first PR as described in the "Nuxt 3
93+
branch"
94+
- [ ] Add all other Nuxt 3 changes, as described in the "Nuxt 3 branch"
95+
- [ ] Re-enable Playwright tests
96+
- [ ] Make all unit tests pass
97+
98+
### Changes to main
99+
100+
- Replace `onBeforeRouteEnter` router guards that don't have access to `pinia`
101+
stores with router `middleware` that does #2234
102+
- Deprecation of CJS modules (the ones that use `require` and `module.exports`):
103+
- `case` package that we use for `kebab-case`, `title` case and `camelCase`
104+
function is CJS. We can either find replacements that use `ESM` modules,
105+
vendor in these functions, or use a workaround that `vite` suggests (instead
106+
of `const { kebab } = require "case"` use
107+
`import casePkg; const { kebab } = casePkg;`)
108+
- home gallery uses `require` when importing the images dynamically. There is
109+
a small number of them, so we should just move them to `static` folder (or
110+
`public` in Nuxt 3) and use static `import`s.
111+
- Tailwind config should be converted to TypeScript.
112+
- Remove old unused modules and code
113+
- `@nuxtjs/style-resources` - this module was used to auto-import `scss`
114+
variables into all components. We don't use `scss` anymore
115+
- Audit and remove the code that was used with old designs or with for work
116+
with the iframe.
117+
- Refactor `search.vue` page: move the route watcher and `fetchMedia` functions
118+
to `setup`
119+
- Refactor image and audio single result pages to show the skeleton page when
120+
the "image"/"audio" is `null`. This is required because the way data is
121+
fetched changes, and _is_ the correct way it _should_ be set up (instead of
122+
not handling the case of `image` being `null` and instead relying on the error
123+
page redirect)
124+
125+
### Changes in Nuxt 3 branch
126+
127+
- The first PR should update the bare minimum to get the app working with Nuxt
128+
3:
129+
- update `nuxt` itself and `i18n`, `tailwind` and `svg-sprite` modules (and
130+
the way they are set up). Remove/comment out other modules, plugins,
131+
middleware.
132+
- update the Typescript config and node version.
133+
- Move the functions that are called at the app set up from
134+
`middleware`/`layout`s to `app.vue`.
135+
- Convert the layouts and pages to use `NuxtPage` instead of `NuxtChild` and
136+
`slot` instead of `Nuxt`. For other necessary changes, look up the Nuxt 3
137+
docs.
138+
- Use the new way of declaring `async components`
139+
- Remove `Vue.set`
140+
- Move `key` from items inside a `v-for` to the surrounding `template`. This
141+
PR would produce an app version that can be run with the `pnpm dev` or
142+
`pnpm build && pnpm start` commands, but would have significantly less
143+
functionality and many console errors/warnings, so it would probably be
144+
pushed using `--no-verify` git flag.
145+
- Set up unit tests and add `.skip` to all the tests that are failing.
146+
Temporarily remove the setting that disallows error logs in the test console.
147+
- Correctly set up the head using `useHead` and `i18n`
148+
- Remove the `@nuxtjs/composition-api` imports, replacing them with the
149+
corresponding `useNuxtApp` or `i18n` import. If not yet possible, comment out
150+
the import and the functionality that uses it.
151+
- Remove all `v-on="$listeners"`, making sure that the `on` handlers are still
152+
passed to the correct component/element.
153+
- Remove the `.native` modifiers, and convert `VLink` to use `NuxtLink`. The
154+
`VButton` that has `as="VLink"` can be tricky here, so we would need to make
155+
sure it works.
156+
- Rewrite data fetching to use the new `useAsyncFetch` composable.
157+
- Re-add the modules listed in the "Modules" section.
158+
159+
## Dependencies
160+
161+
### Infrastructure
162+
163+
<!-- Describe any infrastructure that will need to be provisioned or modified. In particular, identify associated potential cost changes. -->
164+
165+
There should be no changes to infrastructure.
166+
167+
### Tools & packages
168+
169+
<!-- Describe any tools or packages which this work might be dependent on. If multiple options are available, try to list as many as are reasonable with your own recommendation. -->
170+
171+
### Tools & packages
172+
173+
<!-- Describe any tools or packages which this work might be dependent on. If multiple options are available, try to list as many as are reasonable with your own recommendation. -->
174+
175+
Nuxt uses `module`s for adding functionality. The table below describes the
176+
changes that need to be made to the modules we use.
177+
178+
### Nuxt module changes
179+
180+
| Module name | Change needed | Links |
181+
| ---------------------------------- | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
182+
| `"@nuxt/typescript-build"` | Delete as TypeScript is natively supported by Nuxt 3 | |
183+
| `"@nuxtjs/composition-api/module"` | Delete - natively supported by Nuxt 3 | |
184+
| `"portal-vue/nuxt"` | Delete - natively supported by Vue 3 / Nuxt 3 | |
185+
| `"cookie-universal-nuxt"` | Delete - natively supported by Nuxt 3, [useCookie](https://nuxt.com/docs/api/composables/use-cookie) | |
186+
| `"@nuxtjs/svg-sprite"` | Update to current that supports Nuxt 3 | |
187+
| `"@nuxtjs/eslint-module"` | Update to current that supports Nuxt 3 | https://github.com/nuxt-modules/eslint |
188+
| `"@pinia/nuxt"` | Update to current version that supports Nuxt 3 | |
189+
| `"@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 |
190+
| `"@nuxtjs/redirect-module"` | Define Nitro routeRules in `nuxt.config` | https://nitro.unjs.io/config/#routerules |
191+
| `"@nuxtjs/sentry"` | No official support | Workaround in https://github.com/nuxt-community/sentry-module/issues/530 |
192+
| `"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` |
193+
| `"@nuxtjs/sitemap"` | Replace with `nuxt-simple-sitemap` | https://github.com/harlan-zw/nuxt-simple-sitemap |
194+
195+
We should probably add [`nuxt-vitest`](https://github.com/danielroe/nuxt-vitest)
196+
for testing in Nuxt. The package is under active development, so we should pin
197+
to the patch version
198+
199+
The migration to Nuxt 3 also means migration from Vue 2 (with added composition
200+
API) to Vue 3. Below is a list of breaking changes that need to be addressed in
201+
Openverse.
202+
203+
#### Vue 3 breaking changes
204+
205+
- [ ] `v-model`
206+
[changes](https://v3-migration.vuejs.org/breaking-changes/v-model.html)
207+
- [ ] `key` usage on `template v-for` instead of the components inside that
208+
`template`
209+
- [ ] [`v-on:event.native` removed](https://v3-migration.vuejs.org/breaking-changes/v-on-native-modifier-removed.html) -
210+
after removing `.native`, check that links work as expected, sending the
211+
analytics events
212+
- [ ] [`$listeners` has been removed / merged into `$attrs`](https://v3-migration.vuejs.org/breaking-changes/listeners-removed)-
213+
remove the `$listeners` everywhere and make sure that we have
214+
`v-bind="$attrs"` everywhere we had `$listeners` before
215+
- [ ] [`$attrs` includes `class` & `style`](https://v3-migration.vuejs.org/breaking-changes/attrs-includes-class-style.html) -
216+
remove `v-bind="$attrs"` from the root element in components where
217+
`inheritAttrs="false"`
218+
- [ ] `Vue.set` is not necessary anymore to keep array/object reactivity
219+
- [ ] [async components change of syntax](https://v3-migration.vuejs.org/breaking-changes/async-components.html)
220+
(for components that use `Comp = () => import("component.vue")`)
221+
- [ ] [`emits` option](https://v3-migration.vuejs.org/breaking-changes/emits-option.html) -
222+
replace the `defineEvents` custom implementation
223+
224+
#### Nuxt 3 breaking changes
225+
226+
- [ ] `NuxtLink` is now a wrapper around both external and internal links, so we
227+
can replace our custom `VLink` component with it.
228+
- [ ] `app.vue` is a single place where we can put the code that needs to run
229+
once when the app starts up. Currently, we have some layout code that is
230+
duplicated, and `middleware` code that is run before the first load. We
231+
should move it to `app.vue`
232+
- [ ] [Pages and layouts changes](https://nuxt.com/docs/migration/pages-and-layouts)
233+
234+
## Alternatives
235+
236+
<!-- Describe any alternatives considered and why they were not chosen or recommended. -->
237+
238+
Migrate to a non-Nuxt SSR solution for Vue. This would require significant
239+
changes to code for an unclear benefit.
240+
241+
## Design
242+
243+
<!-- Note any design requirements for this plan. -->
244+
245+
The designs should stay exactly the same.
246+
247+
## Parallelizable streams
248+
249+
<!-- What, if any, work within this plan can be parallelized? -->
250+
251+
The Nuxt 2 changes can be worked on immediately. The changes to Nuxt 3 branch
252+
can be parallellized after the initial PR.
253+
254+
## Blockers
255+
256+
<!-- What hard blockers exist which might prevent further work on this project? -->
257+
258+
## Accessibility
259+
260+
<!-- Are there specific accessibility concerns relevant to this plan? Do you expect new UI elements that would need particular care to ensure they're implemented in an accessible way? Consider also low-spec device and slow internet accessibility, if relevant. -->
261+
262+
## Rollback
263+
264+
<!-- How do we roll back this solution in the event of failure? Are there any steps that can not easily be rolled back? -->
265+
266+
Since Nuxt 3 specific features will be in a separate branch, if there is a need
267+
to roll back after merging `nuxt3` branch, we can revert the merge commit.
268+
269+
## Risks
270+
271+
<!-- What risks are we taking with this solution? Are there risks that once taken can’t be undone?-->
272+
273+
Nuxt 3 is ready for production, but several modules that we need are still in
274+
beta. We might need to patch them ourselves if we find bugs.
275+
276+
## Prior art
277+
278+
<!-- Include links to documents and resources that you used when coming up with your solution. Credit people who have contributed to the solution that you wish to acknowledge. -->

0 commit comments

Comments
 (0)