Vue3+Ts+Pnpm+eslint9.0+Prettier+Stylelint+vant(移动/h5)项目搭建记录

1,264 阅读12分钟

一. Vite初始化项目

(官网)

  • 控制台执行pnpm create vitenpm init vite@latest。依次输入新项目名字,选择Vue以及Ts。(包管理工具不要混用要么用pnpm要么用npm)
    PS D:\StudyCode> pnpm create vite
    ../.pnpm-store/v3/tmp/dlx-13276          |   +1 +
    Packages are hard linked from the content-addressable store to the virtual store.
      Content-addressable store is at: D:\.pnpm-store\v3
      Virtual store is at:             ../.pnpm-store/v3/tmp/dlx-13276/node_modules/.pnpm
    ../.pnpm-store/v3/tmp/dlx-13276          | Progress: resolved 1, reused 0, downloaded 1, added 1, done
    √ Project name: ... TeamplateV3
    √ Package name: ... teamplatev3
    √ Select a framework: » Vue
    √ Select a variant: » TypeScript
    
    Scaffolding project in D:\StudyCode\TeamplateV3...
    
    Done. Now run:
    
      cd TeamplateV3
      pnpm install
      pnpm run dev
    
    
  • 执行pnpm install
  • 启动项目:将项目在vscode里打开,打开控制台,执行pnpm run dev启动项目。package.json文件【"dev": "vite --open"】, 设置--open,执行完将会自动打开项目。
  • 生成的项目会在根目录下生成三个文件,分别是tsconfig.json tsconfig.node.jsontsconfig.app.json。其中,tsconfig.json 是项目的主要 TypeScript 配置文件,它引用了其他两个配置文件
    • tsconfig.json 是 TypeScript 项目的主要配置文件,它包含了 TypeScript 编译器的各种选项设置。一些常见的配置选项包括:

      • compilerOptions:用于配置编译器选项,例如目标版本、模块系统、输出目录等。
      • include 和 exclude:用于指定哪些文件应该包含在编译中,哪些文件应该排除在外。
      • files:指定要包含在编译中的文件列表。
      • references:用于配置项目引用,允许在一个 TypeScript 项目中引用另一个 TypeScript 项目。
    • tsconfig.node.json

      • tsconfig.node.json 是针对 Node.js 环境的 TypeScript 配置文件。在这个配置文件中,您可以配置与 Node.js 相关的编译选项,以确保 TypeScript 代码能够正确地在 Node.js 环境中运行。例如,您可以配置模块解析方式、Node.js 版本兼容性等选项。

      注意到 "include": ["vite.config.ts"] 这段代码,它说明 tscnofig.node.json 是专门用于 vite.config.ts 这一文件的 TypeScript 配置文件.项目中的普通代码是运行在浏览器环境中的,因此 TypeScript 需要为这些代码提供 DOM 等浏览器接口的类型支持。而 vite.config.ts 是运行在 Node 环境中的,它不应访问浏览器接口,而相应地它需要各种 Node 接口的类型支持

    • tsconfig.app.json

      • tsconfig.app.json 是针对应用程序的 TypeScript 配置文件。在这个配置文件中,您可以配置与应用程序开发相关的编译选项,例如调试选项、源映射设置、压缩选项等。这样可以根据应用程序的需求进行定制化的 TypeScript 编译配置。

二. 格式化配置

1. 用户vscode配置

vite初始化项目后将会生成.vscode文件夹,里面有extensions.json文件

- extensions.json

{
  "recommendations": [
    "Vue.volar", 
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "stylelint.vscode-stylelint",
  ]
}

recommendations:推荐安装的插件

image.png

- setting.json

setting.json是自己创的,下面的配置看情况加

{
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true,
    "eslint.validate": [
        "typescript",
        "vue"
    ],
    "stylelint.validate": [
        "css",
        "less",
        "scss",
        "vue"
    ],
    "editor.codeActionsOnSave": {
        "source.fixAll": true,
        "source.fixAll.eslint": true,
        "source.fixAll.stylelint": true
    }
}

- prettier配好了但是不生效

