Nuxt3 -实践指南,你不知道的“黑科技“
一、简介
Nuxt3 是基于 Vite、Vue3 和 Nitro 的 Nuxt 框架的现代重写,具有一流的 Typescript 支持,是两年多研究、社区反馈、创新和实验的结果。为每个人提供了一个愉快的 Vue 全栈开发体验。
优势:
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 构建,无需额外步骤
了解不同渲染模式:
传统服务端渲染
在过去传统开发中,页面渲染任务是由服务端完成的,服务器负责获取数据,拼装页面,客户端仅负责内容显示,使用这种方式的典型技术有 JSP、PHP、ASP.NET 等等。
客户端渲染 - CSR
Vue.js、React 这类框架之所以能解决前面提到的问题,主要是因为采用了前后端分离的开发模式,这种方式的特点是页面是由客户端渲染的,应用在客户端首次获取的是空 HTML 文档,浏览器下载并运行 JS,获取数据之后再创建页面,也就是大家熟悉的单页面应用 - SPA
CSR 适合那些不需要 SEO 或者用户访问频率不高的强交互应用,例如:SaaS 系统、后台管理系统、在线文档等。同时,利用浏览器缓存特性,这些应用也可以避免再次下载资源从而提高性能表现。
全局渲染 - SSR;
当用户请求一个 URL 时,先按照传统模式在服务端渲染完整 HTML 页面给浏览器,这样用户立刻可以获得首屏内容;
与此同时,客户端会加载 JS 代码,使前面加载的静态内容重新变成可交互的 SPA,这样后续的页面切换就不再需要刷新和重新获取页面内容了。
为了保证前端程序员能够使用熟悉的方式编写页面,即“同构开发”,服务端渲染时,Nuxt 实际上是在服务器上执行 Vue,将我们编写的组件渲染为 HTML 并返回客户端。客户端激活时执行的 JS 实际上也是 Vue,它会重新接管文档,恢复数据和状态,使静态页面变得可交互,这一过程称为“注水(hydration)”。
可以看到,SSR 保留 CSR 优点的同时,还给用户提供了快速加载首屏的能力,这同时也解决了 SEO 问题。
但这种方式也并不完美,因为服务器和浏览器环境有差异,它们不能给开发者提供相同 API,例如,组件在服务端创建时就没有 mounted 钩子,因为根本没有挂载这一步,这导致不少组件库不能在服务端环境正常使用。
又比如,有时候我们的代码只想在客户端运行,如果不小心在服务端执行了就会报错。这些都给开发带来了复杂度和约束性。同样的,由于页面渲染操作发生在服务端,所以服务器负载增加了,只是由于后续 hydration 操作,这个负载增加量被大幅减少了。最后,大家还应该注意的是,SSR 还额外增加了 node.js / serverless 这样的运行时需求,这实际上也是一笔费用。
静态站点生成 - SSG(Static Site Generate);
Nuxt 项目中 packages.json 文件,里面提供了一个 generate 命令。这个命令的作用是将写好的动态页面基于数据生成为静态网站,这一过程称为静态内容生成 - Static Site Generate,即 SSG。
混合渲染 - hybrid rendering 根据不同路由规则使用不同方式渲染的模式;
Nuxt3 带来一个新的渲染模式,称为混合渲染 - hybrid rendering,顾名思义,这是一种根据不同路由规则使用不同方式渲染的模式。这种方式就可以用来解决前面提出的需求
边缘渲染 - edge-side rendering。
过去,SSR 只能运行在 Node.js 环境,但是 Nuxt3 提供了跨平台支持,能够同时运行在 Node.js、Deno、Workers 等运行时环境。
需要深度优化应用打开和交互速度,例如:实时游戏,交易系统,就可以尝试边缘渲染模式。
几种渲染方式的区别:
- 客户端渲染:开发速度快,节约服务器资源;首屏慢,SEO 不友好;
- 服务端渲染:首屏快,SEO 友好,适应性强;开发约束大,服务器费用高;
- 静态站点生成:首屏极快,SEO 友好,服务器成本低;适应性弱,可维护性差;
- 混合渲染:按需渲染,适应性强,可维护性好;稳定性、可用性不好;
- 边缘渲染:性能好,服务器成本低;稳定性、可用性不好。
演示项目:
SSR 前端技术:Nodejs+Express+Handlebars模板
CSR(单页应用):Vue、React开发的一些项目,管理平台... 、H5等
混合渲染 前端技术:Nuxt3
Lighthouse:性能评测工具,SEO评分等
二、基础知识
1、快速创建项目
Nodejs版本要求:Node.js - v16.10.0 or newer
// 初始化:
npx nuxi init <project-name>
//安装依赖:
yarn install
//运行
yarn dev -o 或者 npm run dev
Nuxt3开发精髓之一是约定式开发,通过约定省去了大部分配置,虽然开发灵活性有所影响,但及大提高代码直观可读性和开发效率。
项目目录:
2、页面创建和约定路由
pages文件夹
项目根目录下app.vue文件中,使用标签,相当于路由出口
代码演示~
pages/index.vue
pages/about.vue 等等
页面中路由跳转:
<NuxtLink to="/">xx页面</NuxtLink>
<li @click="toMy"> 关于我们 </li>
<script setup>
const toMy = () => {
// 第一种写法:
// navigateTo("aboutmy");
// 携带参数写法:编程式路由
navigateTo({
path: "/aboutmy",
query: {
id: 111
},
});
}
</script>
3、动态路由使用
xxx文件夹下,创建[id].vue
参数接受页面中:$route.params.id
js中:
const route = useRoute();
const id = ref(route.params.id);
代码演示~
4、嵌套路由:目录和文件名同名,就制作了嵌套路由
比如:
-| pages/
---| parent/
------| child.vue
---| parent.vue
代码演示~
parent文件下 创建child.vue
//pages下创建 parent页面
<template>
<p>嵌套页面</p>
<!-- 子页面出口 -->
<NuxtPage></NuxtPage>
</template>
// child页面
<template>
<p>child page</p>
</template>
5、布局模板
layouts 下 defalut.vue,有了这个模板后,可以在任何你想要使用的页面中用标签为页面赋予模板中的内容
app.vue是每个页面的出口
代码演示~
// app.vue
<template>
<el-config-provider :locale="zhCn">
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</el-config-provider>
</template>
<script setup>
//中文包
import zhCn from "element-plus/lib/locale/lang/zh-cn";
</script>
// layouts default.vue
<template>
<div>
<HeaderPage></HeaderPage>
<slot />
<FooterPage></FooterPage>
</div>
</template>
6、组件编写
文件夹 components 下编写组件
名称约定、多层级组件的引用
多层级组件就是把一个组件放在一个文件夹里。在实际工作中组件会非常多,所以会把组件分门别类的放置。那这种有层级的组件,我们要如何引用那。比如在 components
文件夹下面,新建一个 test
文件夹,然后在test文件夹下面再创建一个 MyButton.vue
文件。
组件的懒加载:在组件名前面加上Lazy前缀,懒加载组件的目的是在项目打包的时候包更小。简单理解可以理解为只有在组件显示在页面上时才进行加载。
组件,Nuxt 提供了 专门用于仅在客户端渲染组件的组件;
要仅在客户端导入组件,请在仅客户端插件中注册该组件。
<template>
<div>
<ClientOnly>
<!-- 此组件仅在客户端显示 -->
<Comments />
</ClientOnly>
</div>
</template>
代码演示~
页面模块拆分:头部导航、底部导航、主体内容等
7、模块化代码 composable文件夹:
通用的业务逻辑代码,需要模块化管理,这时候就可以试用Composable 这个文件夹来编写。比如我们常用的显示当前时间,这种常用的通用代码,就可以编写成一个单独的代码段,然后在每个页面进行使用
composables 文件夹的引入规则是,只有顶层文件会被引入。
stores.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('userInfo', () => {
const userInfo = ref({
userName: 'zhang',
id: 1,
sex: '男',
})
return {
userInfo,
}
})
//页面中使用
const userInfo = useUserStore().userInfo
console.log("userInfo", userInfo)
8、数据请求:
提供4中数据请求:useAsyncData 、useLazyAsyncData、useFetch、useLazyFetch
首先了解$fetch:服务端渲染,不得不考虑接口的调用时机问题:
首屏渲染,调用发生在服务端;
客户端激活之后,调用发生在客户端。
这导致我们首先需要判断代码执行环境,其次发送请求的 API 可能不同,另外如果在客户端发送请求到其他接口服务器还会存在跨域问题,需要给项目配代理,很复杂是吧!这就是 Nuxt3 为什么替我们封装了 fetch∗∗∗∗,fetch** **,fetch∗∗∗∗,fetch( )方法是nuxt3提供的内置方法,我们直接可以使用。它全局可用,可以智能处理调用时机,还能统一 API,避免配置代理。
const { data } = await $fetch('/api/hello', { query: { name: 'tom' } })
const { result } = await $fetch('/api/post', { method: 'post', body: newPost })
可以看到,fetch的API和fetch是一样的,实际调用的是unjs/ofetch它的用法符合我们之前的编码习惯,返回Promise,然后用户负责处理后续操作。但如果要加上一些其他loading、error等反馈,我们通常要添加额外组件状态来实现,比较繁琐。fetch 的 API 和 fetch 是一样的,实际调用的是 unjs/ofetch它的用法符合我们之前的编码习惯,返回 Promise,然后用户负责处理后续操作。但如果要加上一些其他 loading、error 等反馈,我们通常要添加额外组件状态来实现,比较繁琐。fetch的API和fetch是一样的,实际调用的是unjs/ofetch它的用法符合我们之前的编码习惯,返回Promise,然后用户负责处理后续操作。但如果要加上一些其他loading、error等反馈,我们通常要添加额外组件状态来实现,比较繁琐。fetch API
后来到了 hooks 时代,React 社区出现了诸如 ahooks、swr 等库,通过封装请求,暴露出 data、loading、error 等状态,然后可以在组件内直接使用,非常高效。Nuxt3 也为我们提供了四个接口,通过封装 $fetch,给用户提供响应式数据便于直接使用。
与axios的不同
httpServer.js
创建模拟web服务器
const http = require("http")
let n = 0
// 创建web服务器
const server = http.createServer((req, res) => {
console.log(n++)
res.setHeader('Content-Type', 'text/html;charset=utf-8')
res.end('server')
})
server.listen(8082, () => {
console.log("服务器启动了")
})
//页面中使用axios
// axios.get('http://localhost:8082').then(res => {
// console.log(res)
// })
结果:刷新页面,axios向服务器发送两次请求
a、useFetch 页面、组件或者插件中可以使用useFetch获取任意 URL 资源。useFetch是对useAsyncData和$fetch的封装,只需传入请求的 URL 或者一个请求函数即可,一些选项会自动填入,用起来最简洁,是最推荐的数据获取方式。可以理解为所有的都选择默认配置的useAsyncData 方法
useFetch方法签名:
function useFetch(
url: string | Request | Ref<string | Request> | () => string | Request,
options?: UseFetchOptions<DataT>
): Promise<AsyncData<DataT>>
type AsyncData<DataT> = {
data: Ref<DataT> // 返回数据
pending: Ref<boolean> // 加载状态
refresh: (opts?: { dedupe?: boolean }) => Promise<void> // 刷新数据
execute: () => Promise<void> // 同 refresh,没有去重选项
error: Ref<Error | boolean> // 错误信息
}
使用:
<script setup>
// const posts = await $fetch("/api/posts");
const { data, pending, error, refresh } = await useFetch('getTenArticleList', {
method: 'GET',
baseURL: "http://121.36.81.61:8000/getTenArticleList"
})
datalist.value = toRaw(data.value.data)
console.log("useFetch-data-result", data.value.data)
</script>
//useLazyAsyncData 和useLazyFetch 他们只是把配置选项中的Lazy 设置成了true, 也就是会阻塞页面
//常用lazy,默认是false,设置成true 就是需要数据都返回后,才会显示出来 ,简单说就是会阻塞页面;
//不会阻塞路由导航,这意味着我们需要处理 data 为 null 的情况(或者通过 default 选项给 data 设置一个默认值);
b、 useLazyFetch
该方法等效于useFetch设置了lazy选项为 true,不同之处在于它不会阻塞路由导航,这意味着我们需要处理 data 为 null 的情况(或者通过 default 选项给 data 设置一个默认值)。
网络切换为3G,模拟效果
const { data, pending, error, refresh } = await useLazyFetch('http://121.36.81.61:8000/getTenArticleList')
console.log("useLazyFetch-data-result", data.value.data)
datalist.value = data.value.data
console.log("useLazyAsyncData-data-result", toRaw(data.value.data))
datalist.value = toRaw(data.value.data)
c、useAsyncData 异步获取数据
该方法和 useFetch 相比功能上是相同的,但是更底层,使用方法类似于 ahooks 库中的 useRequest,我们需要提供一个用于缓存去重的 key 和数据请求的处理函数。也就是说,useFetch 相当于:useAsyncData(key, () => $fetch(url))。
useAsyncData签名如下,因此 useAsyncData 有两种用法:一种传 key,一种不传 key,但是即使你不传,Nuxt 也会帮你生成一个,所以该用哪个不用我说了吧!?
function useAsyncData(
handler: (nuxtApp?: NuxtApp) => Promise<DataT>,
options?: AsyncDataOptions<DataT>
): AsyncData<DataT>
function useAsyncData(
key: string,
handler: (nuxtApp?: NuxtApp) => Promise<DataT>,
options?: AsyncDataOptions<DataT>
): Promise<AsyncData<DataT>>
使用:
const { data } = await useAsyncData("getList", () =>
$fetch("http://121.36.81.61:8000/getTenArticleList"),{
pick: ["data"]
}
);
d、useLazyAsyncData
该方法等效于useAsyncData,仅仅设置了lazy选项为true,也就是它不会阻塞路由导航,这意味着我们需要处理 data 为 null 的情况,或者通过 default 选项给 data 设置一个默认值。
刷新数据
有时候页面数据是需要刷新的,比如:翻页、条件过滤、搜索等。
我们可以使用useFetch()等 API 返回的refresh()刷新数据。需要注意,如果请求的 key 参数没有发生变化,我们实际上拿到的还是之前缓存的结果。例如下面代码执行 refresh() 并不会得到最新数据:
const { data, refresh } = useFetch('/api/somedata')
// 数据并没有刷新!
refresh()
而想要获取最新数据,就要在 url 中添加一个参数,并作为函数返回值传给useFetch:
// url需要改为由函数返回
const { data, refresh } = useFetch(() => `/api/somedata?page=${page}`)
// 数据刷新!
page++
refresh()
9、middleware路由中间件:
Nuxt3提供了路由中间件的概念,你可以在整个应用使用它,目的是在导航到某一个页面之前,执行一些代码。最常见的路由守卫就可以用这个实现。
基本格式:
middleware/ auth.js
export default defineNuxtRouteMiddleware((to, from) => {
console.log("要去那个页面:"+to.path)
console.log("来自那个页面:"+from.path)
// 逻辑处理 例如:未登录判断等
const user = useUser();
console.log("useUser", user.value)
// 用户未登录跳转登录页
// if (!user.value) {
// return navigateTo('/login')
// }
})
页面中使用:
<script setup>
definePageMeta({
middleware: ["auth"]
// or middleware: 'auth'
})
</script>
10、内置状态管理方法useState以及Pinia支持
跨组件创建响应性的、对ssr友好的共享状态—— useState
useState 是服务端友好的 ref 替换。它的值在服务端渲染(客户端注水的过程中)将被保留并通过唯一key在组件间共享。
共享状态: 可以利用nuxt的composables自动导入特性,把它们定义在composables目录中,这样他们将成为全局类型安全的状态。
//用户状态信息模块
// useState<T>(key: string, init?: () => T): Ref<T>
//key:唯一键用于去重
//init:提供初始值的函数
composables/useAuth.js
export const useUser = () => useState("user", () => null);
export async function useRefreshUserInfo() {
const token = useCookie("token");
const user = useUser();
// 用户已登录,直接获取用户信息
if (token.value) {
let { data } = await userGetinfo();
if (data.value) {
user.value = data.value.data;
}
}
}
// 页面中使用
const user = useUser();
console.log("user",user)
Pinia支持nuxt.com/modules
//安装:
yarn add @pinia/nuxt
//配置 nuxt.config.js
// nuxt.config.js
export default defineNuxtConfig({
// ... 其他配置
modules: [
// ...
'@pinia/nuxt',
],
})
//使用:
composables文件下创建stores.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('userInfo', () => {
const userInfo = ref({
userName: 'zhang',
id: 1,
sex: '男',
})
return {
userInfo,
}
})
// 页面应用
const userInfo = useUserStore().userInfo
console.log("userInfo",userInfo)
11、插件扩展
Nuxt自动读取 plugins 目录中的文件,并在创建 Vue 应用程序时加载它们。可以在文件名中使用.server或.client后缀来只在服务器端或客户端加载插件。
只有在plugins/目录的顶层的文件(或任何子目录中的索引文件)才会被注册为插件。
传递给插件的唯一参数是 nuxtApp。
import vueQr from "vue-qr/src/packages/vue-qr.vue";
//使用defineNuxtPlugin()注册一个插件:
//唯一的参数是nuxt实例
// export default defineNuxtPlugin(nuxtApp => {
// Doing something with nuxtApp
// })
// 返回一个对象,在里面设置provide key,
export default defineNuxtPlugin(() => {
return {
provide: {
vueqr: vueQr
}
}
})
一个常见应用是给NuxtApp实例提供一些额外的帮助方法,我们可以通过编写一个插件,返回一个对象,在里面设置providekey,比如:
import { defineNuxtPlugin } from '#app'
export default defineNuxtPlugin(() => {
return {
provide: {
hello: () => 'world'
}
}
})
使用这个helper,index.vue:
// 会自动加上$前缀
const { $hello } = useNuxtApp();
console.log($hello())
其他:
其他插件:比如
vue-qr
ant-design-vue
12、环境变量
方法一、 Nuxt CLI在开发模式下以及运行 nuxi build 和 nuxi generate 时内置了 dotenv 支持。
除了任何进程环境变量外,如果您的项目根目录中有一个.env文件,它将在构建、开发和生成时自动加载,并且在 nuxt.config 文件和模块中设置的任何环境变量都将可访问。
如果您想使用不同的文件 - 例如,使用 .env.local 或 .env.prod - 我们可以在使用 nuxi 时传递--dotenv 标志来实现。例如:
npx nuxi dev --dotenv .env.local
在开发模式下更新 .env 文件时,Nuxt 实例会自动重新启动以将新值应用于 process.env。
runtimeConfig API 向应用程序的其余部分公开了诸如环境变量之类的值。默认情况下,这些键只在服务器端可用。runtimeConfig.public 中的键也可以在客户端使用。这些值应该在 nuxt.config 中定义,并且可以使用环境变量重写。我们还可以在 app.config 定义公开变量。二者区别是:
- runtimeConfig:需要在使用环境变量构建后指定的私有或公共令牌。
- app.config:在构建时确定的公共令牌,网站配置,如主题变量,标题和任何不敏感的项目配置。
启动项配置:
"scripts": {
"build": "nuxi build --dotenv .env.production",
"test": "nuxi build --dotenv .env.test",
"dev": "nuxi dev --dotenv .env.development -p 3001",
"generate": "nuxi generate",
"preview": "nuxi preview",
"start": "node .output/server/index.mjs"
},
.env 文件配置:
# api Url
NUXT_PUBLIC_API_BASE_URL = 'https://magiccube-gateway.3weijia.com'
nuxt.config.js 配置:
import { NuxtConfig } from "nuxt/config";
export default defineNuxtConfig({
runtimeConfig: {
public: {
apiBaseUrl: process.env.NUXT_PUBLIC_API_BASE_URL
},
}
});
使用:
const runtimeConfig = useRuntimeConfig();
const { loginUrl, locationOriginUrl } = runtimeConfig.public;
方法二、根目录创建env目录,创建环境变量文件
文件命名规则 .env.[环境变量名,如dev]
env.dev文件,其他文件同理
# 请求接口地址
VITE_REQUEST_BASE_URL = '/m-staff-center/api/v1'
VITE_SERVER_NAME = 'https://md.abc.com.cn/'
# VITE开头的变量才会被暴露出去
// 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"
},
//nuxt.config.js
import { loadEnv } from 'vite'
console.log('基础服务路径', loadEnv(process.argv[process.argv.length-1], './env').VITE_SERVER_NAME)
关于配置的官网文档: Runtime Config
用于持续集成的命令: nuxi build
环境变量文件的说明: .env
配置文件说明: Nuxt Config
13、Nuxt 常用的 Hooks
//1、 useAppConfig:访问项目中的 Nuxt 配置
const appConfig = useAppConfig()
console.log(appConfig)
//2、 useAsyncData 页面、组件和插件中,您可以使用 useAsyncData 来访问异步返回的数据;
const { data, pending, error, refresh } = await useAsyncData(
'mountains',
() => $fetch('https://api.nuxtjs.dev/mountains')
)
//3、useFetch 顾名思义,这就是一个 fetch 请求;
在页面、组件或者插件中可以使用 useFetch 获取任意URL资源。
useFetch是对useAsyncData包装,自动生成key同时推断响应类型,用起来更简单。
const param1 = ref('value1')
const { data, pending, error, refresh } = await useFetch('https://api.nuxtjs.dev/mountains',{
query: { param1, param2: 'value2' }
})
//4、useCookie 在页面、组件和插件中,可以使用 useCookie 一个 SSR 友好的 hooks 来读取和写入 cookie。
//5、useHead Nuxt 提供 useHead 可组合项来添加和自定义 Nuxt 应用程序各个页面的头部属性。
//6、useRoute useRoute 是一个在实际项目开发中使用较多的 hooks,主要返回当前路由的一些数据;并且必须在 setup 函数、插件或路由中间件中调用。
<script setup>
const route = useRoute()
const { data: mountain } = await useFetch(`https://api.nuxtjs.dev/mountains/${route.params.slug}`)
</script>
//7、useRouter useRouter 返回路由器的实例,并且必须在设置函数、插件或路由中间件中调用。
const router = useRouter();
router.back();
router.forward();
router.go();
router.push({ path: "/home" });
router.replace({ hash: "#bio" });
14、配置
使用css/scss/less/stylus
css 的集成有多种方式,有使用原生 css 的,也有使用 less 和 scss 的,也有使用 stylus 的;
为了快速上手,这里我就不一一介绍了,下面主要以 less 为例;
// 安装
pnpm install less less-loader --save-dev
//新建 src/assets/styles 目录添加默认 default.less
$bgColor: rgb(125, 159, 172);
$theme: red;
//在 nuxt.config.js 中添加 less 的配置
vite: {
css: {
preprocessorOptions: {
less: {
additionalData: '@import "@/assets/default.less";',
},
},
},
envDir: "~/env", // 指定env文件夹
}
SEO和Meta配置
// nuxt.config.js
export default defineNuxtConfig({
builder: "vite",
runtimeConfig: {
// 运行时常量
public: {
// 客户端-服务的都能访问
...envData,
},
},
app: {
head: {
titleTemplate: "%s - 官网",
title: "xxx",
charset: "utf-8",
htmlAttrs: {
lang: "zh-cn",
},
bodyAttrs: { class: 'body-class' },
meta: [
{ name: "description", content: "xxx" },
{ name: "keywords", content: "xxx" },
],
script: [
{ src: "https://xxx/jquery.js" }
],
link: [
// { rel:"stylesheet",href:"http://xxx.css" }
],
},
},
modules: ["@element-plus/nuxt"],
vite: {
css: {
preprocessorOptions: {
less: {
additionalData: '@import "@/assets/default.less";',
},
},
},
envDir: "~/env", // 指定env文件夹
},
elementPlus: {
/** Options */
},
imports: {
// Auto-import pinia stores defined in `~/stores`
dirs: ["apis"],
},
// 跨域处理
nitro: {
devProxy: {
"/api": {
target: "http://localhost:3001", // 这里是接口地址
changeOrigin: true,
prependPath: true,
},
},
},
});
部署方式一:使用 pm2
根目录新建 ecosystem.config.js
module.exports = {
apps: [
{
name: 'nuxt3 demo',
port: '8080',
exec_mode: 'cluster',
instances: '3',
script: './.output/server/index.mjs'
}
]
}
三、遇到的问题、解决方法
1、环境变量的问题
最初我是通过 process.env.NODE_ENV 来判断当前环境,然后根据环境来配置不同的变量,然而上线之后遇到了一个问题,测试环境和正式环境的 NODE_ENV 都是 production ,这样就导致了无法区分环境,只能通过手动修改 nuxt.config.ts 文件来切换环境,这样的方式肯定是不行的
2、西瓜视频播放器通过插件形式引入,播放不稳定、出现bug
通过cdn方式加载:
app: {
script: [
{
src: "https://unpkg.byted-static.com/xgplayer/2.31.6/browser/index.js",
},
{
src: "https://unpkg.byted-static.com/xgplayer-hls.js/2.2.2/browser/index.js",
}
],
link: [
// { rel:"stylesheet",href:"http://xxx.css" }
],
},
},
3、渲染第三方插件,服务器渲染与客户端渲染不一致
服务端与客户端渲染的DOM结构不一致;解决办法是在组件最外层加上组件,该组件只是占位且用于仅在客户端渲染
4、nuxt在使用Element 弹框组件,出现默认的白边,如何去掉
先在nuxt.config.js中添加如下配置
export default defineNuxtConfig({
app: {
head: {
bodyAttrs: { class: 'body-class' }
}
}
})
// default.less 中添加css样式
.body-class { width:100%;height: 100%; margin:0; padding: 0;}
四、其他
Nuxt3.x官网nuxt.com/
Nuxt3 issues github.com/nuxt/nuxt/i…
Nuxt3.x中文文档www.nuxt.com.cn/
Nitronitro.unjs.io/
PM2中文网pm2.fenxianglu.cn/
转载自:https://juejin.cn/post/7242623687122354237