一、背景介绍

2022 年 11 月 16 日,全球最大的 Nuxt 会议 Nuxt Nation 2022 在线举行,并正式发布了 Nuxt.js 3.0 的第一个稳定版本。Nuxt 3 是基于 ViteVue3 和 Nitro 的 Nuxt 框架的现代重写,具有一流的 Typescript 支持,是两年多研究、社区反馈、创新和实验的结果。为每个人提供了一个愉快的 Vue 全栈开发体验。

因为nuxt优越的服务端渲染能力,所以对于nuxt3项目关注已久!我们开始吧!

二、官方网址

Nuxt 3 - 中文文档

Nuxt - The Intuitive Vue Framework

Announcing 3.0 · Nuxt

Nuxt - Installation

https://github.com/nuxt/create-nuxt-app/blob/master/README.md

三、新特性介绍

1、更轻量:以现代浏览器为目标的服务器部署和客户端产物最多可缩小 75 倍
2、更快:基于 nitro 提供动态代码分割能力,以优化冷启动性能
3、Hybrid:增量静态生成和其他的高级功能现在都成为可能
4、Suspense:在任意组件和导航前后都可以获取数据
5、Composition API:使用 Composition API 和 Nuxt 3 的 composables 实现真正的代码复用
6、Nuxt CLI:没有任何依赖,帮你轻松搭建项目和集成模块
7、Nuxt Devtools:通过直接在浏览器中查看信息和快速修复实现更快地工作
8、Nuxt Kit:具有 Typescript 和跨版本兼容性的全新模块开发
9、Webpack 5:更快的构建时间和更小的包大小,无需配置
10、Vite:使用 Vite 作为打包工具,体验闪电般快速的 HMR
11、Vue 3:Vue 3 是你下一个 Web 应用程序的坚实基础
12、TypeScript:使用原生 TypeScript 和 ESM 构建,无需额外步骤

Nuxt 3.0 稳定版正式发布,基于 Vue 3 的 Web 框架

四、重要概念

SPA应用:也就是单页应用,这些多是在客户端的应用,不能进行SEO优化(搜索引擎优化)。

SSR应用:在服务端进行渲染,渲染完成后返回给客户端,每个页面有独立的URL,对SEO友好。

约定式路由:不需要配置路由,在根目录pages目录下创建业务页面,即可访问。

约定式配置:如layouts布局、middleware、plugins

五、启动基础项目

https://github.com/nuxt/create-nuxt-app/blob/master/README.md

5.1、创建项目:

创建nuxt3项目:

pnpm dlx nuxi init nuxt-app

npx nuxi init nuxt3-app

5.2、安装依赖

pnpm install --shamefully-hoist

5.3、启动项目

启动成功

六、项目配置、基础使用

6.1、访问pages/index.vue

根目录app.vue,<NuxtWelcome />替换为:<NuxtPage/>

<template><NuxtPage/><!-- <div><NuxtWelcome /></div> -->
</template>

pages/index.vue

<template><div><h1>snow</h1></div>
</template><script setup lang="ts">
</script><style scoped>
</style>

pages/about.vue

<template><div><h1>about</h1></div>
</template><script setup lang="ts">
</script><style scoped>
</style>

这样就可以访问页面了:

6.2、动态路由

6.2.1、目录结构

6.2.2、访问:/user

如果没有pages/user/index页面,只有[id].vue,访问的时候式404页面

6.2.3、访问:/user/1,动态路由,获取动态路由参数

{{$route.params.id}}

6.2.4、访问:/user/1?name=snow,动态路由,获取路由普通参数:

{{$route.query.name}}

6.2.5、通过useRoute()获取路由信息

const route = useRoute()

<template><div><h1>user-id:{{$route.params.id}}</h1><h1>user-name:{{$route.query.name}}</h1></div>
</template><script setup lang="ts">const route = useRoute()console.log(route.params, route.query)
</script><style scoped>
</style>

6.3、路由跳转

经过测试一下几种方式均成功跳转。页面内容均正常展示。

6.3.1、

<NuxtLink to="/user/1">user-id</NuxtLink>

6.3.2、

