首页IT科技vuecli多页面应用开发(2023 最新最细 vite+vue3+ts 多页面项目架构,建议收藏备用!)

vuecli多页面应用开发(2023 最新最细 vite+vue3+ts 多页面项目架构,建议收藏备用!)

时间2025-06-20 23:37:21分类IT科技浏览4323
导读:🌻 前言 本文教程 github地址 、码云。 如果对你有帮助,希望能点个star ⭐️⭐️⭐️ 万分感谢😊😊😊...

🌻 前言

本文教程 github地址             、码云            。 如果对你有帮助           ,希望能点个star ⭐️⭐️⭐️ 万分感谢😊😊😊

🧱 背景

不久前我司需要重新部署一个前端项目                  ,由我来负责这个项目的搭建                 。因为这个项目是需要和app混合开发的h5页面      ,包括以后可能会做一些运营h5           ,所以自然不能采用常规的SPA单页面应用架构(因为大部分页面耦合度低                 ,全都塞一个项目里的话      ,即使打开个纯静态页都要跑起来整个项目      ,严重影响页面的加载速度).

另外                 ,我们其实已经有混合开发h5项目            ,采用的gulp工作流      ,即每个页面都是单独的一个html文件      。这种架构的优势很明显                 ,就是体量小            ,结构清晰等,但是它的缺点也非常明显                 ,例如有些轮子无法使用                  ,组件化                 、模块化开发非常不便影响开发效率等      。

目前此项目已在平稳运行,最近有空闲时间记录一下我搭建项目的过程           ,同时也希望能帮助到有这方面需求的掘友😊

💡 思路 **

综合考虑                  ,我决定用vite + vue3 + ts + esint + prettier + stylelint + husky + lint-stage + commitlint 搭建一套多页面项目                 。

1. 初步定了几个目标:

🍀 支持打包指定子页面      ,打包后的文件夹:各页面相互独立(各子页面解耦           ,避免相互影响) 🍀 支持启动指定子页面(常规的多页面项目                 ,启动后需要手动拼接页面地址      ,或者在根目录做一个重定向的页面      ,总之调试非常不便) 🍀 支持指令化新建页面(手动创建页面太麻烦                 ,每次都得复制一份干净的文件夹) 🍀 自由选择创建ts页面 / js页面(对于一些重要的页面可以使用ts提高规范性            ,一些简单的页面则使用js提高开发效率)

2. 本文将从以下几个方面逐步讲解:

项目目录结构 新建项目 安装依赖及一些基础插件 vite配置项修改 ts配置 多页面入口配置 多页面打包配置 指令化新建子页面(*重点) 多页面架构改造(*重点) 完善项目架构

🌈 教程

一      、 项目目录结构

├── README.md ├── .husky //git hook钩子 │ ├── commit-msg //规范 commit message 信息 │ └── verify-commit-msg.mjs //脚本:commitlint 替代方案 ├── dist //打包输出目录 ├── scripts //存放一些脚本 │ ├── template //创建子页面的js模版 │ ├── template-ts //创建子页面的ts模版 │ ├── index.mjs //创建子页面的脚本 │ └── multiPages.json //子页面描述说明集合文件 ├── src │ ├── arrets //公共静态资源 │ ├── components //公共组件 │ ├── store //pinia 共享状态存储库 │ ├── utils //公共方法 │ └── Projects //多页面文件夹 ├── types //ts 声明文件 ├── .env.development //开发环境-环境变量 ├── .env.production //生产环境-环境变量 ├── .eslintrc.cjs //eslint 配置 ├── .gitignore //git 提交忽略文件 ├── .prettierignore //prettier 忽略文件 ├── .prettierrc.js //prettier 配置 ├── .stylelintignore //stylelint 忽略文件 ├── .stylelintrc.js //stylelint 配置 ├── .pnpm-lock.yaml //锁定项目于一份各个依赖稳定的版本信息 ├── .stats.html //chunck size 分析页面 ├── tsconfig.json //ts 配置 ├── tsconfig.node.json //vite在node环境中的 ts 规则 ├── vite.config.ts //vite 配置 ├── package.json

二      、 新建项目

首先我们用命令行新建一个vite项目      ,不要使用模板创建                 ,就创建一个基础模板就行            ,注意创建过程选择 vue3+typescript           。创建命令如下:

# npm 6.x npm create vite\@latest vue3-mpa # npm 7+, extra double-dash is needed: npm create vite\@latest vue3-mpa # yarn yarn create vite vue3-mpa # pnpm pnpm create vite vue3-mpa

三                 、 安装依赖及一些基础插件

新建项目后记得 npm i 安装依赖      。然后我们先装一些基础的插件,例如vue-router等                 ,方便后面调试                  ,这里可能没装全,毕竟是返工           ,有些东西忘记了                  ,大家根据报错提示自行安装即可                  。

