nuxt3项目总结
仓库
前言
大半年的时间,项目从秋天到春天,从管理后台到APP再到数据大屏,技术栈从vue3到uniApp再到nuxt3,需求不停的改,注释掉代码都快到项目总体的三分之一。
一、准备-搭建项目架子
1.1 创建一个nuxt项目
nuxt中文文档,项目创建有完整的讲解和命令,复制使用就行。
1.2 项目基础配置
1.2.1 代码规范化配置
代码规范化,提高代码质量,遵循一定的规范可以减少错误和漏洞的出现,提高可读性和可维护性。在本项目的初期,搭建项目架子时,因为经验问题,我没有在项目中配置任何的规范性配置,导致其他同事在后期参与进来开发时,出现许多意料之外的错误。
配置命令:
npm install eslint prettier eslint-plugin-prettier eslint-config-prettier --save-dev
在项目运行的终端运行此命令,添加eslint和prettier包,命令运行完成以后,在项目目录下新建**.eslintrc.js**,.eslintignore,.prettierrc.js,.prettierignore四个文件,完成以后目录结构如下图
.eslintrc.js配置文件内容
// @see: http://eslint.cn
module.exports = {
root: true,
env: {
browser: true,
node: true,
es6: true
},
/* 指定如何解析语法 */
parser: "vue-eslint-parser",
/* 优先级低于 parse 的语法解析配置 */
parserOptions: {
parser: "@typescript-eslint/parser",
ecmaVersion: 2020,
sourceType: "module",
jsxPragma: "React",
ecmaFeatures: {
jsx: true
}
},
/* 继承某些已有的规则 */
extends: [
"@nuxtjs",
"@nuxtjs/eslint-config",
"@nuxtjs/eslint-config-typescript",
"plugin:@typescript-eslint/recommended",
"prettier",
"plugin:prettier/recommended"
],
/*
* "off" 或 0 ==> 关闭规则
* "warn" 或 1 ==> 打开的规则作为警告(不影响代码执行)
* "error" 或 2 ==> 规则作为一个错误(代码不能执行,界面报错)
*/
rules: {
// eslint (http://eslint.cn/docs/rules)
"no-var": "error", // 要求使用 let 或 const 而不是 var
"no-multiple-empty-lines": ["error", { max: 1 }], // 不允许多个空行
"no-use-before-define": "off", // 禁止在 函数/类/变量 定义之前使用它们
"prefer-const": "off", // 此规则旨在标记使用 let 关键字声明但在初始分配后从未重新分配的变量,要求使用 const
"no-irregular-whitespace": "off", // 禁止不规则的空白
// typeScript (https://typescript-eslint.io/rules)
"@typescript-eslint/no-unused-vars": "error", // 禁止定义未使用的变量
"@typescript-eslint/prefer-ts-expect-error": "error", // 禁止使用 @ts-ignore
"@typescript-eslint/no-inferrable-types": "off", // 可以轻松推断的显式类型可能会增加不必要的冗长
"@typescript-eslint/no-namespace": "off", // 禁止使用自定义 TypeScript 模块和命名空间。
"@typescript-eslint/no-explicit-any": "off", // 禁止使用 any 类型
"@typescript-eslint/ban-types": "off", // 禁止使用特定类型
"@typescript-eslint/explicit-function-return-type": "off", // 不允许对初始化为数字、字符串或布尔值的变量或参数进行显式类型声明
"@typescript-eslint/no-var-requires": "off", // 不允许在 import 语句中使用 require 语句
"@typescript-eslint/no-empty-function": "off", // 禁止空函数
"@typescript-eslint/no-use-before-define": "off", // 禁止在变量定义之前使用它们
"@typescript-eslint/ban-ts-comment": "off", // 禁止 @ts-<directive> 使用注释或要求在指令后进行描述
"@typescript-eslint/no-non-null-assertion": "off", // 不允许使用后缀运算符的非空断言(!)
"@typescript-eslint/explicit-module-boundary-types": "off", // 要求导出函数和类的公共类方法的显式返回和参数类型
// vue (https://eslint.vuejs.org/rules)
"vue/no-v-html": "off", // 禁止使用 v-html
"vue/script-setup-uses-vars": "error", // 防止<script setup>使用的变量<template>被标记为未使用,此规则仅在启用该no-unused-vars规则时有效。
"vue/v-slot-style": "error", // 强制执行 v-slot 指令样式
"vue/no-mutating-props": "off", // 不允许组件 prop的改变
"vue/custom-event-name-casing": "off", // 为自定义事件名称强制使用特定大小写
"vue/attributes-order": "off", // vue api使用顺序,强制执行属性顺序
"vue/one-component-per-file": "off", // 强制每个组件都应该在自己的文件中
"vue/html-closing-bracket-newline": "off", // 在标签的右括号之前要求或禁止换行
"vue/max-attributes-per-line": "off", // 强制每行的最大属性数
"vue/multiline-html-element-content-newline": "off", // 在多行元素的内容之前和之后需要换行符
"vue/singleline-html-element-content-newline": "off", // 在单行元素的内容之前和之后需要换行符
"vue/attribute-hyphenation": "off", // 对模板中的自定义组件强制执行属性命名样式
"vue/require-default-prop": "off", // 此规则要求为每个 prop 为必填时,必须提供默认值
"vue/multi-word-component-names": "off" // 要求组件名称始终为 “-” 链接的单词
}
};
.eslintignore配置需要忽略的文件
*.sh
node_modules
*.md
*.woff
*.ttf
.vscode
.idea
dist
html
/public
/docs
.husky
.local
/bin
.eslintrc.js
.prettierrc.js
/src/mock/*
.nuxt/
.prettierrc.js代码规范化配置
// @see: https://www.prettier.cn
module.exports = {
// 超过最大值换行
printWidth: 130,
// 缩进字节数
tabWidth: 2,
// 使用制表符而不是空格缩进行
useTabs: true,
// 结尾不用分号(true有,false没有)
semi: true,
// 使用单引号(true单双引号,false双引号)
singleQuote: false,
// 更改引用对象属性的时间 可选值 "<as-needed|consistent|preserve>"
quoteProps: "as-needed",
// 在对象,数组括号与文字之间加空格 "{ foo: bar }"
bracketSpacing: true,
// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>",默认none
trailingComma: "none",
// 在JSX中使用单引号而不是双引号
jsxSingleQuote: false,
// (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid:省略括号 ,always:不省略括号
arrowParens: "avoid",
// 如果文件顶部已经有一个 doclock,这个选项将新建一行注释,并打上@format标记。
insertPragma: false,
// 指定要使用的解析器,不需要写文件开头的 @prettier
requirePragma: false,
// 默认值。因为使用了一些折行敏感型的渲染器(如GitHub comment)而按照markdown文本样式进行折行
proseWrap: "preserve",
// 在html中空格是否是敏感的 "css" - 遵守 CSS 显示属性的默认值, "strict" - 空格被认为是敏感的 ,"ignore" - 空格被认为是不敏感的
htmlWhitespaceSensitivity: "css",
// 换行符使用 lf 结尾是 可选值 "<auto|lf|crlf|cr>"
endOfLine: "auto",
// 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码
rangeStart: 0,
rangeEnd: Infinity,
// Vue文件脚本和样式标签缩进
vueIndentScriptAndStyle: false
};
.prettierignore 忽略文件
/dist/*
/html/*
.local
/node_modules/**
**/*.svg
**/*.sh
/public/*
配置文件完成以后,在项目的package.json文件中增加下面的配置``
"scripts": {
"lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
"lint:fix": "eslint --fix --ext .js,.vue --ignore-path .gitignore .",
}
项目就能在编写时进行代码规范化检测了,并且还可以使用vscode的一些配置进行自动的代码规范化。
1.2.2 插件配置
在本项目中引用element-Plus UI组件库,Echarts,Pinia状态管理器。
element-Plus
npm install element-plus --save
在项目目录中找到plugins文件夹,在文件夹下新建element-plus.client.ts
文件
import { defineNuxtPlugin } from "#app";
import "element-plus/dist/index.full";
import zhCn from "element-plus/dist/locale/zh-cn.mjs";
import ElementPlus from "element-plus";
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.use(ElementPlus, {
locale: zhCn
});
});
在项目配置文件nuxt.config.ts
css修改成css: ["element-plus/dist/index.css"],
,将element的样式引入到项目中。
Echarts
一个基于 JavaScript 的开源可视化图表库
npm install echarts --save
在项目目录中找到plugins文件夹,在文件夹下新建echarts.ts
文件
import * as echarts from "echarts"; // echarts 按需引入
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.config.globalProperties.$echarts = echarts;
});
在项目配置文件nuxt.config.ts
中vite下面的build要将echarts写入
build: {
transpile: ["echarts"]
}
在本项目中echarts是按需引入,为了减少项目的体积,因此,在查阅文档请查看echarts的按需引入源码。
项目还引入了highcharts,完成一些特殊的图表。highcharts是一个完全的js库,因此不需要使用上面的插件引入,只需要安装好包之后,在页面直接使用进行。
安装命令
npm i highcharts --save
使用示例
import Highcharts from 'highcharts'
import HighchartsMore from 'highcharts/highcharts-more'
HighchartsMore(Highcharts)
Pinia状态管理器
Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。
安装命令
npm install pinia @pinia/nuxt
在项目目录中找到plugins文件夹,在文件夹下新建pinia.ts
文件
// plugins/pinia.ts
import { defineNuxtPlugin } from "#app";
import { createPinia } from "pinia";
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.use(createPinia());
});
简单使用示例
在项目目录下新建文件夹stores
,这个文件夹存放所有的状态变量。在文件夹下新建文件demo.ts
// stores/demo.ts
import { defineStore } from "pinia";
//
export const useExampleCount = defineStore({
id: "pageState",
state: () => ({
Count: 0
}),
actions: {
increment() {
this.Count++;
}
}
});
在需要使用的页面引入使用
import { useExampleCount } from '@/stores/demo';
const pageState = useExampleCount();
使用时pageState.state
代表状态的值,pageState.increment
表示修改值的方法
1.2.3 数据请求
数据获取这一个块,Nuxt 提供了两个组合函数和一个内置库,用于在浏览器或服务器环境中执行数据获取:useFetch、useAsyncData 和 $fetch,点击查看详细教程。不过,在搭建架子时,我没注意到这两个函数,因此我引入axios,同时方便我写请求拦截和相应拦截。
安装命令
npm i axios
安装命令完成以后,在项目目录下找到server
文件夹,在api文件夹下新建request.ts
文件
// 我们使用的是vue封装好的异步,所以需要引入axios
import axios from "axios";
// 引入element-plus 是为了请求失败时调用element-plus的弹框组件
import { ElMessage } from "element-plus";
// 创建axios实例
const service = axios.create({
// 设置基础访问路径,看自己需要修改
baseURL: "http://192.168.2.217", // 测试服务器地址
timeout: 15000 // 请求超时时间
});
// http request 拦截器
service.interceptors.request.use(
config => {
// 这里可以处理 token ,需要根据需要进行处理,我这里先不处理,
return config;
},
// 抛出错误,阻止程序运行
err => {
return Promise.reject(err);
}
);
// http response 拦截器
service.interceptors.response.use(
response => {
// 判断请求是否正常
if (response.data.code !== "000000") {
// 出现错误,使用element-plus的弹窗组件,提示错误信息
ElMessage({
showClose: true,
message: response.data.message,
type: "error"
});
return Promise.reject(response.data);
} else {
// 成功返回数据
return response.data;
}
},
// 抛出错误
error => {
return Promise.reject(error.response);
}
);
// 导出service
export default service;
在同级目录中,新建api.ts
用来存放请求API
/ 这里引入我们封装的axios,看你自己的路径
import request from "@/server/api/request";
// const api_name = '/api/member/'
export default {
/**
* 示例
* @param params
* @returns
*/
getdemo(params: any) {
return request({
url: ``,
method: "post",
data: params
});
}
};
至此,项目的基础配置和一些必要的配置已经完成。
二,一些问题的记录
2.1 build
在我完成,最初一版需求编写完成以后,我觉得一切都很顺利,不过当我build的时候,项目一直报错,说找不到相应的项目文件,但当我检查对应文件时,并没有任何的问题。随后,便是查资料,定位问题最后发现项目的父级目录是中文名导致一直找不到文件,在更换项目父级目录名之后,成功build。
2.2 部署
由于公司此前并没有这样的SSR项目,以前的web项目都是由后端的同事通过nginx部署的。我只能自己使用pm2部署,由于此前服务器上的node环境是12,我又去更改node版本,修改环境变量,编写执行脚本,最终才将项目部署完成。
但是不太明白的时,每次重新登录服务器之后都要source /etc/profile
重启配置文件,才能将node版本切回16,否则它就是12.
2.3 打包时清除打印日志与debug
起初,我并没有关注这个问题,但在项目中大量使用WebSocke来达到实时通信传递数据的要求。打包时,没有清除掉这些打印日志,导致项目在正式环境运行到半个小时以后网页直接崩溃。
后来,就着手解决这个问题,但在查了许多插件以后,都是支持vue3但不支持nuxt3,最后翻看公司以前的项目时,才找vite自带了这个能力,刚好nuxt3也使用vite,在nuxt配置文件中修改以后,打印时成功消除了注释。
vite: {
css: {
preprocessorOptions: {
scss: {
additionalData: '@use "@/assets/styles/default.scss" as *;' // 注意文件路径要配成自己的
}
}
},
plugins: [],
esbuild: {
// * 打包去除 console.log && debugger
pure: ["console.log", "debugger"]
}
},
2.4 keep alive页面保活
查看nuxt的官网,就只有一句简单的介绍
老实说,真的没太明白要怎么用,后来又找了不少资料,才明白它这个keepalive是在app.vue中来配置的
<template>
<div>
<NuxtPage keepalive />
</div>
</template>
<script setup>
definePageMeta({
key: route => route.slug,
transition: {
name: "page"
},
keepalive: {
exclude: ["index"] // 需要缓存的页面
}
});
</script>
2.5 全局自动适配
一开始时,也是尝试了不少方法,来满足项目在适合尺寸的屏幕上的适配。后来找到一些资料可以通过调整document的zoom属性来全局适配。到这里,项目已经能够完美的适配大屏了,我觉得这部分代码应该不会再改了。但我还是低估人的创造能力,突然,有一天客户拿着pad加载项目,问我为什么不适配。我顿时就麻了,有人拿移动设备来看数据大屏,这谁能想到,但是没办法接着改吧。
// 全局根据屏幕的变化进行适配 在app.vue中
onMounted(() => {
if (typeof window !== "undefined") {
const percentageOn1 = (window.screen.width / 1920) * 100;
document.body.style.zoom = percentageOn1 + "%";
}
if (window.screen.width > window.screen.height) {
const percentageOn1 = (window.screen.width / 1920) * 100;
document.body.style.zoom = percentageOn1 + "%";
}
else {
const percentageOn1 = (window.screen.height / 1920) * 100;
document.body.style.zoom = percentageOn1 + "%";
}
});
写在最后
最近时间不忙的话,会尽快将app中一些东西也记录一下,时间拖久了很多细节自己也会忘记。