使用 Vue3+TS+Vite+PNPM 搭建前端工程基础工作流配置

注:本篇文章里会介绍以下内容:

  • 选择哪些工具来初始化我们的前端工程的基础框架;
  • 相关工具的简单介绍;
  • 如何良好地完善相关配置

不会涉及工具类的封装、路由系统的设计、权限设计、缓存方案等等趋向于业务结合的内容

文章的关注点:前端开发流程链路各环节的工具配置,初始化项目(包管理器+开发/构建工具)--> 各类开发工具配置(TS + 样式预处理器 + Lint + Git工具 + 前端测试 + 格式化等) --> 测试辅助工具的可用性及适用性 --> 功能/业务代码开发(本文不涉及)--> 校验、测试、规范化、Git操作等

这里提前粘贴一下 package.json 中的依赖配置项,以便从中快速浏览工程初始化时使用到的一些三方类库:

 1   "devDependencies": {
 2     "@commitlint/cli": "^17.0.3",
 3     "@commitlint/config-conventional": "^17.0.3",
 4     "@commitlint/format": "^17.0.0",
 5     "@commitlint/types": "^17.0.0",
 6     "@types/json-server": "^0.14.4",
 7     "@types/node": "^18.6.4",
 8     "@typescript-eslint/eslint-plugin": "^5.32.0",
 9     "@typescript-eslint/parser": "^5.32.0",
10     "@vitejs/plugin-vue": "^3.0.1",
11     "@vitejs/plugin-vue-jsx": "^2.0.0",
12     "eslint": "^8.20.0",
13     "eslint-plugin-vue": "^9.3.0",
14     "husky": "^8.0.1",
15     "json-server": "^0.17.0",
16     "less": "^4.1.3",
17     "lint-staged": "^13.0.3",
18     "only-allow": "^1.1.1",
19     "postcss": "^8.4.14",
20     "postcss-html": "^1.5.0",
21     "postcss-less": "^6.0.0",
22     "stylelint": "^14.9.1",
23     "stylelint-config-recess-order": "^3.0.0",
24     "stylelint-config-recommended-less": "^1.0.4",
25     "stylelint-config-recommended-vue": "^1.4.0",
26     "stylelint-less": "^1.0.6",
27     "stylelint-order": "^5.0.0",
28     "typescript": "^4.7.4",
29     "unplugin-vue-components": "^0.22.0",
30     "vite": "^3.0.4",
31     "vitest": "^0.21.0",
32     "vue-tsc": "^0.39.4"
33   },
34   "dependencies": {
35     "@ant-design/icons-vue": "^6.1.0",
36     "ant-design-vue": "^3.2.10",
37     "axios": "^0.27.2",
38     "dayjs": "^1.11.4",
39     "pinia": "^2.0.17",
40     "rxjs": "^7.5.6",
41     "vue": "^3.2.37",
42     "vue-router": "^4.1.3"
43   }

 

# PNPM

首先,我们使用 PNPM (快速的,节省磁盘空间的)作为项目的包管理器。

在Mac OS上安装:

curl -fsSL https://get.pnpm.io/install.sh | sh -

(更多详情,可以查看官网)

为什么使用 PNPM?

1. 节约磁盘空间并提升安装速度 

当使用 npm 或 Yarn 时,如果你有 100 个项目使用了某个依赖(dependency),就会有 100 份该依赖的副本保存在硬盘上。  而在使用 pnpm 时,依赖会被存储在内容可寻址的存储中,所以:

  • 如果你用到了某依赖项的不同版本,只会将不同版本间有差异的文件添加到仓库。 例如,如果某个包有100个文件,而它的新版本只改变了其中1个文件。那么 pnpm update 时只会向存储中心额外添加1个新文件,而不会因为仅仅一个文件的改变复制整新版本包的内容。
  • 所有文件都会存储在硬盘上的某一位置。 当软件包被被安装时,包里的文件会硬链接到这一位置,而不会占用额外的磁盘空间。 这允许你跨项目地共享同一版本的依赖。

因此,您在磁盘上节省了大量空间,这与项目和依赖项的数量成正比,并且安装速度要快得多!

2. 创建非扁平化的 node_modules 文件夹

使用 npm 或 Yarn Classic 安装依赖项时,所有包都被提升到模块目录的根目录。 因此,项目可以访问到未被添加进当前项目的依赖。

而使用 pnpm 会避免这种情况出现。默认情况下,pnpm 使用软链的方式将项目的直接依赖添加进模块文件夹的根目录。

注:当使用了 PNPM 后,我们还可以做哪些延伸的配置呢

1. 可以统一团队项目的包管理器为pnpm

