Nuxt+Vue3+TS+Vite Getting Started Tutorial

introduce

What is Nuxt3

Nuxt3 is an application framework based on Vue.js. It provides some default configurations and conventions, allowing developers to build high-quality Vue.js applications more quickly. Nuxt3 is the next generation version of Nuxt.js, which adopts a new architecture and design to provide better performance and scalability.

Advantages of Nuxt3

1. Faster startup and rendering speed
2. Better performance and scalability
3. More flexible configuration and plug-ins System
4. Better development experience and documentation support

Nuxt3 Ecology

Nuxt3 has a very rich ecosystem, including many plug-ins, modules, component libraries, tools, etc. The relevant Nuxt3 ecology can be found on the ecology page of the Nuxt3 official website (https://nuxt.com/modules).

Install

Install nuxt3

Before installing Nuxt3, you need to ensure that your node.js is greater than 16.10.0 or the latest version

Create a nuxt project

npx nuxi init <project-name>

Switch to the root directory of the project you just created

cd <project-name>

Download related dependencies

npm install

Base

Directory structure of Nuxt3

  • assets/: stores static resource files, such as styles, pictures, fonts, etc.
  • components/: stores component files, which can be referenced in the page.
  • layouts/: stores layout files, which can be referenced in the page.
  • middleware/: stores middleware files, which can be used in routing.
  • composables/: stores reusable logic code that can be used in pages, components and plug-ins.
  • pages/: stores page files, each file corresponds to a route.
  • plugins/: stores plug-in files that can be used in applications.
  • static/: stores static files, such as robots.txt, favicon.ico, etc.
  • store/: stores Vuex store files.
  • server/: stores server-side code, including middleware, API, plug-ins, etc.
  • utils/: stores tool function files.
  • nuxt.config.ts: Nuxt3 configuration file, written in TypeScript.
  • package.json: project dependencies and script configuration files.
  • tsconfig.json: TypeScript configuration file.

Pages and routes

Nuxt3's pages and routes are a file system-based routing system that allows developers to define pages and routes by creating .vue files in the pages directory. Each .vue file corresponds to a route, and Nuxt3 will automatically generate the routing path based on the file name. For example, the routing path corresponding to pages/index.vue is /, and the routing path corresponding to pages/about.vue is /about. In addition, Nuxt3 also supports dynamic routing and nested routing, which can be defined by using [] and _ in the file name. For example, the dynamic routing path corresponding to pages/posts/[id].vue is /posts/:id, and the nested routing path corresponding to pages/posts/_slug/comments.vue is /posts/:slug/comments.

dynamic routing
-| pages/
---| index.vue
---| users-[group]/
-----| [id].vue
// 你可以通过使用$route.params来获取传递的参数
<template>
  <p>{
   
   { $route.params.group }} - {
   
   { $route.params.id }}</p>
</template>

If you want to access routes using the composition API, there is a global function that allows you to access routes just like in the options API.

<script setup>
const route = useRoute()

if (route.params.group === 'admins' && !route.params.id) {
      
      
  console.log('Warning! Make sure user is authenticated!')
}
</script>

If you want a parameter to be optional, you must enclose it in double square brackets - for example, or you will match both and . ~/pages/[[slug]]/index.vue ~/pages/[[slug]].vue

Nested routing

If the file name and directory have the same name, nuxt3 will automatically create a nested route for you. Use the NuxtChild component in the parent component to display the content of the nested sub-component.

比如下面目录结构:
-| pages/
---| parent/
------| child.vue
---| parent.vue
// pages/parent.vue
<template>
  <div>
    <h1>I am the parent view</h1>
    <NuxtPage :foobar="123" />
  </div>
</template>

navigation

To navigate between your app's pages, you should use components. This component is included in Nuxt, so you don't have to import it like other components.

<template>
  <NuxtLink to="/">Home page</NuxtLink>
</template>
Programming Navigation

Nuxt 3 allows programmatic navigation via utility methods. Using this utility method, you will be able to programmatically navigate users through your app. This is great for getting input from the user and dynamically navigating them throughout the application.
In this example, we have a simple method called navigate() that is called when the user submits the search form.

<script setup>
const router = useRouter();
const name = ref('');
const type = ref(1);

function navigate(){
      
      
  return navigateTo({
      
      
    path: '/search',
    query: {
      
      
      name: name.value,
      type: type.value
    }
  })
}
</script>

Layout and components

default layout

Nuxt provides a customizable layout framework that you can use throughout your application, perfect for extracting common UI or code patterns into reusable layout components. Layouts are placed in directories and automatically loaded via asynchronous import when used.

// ~/layouts/default.vue
<template>
  <div>
    Some default layout shared across all pages
    <slot />
  </div>
</template>

In the layout file, the content of the layout will be loaded in, rather than using special components.

If you use, you also need to add in app.vue

<template>
  <NuxtLayout>
    some page content
  </NuxtLayout>
</template>
Use other custom components
-| layouts/
---| default.vue
---| custom.vue
<template>
  <NuxtLayout :name="layout">
    <NuxtPage />
  </NuxtLayout>
</template>

<script setup>
// You might choose this based on an API call or logged-in status
const layout = "custom";
</script>
Dynamically modify layout components
<template>
  <div>
    <button @click="enableCustomLayout">Update layout</button>
  </div>
</template>

<script setup>
function enableCustomLayout () {
      
      
  setPageLayout('custom')
}
definePageMeta({
      
      
  layout: false,
});
</script>

For more introduction, please see

Component Catalog

The components/ directory is where you put all your Vue components, which can then be imported into your page or other components. Nuxt will automatically import any components in the directory (as well as any module components you may be using).

| components/
--| TheHeader.vue
--| TheFooter.vue
// layouts/default.vue
<template>
  <div>
    <TheHeader />
    <slot />
    <TheFooter />
  </div>
</template>
Custom directory

By default, only the components directory is scanned for automatic import. If you want to add additional directories, or change how components are scanned in subfolders of this directory, you can add additional directories to the configuration

export default defineNuxtConfig({
    
    
  components: [
    {
    
     path: '~/components/special-components', prefix: 'Special' },
    '~/components'
  ]
})
Component name

If there are the following components in the nested directory, for example:

| components/
--| base/
----| foo/
------| Button.vue

The component's name will then be based on its own path directory and filename, with duplicate segments removed. Therefore, the name of the component will be:

<BaseFooButton />
dynamic components

If you want to use Vue syntax, you need to use the API provided by Vue

<template>
  <component :is="clickable ? MyButton : 'div'" />
</template>

<script setup>
const MyButton = resolveComponent('MyButton')
</script>
Dynamic import (lazy loading of components)

To dynamically import a component (also known as lazy loading a component), you just need to add the prefix lazy to the component's name.

// layouts/default.vue
<template>
  <div>
    <TheHeader />
    <slot />
    <LazyTheFooter />
  </div>
</template>
<template>
  <div>
    <h1>Mountains</h1>
    <LazyMountainsList v-if="show" />
    <button v-if="!show" @click="show = true">Show List</button>
  </div>
</template>

<script>
export default {
      
      
  data() {
      
      
    return {
      
      
      show: false
    }
  }
}
</script>
Explicitly import components

You can also explicitly import components from it if you want or need to bypass Nuxt's automatic import functionality.

<template>
  <div>
    <h1>Mountains</h1>
    <LazyMountainsList v-if="show" />
    <button v-if="!show" @click="show = true">Show List</button>
    <NuxtLink to="/">Home</NuxtLink>
  </div>
</template>

<script setup>
  import {
      
       NuxtLink, LazyMountainsList } from '#components'
  const show = ref(false)
</script>

For more content, please move here

Data acquisition and rendering

retrieve data

Nuxt provides four APIs useFetch, useLazyFetch, useAsyncData and useLazyAsyncData to handle data requests.

useFetch

You can use useFetch to universally fetch data from any URL in your pages, components, and plugins. This API is composed of useAsyncData and $fetch. It automatically generates keys based on URL and fetch options, provides type hints for request URLs based on server routes, and infers API response types.

<script setup>
const {
      
       data: count } = await useFetch('/api/count')
</script>

<template>
  Page visits: {
   
   { count }}
</template>
useLazyFetch

This composable object behaves the same as using Fetch with the lazy: true option set. In other words, async functions do not block navigation. This means you will need to handle the case where the data is null (or whatever value you provide in your custom default factory function).

<template>
  <!-- you will need to handle a loading state -->
  <div v-if="pending">
    Loading ...
  </div>
  <div v-else>
    <div v-for="post in posts">
      <!-- do something -->
    </div>
  </div>
</template>

<script setup>
const {
      
       pending, data: posts } = useLazyFetch('/api/posts')
watch(posts, (newPosts) => {
      
      
  // Because posts starts out null, you will not have access
  // to its contents immediately, but you can watch it.
})
</script>
you are in AsyncData

You can use this to access asynchronously parsed data in your pages, components and plugins

// server/api/count.ts
let counter = 0
export default defineEventHandler(() => {
    
    
  counter++
  return counter
})
<script setup>
const {
      
       data } = await useAsyncData('count', () => $fetch('/api/count'))
</script>

<template>
  Page visits: {
   
   { data }}
</template>
you are in LazyAsyncData

This composable object behaves the same as an options set. In other words, async functions do not block navigation. This means you will need to handle the case where the data is (or whatever value you provide in your custom factory function)

<template>
  <div>
    {
   
   { pending ? 'Loading' : count }}
  </div>
</template>

<script setup>
const {
      
       pending, data: count } = useLazyAsyncData('count', () => $fetch('/api/count'))
watch(count, (newCount) => {
      
      
  // Because count starts out null, you won't have access
  // to its contents immediately, but you can watch it.
})
</script>

For more content, please move here

Advanced

Plugins and modules
Plug-in directory

Nuxt3 plug-ins are used to extend application functionality. They can run before or after the application starts, and can access the Nuxt3 context object. Plug-ins can be used to add third-party libraries, set global variables, add instance methods, add Vue components, etc. Plugins can be defined in the plugins directory and configured in the nuxt.config.ts file.
Nuxt automatically reads the files in the plugin directory and loads them when creating a Vue application. You can use the .server or .client suffix in the file name to load the plugin only on the server or client side.

Only files at the top level of the directory (or index files in any subdirectories) will be registered as plugins.

plugins
 | - myPlugin.ts  // scanned
 | - myOtherPlugin
 | --- supportingFile.ts   // not scanned
 | --- componentToRegister.vue   // not scanned
 | --- index.ts  // currently scanned but deprecated
Create a new plugin
export default defineNuxtPlugin(nuxtApp => {
    
    
  // Doing something with nuxtApp
})

For more content, please move here

module directory

Nuxt scans the modules/ directory and loads them before starting. Any native modules you develop can be placed here when building your application.
The automatically registered file mode is:

modules/*/index.ts
modules/*.ts

You don't need to add these local modules to nuxt.config.ts separately.

// modules/hello/index.ts

// `nuxt/kit` is a helper subpath import you can use when defining local modules
// that means you do not need to add `@nuxt/kit` to your project's dependencies
import {
    
     createResolver, defineNuxtModule, addServerHandler } from 'nuxt/kit'

export default defineNuxtModule({
    
    
  meta: {
    
    
    name: 'hello'
  },
  setup () {
    
    
    const {
    
     resolve } = createResolver(import.meta.url)

    // Add an API route
    addServerHandler({
    
    
      route: '/api/hello',
      handler: resolve('./runtime/api-route')
    })
  }
})
export default defineEventHandler(() => {
    
    
  return {
    
     hello: 'world' }
}

When starting Nuxt, the hello module will be registered and the /api/hello route will be available.

Middleware and interceptors
middleware

Nuxt's middleware is a customizable routing middleware framework that can be used throughout your application. It's great for extracting code to run before navigating to a specific route. Middleware can be used to authenticate users, check permissions, prefetch data, etc. In Nuxt, middleware can be defined in the middleware/ directory and configured in the nuxt.config.ts file. Middleware can be global or page-specific. Global middleware will run on every page, while page-specific middleware will run on that page only. In middleware, you can access context objects such as context.app, context.store, and context.route.

A simple interceptor case encapsulated by middleware:

import {
    
     api } from '~/api/api';
import {
    
     userStore } from '~/stores/user';

export default defineNuxtRouteMiddleware((to, from) => {
    
    
    const token = useCookie('token')
    const store = userStore();

    if (typeof (token.value) == 'undefined') {
    
    
        return navigateTo('/')
    }

    api.user.getInfo().then(info => {
    
    
        if (!info.success) {
    
    
            store.$patch({
    
    
                isLogin: !store.isLogin
            })
            store.$patch({
    
    
                isLogin: false
            })
            token.value = undefined
            store.$patch({
    
    
                showLogin: true
            })
            navigateTo('/')
        }
    })
})

For more content, please move here

Hooks and the server
composables(Hooks)

Nuxt's composables (Hooks) are reusable logical code blocks that can be used in different pages, components and plug-ins. They are built on top of Vue 3’s Composition API, allowing you to more easily manage and share state, side effects, and calculation logic. Nuxt provides some built-in composables such as useAsyncData, useFetch, and useRoute, or you can create your own composables. Using composables can make the code more modular and maintainable, while also improving the reusability and testability of the code.

In terms of server-side rendering, Nuxt’s composables can run on both the server and client sides because they are built on top of Vue 3’s Composition API. However, it is important to note that some composables may produce different behavior on the server side and client side, so you need to carefully test your code to ensure that they work correctly in both environments. Also, due to the special nature of server-side rendering, some composables may not run on the server side, so you need to read Nuxt's documentation carefully to understand which composables are suitable for server-side rendering.

All in all, Nuxt's composables are a very useful tool that can help you manage and share state, side effects, and computational logic more easily. Whether you're writing code on the client or server side, you can use composables to make your code more reusable and testable.

Nuxt3 uses the compositables/ directory to automatically import Vue composable files into the application using auto-import!

// 方法1:使用命名导出
export const useFoo = () => {
    
    
  return useState('foo', () => 'bar')
}
// 方法2:使用默认导出
// It will be available as useFoo() (camelCase of file name without extension)
export default function () {
    
    
  return useState('foo', () => 'bar')
}

Usage: You can now use automatically imported composable files in .js, .ts and .vue files

<template>
  <div>
    {
   
   { foo }}
  </div>
</template>

<script setup>
const foo = useFoo()
</script>

For more content, please move here

Server

The server/ directory is the folder in the Nuxt project used for server-side rendering (SSR) and server middleware. When Nuxt runs in SSR mode, it uses Node.js to render Vue components on the server and send the resulting HTML to the client. The server/ directory contains files used to configure the server and handle requests.
An important file in the server/ directory is routes, which is used to create server instances and configure middleware. This file exports a function that takes a nuxtApp object as a parameter and can be used to access the Nuxt application instance and configure the server.
Another important file in the server/ directory is middleware, which is used to define server middleware. Server middleware is similar to client middleware, but it runs on the server instead of the client. Server middleware can be used to handle requests, modify responses, or perform other server-side tasks.
In addition to these files, the server/ directory may contain other files used to configure the server or handle requests. For example, a server/api file can be used to define API endpoints that clients can access.
In short, the server/ directory is an important part of the Nuxt project and is used to configure the server and handle requests in SSR mode.

Create a new file in server/api/hello.ts:

export default defineEventHandler((event) => {
    
    
  return {
    
    
    api: 'works'
  }
})

You can now call this API universally using wait$fetch("/API/hello").

Server routing

Files in /server/api will automatically be prefixed with /api in their routes. To add server routes without the /api prefix, you can place them in the /server/routes directory.

Create a new file in server/routes/hello.ts

export default defineEventHandler(() => 'Hello World!')

Given the example above, the /hello route would be at http://localhost:3000/hello.

Server middleware

Nuxt will automatically read any file in ~/server/middleware to create server middleware for your project.
A middleware handler that will be run on each request to add or check headers, log the request, or extend the event's request object before any other server routes.

// server/middleware/log.ts
export default defineEventHandler((event) => {
    
    
  console.log('New request: ' + event.node.req.url)
})
// server/middleware/auth.ts
export default defineEventHandler((event) => {
    
    
  event.context.auth = {
    
     user: 123 }
})

For more content, please move here

Configure environment variables

To configure Nuxt environment variables, you need to understand the following knowledge points:
Nuxt environment variable configuration file: Nuxt uses .env files to configure environment variables. You can create an .env file in your project root directory and define your environment variables in it. For example, you can define an environment variable called API_URL in your .env file whose value is the URL of your API.
How to access environment variables: You can use the process.env object to access the environment variables you define in the .env file. For example, if you define an environment variable called API_URL in your .env file, you can access it in your code using process.env.API_URL.
Scope of environment variables: Nuxt's environment variables can be used on the client and server. If you need to use the same environment variable on client and server side, you can define it in .env file. If you need to use different environment variables on the client and server side, you can define them in the .env.client and .env.server files.
Injection of environment variables: Nuxt will inject the environment variables you define in the .env file into the client-side and server-side JavaScript code. This means you can use the process.env object to access in both client-side and server-side JavaScript code

# 请求接口地址
VITE_REQUEST_BASE_URL = 'https://www.xxxxxx.net'
VITE_SERVER_NAME = 'https://www.xxxxxx.net/api'
# VITE开头的变量才会被暴露出去
import {
    
     loadEnv } from 'vite'
const envName = loadEnv(process.argv[process.argv.length-1], './env').VITE_SERVER_NAME

export default defineNuxtConfig({
    
    
  app: {
    
    
    head: {
    
    
      meta: [
        {
    
     name: 'viewport', content: 'width=device-width, initial-scale=1' }
      ],
      script: [
        // { src: 'http://xxx.js' }
      ],
      link: [
        // { rel: 'stylesheet', href: 'https://awesome-lib.css' }
      ],
    }
  },
  srcDir: 'src/',
  css: [
    '@/assets/styles/reset.css'
  ],
  modules: [
    // ...
    '@pinia/nuxt',
    '@vueuse/nuxt',
    '@element-plus/nuxt',
  ],
  vite: {
    
    
    css: {
    
    
      preprocessorOptions: {
    
    
        scss: {
    
    
          additionalData: '@import "@/assets/styles/default.scss";'	
        }
      }
    }
  },
  runtimeConfig: {
    
     // 运行时常量
    public: {
    
     // 客户端-服务的都能访问
      baseUrl: envName
    }
  }
})

For more content, please move here

deploy

Nuxt.js has two packaging methods: static and server-side rendering (SSR). The static packaging method generates static HTML files, which can be directly deployed to any static file server. The SSR packaging method requires running Node.js on the server, rendering the Vue component into HTML and sending it to the client. Therefore, the SSR packaging method needs to be deployed on a server that supports Node.js.
Regarding deployment to servers and cloud platforms, you can upload the packaged files to the server or cloud platform, and run Node.js on the server to start the Nuxt.js application. You can use process management tools such as PM2 to manage Node.js processes and reverse proxy servers such as Nginx to handle HTTP requests.

Pack

For static packaging, you can use the following command to package:

npm run generate

For SSR packaging method, you can use the following command to package:

npm run build

This will generate a .nuxt directory that contains all the server-side rendering code and related resource files. You can upload these files to a Node.js-enabled server and launch your Nuxt.js application using the following command:

Deploy to server

1. Install necessary software such as Node.js and Nginx on the server. Node.js can be installed on Ubuntu using the following command:

sudo apt-get update
sudo apt-get install nodejs

2. You can use the following command to install Nginx on Ubuntu:

sudo apt-get update
sudo apt-get install nginx

3. Configure Nginx reverse proxy server. You need to configure Nginx to forward HTTP requests to the Node.js server. You can use the following configuration files as a reference:

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

4. Restart nginx after configuring

nginx -s reload

5. Start the Nuxt.js application. You can start a Nuxt.js application using the following command:

npm run start

6. Use process management tools such as PM2 to manage the Node.js process. PM2 can be installed using the following command:

npm install pm2 -g

7. You can use the following command to start the Nuxt.js application and use PM2 to manage the process. Go to the folder corresponding to the nuxt project and execute:

pm2 --name=你的服务名 start npm -- run start
pm2 common commands
pm2 list                             查看所有进程
pm2 show 0                           查看进程详细信息,0为PM2进程id 
pm2 stop all                         停止PM2列表中所有的进程
pm2 stop 0                           停止PM2列表中进程为0的进程
pm2 reload all                       重载PM2列表中所有的进程
pm2 reload 0                         重载PM2列表中进程为0的进程
pm2 delete 0                         删除PM2列表中进程为0的进程
pm2 delete all                       删除PM2列表中所有的进程

Guess you like

Origin blog.csdn.net/weixin_41535944/article/details/129794934