2. Eslint

  1. 执行pnpm create @eslint/config 或者 npm init @eslint/config@latest, 将会自动生成eslint.config.js配置文件。默认使用eslint9.x,与以往版本的配置写法不同。

    image.png

    • typescript-eslint: ts-eslint解析器,使 eslint 可以解析 ts 语法,
      • @typescript-eslint/parser: ESLint 默认使用的是 Espree 进行语法解析,所以无法对部分 typescript 语法进行解析,需要替换掉默认的解析器
      • @typescript-eslint/eslint-plugin: 作为 eslint 默认规则的补充,提供了一些额外的适用于 ts 语法的规则
    • eslint-plugin-vue: 这个插件允许我们用 ESLint 检查文件的<template>和,以及文件中的 Vue 代码。
  2. 修改eslint.config.js文件

    import globals from 'globals'; //https://eslint.org/docs/latest/use/configure/language-options
    import pluginJs from '@eslint/js';
    import tseslint from 'typescript-eslint'; //https://typescript-eslint.io/getting-started/
    import pluginVue from 'eslint-plugin-vue'; //https://eslint.vuejs.org/user-guide/
    import vueEslintParser from 'vue-eslint-parser'; // vue文件解析器
    
    export default [
        {
            languageOptions: {
                globals: { ...globals.browser, ...globals.node },
                parser: vueEslintParser, // 使用vue解析器,这个可以识别vue文件
                parserOptions: {
                    ecmaVersion: 'latest',
                    parser: tseslint.parser, // 在vue文件上使用ts解析器
                    sourceType: 'module'
                }
            }
        },
        pluginJs.configs.recommended,
        ...tseslint.configs.recommended,
        ...pluginVue.configs['flat/essential'],
        {
            rules: {
                // override/add rules settings here, such as:
                // 'vue/no-unused-vars': 'error',
            }
        }
    ];
    
    
  3. 配置ignore

3. Prettier

[官网]

  1. 安装pnpm add prettier eslint-plugin-prettier eslint-config-prettier -D

    • eslint-plugin-prettier 将Prettier作为ESLint规则运行,并将差异报告为单独的 ESLint 问题。
    • eslint-config-prettier
      • 启用prettier/prettier规则。
      • 禁用与该插件有问题的arrow-body-styleprefer-arrow-callback规则
      • 启用eslint-config-prettier配置将关闭与 Prettier 冲突的 ESLint 规则。
  2. 创建配置文件node --eval "fs.writeFileSync('.prettierrc','{}\n')"

  3. 修改 .prettierrc文件如下

    {
        "printWidth": 100,
        "tabWidth": 4,
        "useTabs": false,
        "semi": true,
        "singleQuote": true,
        "quoteProps": "as-needed",
        "jsxSingleQuote": false,
        "trailingComma": "none",
        "bracketSpacing": true,
        "jsxBracketSameLine": false,
        "proseWrap": "always",
        "htmlWhitespaceSensitivity": "ignore",
        "arrowParens": "avoid",
        "endOfLine": "auto"
    }
    
  4. 修改 .eslint.config.js文件如下

import globals from 'globals'; //https://eslint.org/docs/latest/use/configure/language-options
import pluginJs from '@eslint/js';
import tseslint from 'typescript-eslint'; //https://typescript-eslint.io/getting-started/
import pluginVue from 'eslint-plugin-vue'; //https://eslint.vuejs.org/user-guide/
import vueEslintParser from 'vue-eslint-parser'; // vue文件解析器

//关闭所有不必要的或可能与Prettier冲突的规则。https://github.com/prettier/eslint-plugin-prettier?tab=readme-ov-file#configuration-new-eslintconfigjs
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';

export default [
    {
        languageOptions: {
            globals: { ...globals.browser, ...globals.node },
            parser: vueEslintParser, // 使用vue解析器,这个可以识别vue文件
            parserOptions: {
                ecmaVersion: 'latest',
                parser: tseslint.parser, // 在vue文件上使用ts解析器
                sourceType: 'module'
            }
        }
    },
    pluginJs.configs.recommended,
    ...tseslint.configs.recommended,
    ...pluginVue.configs['flat/essential'],
    eslintPluginPrettierRecommended, // 放在最后面
    {
        rules: {
            // override/add rules settings here, such as:
            // 'vue/no-unused-vars': 'error',
            'prettier/prettier': [
                'error',
                {
                    // endOfLine: "auto"
                }
            ]
        }
    }
];

4. Stylelint

官网

  1. 执行pnpm create stylelint或者npm init stylelint,将会生成.stylelintrc.json文件, 自动安装stylelintstylelint-config-standard依赖

  2. 执行pnpm add stylelint-config-recommended-less stylelint-config-standard-vue less -D

    • stylelint-config-recommended-less -- less的推荐可共享配置规则
    • stylelint-config-standard-vue 可识别vue文件

    从 Stylelint v15 开始,所有与样式相关的规则都已弃用。如果您使用的是 v15 或更高版本,并且未使用这些弃用的规则,则stylelint-config-prettier插件不再是必要的

  3. .stylelintrc.json

    {
        "extends": [
            "stylelint-config-standard",
            "stylelint-config-recommended-less",
            "stylelint-config-standard-vue"
        ]
    }
    