首先,通过 pnpm add -D only-allow 安装only-allow,并在package.json中配置以下命令脚本:

{
  "scripts": {
    "preinstall": "npx only-allow pnpm"
  }
}

安装并配置好后,当你通过其他包管理器添加/下载依赖时,便会被阻断并提示(如下图)

尝试通过yarn下载dayjs

yarn add dayjs

2. 可以锁定工程所依赖的Node版本

具体配置步骤可查看我的另一篇文章 《锁定前端工程的Node版本

 

# Vue

Vue3,就不多说了。。

VS Code插件:

- Vue Language Features (Volar)

- TypeScript Vue Plugin (Volar) 

 

# TypeScript

前端工程化开发的新标准。

VS Code插件:JavaScript and TypeScript Nightly

配置详情:

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "useDefineForClassFields": true,
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "lib": ["esnext", "dom"],
    "skipLibCheck": true,
    "types": ["vite/client"],
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.d.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "components.d.ts"
  ],
  "references": [{ "path": "./tsconfig.node.json" }]
}

tsconfig.node.json

{
  "compilerOptions": {
    "composite": true,
    "module": "esnext",
    "moduleResolution": "node"
  },
  "include": [
    "vite.config.ts",
    "http-proxy.ts"
  ]
}

 

# Vite

安装好 pnpm 之后,我们就可以配合使用 vite 初始化项目

pnpm create vite _app-name_ -- --template vue-ts

英文官网:https://vitejs.dev/

早在一年多之前,我所在的团队已经选择使用vite作为前端开发与构建工具,完成的一套上线应用。

目前版本已经更新到3.0.x,完全可以放心应用到新的实际项目中。

最直观的体验是“快速”、“清爽”,开发效率也得到明显提升(解决掉了webpack开发服务器存在的痛点)。

初始化完成后,工程目录如下:

VS Code插件:Vite

配置详情:

vite.config.ts

import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJSX from '@vitejs/plugin-vue-jsx';
import Components from 'unplugin-vue-components/vite';
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
import { resolve } from 'path';
import { initDevProxy } from './http-proxy';

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '');
  return {
    // 自定义公共基础路径(取自 .env(.*) 文件)
    base: env.VITE_BASE_PATH,
    // 定义全局常量替换方式
    define: {
      // 取消启用Vue.2x中选项式api(这部分不会被打包)
      '__VUE_OPTIONS_API__': false,
    },
    // 配置vite插件
    plugins: [
      vue(),
      vueJSX(),
      // 自动化的组件按需引入配置
      Components({
        extensions: ['vue', 'tsx'],
        resolvers: [
          AntDesignVueResolver({ resolveIcons: true }),
        ],
        include: [/\.vue$/, /\.vue\?vue/, /\.tsx$/],
      }),
    ],
    // 配置解析项
    resolve: {
      // 路径别名
      alias: {
        '@/': resolve(__dirname, 'src') + '/',
      },
    },
    // 样式处理配置项
    css: {
      // CSS module
      modules: {
        generateScopedName: `_[name]_[local]_[hash:base64:6]_`,
      },
      // 传递给特定css样式预处理器的配置
      preprocessorOptions: {
        less: {
          javascriptEnabled: true,
        },
      },
    },
    // 配置开发服务器
    server: {
      open: true,
      proxy: initDevProxy(),
    },
    // 自定义打包项配置
    build: {
      // 大文件告警阈值(kb)
      chunkSizeWarningLimit: 400,
    },
  };
});

http-proxy.ts

import type { ProxyOptions } from 'vite';

/**
 * 初始化开发服务器代理
 */
export const initDevProxy = (): Record<string, string | ProxyOptions> => {
  return {
    // 临时示例
    '/api': {
      target: '',
      changeOrigin: true,
    },
  };
};

注:关于Vite首屏渲染慢、响应迟缓问题的处理方案

 

# Vitest

上面介绍了vite,所以这里简单介绍一下vitest。

它是一个 Vite 原生的极速单元测试框架。

英文官网:https://vitest.dev/

主要特点

1. 重复使用 Vite 的配置、转换器、解析器和插件;
2. 由 esbuild 提供的开箱即用 ESM、TypeScript 和 JSX 支持;
3. 拥有预期、快照、覆盖等 - 从 Jest 迁移很简单;
4. 智能文件监听模式,就像是测试的 HMR;
5. 内置 Chai 进行断言 + 与 Jest expect 语法兼容的 API;
6. 使用 jsdom 或 happy-dom 用于 DOM 模拟;
7. 类似于 Rust 语言的 源码内联测试;

等等。。

VS Code插件:Vitest

配置 vitest,需要在项目中的 Vite 配置中添加 test 属性。

