vite + vue3 多页面实战优化续集:eslint+lint-staged+husky+stylelint

目的:项目投入使用发现很多使用起来不舒服的地方,进行优化

注意!!!:最新的一次创建项目运行时候以及配置eslint部分出现了许多问题,可以结合最新的一篇vite+vue+ssg做官网 再记录一下项目创建结合起来查看是否有你遇到的问题

前提:在上一篇vite + vue3多页面配置记录references,loadEnv等中我详细记录了通过各种配置了解多页面项目。
结果:最终代码放到gitee这里的release分支vite-vue3-multip-release

之前配置不合理的地方:

  1. 为了让项目启动的时候自动打开html,修改了项目根目录到views下面root:'./src/views/',以至于outDir,windicss也要改。
  2. 所有生成的html全部扎堆生成在views下面,结构混乱
  3. 未配置eslint,保存自动格式化
  4. 未配置代码提交自动跑eslint检测。使用lint-staged + husky
  5. 未配置stylelint,规范css书写
  6. 未配置快速生成页面脚本:用plop搞个模版生成index.vue和main.ts,可以直接看代码库代码
上一版本文件结构.png

项目到实践中肯定是不合理的,用起来不舒服。逐步解决上面的问题

第一步:不修改根目录路径;在根目录新建一个html文件夹,并将生成的html放到根目录统一管理,且要支持多级页面

目录结构.png

通过上图目录结构可以看到,src/views下面有多级页面,最后生成到src同级目录下的html文件夹中,且结构与之对应。这样看起来就很舒服,html文件夹中的东西根本不用动,通过脚本,每次dev的时候自动生成

我们看代码实现,主要还是去修改build/getPage.ts, 利用mkdirp生成多级文件夹

import glob from 'glob'
import fs from 'fs'
import mkdirp from 'mkdirp'
import { resolve } from 'path'

const input = {}
const mainEntry = []
const iconDirs = []
function getPages () {
  // 遍历文件夹中含有main.ts的文件夹路径
  const allEntry = glob.sync('./src/views/**/main.ts')
  // console.log(allEntry)

  // console.log('allEntry', allEntry)
  // 创建多页面模板
  allEntry.forEach((entry: string) => {
    const pathArr = entry.split('/')
    const tsName = pathArr[pathArr.length - 2]
    pathArr.pop()
    const targetFilePath = pathArr.splice(3).join('/')
    // 创建多级文件夹,去掉最后一个
    const mkdirPath = targetFilePath.replace(`/${tsName}`, '')
    const srcArr = entry.replace('./', '')
    // console.log(targetFilePath, mkdirPath)
    // 判断文件是否存在
    try {
      fs.accessSync(`./html/${targetFilePath}.html`)
    } catch (err) {
      if (targetFilePath.includes('/')) {
        mkdirp(`./html/${mkdirPath}`).then(() => {
          generete(targetFilePath, srcArr)
        })
      } else {
        generete(targetFilePath, srcArr)
      }
    }

    const svgPath = srcArr.split('/')
    svgPath.splice(svgPath.length - 1, 1)
    // input中的配置
    input[targetFilePath] = resolve(`html/${targetFilePath}.html`)
   // vconsole用
    mainEntry.push(resolve(`${srcArr}`))
    iconDirs.push(resolve(process.cwd(), `${svgPath.join('/')}/svg`))
  })
};

function generete (targetFilePath, srcArr) {
  // 获取模板
  const temp = fs.readFileSync('./index.html')
// 多级相对路径
  let relativeStr = ''
  targetFilePath.split('/').forEach(() => {
    relativeStr += '../'
  })
  console.log(`创建${targetFilePath}.html文件`)
  const index = temp.toString().indexOf('</body>')
  const content =
    temp.toString().slice(0, index) +
    `<script type="module" src="${relativeStr}${srcArr}"></script>` +
    temp.toString().slice(index)
  fs.writeFile(`./html/${targetFilePath}.html`, content, err => {
    if (err) console.log(err)
  })
}
getPages()
// console.log(input, mainEntry, iconDirs)
export { input, mainEntry, iconDirs }


有了以上代码。每次运行都会根据入口main.ts,生成对应的html。但是启动项目怎么直接打开我想要的index.html呢?

server里面有配置,配置open即可。想到当时仅仅为了启动项目打开入口页面就更改root是多么的不理智了

// vite.config.ts
 server: {
      open: '/html/index.html',
      proxy: {
        '/api': {
          target: 'https://app-api-0.com',
          changeOrigin: true
        }
      }
    },

第二步:配置eslint