三. Src设置别名

  1. 更改 vite.config.ts文件
    import { join } from 'path';
    function resolve(dir: string):string {
      return join(__dirname, dir);  //可以用process.cwd() path.join()和path.resolve()
    }
    export default defineConfig({
      plugins: [vue()],
      resolve: {
        alias: {
          '@': resolve('/src'),
          '#': resolve('/types'),
        }
      }
    })
    
  2. 此时会出现波浪线,执行pnpm i --save-dev @types/node
  3. 修改tsconfig.json
    "compilerOptions": {
         "baseUrl": ".", // 用于设置解析非相对模块名称的基本目录,相对模块不会受到baseUrl的影响
         "paths": { // 用于设置模块名到基于baseUrl的路径映射
              "@/*": ["src/*"],
              "#/*": ["types/*"],
            }
    }
       
    
  4. 重启vscode生效

四. 配置自动导入

  1. pnpm add unplugin-auto-import unplugin-vue-components -D

  2. 修改vite.config.ts

    import { defineConfig } from 'vite';
    import { join } from 'path';
    import vue from '@vitejs/plugin-vue';
    import AutoImport from 'unplugin-auto-import/vite';
    import Components from 'unplugin-vue-components/vite';
    import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
    
    function resolve(dir: string): string {
        return join(__dirname, dir); //可以用process.cwd() path.join()和path.resolve()
    }
    
    // https://vitejs.dev/config/
    export default defineConfig({
        plugins: [
            vue(),
            AutoImport({
                //自动导入第三方库或组件 不需要手动编写import {xxx} from vue
                // dts: true, // 如果使用 Typescript,需要设置 dts 为 true 插件会在项目根目录生成类型文件 auto-imports.d.ts ,确保该文件在 tsconfig 中被 include
                dts: 'types/auto-imports.d.ts',
                dirs: ['src/composables'], //文件夹。看情况加
                imports: [
                    'vue',
                    'vue-router',
                    '@vueuse/core',
                    'pinia'
                    // 其他需要自动导入的库
                ]
            }),
            Components({
                dts: 'types/components.d.ts', // 输出文件,里面都是一些import的组件键值对
                dirs: ['src/components'], //让src/components里的组件不用再手动引入
                // 配置需要自动注册的组件
                resolvers: [
                    AntDesignVueResolver({
                        //ant-design-vue不用手动按需引入
                        importStyle: false // css in js
                    })
                ]
            })
        ],
        resolve: {
            alias: {
                '@': resolve('/src'),
                '#': resolve('/types')
            }
        }
    });
    
    
  3. UI组件库的按需自动导入(看各自的官网)

    • vant
    • ant-design-vue
      import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
      
      Components({
          // 配置需要自动注册的组件
          resolvers: [
              AntDesignVueResolver({
                  //ant-design-vue不用手动按需引入
                  importStyle: false // css in js
              })
          ]
      })
      
  4. 安装其他依赖 pnpm i @vueuse/core vue-router pinia axios

  5. 确保该文件在 tsconfig.json 中被 include

{
    "compilerOptions": {
        "target": "ES2020",
        "useDefineForClassFields": true,
        "module": "ESNext",
        "lib": ["ES2020", "DOM", "DOM.Iterable"],
        "skipLibCheck": true,

        /* Bundler mode */
        "moduleResolution": "bundler",
        "allowImportingTsExtensions": true,
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true,
        "jsx": "preserve",
        "jsxImportSource": "vue",

        /* Linting */
        "strict": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "noFallthroughCasesInSwitch": true,

        /* path */
        "baseUrl": ".", // 用于设置解析非相对模块名称的基本目录,相对模块不会受到baseUrl的影响
        "paths": {
            // 用于设置模块名到基于baseUrl的路径映射
            "@/*": ["src/*"],
            "#/*": ["types/*"]
        }
    },
    "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "types/**/*.d.ts"],
    "references": [{ "path": "./tsconfig.node.json" }]
}


新建style文件夹。滚动条样式 npprogress\路由过渡样式等

五. 创建环境变量