如果直接使用 vite 的 defineConfig 方法,还需要将 三斜线指令 写在配置文件的顶部。

配置详情:

vite.config.ts

/// <reference types="vitest" />
import { defineConfig, loadEnv } from 'vite';
// ...
// ...

export default defineConfig(({ mode }) => {
  return {
    // ...
    // 其他配置项 ... 
    // ...
    
    // Vitest配置
    test: {
      /**
       * 可以在测试文件中以全局变量的形式使用,不用在手动import { describe } ...,
       * 注意,同时需要在tsconfig.json中配置 `"types": ["vitest/globals"]`
       */
      globals: true,
      /**
       * 全局调整测试环境,模拟浏览器环境(DOM操作)可设置如下:
       * 或通过在单个文件顶部添加注释 `// @vitest-environment happy-dom` 来单独设置
       * 注意,需安装相关依赖(如happy-dom)
       */
      environment: 'happy-dom',
      /**
       * 调整模块转换方式(如使用到jsx)
       */
      transformMode: {
        web: [/.[tj]sx$/],
      },
    },
  };
});

在根目录下,创建test文件夹,然后根据需要添加相应的测试文件。

示例(test/basic.test.ts):

import { test, expect } from 'vitest';

test('Math.sqrt()', () => {
  expect(Math.sqrt(4)).toBe(2);
});

同时,在package.json文件中添加测试的命令脚本:

"scripts": {
  //...
  "test": "vitest"
  // ...
}

 

# ESLint

JavaScript 代码监测工具

本工程中用到了TS,可能会有疑问需不需要用tslint,答案是:不用,直接用eslint即可。

因为目前TSLint已经被废弃,统一采用ESLint为标准,关于TSLint和ESLint更多的故事,可以查看这篇文章:

《TSLint 和 ESLint 是怎么融合在一起的》

个人觉得文章总结得蛮好。

另外,关于ESLint的新配置模式预告(2022.08.05):

《ESLint's new config system

VS Code插件:ESLint

配置详情:

.eslintrc.js(.eslintrc.json/.eslintrc.yaml亦可)

module.exports = {
  root: true,
  env: {
    browser: true,
    es2022: true,
    node: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:vue/vue3-essential',
    'plugin:@typescript-eslint/recommended',
  ],
  parser: 'vue-eslint-parser',
  parserOptions: {
    ecmaVersion: 'latest',
    parser: '@typescript-eslint/parser',
    sourceType: 'module',
    ecmaFeatures: {
      jsx: true,
    },
  },
  plugins: [
    'vue',
    '@typescript-eslint',
  ],
  rules: {
    // 强制分号结尾
    semi: ['error', 'always'],
    // 引号
    quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: true }],
    // 属性引号
    'quote-props': ['error', 'as-needed'],
    // JSX内的引号
    'jsx-quotes': ['error', 'prefer-double'],
    // 判等规则
    eqeqeq: ['error', 'smart'],
    // 缩进(2个空格)
    indent: ['error', 2],
    // 箭头函数参数体统一用括号包裹
    'arrow-parens': ['error', 'always'],
    // 函数调用规则(括号前后不能有空格)
    'func-call-spacing': ['error', 'never'],
    // 单个函数的最大代码行数
    'max-lines-per-function': ['error', { max: 108, skipBlankLines: true, skipComments: true }],
    // 连续声明变量
    'one-var': ['error', 'never'],
    // 函数名称与括号之间有一个空格
    'space-before-function-paren': ['error', {
      anonymous: 'never',
      named: 'never',
      asyncArrow: 'always',
    }],
    // 键后的冒号
    'key-spacing': ['error', { beforeColon: false, afterColon: true }],
    // 关键词
    'keyword-spacing': ['error', { before: true, after: true }],
    // switch-case冒号空格
    'switch-colon-spacing': ['error', { after: true, before: false }],
    // 混用操作符
    'no-mixed-operators': 'error',
    // 连续赋值
    'no-multi-assign': 'error',
    // 注释空格
    'spaced-comment': ['error', 'always'],
    // alert
    'no-alert': 'error',
  },
  ignorePatterns: [
    'src/**/*.test.ts',
    'src/**/*.d.ts',
  ],
};

 

# StyleLint

现代的样式书写标准约定和监测工具

在个人看来,Stylelint的应用普及度不及ESLint。

一方面,可能是因为部分开发者主观上觉得样式没有lint的;

另一方面,可能是因为对样式方面的开发重视度不够(think it is easy ...)

总之,样式规范的确立和校验在团队协作中是绝对有必要的。

VS Code插件:Stylelint 

配置详情:

.stylelintrc.json