<a href="/user/2">user-id-2</a>

6.3.3、

<NuxtLink :to="{ path: `/user/${3}`}">user-id-3</NuxtLink>

6.3.4、编程式路由

<script setup lang="ts">function toUser() {navigateTo({path: '/user/4',query: {name: 'snow'}})
}</script>

6.4、加载静态资源

<div><img src="~/assets/nginx.jpg" alt="nginx"><img src="~/public/nginx.jpg" alt="nginx">
</div>

nuxt项目tsconfig.json有配置,public目录下的文件可以省略/public目录,我这里测试不可以,后续会再研究

已测试成功,可以省略 “~/public” 目录

6.5、设置页面title,不会在页面展示,只会在页面title部分展示

6.5.1、

<Title>snow-title</Title>

<template><Title>snow-title</Title>
</template><script setup lang="ts">
</script><style scoped>
</style>

如图:

ctrl + u:

6.5.2、使用useHead()方法

useHead({title: 'snow-title-2'
})

设置成功,useHead优先级小于<Title>标签。

6.5.3、同理使用useHead设置页面的TDK信息

<script setup lang="ts">
useHead({title: 'snow-title-2',meta: [{ name: 'description', content: 'snow-desc'},{ name: 'keywords', content: 'snow-kw'}]
})
</script>

6.6、layouts

6.6.1、理解:布局、页面布局、公共布局、基础布局

6.6.2、根目录创建layouts目录,/layouts/default.vue

<template><div>snow-default-layout</div><slot />
</template><script setup lang="ts"></script><style scoped></style>

6.6.3、app.vue

<template><NuxtLayout><NuxtPage/></NuxtLayout><!-- <div><NuxtWelcome /></div> -->
</template>

6.6.4、

6.6.5、某页面不想使用layout:

definePageMeta({layout: false
})

6.6.6、某页面使用指定layout

definePageMeta({layout: 'layout-snow'
})

6.6.7、动态设置layout

const router = useRoute()
function enableLayout () {router.meta.layout = "layout-snow"
}

6.6.8、全局设置,指定layout

<template><NuxtLayout :name="layoutSnow"><NuxtPage/></NuxtLayout><!-- <div><NuxtWelcome /></div> -->
</template>
<script setup lang="ts">
const layoutSnow = ref("layout-snow")
</script>

6.7、plugins

/plugins/index.ts

export default defineNuxtPlugin(()=>{return {provide: {hello: (msg: string) => `hello ${msg}`}}
})

/pages/plugin.vue

<template><div>snow-plugin</div>
</template><script setup lang="ts">
const { $hello } = useNuxtApp()
console.log('9', $hello('world'))
</script><style scoped>
</style>

6.8、middleware

/middleware/auth.ts

export default defineNuxtRouteMiddleware((to, from)=>{console.log("auth")
})

/middleware/snow.ts

export default defineNuxtRouteMiddleware((to, from)=>{console.log("snow")
})

/pages/plugin.vue

<template><div>snow-plugin</div>
</template><script setup lang="ts">definePageMeta({middleware: ["auth", "snow"]
})</script><style scoped>
</style>

如图:

6.9、server

6.9.1、目录

6.9.2、server/api/hello.ts

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

6.9.3、server/api/test.get.ts

export default defineEventHandler((event) => {return `test get ts`
})

6.9.4、server/api/test.post.ts

export default defineEventHandler((event) => {return `test post ts`
})

post请求需要使用postman工具:

6.9.5、 server/api/foo/[...].ts

可以带有参数

export default defineEventHandler(() => `default api handle`)

6.9.6、server/api/submit.post.ts

export default defineEventHandler (async (event) => {const body = await readBody(event);return { body }
})

6.9.7、server/api/query.get.ts

export default defineEventHandler((event) => {const query = getQuery(event)return { a: query.param1, b: query.param2 }
})

6.10、使用element-plus

6.10.1、安装

pnpm install element-plus

pnpm add  sass sass-loader -D

pnpm add unplugin-auto-import unplugin-icons unplugin-vue-components -D

6.10.2、package.json

