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.cnmodule.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.cnmodule.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>",默认nonetrailingComma: "none",// 在JSX中使用单引号而不是双引号jsxSingleQuote: false,// (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid:省略括号 ,always:不省略括号arrowParens: "avoid",// 如果文件顶部已经有一个 doclock,这个选项将新建一行注释,并打上@format标记。insertPragma: false,// 指定要使用的解析器,不需要写文件开头的 @prettierrequirePragma: 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 && debuggerpure: ["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中一些东西也记录一下,时间拖久了很多细节自己也会忘记。