这个就比较简单了,网上也有很多教程,当走到教程前面几步就可以了。我这里也记录一下

  1. 安装eslint npm i eslint -D
  2. 初始化配置:npx eslint --init
    然后根据提示一步步操作
    2.1 选择模式: (To check syntax and find problems)
    我选第三个:To check syntax, find problems, and enforce code style
    2.2 (选JavaScript modules): 选第一个:JavaScript modules (import/export)
    2.3 选择语言框架 (选Vue.js)
    2.4 是否使用ts : 我这里选yes
    2.5 代码在哪里运行 (用空格选中 Browser+Node)
    2.6 选择一个风格:我选的Standard, 完全就够用了
    后面就是yes安装,会发现安装了这些插件
"eslint-config-standard": "^17.0.0",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-n": "^15.2.4",
    "eslint-plugin-promise": "^6.0.0",
    "eslint-plugin-vue": "^9.2.0",
"@typescript-eslint/eslint-plugin": "^5.30.7",
    "@typescript-eslint/parser": "^5.30.7",

一些教程里面还单独安装@typescript-eslint/parser,我实践中走完上面就已经全部有了,生成的.eslintrc.js也不需要修改。

只是部分规则不适用vue3,我们可以在rules直接关掉即可:比如 vue/multi-word-component-names, no-irregular-whitespace

3.选择性安装vite-plugin-eslint, 用于配置vite运行的时候自动检测eslint规范,使用npm run dev时会主动检查代码并报错

npm i -D vite-plugin-eslint

使用
import eslint from 'vite-plugin-eslint'

export default defineConfig({
  plugins: [
    vue(),
   eslint()
  ]
})
  1. setting.json 需要的内容
// setting.json
{
  // 重新设定tabsize
  "editor.tabSize": 2,
  // 每次保存的时候自动格式化 
  "editor.formatOnSave": false,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
 }

这里提一嘴i18n-ally多语言翻译这个vscode 插件,好用。

// setting.json中加入
{
  "i18n-ally.localesPaths": ["src/views/login/lang"],
  "i18n-ally.keystyle": "nested",
  "i18n-ally.sortKeys": true,
// pathMatcher 必需开启namespace ,{locale}指的就是翻译文件名"i18n-ally.localesPaths",{ext}就是enabledParsers中的文件后缀
  "i18n-ally.namespace": true,
  "i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}",
  "i18n-ally.enabledParsers": ["js", "json", "ts"],
  "i18n-ally.sourceLanguage": "en",
  "i18n-ally.displayLanguage": "zh", // 展示中文
  "i18n-ally.enabledFrameworks": ["vue", "react"],
}

主要提这个i18n-ally.pathMatcher路径匹配,多份翻译文件,放在在同一个二级文件src/lang/en,src/lang/zh夹就能通过它namespaces匹配到且生效

效果图.png

第三步:配置lint-staged + husky。在git commit 的时候对提交文件进行校验

lint-staged工具对暂存的代码进行 lint,通常都是配配合husky使用.
husky帮助你在git操作环节执行lint-staged,也就是里面的 eslint --fix 对暂存的src下面的文件进行eslint校验。
一般我们会看到如下package.json配置

//package.json
{
  "lint-staged": {
    "src/**/*.{js,jsx,ts,tsx,vue}": [ 
      "eslint --fix" // 仅仅校验修改暂存的文件
       // "npm run lint:eslint". 如果要校验所有文件的也可以,除非你想这么做
    ]
  }
}

//"scripts": {
//"lint:eslint": "eslint --cache --max-warnings 0  \"{src,mock}/**/*.{vue,ts,js,tsx}\" --fix",
// }

通过husky安装参考文档可以发现,安装husky有两种方式,结果是一样的

  1. 自动方式,只需要执行一句npx husky-init && npm install
npx husky-init && npm install       # npm
npx husky-init && yarn              # Yarn 1
yarn dlx husky-init --yarn2 && yarn # Yarn 2+
pnpm dlx husky-init && pnpm install # pnpm

执行完后会在package.json/scripts 自动加上"prepare": "husky install"
在根目录生成了一个.husky文件夹,里面有个_pre-commit脚本文件

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm test

修改npm test为自己的脚本命令,比如:npx lint-staged

这里的命令修改就可以自由发挥了,只要能触发package.json中的 lint-staged就成
比如我可以在这里写npm run lint:lint-staged,那package.json/scripts中有对应的命令"lint:lint-staged": "lint-staged"即可
tip:不走lint-staged,直接在这里写npm run lint:eslint也是可以的(lint:eslint是scripts中的eslint --fix命令)。说明仅仅只安装husky也是可以的,那也就是校验所有文件了。配合lint-staged只校验暂存区文件才是最好的

  1. 手动方式,按照顺序多执行几个命令
  // 先安装
npm i husky -D.
// 先执行这句才能执行有第四句
npx husky install 
 // 在package.json/scripts 加上`"prepare": "husky install"`。自己手动去加也行