vite环境变量

  • 根级目录下创建文件.env.development.env.production

    # 环境
    NODE_ENV=production
    
    # 接口前缀
    VITE_APP_BASE_API=dev
    
    # 打包路径
    VITE_BASE_PATH=/dist-dev/
    
    # 是否删除debugger
    VITE_DROP_DEBUGGER=false
    
    # 是否删除console.log
    VITE_DROP_CONSOLE=false
    
    # 是否sourcemap
    VITE_SOURCEMAP=true
    
    # 输出路径
    VITE_OUT_DIR=dist-dev
    
    # 标题
    VITE_APP_TITLE=ElementAdmin
    
  • 获得 TypeScript 的智能提示

    默认情况下,Vite 在 vite/client.d.ts 中为 import.meta.env 提供了类型定义。随着在 .env[mode] 文件中自定义了越来越多的环境变量,你可能想要在代码中获取这些以 VITE_ 为前缀的用户自定义环境变量的 TypeScript 智能提示。要想做到这一点,你可以在 src 目录下创建一个 vite-env.d.ts 文件(vite项目初始化时默认创建了),接着按下面这样增加 ImportMetaEnv 的定义:

    /// <reference types="vite/client" />
    
    interface ImportMetaEnv {
        readonly VITE_APP_TITLE: string; //网站标题
        readonly VITE_APP_BASE_API: string; //接口前缀
        readonly VITE_BASE_PATH: string; //打包路径
        readonly VITE_DROP_DEBUGGER: string; //是否删除debugger
        readonly VITE_DROP_CONSOLE: string; //是否删除console.log
        readonly VITE_SOURCEMAP: string; //是否sourcemap
        readonly VITE_OUT_DIR: string; //输出路径
        // 更多环境变量...
    }
    
    interface ImportMeta {
        readonly env: ImportMetaEnv;
    }
    

    image.png

    • 使用举例:import.meta.env.VITE_APP_TITLE
    • 在配置vite.config.ts中使用环境变量
    import { defineConfig, loadEnv } from 'vite'
    
    export default defineConfig(({ command, mode }) => {
      // 根据当前工作目录中的 `mode` 加载 .env 文件
      // 设置第三个参数为 '' 来加载所有环境变量,而不管是否有 `VITE_` 前缀。
      const env = loadEnv(mode, process.cwd(), '')
      return {
        // vite 配置
        define: {
          __APP_ENV__: JSON.stringify(env.APP_ENV),
        },
      }
    })
    
    • HTML 环境变量替换
    <h1>Vite is running in %MODE%</h1>
    <p>Using data from %VITE_API_URL%</p>
    

    如果环境变量在 import.meta.env 中不存在,比如不存在的 %NON_EXISTENT%,则会将被忽略而不被替换,这与 JS 中的 import.meta.env.NON_EXISTENT 不同,JS 中会被替换为 undefined

六. 浏览器适配