//安装vue-router4 npm install vue-router\@next -S //安装 sass npm install sass -D //安装 chalk(chalk是一个颜色的插件           。可以通过chalk.blue(‘hello world’)来改变console打印的颜色) npm install chalk@4.1.2 //处理使用 node 模块代码飘红      ,例如 ‘找不到模块 “path“ 或其相对应的类型声明’ npm install @types/node --save-dev

四           、 vite配置项修改

对vite.config.ts进行调整           ,先做一些基础的配置                 ,后面我们调通项目之后再丰富项目插件。

🍀 配置下启动端口      ,热更新

server: { host: localhost, // 指定服务器主机名 port: 8880, // 指定服务器端口 hmr: true, // 开启热更新 open: true, // 在服务器启动时自动在浏览器中打开应用程序 https: false // 是否开启 https }

🍀 配置文件路径的别名      ,方便书写文件引入路径                  。

resolve: { alias: { @: path.join(__dirname, ./src), @Project: path.join(__dirname, ./src/Project) } }

五      、 ts配置

项目根目录下找到 tsconfig.json 文件                 ,它是是用来配置 TS 编译选项的                 。

这一步可以晚一点配置            ,但是避免后面操作过程中的一些报错      ,可以提前配置好                 ,以下是我使用的配置项            ,基本对每一项都做了解释。 { "compilerOptions": { "target": "esnext", //用于指定 TS 最后编译出来的 ES 版本 "types": ["vite/client"], //要包含的类型声明文件名列表 "useDefineForClassFields": true, //将 class 声明中的字段语义从 [[Set]] 变更到 [[Define]] "module": "esnext", // 设置编译后代码使用的模块化系统:commonjs | UMD | AMD | ES2020 | ESNext | System "moduleResolution": "node", // 模块解析策略,ts默认用node的解析策略                 ,即相对的方式导入 "strict": true, //开启所有的严格检查 "jsx": "preserve", //`.tsx`文件里支持JSX: `"React"``"Preserve"` "sourceMap": false, // 生成目标文件的sourceMap文件 "resolveJsonModule": true, //允许导入扩展名为“.json           ”的模块 "isolatedModules": true, //确保每个文件都可以在不依赖其他导入的情况下安全地进行传输 "esModuleInterop": true, //支持导入 CommonJs 模块 "lib": ["esnext", "dom", "ES2015"], //TS需要引用的库                  ,即声明文件,es5 默认引用dom                  、es5           、scripthost,如需要使用es的高级版本特性           ,通常都需要配置                  ,如es8的数组新特性需要引入"ES2019.Array", // "noLib": false, //不包含默认的库文件( lib.d.ts) "skipLibCheck": true, //忽略所有的声明文件( *.d.ts)的类型检查 "allowJs": true, // 允许编译器编译JS      ,JSX文件 "noEmit": true, // 不输出文件,即编译后不会生成任何js文件 "allowSyntheticDefaultImports": true, //允许从没有设置默认导出的模块中默认导入            。这并不影响代码的输出           ,仅为了类型检查                 。默认值:module === "system" 或设置了 --esModuleInterop 且 module 不为 es2015 / esnext "baseUrl": "./", 解析非相对模块的基地址                 ,默认是当前目录 "paths": { "@/*": ["src/*"], //解决引入报错 找不到模块“@/xxxx                  ” 或其相应的类型声明 "@Project": ["src/Project/*"] } }, "include": [ "scripts/**/*.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "scripts/index.mts", "scripts/template-ts/router/routes.ts", "scripts/template-ts/router/index.ts", "scripts/template-ts/main.ts", "src/env.d.ts", "src/global.d.ts" ], "exclude": ["vite.config.ts"], "references": [{ "path": "./tsconfig.node.json" }] //每个引用的`path`属性都可以指向到包含`tsconfig.json`文件的目录      ,或者直接指向到配置文件本身(名字是任意的) }

六、 多页面入口配置

vite 和 webpack 配置多页面的方式不同      。vite 使用的是 rollup 的打包方式            。

1. 基本配置

想要将项目改造成多页面项目      ,我们可以自定义底层的 Rollup 打包配置                 ,只需要指定多个 .html 文件作为入口点即可            ,此设置在build.rollupOptions.input 配置项下                 。

首先我们现在 Project 文件夹下新建两个子页面 pageone                  、pagetwo       ,目录结构如下:

然后在 vite.config.ts 文件中指定这两个子页面的入口      。

build: { rollupOptions: { //自定义底层的 Rollup 打包配置 input: { project1: resolve(__dirname, src/Project/pageone/index.html), project2: resolve(__dirname, src/Project/pagetwo/index.html) } } }

这里需要注意的是: __dirname 占位符指的是 vite.config.js 文件所在的目录                 ,即使修改了项目的根目录            ,它的值也不会变(后面我们将会修改项目的根目录)      。

2. 动态生成多页面入口

因为我们要不断新建子页面,不可能每个子页面都手动去配置入口                 ,所以可以获取到/Progect文件夹下文件名后                  ,动态配置多页面入口                 。

fs 模块是 Node.js 官方提供的                 、用来操作文件的模块           。它提供了一系列的方法和属性,用来满足用户对文件的操作需求           ,这里我们用到了fs.readdirSync 方法      。

fs.readdirSync 方法同步返回一个包含“指定目录下所有文件的名称      ”的数组对象                  。 import fs from "fs"; function getEntryPath () { const map = {} //最后生成的多页面配置项 const PAGE_PATH = path.resolve(\__dirname, ./src/Project) //指定要查询的目录 const entryFiles = fs.readdirSync(PAGE_PATH) //获取到指定目录下的所有文件名 entryFiles.forEach(filePath => { //遍历处理每个子页面的入口 map[filePath] = path.resolve(__dirname, `src/Project/${filePath}/index.html` ) }) return map } // 自定义底层的 Rollup 打包配置 rollupOptions: { input: getEntryPath() }

3. 配置重定向页面

配置完多页面入口后                  ,我们可以启动项目看看效果           。npm run dev 启动项目:

你会发现什么都没有      ,因为此时项目跟路径还是‘/’           ,找不到可以作为入口的index.html文件                 ,这时我们只能手动拼接上地址/src/Project/pageone/      ,进入子项目的 index.html 文件

每次启动项目的时候都手动拼接地址未免也太麻烦了      ,太沙壁了😅。ok                 ,那我们在项目根目录下写一个重定向的页面            ,专门用来启动项目后跳转到指定的子项目      ,代码如下:

注意: 到目前为止我们没有修改过项目根目录                 ,仍然在 vite.config.ts 文件同级文件夹下                  。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>重定向</title> </head> <body> <p><a href="./src/Project/pageone/index.html">子页面1</a></p> <p><a href="./src/Project/pagetwo/index.html">子页面2</a></p> <script> </script> </body> </html>

七、 多页面打包配置

build 选项指定多个入口之后            ,就可以进行多页面打包了                 。我们执行 npm run build 看看打包生成的 dist 文件夹结构。

你会发现所有静态资源全都打包到了assets文件夹下,我们可以修改 rollupOptions 选项中的 output 选项修改输出文件夹的格式                 ,如下:

build: { rollupOptions: { input: 指定多页面入口, output: { assetFileNames: [ext]/[name]-[hash].[ext], //静态文件输出的文件夹名称 chunkFileNames: js/[name]-[hash].js, //chunk包输出的文件夹名称 entryFileNames: js/[name]-[hash].js, //入口文件输出的文件夹名称 } } },

占位符说明 >>>

[extname] :文件扩展名                  ,包括前面的 . ,例如 .css; [ext] :文件扩展名,不包括前面的 . ,例如 css; [name] :文件名; [hash] :基于文件内容生成的哈希值           ,可以通过[hash:10]设置特定的哈希长度;

八            、 指令化新建子页面(重点来了~)

到这里其实已经改造出来了一个多页面项目脚手架            。但是离我们都目标还相差甚远:

☘️ 不能指令化创建页面 ☘️ 不能单独启动指定的子项目 ☘️ 打包后所有子项目的静态文件都混淆在一起

那么怎么解决这些问题呢? 我们逐个剖析:

先来解决指令化新建页面的问题                  ,既然要创建页面      ,就是要和文件打交道           ,所以我们还是要使用到 fs 文件系统模块                 。先来了解它的一下几个方法                 ,我们之后会用到(这里只是大概对方法简单说明      ,具体使用自行查询):

🔥 fs.mkdirSync( path, options ) 方法用于同步创建目录      ,创建子页面主要就是使用这个方法      。

🔥 fs.readFile( filename, encoding, callback_function ) 方法用于异步读取指定文件中的内容            。

🔥 fs.writeFile( file, data, options, callback ) 方法用于异步读取指定文件中的内容                 。

🔥 fs.existsSync( path ) 方法用于同步检测目录是否存在;

🔥 fs.readdirSync( path, options ) 方法用于同步读取给定目录的内容      。该方法返回一个数组                 ,其中包含目录中的所有文件名或对象      。

🔥 fs.copyFileSync( src, dest, mode ) 方法用于将文件从源路径同步复制到目标路径                 。

了解这些以后            ,我们捋一下创建文件的步骤:

package.json 文件中添加以下指令      ,以执行创建子页面的脚本; "scripts": { ... "new:page": "node ./scripts/index.mjs" } 然后开发写创建子页面的脚本                 ,第一步要先提示用户输入要创建的页面名称和描述            ,并验证输入的格式; //./scripts/index.mjs const log = (message) => console.log(chalk.green(`${message}`)) const successLog = (message) => console.log(chalk.blue(`${message}`)) const errorLog = (error) => console.log(chalk.red(`${error}`)) log(请输入要生成的"页面名称:页面描述"                 、会生成在 /src/Project 目录下) 使用 fs.existsSync 方法验证是否已存在同名页面; //process.stdin属性是流程模块的内置应用程序编程接口,用于侦听用户输入                 ,它使用on()函数来监听事件           。 process.stdin.on(data, async (chunk) => { // 获取输入的信息 const content = String(chunk).trim().toString() const inputSearch = content.search(:) if (inputSearch == -1) { errorLog(格式错误                  ,请重新输入) return } // 拆分用户输入的名称和描述 const inputName = content.split(:)[0] const inputDesc = content.split(:)[1] || inputName const isTs = process.env.npm_config_ts successLog(`将在 /src/Project 目录下创建 ${inputName} 文件夹`) const targetPath = resolve(./src/Project, inputName) // 判断同名文件夹是否存在 const pageExists = fs.existsSync(targetPath) if (pageExists) { errorLog(页面已经存在,请重新输入) return } }) 在同级 script 文件夹下           ,新建 multiPages.json 用于记录目前已有的页面名称                  ,每次新建页面都会写入进去; // 获取multiPages.json文件内容      ,获取当前已有的页面集合 await fs.readFile( path.resolve(./scripts, multiPages.json), utf-8, (err, data) => { //获取老数据 let datas = JSON.parse(data) //和老数据去重 let index = datas.findIndex((ele) => { return ele.chunk == inputName }) if (index == -1) { //写入新页面的 let obj = { chunk: inputName, chunkName: inputDesc } datas.push(obj) setFile(datas) } } ) // 写入multiPages.json function setFile(datas) { // 通过writeFile改变数据内容 fs.writeFile( path.resolve(./scripts, multiPages.json), JSON.stringify(datas), utf-8, (err) => { if (err) throw err // 在project中建立新的目录 fs.mkdirSync(targetPath) const sourcePath = resolve( isTs ? ./scripts/template-ts : ./scripts/template ) copyFile(sourcePath, targetPath) process.stdin.emit(end) } ) } ... process.stdin.on(end, () => { console.log(exit) process.exit() }) 将新页面的信息写入 multiPages.json 文件后           ,在 Project 文件夹下复制我们提前创建好的模板页面      。我这里创建了两个模版页面                 ,分别是js和ts的模版      ,如果需要创建支持 TS 的子页面      ,创建命令为 npm run new:page --ts // 判断文件夹是否存在                 ,不存在创建一个 const isExist = (path) => { if (!fs.existsSync(path)) { fs.mkdirSync(path) } } //递归复制模版文件夹内的文件 const copyFile = (sourcePath, targetPath) => { const sourceFile = fs.readdirSync(sourcePath, { withFileTypes: true }) sourceFile.forEach((file) => { const newSourcePath = path.resolve(sourcePath, file.name) const newTargetPath = path.resolve(targetPath, file.name) //isDirectory() 判断这个文件是否是文件夹            ,是就继续递归复制其内容 if (file.isDirectory()) { isExist(newTargetPath) copyFile(newSourcePath, newTargetPath) } else { fs.copyFileSync(newSourcePath, newTargetPath) } }) }

九      、 多页面架构改造

到这里可以做如下思考:

🤔 如何支持单独启动指定的子页面?

指定子页面可以在执行 npm run dev 命令时配置自定义环境变量                  。格式为 npm run dev --变量名=值       ,例如我要单独启动 pageone 子页面: npm run dev --page=pageone           。关于npm环境变量

的使用可以查看传送门

如何启动后直接进入这个子页面呢?这时候我们就需要修改项目的根路径了:

注意:将根路径修改到指定子页面目录下后                 ,就只能单独启动/打包 指定的子页面了            ,无法打包全部的子页面。这么做有以下优缺点: 优点:打包后的子页面相互独立,可以直接启动指定的子页面; 缺点:无法一次性打包全部页面                 ,需要配置重定向页面方便调试

所以你可以根据需要决定是否要修改项目根目录                  ,因为我考虑到页面是逐步新增的,需要一次性打包全部页面的情况很少           ,而且我认为打包后的子页面相互独立非常重要                  ,避免出现一些意料之外的问题影响多个页面      ,所以我果断选择了每次都单独打包页面                  。

这里我把两种情况的处理都列出来:

情况1:支持单页面打包和打包全部页面

处理方式:

多页面入口配置\

使用说明: npm run build打包全部页面; npm run build --page=页面名称 打包单页面;

//vite.config.ts // 引入多页面配置文件 const project = require(./scripts/multiPages.json) // 获取npm run dev后缀 配置的环境变量 const npm_config_page:string = process.env.npm_config_page || let filterProjects = [] if (npm_config_page) { //如果指定了单页面打包           ,过滤出这个页面的配置项 filterProjects = project.filter((ele) => { return ele.chunk.toLowerCase() === npm_config_page.toLowerCase() }) console.log(`--------单独构建:${filterProjects[0][chunkName]}--------`) } else { filterProjects = project } //多页面入口 const getEnterPages = (p) => { const pages = {} p.forEach((ele) => { const htmlUrl = path.resolve( __dirname, `src/Project/${ele.chunk}/index.html` ) pages[ele.chunk] = htmlUrl }) return pages } //入口配置 build: { rollupOptions: { input: getEnterPages(), ...

项目根路径修改为 root: ./src/Project/                  ,不修改其实也能实现      ,但是不改的话打包后dist文件夹层级太深;

修改打包的输出路径为:

build: { outDir: path.resolve(__dirname, `dist`), // 指定输出路径 ...

打包后的dist目录结构:

4. 修改 `envDir` 配置项      ,修改到项目根的路径                 ,用于加载`.env` 环境变量文件

envDir: path.resolve(__dirname) 在自定义的 root 根路径下(这里是 src/Project 文件夹下)创建重定向页面            ,方便启动后调试                 。

情况2:只支持单页面打包

多页面入口配置\

使用说明: npm run build --page=页面名称 单独打包指定页面。

//vite.config.ts import chalk from chalk // 引入多页面配置文件 const project = require(./scripts/multiPages.json) // 获取npm run dev后缀 配置的环境变量 const npm_config_page:string = process.env.npm_config_page || // 命令行报错提示 const errorLog = (error) => console.log(chalk.red(`${error}`)) //获取指定的单页面入口 const getEnterPages = () => { if (!npm_config_page) errorLog(-------------------请在命令行后以 `--page=页面名称` 格式指定页面名称!-------------------) const filterArr = project.filter(item => item.chunk.toLowerCase() == npm_config_page.toLowerCase()) if (!filterArr.length) errorLog(-------------------不存在此页面      ,请检查页面名称!-------------------) return { [npm_config_page] : path.resolve( __dirname, `src/Project/${npm_config_page}/index.html` ) } } //入口配置 build: { rollupOptions: { input: getEnterPages(), ... 项目根路径修改到用户输入的单页面文件夹下 root: path.resolve(__dirname, `./src/Project/${npm_config_page}`) 修改打包的输出路径为: build: { outDir: path.resolve(__dirname, `dist/${ npm_config_page }`) // 指定输出路径 ...

打包后的dist目录结构:

修改 envDir 配置项                 ,修改到项目根的路径            ,用于加载.env 环境变量文件 envDir: path.resolve(__dirname)

到这里,多页面架构已经基本改造完成了🎉🎉🎉

🤔 再做一些打包的优化:

build: { sourcemap: false, // 这个生产环境一定要关闭                 ,不然打包的产物会很大 assetsInlineLimit: 4096, //小于此阈值的导入或引用资源将内联为 base64 编码                  ,以避免额外的 http 请求 emptyOutDir: true, //Vite 会在构建时清空该目录 rollupOptions: { input: ... output: { ... compact: true, //压缩代码,删除换行符等 manualChunks: (id: string) => { //配置分包 if(id.includes("node_modules")) { return id.toString().split(node_modules/)[1].split(/)[0].toString(); // 拆分多个vendors } } } } ...

十            、 完善项目架构

1. pnpm 替代 npm 管理依赖包

pnpm 是一款磁盘空间高效的软件包管理器            。

如果你还在用 npm 管理依赖包           ,我建议你不妨试试pnpm                  ,因为他是真的香      ,速度杠杠的😆

详细介绍这里就不做展开了           ,官网传送门https://pnpm.io/zh/motivation //全局安装 pnpm npm install -g pnpm //切换淘宝源 pnpm config set registry https://registry.npmmirror.com/ //删除node_modules文件夹                 ,执行 pnpm i

2. 引入eslint + stylelint + prettier 规范代码风格和质量

eslint 是代码检查工具(lint工具)      ,我们用它来避免低级错误和统一代码的风格      ,以保证代码质量;

stylelint 为css的lint工具                 。可格式化css代码                 ,检查css语法错误与不合理的写法            ,指定css书写顺序等;

prettier 是代码格式化工具      ,我们用它来统一代码格式                 ,风格      。

🍀 首先先来安装 eslint            ,依次执行以下命令:

// 安装 eslint pnpm add eslint -D // eslint初始化 pnpm eslint --init

初始化配置项如下:

eslint初始化之后,会生成.eslintrc.cjs配置文件            。刚初始化完的时候你会发现有个 module 报错了                 ,很简单                  ,只要在 env 配置项下新增选项 "node": true 即可                 。

// --ext 为指定lint哪些后缀的文件 --fix 开启自动修复 "lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx --fix"

此时打开.eslintrc.cjs配置文件会出现一个报错,需要再env字段中增加node: true配置以解决eslint找不到module的报错      。

注意: .eslintrc.cjs 配置文件名需以.cjs结尾           ,如果以 .js 结尾                  ,需要删除package.json 文件中的字段"type": "module"      。prettier 同理      ,因为我们要用到 chalk 插件           ,所以统一采用 .cjs 文件                 。

具体eslint规则根据自己的习惯进行配置                 ,这里也贴下我的粗糙配置:

module.exports = { "env": { "browser": true, "es2021": true, "node": true }, "extends": [ "eslint:recommended", "plugin:vue/vue3-essential", "plugin:@typescript-eslint/recommended" ], "overrides": [ ], "parser": "vue-eslint-parser", "parserOptions": { "ecmaVersion": "latest", "sourceType": "module", "parser": "@typescript-eslint/parser" }, "plugins": [ "vue", "@typescript-eslint", "prettier" ], "rules": { @typescript-eslint/no-var-requires: 0, //解决报错:Require statement not part of import statement. vue/multi-word-component-names: off //关闭组件命名规则娇艳 }, "root": true }

🍀 再来安装stylelint

pnpm add stylelint stylelint-order stylelint-config-standard stylelint-config-prettier -D

依赖说明:

stylelint:检验工具 stylelint-order:css样式书写顺序插件 stylelint-config-standard:stylelint的推荐配置 stylelint-config-prettier:关闭所有不必要的或可能与 Prettier 冲突的规则

创建 .stylelintrc.js 配置文件:

module.exports = { // 注册 stylelint 的 prettier 插件 plugins: [stylelint-prettier], // 继承一系列规则集合 extends: [ stylelint-config-standard-scss, stylelint-config-html/vue, stylelint-config-recommended-vue/scss, stylelint-config-recess-order, // 接入 Prettier 规则 stylelint-config-prettier, stylelint-prettier/recommended ], // 配置 rules rules: { // 开启 Prettier 自动格式化功能 prettier/prettier: true } }

及忽略文件 .stylelintignore

node_modules/* /dist/

最后配置命令

{ "script":{ "lint:stylelint": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/" } }

🍀 最后安装prettier

pnpm add prettier -D

安装好之后在项目根目录创建 .prettierrc.cjs 配置文件      ,这里也贴下我的配置      ,大家自己根据需要调整规则           。

//.prettierrc.cjs module.exports = { printWidth: 80, //一行的字符数                 ,如果超过会进行换行            ,默认为80 singleAttributePerLine: false, //每行强制换行      ,只能使用单个属性 tabWidth: 2, // 一个 tab 代表几个空格数                 ,默认为 2 个 useTabs: false, //是否使用 tab 进行缩进            ,默认为false,表示用空格进行缩减 singleQuote: true, // 字符串是否使用单引号                 ,默认为 false                  ,使用双引号 semi: false, // 行尾是否使用分号,默认为true trailingComma: none, // 是否使用尾逗号 bracketSpacing: true, // 对象大括号直接是否有空格           ,默认为 true                  ,效果:{ a: 1 } endOfLine: auto, jsxBracketSameLine: false // 在jsx中把> 是否单独放一行 }

同时创建 .prettierignore 为Prettier忽略指定文件

.DS_Store node_modules dist dist-ssr **/*.svg **/*.sh

eslint 和 prettier 的配置难免会有冲突      ,目前比较成熟的方案是使用以下两个插件:

eslint-plugin-prettier: 基于 prettier 代码风格的 eslint 规则           ,即eslint使用pretter规则来格式化代码      。

eslint-config-prettier: 禁用所有与格式相关的 eslint 规则                 ,解决 prettier 与 eslint 规则冲突      ,确保将其放在 extends 队列最后      ,这样它将覆盖其他配置

pnpm add eslint-config-prettier eslint-plugin-prettier -D

安装完成后在 .eslintrc.cjs 文件中extends的最后添加一个配置

{

extends: [

‘eslint:recommended’,

‘plugin:vue/vue3-essential’,

‘plugin:@typescript-eslint/recommended’,

// 新增                 ,必须放在最后面

‘plugin:prettier/recommended’

]

}

3. 引入husky + lint-staged + Commitlint 规范 git 工作流程

在团队协作开发时            ,为了避免开发人员代码格式和风格不同导致的冲突      ,我们最好遵循husky+Commitlint+lint-staged git工作流规范                 ,这样在本地提交代码前            ,能够强制让开发人员进行统一的代码规范化处理,避免造成冲突和一些潜在问题                  。

husky 是常见的git hook工具                 ,使用husky可以挂载Git钩子                  ,当我们本地进行git commit或git push等操作前,能够执行其它一些操作           ,比如进行ESLint检查                  ,如果不通过      ,就不允许commit或push           。

pnpm add husky -D # 执行以下命令会生成 .husky 文件 npx husky install // 配合lint-staged使用 npx husky add .husky/pre-commit "npx lint-staged"

Lint-staged 可以在git staged阶段(即git add 后的暂存阶段)的文件上执行Linters           ,简单说就是当我们运行ESlint或Stylelint命令时                 ,可以通过设置指定只检查我们通过git add添加到暂存区的文件      ,可以避免我们每次检查都把整个项目的代码都检查一遍      ,从而提高效率。

pnpm add husky lint-staged -D

在 package.json 文件中配置lint-staged

"lint-staged": { "src/**/*.{js,ts,vue}": [ "pnpm run lint:script", "pnpm run lint:prettierrc", "git add ." ] }

Commitlint 是用来规范git提交代码时 Commit Message 格式的工具                  。结合husky一起使用                 ,可以在开发者进行commit前就对Commit Message进行检查            ,只有符合规范      ,才能够进行commit                 。

安装Commitlint

pnpm add @commitlint/cli @commitlint/config-conventional

Commitlint配合 husky 使用:执行下方命令                 ,会在 .husky 目录下生成 commit-msg 文件。

npx husky add .husky/commit-msg npx --no -- commitlint --edit $1

然后在根目录创建 commitlint.config.js 文件进行配置            。

module.exports = { extends: [@commitlint/config-conventional], rules: { type-case: [2, always, [lower-case, upper-case]], type-enum: [ 2, always, [ feat, //新的特性 fix, //修复Bug docs, //添加或更新文档 style, //代码格式的更改 refactor, //代码进行重构 perf, //提升性能 test, //添加或更新测试用例 chore, //更改配置文件 revert, //版本回退 merge, //分支合并 build, //打包工具的更改 release, //发布/版本标签 ci //对CI配置和脚本的更改 ] ] } }

🌈 脚本替代Commitlint方案

我这里为了在输入 commit msg 时有比较清晰的报错提示            ,所以决定采用脚本代替 Commitlint ,当然                 ,你也可以采用 Commitlint 的 prompt (命令行提示工具)                   ,并在package.json 文件中添加 commit 命令来规范 git 提交操作(但是我认为这么整太麻烦了,降低开发效率)                 。

脚本的思路无非就是定义一个 commit type 的字典集           ,然后比对输入的类型                  ,不符合要求则用node插件boxen(控制台输出盒子)进行规范化提示      。

注意要将 husky 的 commit-msg 钩子修改为我们的脚本地址

//修改husky文件夹下的 commit-msg 文件 #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" node .husky/verify-commit-msg.mjs

在mac上如果报错[hint](https://so.csdn.net/so/search?q=hint&spm=1001.2101.3001.7020): The .husky/pre-commit hook was ignored because its not set as executable.      ,因为指定的文件是不可执行的           ,只需要执行以下命令即可解决:

chmod 777 ./husky/* //安装 boxen插件 pnpm add boxen -D import fs from fs import chalk from chalk //设置chalk等级 解决颜色无效问题 chalk.level = 1 // 引入node控制台输出盒子插件 import boxen from boxen // 挂载boxen console.boxen = (text) => { const options = { margin: { top: 1, bottom: 1 }, padding: { left: 1, right: 1 }, borderColor: yellow, borderStyle: classic, title: Vite-demo } console.log(`\n${boxen(text, options)}`) } const TYPE_MAP = new Map([ [feat, { emoji: , title: feat, description: 新的特性 }], [fix, { emoji: 🐛, title: fix, description: 修复Bug }], [merge, { emoji: 🔀, title: merge, description: 分支合并 }], [style, { emoji: 🎨, title: style, description: 代码格式的更改 }], [perf, { emoji: 🚀, title: perf, description: 提升性能 }], [test, { emoji: , title: test, description: 添加或更新测试用例 }], [revert, { emoji: ⏪️, title: revert, description: 版本回退 }], [build, { emoji: 📦, title: build, description: 打包工具的更改 }], [chore, { emoji: 🔧, title: chore, description: 更改配置文件 }], [ci, { emoji: 👷, title: ci, description: 对CI配置和脚本的更改 }], [refactor, { emoji: 💻, title: refactor, description: 代码进行重构 }], [docs, { emoji: 📝, title: docs, description: 添加或更新文档 }], [release, { emoji: 🔖, title: release, description: 发布/版本标签 }] ]) // commit regexp const commitRE = new RegExp( `^(${[...TYPE_MAP.values()] .map(({ title, emoji }) => `${title}|${emoji}${title}`) .join(|)})(\\(.+\\))?: .{1,100}` ) try { const msgPath = process.argv.slice(2, 3)[0] const msg = fs.readFileSync(msgPath, utf-8).replace(/\n#.*/g, ).trim() if (/Merge.+branch \.+\/.test(msg)) { fs.writeFileSync(msgPath, `🔀 ${msg.replace(Merge, merge:)}`) process.exit(0) } if (msg.length > 100) { throw `commit信息内容不得超出100个字符串长度` } if (commitRE.test(msg)) { // 添加emoji for (const [key, { emoji }] of TYPE_MAP) { if (msg.startsWith(key)) { fs.writeFileSync(msgPath, `${emoji}${msg}`) break } } } else { // show error feedback console.log( `${chalk.hex(#fbb957)(✨feat: 新的特性)}\n${chalk.hex(#41ae3c)( 🐛fix: 修复Bug )}\n${chalk.hex(#51c4d3)(🔀merge: 分支合并)}\n${chalk.hex(#813c85)( 🎨style: 代码格式的更改 )}\n${chalk.hex(#ef475d)(🚀perf: 提升性能)}\n${chalk.hex(#40a070)( ✅test: 提升性能添加或更新测试用例 )}\n${chalk.hex(#63bbd0)(⏪️revert: 版本回退)}\n${chalk.hex( #f8df70 )(📦build: 打包工具的更改)}\n${chalk.hex(#158bb8)( 🔧chore: 更改配置文件 )}\n${chalk.hex(#f9d367)(👷ci: 对CI配置和脚本的更改)}\n${chalk.hex( #f86b1d )(💻refactor: 代码进行重构)}\n${chalk.hex(#d2568c)( 📝docs: 添加或更新文档 )}\n${chalk.hex(#f9d367)(🔖release: 发布/版本标签)}` ) console.boxen( `commit信息不符合规范\n正确示例: "feat: 新增xxx功能..."\n正确示例: "feat(moduleName): 新增xxx功能..." ` ) // process quit process.exit(1) } } catch (err) { console.error(err) console.boxen(commit 提交异常) process.exit(1) }

4. 配置 .env 环境变量

因为我们修改了项目的根目录                 ,所以在配置环境变量前      ,一定要记得在 vite.config.ts 中修改 envDIr 到相对于项目根的路径:

envDir: path.resolve(__dirname)

然后就可以在根目录创建 .env.development 和 .env.production 文件来分别定义开发环境和生产环境的环境变量了            。

需要注意的是: 只有以 VITE_ 为前缀的变量才会生效                 。例如我们设置开发环境的接口基础路径:

VITE_BASE_URL = https://api-test.xxx.com/

5. 安装一些插件

unplugin-vue-components 【组件自动按需导入】

这里以 vant 为例      ,如下配置后                 ,就不需要引入vant插件了            ,直接可以使用:

pnpm add vant pnpm add unplugin-vue-components -D //vite.config.ts import Components from unplugin-vue-components/vite //组件自动按需引入 import { VantResolver } from unplugin-vue-components/resolvers; plugins: [ Components({ resolvers: [VantResolver()] }) ] unplugin-auto-import/vite 【自动导入 Composition API】

配置这个插件后      ,就不需要引入例如 ref                 、reactive      、useRouter 等 api 了      。

为了避免这些 api undefined 报错                 ,需要生成 auto-import.d.ts 说明文件            ,注意在项目根路路径生成      。 pnpm add unplugin-auto-import/vite -D import autoImport from unplugin-auto-import/vite //自动导入 Composition API //vite.config.ts plugins: [ autoImport({ imports: [ vue, vue-router, pinia ], dts: path.resolve(__dirname,"types/auto-import.d.ts"), eslintrc: { // 已存在文件设置默认 false,需要更新时再打开                 ,防止每次更新都重新生成 enabled: false, // 生成文件地址和名称 filepath: path.resolve(__dirname,"./.eslintrc-auto-import.json"), globalsPropValue: true, } }) ] rollup-plugin-visualizer 【打包size分析工具】

打包后会在根目录下生成一个 stats.html 文件                  ,用浏览器打开即可查看 chunk size 的结构                 。

pnpm add rollup-plugin-visualizer -D import { visualizer } from rollup-plugin-visualizer //打包size分析工具 //vite.config.ts plugins: [ visualizer() ] vite-plugin-compression 【打包压缩工具 gzip / br 】

打包时使用 gzip 或 brotli 进行压缩资源,以减小打包体积:

pnpm add vite-plugin-compression -D import compression from vite-plugin-compression //gzip/br 压缩 //vite.config.ts plugins: [ // gzip格式 compression({ threshold: 1024 * 500, // 体积大于 threshold 才会被压缩,单位 b ext: .gz, // 压缩文件格式 deleteOriginFile: false // 是否删除源文件 }), // br格式 // compression({ // threshold: 1024 * 500, // 体积大于 threshold 才会被压缩,单位 b // ext: .br, // algorithm: brotliCompress, // deleteOriginFile: false // }) ]

⏰ 写在最后

在搭建的过程中           ,一定要注意因为修改了项目根目录(root)所带来的问题                  ,利用 path.resolve(__dirname, ...) 将路径重置到相对于项目根的位置!

关于如何使用这个多页面脚手架      ,可以看 README.md 文件           。

github地址       、码云      。 如果对你有帮助           ,希望能点个star ⭐️⭐️⭐️ 万分感谢😊😊😊

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
php门户cms(PHPCMS如何添加广告?)