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 and useTimer 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