Introduction
Are you considering migrating your Vue.js project to Nuxt 3? Transitioning between frameworks can be a transformative step, and our experts are here to guide you through the process. In this comprehensive guide, we’ll share top tips and insights to ensure a seamless migration and help you make the most of Nuxt 3’s powerful features. Let’s begin.
Setup a New Nuxt 3 Project
Start by creating a new Nuxt 3 project using command
npx nuxi init <PROJECT_NAME>
.
Links in page <head> section
// === [Vue 3] /index.html <html lang="en"> <head> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Bubblegum Sans&display=swap"> </head> </html> // === [Nuxt 3] /nuxt.config.ts export default defineNuxtConfig({ app: { head: { link: [ { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Bubblegum Sans&display=swap' }, ], }, }, });
Global CSS
// === [Vue 3] /src/main.js import './style.css'; // CSS file: /src/style.css // === [Nuxt 3] /nuxt.config.ts export default defineNuxtConfig({ css: [ '@/assets/css/main.scss', ], }); // CSS file: /assets/css/main.scss
import.meta
By default using
import.meta
will throw error (esbuild plugin) [esbuild] (.nuxt/dist/server/_nuxt/…) “import.meta” is not available in the configured target environment (“es2019”) and will be empty during nuxt generate
. The following setting will allow usage of import.meta
and window
.
// === [Nuxt 3] /nuxt.config.ts export default defineNuxtConfig({ nitro: { esbuild: { options: { target: 'node18', } } }, }); // Note: Change node18 to the node version that you are using
Entry Point
Vue 3:
/index.html
Nuxt 3:
/app.vue
Modify <head> Settings
// === [Vue 3] /index.html <html lang="en"> <head> <meta name="description" content="..." /> <title>... </head> </html> // === [Vue 3] /src/*.vue document.title = ...; document.querySelector('meta[name="description"]').setAttribute('content', ...); // === [Nuxt 3] /pages/*.vue, /components/*.vue, /composables/*.ts... useSeoMeta({ description: () => ..., title: () => ..., });
Routing
// === [Vue 3] /index.html <html lang="en"> <head> <script async type="module" src="/src/main.js"> </head> </html> // === [Vue 3] /src/main.js import { createApp } from 'vue'; import App from '@/App.vue'; const app = createApp(App); import router from '@/router'; app.use(router); app.mount('#app'); // === [Vue 3/Vue Router] src/router/index.js import { createRouter, createWebHistory } from 'vue-router'; const routes = [ { path: '/', component: () => import('@/components/index.vue'), }, { path: '/about', component: () => import('@/components/AboutUs.vue'), }, ]; const router = createRouter({ history: createWebHistory(), routes, }); export default router; // === [Vue 3] /src/components/index.vue <template> <h1>Hello World </template> // === [Vue 3] /src/components/AboutUs.vue <template> <h1>About Us </template> // === [Nuxt 3] /pages/index.vue // Note: Creating components within the/pages
folder will automatically create a route, index.vue is the root (/
) <template> <h1>Hello World </template> // === [Nuxt 3] /pages/about.vue // Creates route/about
<template> <h1>About Us </template>
Asset Files
Images, audio, video files etc.
Vue 3: Folder
/src/assets/*
, url reference new URL(`/src/assets/images/${fileName}`, import.meta.url).href
Nuxt 3: Folder
/assets/*
, url reference new URL(`../assets/img/${fileName}`, import.meta.url).href
Composable
Nuxt 3: Composables will be automatically imported as long as they are placed in folder
/composables
// === Vue 3 import { computed } from 'vue'; import useTimer from '@/composables/useTimer.js'; const counter = computed(() => { ... }); const timer = useTimer(); // === Nuxt 3 // Note:computed
anduseTimer
can be used directly without import const counter = computed(() => { ... }); const timer = useTimer();
Static Hosting
// === Vue 3 yarn build // Copy all files from folder/dist/
to remote server // === Nuxt 3 yarn generate // Copy all files from folder/.output/public/
to remote server