Vant 默认使用 px 作为样式单位,如果需要使用 viewport 单位 (vw, vh, vmin, vmax),推荐使用 postcss-px-to-viewport 进行转换。

  1. 安装依赖pnpm add -D postcss-px-to-viewport-8-plugin

    安装postcss-px-to-viewport时,当前版本v1.1.1长期未更新,include在vue3项目中实测不生效。不设置或者将其设置成include: undefined 如果控制台会报以下错误:postcss-px-to-viewport: postcss.plugin was deprecated. Migration guide:可以通过将 postcss-px-to-viewport 换成 postcss-px-to-viewport-8-plugin 解决

  2. vite.config.ts配置

    import pxtovw from 'postcss-px-to-viewport-8-plugin';
    css: {
        devSourcemap: true, //在开发过程中是否启用 sourcemap。
        postcss: {
            plugins: [
                pxtovw({
                        unitToConvert: 'px', // 要转化的单位
                        viewportWidth: 375, // UI设计稿的宽度
                        unitPrecision: 6, // 转换后的精度,即小数点位数
                        propList: ['*'], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
                        viewportUnit: 'vw', // 指定需要转换成的视窗单位,默认vw
                        fontViewportUnit: 'vw', // 指定字体需要转换成的视窗单位,默认vw
                        selectorBlackList: [], // 指定不转换为视窗单位的类名,
                        minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
                        mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
                        // replace: true, // 是否直接更换属性值,而不添加备用属性
                        exclude: [/^(?!.*node_modules\/vant)(?!.*__uno\.css)/], // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
                        // include: undefined, // 如果设置了include,那将只有匹配到的文件才会被转换
                        landscape: false // 是否处理横屏情况
                })
            ]
        }
    },
    

    注意

    • postcss-px-to-viewport 对内联css样式,外联css样式,内嵌css样式有效,对js动态css无效。 所以要动态改变css展示效果的话,要使用静态的class定义变化样式,通过js改变dom元素的class实现样式变化
    • vue模板中的px单位不会被转换,如需转换请使用postcss-style-px-to-viewport工具
  3. 解决vant和postcss-px-to-viewport的配合

    一般我们的设计稿都是750,而vant的设计稿是375,这就出现一种冲突。以750执行的话,则vant组件会变小

    在vant库里,我们依然用375的设计稿的宽度,其它的文件我们依然用750设计稿的宽度

    //postcss.config.js
    const path = require('path');
    module.exports = ({webpack }) => {
      const designWidth = webpack.resourcePath.includes(path.join('node_modules', 'vant')) ? 375 : 750;
      return {
        plugins: {
          'postcss-px-to-viewport': {
            viewportWidth: designWidth, // 视窗的宽度,对应的是我们设计稿的宽度,一般是750
            // viewportHeight: 1334, // 视窗的高度,根据750设备的宽度来指定,一般指定1334,也可以不配置
          },
        }
      }
    } 
    
    //vite.config.ts
    pxToViewport({
        unitToConvert: 'px', // 要转化的单位
        viewportWidth: file => (join(file).includes(join('node_modules', 'vant')) ? 375 : 750), // UI设计稿的宽度
        unitPrecision: 6, // 转换后的精度,即小数点位数
        propList: ['*'], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
        viewportUnit: 'vw', // 指定需要转换成的视窗单位,默认vw
        fontViewportUnit: 'vw', // 指定字体需要转换成的视窗单位,默认vw
        selectorBlackList: [], // 指定不转换为视窗单位的类名,
        minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
        mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
        // replace: true, // 是否直接更换属性值,而不添加备用属性
        exclude: [/^(?!.*node_modules\/vant)(?!.*__uno\.css)/], // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
        // include: undefined, // 如果设置了include,那将只有匹配到的文件才会被转换
        landscape: false // 是否处理横屏情况
    })
    

    注意:这里使用path.join('node_modules', 'vant')是因为适应不同的操作系统,在mac下结果为node_modules/vant,而在windows下结果为node_modules\vant

    • Vant组件的设计稿尺寸是375px,可用通过覆盖:root下的Vant的css变量中px单位的方式,对Vant组件做适配

七. 引入Unocss

  1. pnpm add -D unocss

  2. vite.config.ts

    // vite.config.ts
    import UnoCSS from 'unocss/vite'
    import { defineConfig } from 'vite'
    
    export default defineConfig({
      plugins: [
        UnoCSS(),
      ],
    })
    
  3. 创建 uno.config.ts 文件:

    // uno.config.ts
    import { defineConfig, presetTypography, presetUno } from 'unocss';
    import presetRemToPx from '@unocss/preset-rem-to-px';
    
    export default defineConfig({
        //  排除
        content: {
            pipeline: {
                exclude: ['node_modules']
            }
        },
        // ...UnoCSS options
        presets: [
            //  默认预设
            presetUno(),
            //  文字排版预设
            presetTypography(),
            presetRemToPx({
                baseFontSize: 4 // 设置为4,实现w-1=1px
            })
        ],
        /** 自定义规则 */
        rules: [
            // ['font-bold', { fontWeight: 'bold' }],
            // ['text-base', { fontSize: '16px'}]
        ],
        /** 自定义快捷方式 */
        shortcuts: {
            'm-0-auto': 'm-0 ma', // margin: 0 auto
            'wh-full': 'w-full h-full', // width: 100%, height: 100%
            'flex-center': 'flex justify-center items-center', // flex布局居中
            'flex-x-center': 'flex justify-center', // flex布局:主轴居中
            'flex-y-center': 'flex items-center', // flex布局:交叉轴居中
            'text-overflow': 'overflow-hidden whitespace-nowrap text-ellipsis', // 文本溢出显示省略号
            'text-break': 'whitespace-normal break-all break-words' // 文本溢出换行
        }
    });
    
    
  4. 将 virtual:uno.css 添加到您的主入口文件:

    // main.ts
    import 'virtual:uno.css'
    
  5. 使用插件 @unocss/preset-rem-to-px,这个插件的作用就是将 unocss 的预设单位rem转换成px

    • pnpm add @unocss/preset-rem-to-px -D

六. 封装Axios

src同级新建untils文件夹,创建request.ts文件。即utils/request.ts 。。。。。没写完