{
  "extends": [
    "stylelint-config-recess-order",
    "stylelint-config-recommended-less",
    "stylelint-config-recommended-vue"
  ],
  "plugins": [
    "stylelint-order",
    "stylelint-less"
  ],
  "rules": {
    "string-quotes": "single",
    "indentation": 2,
    "color-no-invalid-hex": true,
    "color-hex-case": "lower",
    "color-hex-length": "short",
    "function-calc-no-unspaced-operator": true,
    "function-linear-gradient-no-nonstandard-direction": true,
    "custom-property-no-missing-var-function": true,
    "keyframe-block-no-duplicate-selectors": true,
    "block-no-empty": [true, { "ignore": ["comments"] }],
    "selector-pseudo-element-no-unknown": true,
    "media-feature-name-no-unknown": true,
    "no-invalid-double-slash-comments": true,
    "length-zero-no-unit": true,
    "font-family-name-quotes": "always-where-recommended",
    "function-url-quotes": "always",
    "number-max-precision": 2,
    "declaration-no-important": true,
    "selector-attribute-quotes": "always",
    "max-empty-lines": [2, { "ignore": ["comments"] }],
    "no-eol-whitespace": [true, { "ignore": ["empty-lines"] }],
    "no-extra-semicolons": true
  }
}

## 关于工程的样式

本工程中样式的预处理是选用的Less,当然也换成Scss、styled-components亦可。
 

# husky

 

Git Hooks工具,可以让你更容易、更方便地使用git hook。

简单来说,它可以帮你在提交代码前自动地去 校验代码、跑测试case、检验commit备注信息的规范性。

通过官方命令脚本,在根目录创建.husky文件夹后,一般会用到2个文件:

.husky/pre-commit

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

npx lint-staged

.husky/commit-msg

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

npx --no -- commitlint --edit "\${1}"

 

# lint-staged

一般会用来在pre-commit阶段自定完成一些代码校验工作。

配置详情:

.lintstagedrc.json

{
  "src/**/*.{ts,tsx,vue,js}": "eslint --cache",
  "src/**/*.{less,css}": "stylelint --cache --custom-syntax postcss-less",
  "src/**/*.vue": "stylelint --cache --custom-syntax postcss-html"
}

// 需要跑测试case,可在json配置项中加入代码(示范)
// "src/**/*.test.ts": "vitest"

 

commitlint

代码提交的commit备注也需要规范、校验的,不过在团队开发中,你会很检索出以前的特定的提交,也有可能无法快速看懂他人的某一次提交具体干了什么。

VS Code插件:commitlint

配置详情:

commitlint.config.ts

import type { UserConfig } from '@commitlint/types';

const CommitlintConfiguration: UserConfig = {
  extends: ['@commitlint/config-conventional'],
  formatter: '@commitlint/format',
  rules: {
    'type-enum': [2, 'always', [
      // 新功能/重要更新
      'feat',
      // 修复BUG
      'fix',
      // 样式相关的调整
      'style',
      // 重构性的代码
      'refactor',
      // 回滚操作
      'revert',
      // 依赖(第三方)升级
      'upgrade',
      // 文档更新
      'docs',
      // 小补丁
      'patch',
      // 代码优化
      'perf',
      // 构建/部署
      'ci',
      // 测试
      'test',
      // 打包
      'build',
      // 不属于以上的日常提交
      'chore',
    ]],
  },
};

export default CommitlintConfiguration;

 

# json-server

Mock方案可以采用 json-server,它的主要特点:

1. 配置简易快速,30秒内即可启动一个 Rest 风格的接口服务器;

2. 操作体验接近真实的增删改查;

3. 自定义程度高;

配置详情:

mocks/db.json(简易的本地数据库)

{
  "books": [
    {
      "id": 1,
      "name": "Vue.js设计与实现"
    }
  ]
}

package.json

"scripts": {
  // ...
  "mock": "json-server mocks/db.json --watch",
  // ...
}

 

# Prettier

Prettier是一个“opinionated”(固执己见)的代码格式化工具。

它很棒,但团队中有些同事觉得它的干预性、入侵性太强,尽管格式化美化工作完成的不错,但扼杀了程序员的个人编程习惯(的确,有些程序员的水平并不需要自动格式化工具)。

一开始,团队项目中使用了Prettier,但大多数成员觉得没必要。最后,我们并没有配置Prettier,尊重大家的意愿,也对大家的能力、编码规范意识有自信,提供一个easy、开放的编程环境是重要的!

所以,这里就不再介绍相关配置。

 

最终,工程目录概览:

 

posted @ 2022-08-07 21:49  樊顺  阅读(3508)  评论(0编辑  收藏  举报