npm set-script prepare "husky install" 
// 这句就是在`_pre-commit`脚本文件加上自己的命令啦
npx husky add .husky/pre-commit "npx  lint-staged"

以上就能成功了。

第四步:配置stylelint

vscode 扩展必不可少:
stylelint.png
  1. 通过stylelint官方文档我们先安装三个插件:我项目用的less,多来一个postcss-less。如果你用scss,来一个postcss-scss就好,下面配置一样的
npm i stylelint stylelint-config-standard postcss-less -D
  1. 新建文件.stylelintignore
/dist/*
/public/*
public/*
  1. 新建.stylelintrc.js。stylelint默认只能识别css文件,我项目使用的less,上面安装一个postcss-less,使用官网提到的自定义语法customSyntax参数让其能够识别less文件。
    如果没有下面配置的overrides/customSyntax,less文件中会有看不懂的报错:Unknown word (CssSyntaxError)Stylelint(CssSyntaxError)
// .stylelintrc.js
module.exports={
  extends:["stylelint-config-standard",],
  overrides:[
          {
            files:["**/*.less"],
              customSyntax:"postcss-less"
          }
    ]
}
  1. 有了上面的操作,已经能看到less文件中的样式各种红色提示了,还需要保存自动格式化,在.vscode/setting.json中增加下面的内容就可以了。
 "editor.codeActionsOnSave": {
    "source.fixAll.stylelint": true
  }
  1. 项目是vue项目,vue文件中的样式无法识别,而且能看到输出的报错信息,提示我要postcss-html,安装它
    输出提示vue文件识别样式.png

    在.stylelintrc.js中加入它
module.exports={
  extends:["stylelint-config-standard"],
  customSyntax: "postcss-html",
  overrides: [
    {
      files:["**/*.less"],
      customSyntax:"postcss-less"
    }
  ],
}

这时候你会发现vue文件中样式并没有提示问题。还差一步,在.vscode/settings.json中增加

"stylelint.validate": ["vue", "less", "css"]

有了以上的简单配置,就可以保存自动按照stylelint格式化你的样式了

  1. 升级内容
    (1)结合lint-staged,提交检测样式,在package.json中增加
"lint-staged": {
    "**/*.{css,less,scss,vue}":[
      "stylelint --fix"
    ]
  }

(2)插件帮助我们css按照顺序书写

// 安装插件
npm i -D stylelint-order stylelint-config-rational-order

stylelint-config-rational-order插件用来简化了插件stylelint-order的引用和配置。你只用stylelint-order也是可以的

//.stylelintrc.js 中使用插件
module.exports={
  extends:["stylelint-config-standard", 'stylelint-config-rational-order'],
}

下面是一些问题记录

1. 当项目中使用了自动导入unplugin-auto-import/vite插件,eslint会提示ref等不存在

(1) 安装 vue-global-api
(2) 在eslintrc.js中加入它

extends: [
    'plugin:vue/vue3-essential',
    'standard',
    'vue-global-api'
  ],
2. 记录一下cross-env,cross-env 使用单个命令,而不用担心环境变量的设置

安装

npm i cross-env -D

使用

"report": "cross-env REPORT=true npm run build",

取参数

const isReport = process.env.REPORT === 'true'
isReport
      ? visualizer({
   //生成的stats放到别的地方去
        filename: './node_modules/.cache/visualizer/stats.html',
        open: true,
        gzipSize: true,
        brotliSize: true
      })
      : [],
3. 项目中加入一个插件后,在linux编译时莫名其妙报错:Error: The package "esbuild-linux-64" could not be found, and is needed by esbuild.

If you are installing esbuild with npm, make sure that you don't specify the
"--no-optional" flag. The "optionalDependencies" package.json feature is used
by esbuild to install the correct binary executable for your current platform.

按照道理说jenkins工作区域的node_modules早就有了,怎么突然没这个依赖了呢?
直接删除工作区域代码,重新npm i 跑一遍解决了

4. 该项目开发的多页面是给安卓app用的,用的lzyzsd/JsBridge。旧版app使用registerHandler提供native调用js的能力,在新版app失效,这个库issue里面也提到了

直接将js方法挂到window下面,native去调用

// 该方法给安卓调用,安卓返回是否开启消息提醒
window.getPunchInReminderStatus = (res) => {
systemRemindOpen = res === '1'
}
5. window.onresize不触发

旧版本安卓在进入页面或者失去焦点的时候会触发window.onresize,当时使用它时为了控制fixed元素不被键盘顶起来。
在新版安卓中,键盘并没有将底部fixed元素顶起来,且失去焦点的时候window.onresize不触发了,用不上它了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容