{"private":true,"scripts":{"build":"nuxt build","dev":"nuxt dev","generate":"nuxt generate","preview":"nuxt preview","postinstall":"nuxt prepare"},"devDependencies":{"nuxt":"3.0.0","sass":"1.57.1","sass-loader":"13.2.8","unplugin-auto-import":".12.1","unplugin-icons":".14.15","unplugin-vue-components":".22.12"},"dependencies":{"element-plus":"^2 .2.27"}
}

6.10.3、assets/scss/index.scss

@use "element-plus/dist/index.css";

6.10.4、tsconfig.json

{// https://nuxt.com/docs/guide/concepts/typescript"extends": "./.nuxt/tsconfig.json","compilerOptions": {"types": ["element-plus/global"]}
}

6.10.5、 nuxt.config.ts

import AutoImport from 'unplugin-auto-import/vite'
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import IconsResolver from "unplugin-icons/resolver";
const lifecycle = process.env.npm_lifecycle_event;
export default defineNuxtConfig({vite: {plugins: [AutoImport({resolvers: [ElementPlusResolver(),IconsResolver()]}),Components({dts: true,resolvers: [ElementPlusResolver({importStyle: false})]}),],},components: true,css: ["~/assets/scss/index.scss"],transpile: ["element-plus"],build: {transpile: lifecycle === "build" ? ["element-plus"] : [],},
})

6.10.6、plugins/element-plus.ts

import { ID_INJECTION_KEY } from 'element-plus';export default defineNuxtPlugin(nuxtApp => {// Doing something with nuxtAppnuxtApp.vueApp.provide(ID_INJECTION_KEY,{prefix: Math.floor(Math.random() * 10000),current: 0,})})

6.10.7、pages/index.vue

<el-button> ElButton </el-button>

6.10.8、成功实现效果

6.11、获取数据 | Nuxt 3 - 中文文档

请求数据的方法有:useAsyncData、useLazyAsyncData (useAsyncData+lazy:true)、useFetch、useLazyFetch (useFetch+lazy:true)

pages/req.vue

<template><div class="container"><h1>snow</h1></div>
</template>
<script setup lang="ts">
const token = useCookie("token");
const useFetchData = await useFetch('https://md.abc.com.cn/m-staff-center/api/v1/role/pageList',{method: "get",headers: {'Authorization' : `Bearer ${token.value}`}
})
console.log('17useFetchData', useFetchData.data._rawValue)
const useAsyncDataData = await useAsyncData('getRoleList', () => $fetch('https://md.abc.com.cn/m-staff-center/api/v1/role/pageList', {method: "get",headers: {'Authorization' : `Bearer ${token.value}`}
}))
console.log('24useAsyncDataData', useAsyncDataData.data._rawValue)
</script>

数据获取成功:

注:1,这里使用的全路径接口地址请求的数据,没有因为是本地开发出现跨域问题,同时没有配置代理。2、多次尝试配置代理,使用方法包括vite、nitro,均没有成功,网上暂时也没有找到明确的解答。3、如果后续有了代理相关的进展会及时更新。4、既然本地使用全路径没有跨域问题,那么我考虑在封装请求时候使用全局环境变量来拼接不同环境的域名+接口地址。

6.12、封装请求

6.12.1、utils/request.ts

import { ElMessage } from 'element-plus'const fetch = (url: string, options?: any): Promise<any>  => {const token = useCookie("token");const headers = { // headers信息'Authorization' : `Bearer ${token.value}`}const { public: { baseUrl } } = useRuntimeConfig()const reqUrl = baseUrl + urlreturn new Promise((resolve, reject) => {useFetch(reqUrl, { ...options, headers }).then(({ data }: any) => {const value = data.valueif (!data._rawValue) {// 这里处理错误回调reject(value)}else if(data._rawValue.code !== '0'){ElMessage({message: data._rawValue.msg,type: 'error',})} else {console.log('40data', data._rawValue)resolve(ref(data))}}).catch((err: any) => {reject(err)})})
}export default new class Http {get(url: string, params?: any): Promise<any> {return fetch(url, { method: 'get', params })}post(url: string, params?: any): Promise<any>  {return fetch(url, { method: 'post', params })}put(url: string, body?: any): Promise<any>  {return fetch(url, { method: 'put', body })}delete(url: string, body?: any): Promise<any>  {return fetch(url, { method: 'delete', body })}
}

6.12.2、baseUrl

// 参见本文6.13多环境开发import { loadEnv } from 'vite'runtimeConfig: { // 运行时常量public: { // 客户端-服务的都能访问baseUrl: loadEnv(process.argv[process.argv.length-1], './env').VITE_SERVER_NAME}},  

6.12.3、utils/api.ts

import Http from '@/utils/request'export const config1 = (params: any) => {return Http.get('/m-staff-center/api/v1/pageList', params)
}
export const getVideoList = (params: any) => {return Http.post('/m-staff-center/api/v1/getName', params)
}

6.12.4、使用

config1('').then((res: any) => {console.log('27', res)
}).catch((err: any)=>{console.log('29', err)
})getVideoList('').then((res: any) => {console.log('51', res)
}).catch((err: any)=>{console.log('54', err)
})

经测试,成功。

6.13、多环境开发

生产使用的项目通常会有dev、test、uat、pre、prd等环境,我们需要配置多种开发环境满足企业级开发要求。

6.13.1、根目录创建env目录,创建环境变量文件

文件命名规则 .env.[环境变量名,如dev]

.env.dev文件,其他文件同理

# 请求接口地址
VITE_REQUEST_BASE_URL = '/m-staff-center/api/v1'
VITE_SERVER_NAME = 'https://md.abc.com.cn/'
# VITE开头的变量才会被暴露出去

6.13.2、package.json

  "scripts": {"build": "nuxt build","dev": "nuxt dev --mode dev","test": "nuxt dev --mode test","uat": "nuxt dev --mode uat","pre": "nuxt dev --mode pre","prd": "nuxt dev --mode prd","generate": "nuxt generate","preview": "nuxt preview","postinstall": "nuxt prepare"},

6.13.3、nuxt.config.ts

import { loadEnv } from 'vite'
console.log('基础服务路径', loadEnv(process.argv[process.argv.length-1], './env').VITE_SERVER_NAME)

多环境配置成功,环境变量可以用于本地代理使用,如本地代理使用环境域名,等。

6.14、服务器部署

npm run build

使用“混合渲染模式”创建一个.output目录。
其中包含所有应用程序、服务器和依赖项,可用于生产。
可通过node、pm2等启动后提供WEB服务。

打包成混合渲染程序,常用。

打包生成.output
npm run generate

使用“SPA方式预渲染应用程序”的每个路由(启动server对整个程序代码中涉及的URL进行一次服务端和客户端渲染),将结果存储在纯 HTML 文件中,可以部署在任何静态托管服务上。
该命令触发nuxi build带有prerender:true的参数。

打包成SPA客户端渲染程序,常用。

打包生成dist

build:混合渲染模式,node启动项目(或者使用pm2),nginx做代理转发。

node

node ./.output/server/index.mjs

pm2

pm2 start ecosystem.config.js

// 使用pm2,根目录创建ecosystem.config.js
module.exports = {apps: [{name: 'NuxtAppName',exec_mode: 'cluster',instances: 'max',script: './.output/server/index.mjs',}]}

未测试。

// nginx配置
{listen 80;server_name www.abc.com; // 域名location / {proxy_pass http://127.0.0.1:3000;   // 转发到当前服务器3000端口}
}

已测试,成功。

generate:预渲染模式,生成静态资源,nginx直接启服务。

已测试,成功。

6.15、其他内容

待补充

七、过程记录

7.1、init项目不成功

解1:墙内的同学可能创建不成功,这里推荐一个链接:https://github.com/nuxt/starter

解2:开始使用科学上网的方法也没有下载成功,后来使用了付费科学上网的方法下载成功。下载成功后如图。

7.2、useHead接收参数如下:

useHead(meta: Computable<MetaObject>): voidinterface MetaObject extends Record<string, any> {charset?: stringviewport?: stringmeta?: Array<Record<string, any>>link?: Array<Record<string, any>>style?: Array<Record<string, any>>script?: Array<Record<string, any>>noscript?: Array<Record<string, any>>titleTemplate?: string | ((title: string) => string)title?: stringbodyAttrs?: Record<string, any>htmlAttrs?: Record<string, any>
}
charset: 指定 HTML 的字元编码,预设为 utf-8。
viewport: 设定网页的可见区域,预设为 width=device-width, initial-scale=1。
meta: 接受一个阵列,阵列中的每个元素,都將会建立一个 <meta> 标记,元素中物件的属性将对应至的属性。
link: 接受一个阵列,阵列中的每个元素,都将会建立一个 <link> 标记,元素中物件的属性将对应至的属性。
style: 接受一个阵列,阵列中的每個元素,都将会建立一个 <style> 标记,元素中物件的属性将对应至的属性。
script: 接受一个阵列,阵列中的每個元素,都将会建立一个 <script> 标记,元素中物件的属性将对应至的属性。
noscript: 接受一个阵列,阵列中的每個元素,都将会建立一个 <noscript> 标记,元素中物件的属性将对应至的属性。
titleTemplage: 接受一個字串或函數,用來动态的设定该页面元件的网页标题。
title: 在页面元件设置静态的网页标题。
bodyAttrs: 接受一个物件,设置网页中标识的属性,物件中的属性将对应至的属性。
htmlAttrs: 接受一个物件,设置网页中标识的属性,物件中的属性将对应至的属性。

理解useHead:相当于设置页面<head>标签内相关内容。

7.3、出现类似包不能解析的问题

解决:

根目录创建 .npmrc 文件

shamefully-hoist = true

删除node_modules,再次执行pnpm install ,解决成功

有些包仅在根目录的node_modules时才有效,可以通过此配置,提升那些不在node_modules根目录的包。

或者执行:

pnpm i --shamefully-hoist

两种方法均测试成功。

7.4、publicPath (nuxt2.X)  等同于  baseURL (nuxt3.0)

Nuxt Configuration Reference · Nuxt

7.4.1、nuxt2.x,nuxt.config.js

build: {publicPath: process.env.PUBLIC_PATH,
}

7.4.2、nuxt3,nuxt.config.ts

app: {baseURL: '/m-abc-pc',
}

7.4.3、使用场景

使用这一项配置的时候请求资源的地址就会有这个目录,如下图,在服务区部署时候很重要。

7.5、开发环境修改端口

7.6、设置网站 favicon

7.6.1、favicon.ico 文件放在public目录下。

7.6.2、nuxt.config.ts  app/head/link下增加相应内容

link: [{ rel: "icon", href: "/favicon.ico", type: 'image/x-icon'},
],

经过测试,成功。

八、欢迎交流指正,关注我,一起学习。

参考链接:

Configuration | ⚗️ Nitro

[Day 24] Nuxt 3 搜尋引擎最佳化 (SEO) 與 HTML Meta Tag - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天

Nuxt3-动态更改meta信息(关键词、标题、描述)_fat_shady的博客-CSDN博客

令人愉快的 Nuxt3 教程 (一): 应用的创建与配置 - 知乎

技术胖-Nuxt3从零到实战手把手 免费视频图文教程

Nuxt.js 3.0 正式发布! - 知乎

nuxt3:我们开始吧-开发-配置-部署相关推荐

  1. 基础、数据、开发、部署,AI 时代企业的全方位升级

    当"AI+"的趋势无可回避,企业领导者们需要比过往更认真地思考,如何适应全新的AI时代和其所代表的未来发展趋势. 头图来源 | 视觉中国 当AI成为基础设施 眼下,已经没有企业的领 ...

  2. 笔记合并_.NET Core开发实战(第23课:静态文件中间件:前后端分离开发合并部署骚操作)学习笔记(上)...

    23 | 静态文件中间件:前后端分离开发合并部署骚操作 我们先来看一下静态文件中间件有哪些能力 1.支持指定相对路径 2.支持目录的浏览 3.支持设置默认文档 4.支持多目录映射 源码链接: http ...

  3. 告别繁琐提升效率,Docker 帮您降低从开发到部署的复杂性

    出品丨Docker公司(ID:docker-cn) 编译丨小东 每周一.三.五晚6点10分 与您不见不散! 在 Mobelux,开发项目永远不会停止.我们一直在研究新的和现有的代码库.无论何时,都有多 ...

  4. 居然仅用浏览器,就完成了Spring Boot应用的开发与部署!

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 最近有幸试用了一下阿里云的一个新产品:云开发平台,体验一 ...

  5. SQL Server Integration Services 包的开发与部署初探

    说到数据库之间的数据同步,我们经常会结合的SQL Server 2000中的DTS和作业功能来实现按时.按条件的数据传输.但是SQL Server 2005 以后,不再支持SQL Server 200 ...

  6. 以 OSGi 包的形式开发和部署 Web 服务

    简介 OSGi 是一个面向 Java 的动态模块系统.OSGi Alliance(请参见 参考资料)发布了模块系统的规范.一些受欢迎的 OSGi 容器包括 Eclipse Equinox(请参见 参考 ...

  7. 某系统有6台输出设备 有多个进程均需要使用2台_从零开始学K8s: 2.开发与部署方式的演变...

    近年来,应用开发和部署发生了一些变化.这些变化是由两方面促成的,一方面是大型单体应用被拆解为更多小型的微服务,另一方面是应用程序运行所依赖的基础架构发生了变化.理解这些变化,将使我们更好的看到使用k8 ...

  8. 如何基于Restful ABAP Programming模型开发并部署一个支持增删改查的Fiori应用

    Jerry之前的文章30分钟用Restful ABAP Programming模型开发一个支持增删改查的Fiori应用 发布之后,有朋友问我,"没错, 我是在你的文章里看到了Fiori应用的 ...

  9. 前后端分离的项目部署到tomcat_如何在开发时部署和运行前后端分离的JavaWeb项目...

    在开发中大型的JavaEE项目时,前后端分离的框架逐渐成为业界的主流,传统的单机部署前后端在同一个项目中的工程项目越来越少.这类JavaWeb项目的后端通常都采用微服务的架构,后端会被分解为诸多个小项 ...

最新文章

  1. php源码安全加密之PHP混淆算法.
  2. QT报错“qt.network.ssl: QSslSocket: cannot resolve SSLv2_client_method”
  3. 部署Small Business Server 2003服务器之四
  4. python画折线图详解-手把手教你Python yLab的绘制折线图的画法
  5. android的logcat详细用法
  6. selenium打开Firefox、IE、Chrome浏览器【python】
  7. 阿里云和中移物联网M5311的MQTT通讯
  8. MySQL深度剖析之undo log redo log binlog专题(2021)
  9. 基于XML配置方式实现对action的所有方法进行校验
  10. e站app里站hosts_硬核干货区 | E站的国际站运营知识星球上线啦
  11. 前端几个常用简单的开发手册拿走不谢
  12. AOJ-776 马的走法 动态规划
  13. linux内核默认imx6速率配置,Linux4.1.15内核移植-imx6ull
  14. fdisk:Linux 下管理磁盘分区的利器
  15. 使用 BOL API 创建 SAP CRM IBASE 数据
  16. 正则表达式语法及常用实例
  17. 106短信群发如何在移动信息时代下实现精准营销
  18. 一个手机号可以注册绑定5个百度网盘,永久2T
  19. 海思联咏安霸视觉AI SOC横向对比,你心中的王者有没有动摇过。
  20. ef1a启动子_英茂盛业-EF1a启动子双标非融合慢病毒表达载体

热门文章

  1. Somethings about Floors题解
  2. 基克的聚合 机器人_lol机器人出装?lol机器人辅助出装2020
  3. 异常:non-compatible bean definition of same name and class【com.xxx.xxx.XXX】
  4. html段落标签p的简介以及和换行标签br的区别
  5. 安装SVN没有svn.exe
  6. Linux resume流程
  7. (莫寒杂谈)C++开发是青春饭吗?
  8. CocosCreator热更新(v1.10.2)
  9. html制作柱状图,利div+css做的柱状图,代码超级简洁
  10. linux内核memset,linux内核API每天来一发(2)