Vite3搭建Vue3项目

Vite3创建项目

  1. 创建:pnpm create vite editor --template vue
  2. 配置:
    /* vite.config.js */
    import { defineConfig } from 'vite';
    import { resolve } from 'path';
    import vue from '@vitejs/plugin-vue';
    
    export default defineConfig({
        base: './',
        plugins: [
            vue(),
        ],
        resolve: {
            alias: {
                '@': resolve(__dirname, './src') ,
            },
        },
        server: {
            // 是否开启 https
            https: false,
            // 端口号
            port: 3000,
            // 监听所有地址
            host: '0.0.0.0',
            // 服务启动时是否自动打开浏览器
            open: true,
            // 允许跨域
            cors: true,
            // 自定义代理规则
            proxy: {},
        },
        build: {
            // 设置最终构建的浏览器兼容目标
            target: 'es2015',
            // 构建后是否生成 source map 文件
            sourcemap: false,
            //  chunk 大小警告的限制(以 kbs 为单位)
            chunkSizeWarningLimit: 2000,
            // 启用/禁用 gzip 压缩大小报告
            reportCompressedSize: false,
        },
    });
    

目录结构

├── dist/
└── src/
    ├── api/                       // 接口请求目录
    ├── assets/                    // 静态资源目录
    ├── common/                    // 通用类库目录
    ├── components/                // 公共组件目录
    ├── router/                    // 路由配置目录
    ├── store/                     // 状态管理目录
    ├── style/                     // 通用样式目录
    ├── utils/                     // 工具函数目录
    ├── views/                     // 页面组件目录
    ├── App.vue
    ├── main.js
├── tests/                         // 单元测试目录
├── index.html
├── jsconfig.json                  // JavaScript 配置文件
├── vite.config.js                 // Vite 配置文件
└── package.json
└── pnpm-workspace.yaml            // 工作空间

pnpm 工作空间

创建 pnpm-workspace.yaml

packages:
  - 'src/*'

vue-router

  1. 安装:pnpm add vue-router -w
  2. 目录
    └── src/
        ├── router/
            ├── index.js
            ├── modules/          // 各路由模块目录
                ├── index.js      // 集成导出各路由模块
                ├── test.js
                ├── ...
    
  3. 定义 router
    /* src/router/index.js */
    import { createRouter, createWebHistory } from "vue-router";
    import modules from './modules';
    
    const routes = [...modules];
    
    const router = createRouter({
        history: createWebHistory(import.meta.env.BASE_URL),
        routes,
        scrollBehavior(){
            return {
                el: '#app',
                top: 0,
                behavior: 'smooth',
            };
        },
    });
    
    export default router;
    
  4. 集成
    /* src/main.js */
    import router from './router';
    
    const app = createApp(App);
    app.use(router);
    

Pinia

  1. 安装:pnpm add pinia -w
    • pinia 没有 modules 概念
    • pinia 没有 mutations 概念
    • pinia 的 actions 可同步可异步
    • 定义:
      /* src/store/modules/test.js */
      import { defineStore } from 'pinia';
      
      /**
      * import { useStore } from '@/store'
      * const store = useStore()
      * 重置store:store.$reset()
      * sotre.$patch({}) / store.$patch((state) => {})
      *
      */
      export const useTestStore = defineStore('test', {
          state: () => ({}),
          // getters 可以用来进行一些计算的操作
          getters: {
      
          },
          // 没有 mutation
          // 没有 modules
          // actions 可以是同步也可以是异步
          // actions 异步调用接口,处理响应结果
          actions: {
              test(){
                  // 执行一些操作
              }
          }
      });
      
      // 扁平化,不再使用 modules
      export const useToDoStore = defineStore('todo', {});
      
    • 使用
      <script setup>
          import { useTestStore } from '@/store';
      
          const testStore = useTestStore;
      
          // 调用 test actions
          testStore.test();
      </script>
      
  2. 目录
    └── src/
        ├── store/
            ├── index.js
            ├── modules/
                ├── index.js
                ├── test.js
                ├── ...
    
  3. 定义 store
    /* src/store/index.js */
    import { createPinia } from "pinia";
    
    const store = createPinia();
    
    export default store;
    export * from './modules';
    
  4. 集成
    /* src/main.js */
    import store from './store';
    
    const app = createApp(App);
    app.use(store);
    

element-plus

  1. 安装:pnpm add element-plus -w
  2. 按需引入:pnpm add -w -D unplugin-vue-components unplugin-auto-import
    /* vite.config.ts */
    import { defineConfig } from 'vite';
    import AutoImport from 'unplugin-auto-import/vite';
    import Components from 'unplugin-vue-components/vite';
    import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
    
    export default defineConfig({
        // ...
        plugins: [
            // ...
            AutoImport({
            resolvers: [ElementPlusResolver()],
            }),
            Components({
            resolvers: [ElementPlusResolver()],
            }),
        ],
    });
    
    使用组件时不需要再导入。
  3. 全局配置
    <!-- src/App.vue -->
    <template>
        <el-config-provider :size="size" :z-index="zIndex">
            <router-view />
        </el-config-provider>
    </template>
    
    <script setup>
        const zIndex = ref(3000);
        const size = ref('small');
    </script>
    

axios

  1. 安装:pnpm add axios -w
  2. 封装
    /* src/utils/request.js */
    import axios from 'axios';
    
    // 创建请求实例
    const instance = axios.create({
        baseURL: '/api',
        // 指定请求超时的毫秒数
        timeout: 1000,
        // 表示跨域请求时是否需要使用凭证
        withCredentials: false,
    });
    
    // 前置拦截器(发起请求之前的拦截)
    instance.interceptors.request.use(
        (config) => {
            /**
            * 在这里一般会携带前台的参数发送给后台,比如下面这段代码:
            * const token = getToken()
            * if (token) {
            *  config.headers.token = token
            * }
            */
            return config;
        },
        (error) => {
            return Promise.reject(error);
        },
    );
    
    // 后置拦截器(获取到响应时的拦截)
    instance.interceptors.response.use(
        (response) => {
            /**
            * 根据你的项目实际情况来对 response 和 error 做处理
            * 这里对 response 和 error 不做任何处理,直接返回
            */
            return response;
        },
        (error) => {
            const { response } = error;
            if (response && response.data) {
            return Promise.reject(error);
            }
            const { message } = error;
            console.error(message);
            return Promise.reject(error);
        },
    );
    

less

vite 内置 less,仅需安装即可

  1. 安装:pnpm add less -w -D
  2. 全局样式:
    /* vite.config.js */
    export default defineConfig({
        css: {
            preprocessorOptions: {
                less: {
                    javascriptEnabled: true,
                    additionalData: `@import "${resolve(__dirname, 'src/style/variables.less')}";`
                }
            }
        }
        //   css: {
        //     preprocessorOptions: {
        //       less: {
        //         modifyVars: {
        //           hack: `true; @import (reference) "${resolve('src/style/variables.less')}";`,
        //         },
        //         math: 'strict',
        //         javascriptEnabled: true,
        //       },
        //     },
        //   },
    });
    
    创建 src/style/variables.less

EditorConfig

EditorConfig helps maintain consistent coding styles for multiple developers working on the same project across various editors and IDEs.

EditorConfig帮助跨不同编辑器和ide从事同一项目的多个开发人员维护一致的编码风格。

  1. VScode 安装插件 EditorConfig for VSCode
  2. 配置( .editorconfig ):
     # .editorconfig
    
     # 表示最顶层的 EditorConfig 配置文件
     root = true
    
     # 表示所有文件适用
     [*]
    
     # 缩进风格(space|tab|unset)
     indent_style = space
    
     # 控制换行类型(lf|cr|crlf|unset)
     end_of_line = lf
    
     # 设置文件字符集 utf-8
     charset = utf-8
    
     # 去除行首的任意空白字符
     trim_trailing_whitespace = true
    
     # 始终在文件末尾插入一个新行
     insert_final_newline = true
    
    
    
     # 表示 *.md 文件适用以下规则
     [*.md]
    
     max_line_length = off
     trim_trailing_whitespace = false
    
    
    
     # 表示仅 ts、js、vue、css 文件适用以下规则
     [*.{ts,js,vue,css}]
     indent_size = 4
    

eslint

ESLint 可组装的JavaScript和JSX检查工具

  1. 安装

    • ESLint: ESLint 本体
    • eslint-define-config: 改善 ESLint 规范编写体验
    • eslint-plugin-vue: 适用于 Vue 文件的 ESLint 插件
    • eslint-config-airbnb-base: Airbnb JavaScript 风格指南
    • eslint-plugin-import: 使用 eslint-config-airbnb-base 时必须安装的前置插件
    • vue-eslint-parser: 使用 eslint-plugin-vue 时必须安装的 ESLint 解析器
    pnpm add -w eslint eslint-define-config eslint-config-airbnb-base eslint-plugin-import eslint-plugin-vue vue-eslint-parser -D
    
  2. VSCode 安装插件 ESLint

  3. 配置( .eslintrc.js

    /* .eslintrc.js */
    const { defineConfig } = require('eslint-define-config');
    
    module.exports = defineConfig({
        root: true,
        env: {
            browser: true,
            jest: true,
            node: true,
            es6: true
        },
        plugins: ['vue'],
        parser: 'vue-eslint-parser',
        parserOptions: {
            ecmaVersion: 'latest',
            sourceType: 'module',
            allowImportExportEverywhere: true,
            ecmaFeatures: {
                jsx: true,
            },
        },
        extends: [
            'airbnb-base',
            'eslint:recommended',
            'plugin:vue/vue3-essential',
            'plugin:vue/vue3-recommended',
            // 解决 prettier 冲突
            'plugin:prettier/recommended',
        ],
        rules: {
            // 禁止使用多余的包
            'import/no-extraneous-dependencies': 0,
            // 确保在导入路径内一致使用扩展名
            'import/extensions': 0,
            // 确保导入指向可以解析的文件/模块
            'import/no-unresolved': 0,
            // 首选默认导出导入/首选默认导出
            'import/prefer-default-export': 0,
            // 要求使用 let/const,而不是 var
            'no-var': 'error',
            // 禁止使用 new 以避免产生副作用
            'no-new': 1,
            // 禁止变量声明与外层作用域变量同名
            'no-shadow': 0,
            // 禁用 console
            'no-console': 0,
            // 禁止标识符中有悬空下划线
            'no-underscore-dangle': 0,
            // 禁止在可能与比较操作符相混淆的地方使用箭头函数
            'no-confusing-arrow': 0,
            // 禁用一元操作符 ++ 和 --
            'no-plusplus': 0,
            // 禁止对 function 参数进行重新赋值
            'no-param-reassign': 0,
            // 禁用特定的语法
            'no-restricted-syntax': 0,
            // 禁止在变量定义之前使用它们
            'no-use-before-define': 0,
            // 禁止直接调用 Object.prototypes 的内置属性
            'no-prototype-builtins': 0,
            // 禁止可以在有更简单的可替代的表达式时使用三元操作符
            'no-unneeded-ternary': 'error',
            // 禁止重复模块导入
            'no-duplicate-imports': 'error',
            // 禁止在对象中使用不必要的计算属性
            'no-useless-computed-key': 'error',
            // 强制使用一致的缩进(4个空格)
            indent: ['error', 4],
            // 强制使用驼峰式写法
            camelcase: 0,
            // 强制类方法使用 this
            'class-methods-use-this': 0,
            // 要求构造函数首字母大写
            'new-cap': 0,
            // 强制一致的使用 function 声明函数或表达式
            'func-style': 0,
            // 强制一行的最大长度
            'max-len': 0,
            // 要求 return 语句要么总是指定返回的值,要么不指定
            'consistent-return': 0,
            // 强制 switch 要有 default 分支
            'default-case': 2,
            // 强制剩余和扩展运算符及其表达式之间有空格
            'rest-spread-spacing': 'error',
            // 要求使用 const 声明那些声明后不再被修改的变量
            'prefer-const': 'error',
            // 强制箭头函数的箭头前后使用一致的空格
            'arrow-spacing': 'error',
        },
        // overrides: [
        //     {
        //         file: ['*.vue'],
        //         rules: {
        //             // 要求组件名称总是多个单词
        //             'vue/multi-word-component-names': 0,
        //         }
        //     }
        // ]
    });
    

prettier

prettier 是代码格式化工具

  1. VSCode 安装插件 Prettier - Code formatter

  2. 安装:pnpm add -w prettier -D

  3. 配置( .prettierrc.js

    /* .prettierrc.js */
    module.exports = {
        // 一行最多 120 个字符
        printWidth: 120,
        // 不用 tab,用空格
        useTabs: false,
        // 缩进4个空格
        tabWidth: 4,
        // 行尾要有分号
        semi: true,
        // 使用单引号
        singleQuote: true,
        // 对象的 key 仅在必要时用双引号
        jsxSingleQuote: false,
        // 末尾需要有逗号
        trailingComma: 'all',
        // 大括号内的首尾需要空格
        bracketSpacing: true,
        // jsx 标签的反尖括号需要换行
        jsxBracketSameLine: false,
        // 箭头函数,只有一个参数的时候,也需要写括号
        arrowParens: 'always',
        // 每个文件格式化的范围是文件的全部内容
        rangeStart: 0,
        rangeEnd: Infinity,
        // 不需要写文件开头的 @prettier
        requirePragma: false,
        // 不需要自动在开头插入 @prettier
        insertPragma: false,
        // 使用默认的折行标准
        proseWrap: 'preserve',
        // 根据显示样式决定 html 要不要折行
        htmlWhitespaceSensitivity: 'css',
        // vue 文件中的 script 和 style 内不用缩进
        vueIndentScriptAndStyle: false,
        // 换行符使用 lf
        endOfLine: 'lf',
        // 格式化嵌入的内容
        embeddedLanguageFormatting: 'auto',
        // html, vue, jsx 中的每个属性占一行
        singleAttributePerLine: false,
    }
    
  4. 过滤( .prettierignore

    ## OS
    .DS_Store
    .idea
    .editorconfig
    pnpm-lock.yaml
    .npmrc
    
    # Ignored suffix
    *.log
    *.md
    *.svg
    *.png
    *.ico
    *ignore
    
    ## Local
    .husky
    
    ## Built-files
    .cache
    dist
    
  5. 解决与 ESLint 冲突

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

stylelint

  1. 安装:pnpm add -w -D stylelint stylelint-config-standard stylelint-config-prettier stylelint-config-recommended-vue

  2. 配置( .stylelintrc.js

    module.exports = {
        root: true,
        defaultSeverity: 'error',
        extends: [
            'stylelint-config-standard',
            'stylelint-config-prettier',
        	'stylelint-config-recommended-vue',
        ],
        plugins: ['stylelint-order'],
        rules: {
            // 不允许未知函数
            'function-no-unknown': null,
            // 指定类选择器的模式
            'selector-class-pattern': null,
            // 禁止空源码
            'no-empty-source': null,
            // 指定字符串使用单引号
            'string-quotes': 'single',
            // 禁止未知的@规则
            'at-rule-no-unknown': [
                true,
                {
                    ignoreAtRules: [
                        'tailwind',
                        'apply',
                        'variants',
                        'responsive',
                        'screen',
                        'function',
                        'if',
                        'each',
                        'include',
                        'mixin',
                    ],
                },
            ],
            // 指定@规则名的大小写
            'at-rule-name-case': 'lower',
            // 指定缩进
            indentation: [
                2,
                {
                    severity: 'warning',
                },
            ],
            // 禁止未知的伪类选择器
            'selector-pseudo-class-no-unknown': [
                true,
                {
                    ignorePseudoClasses: ['global'],
                },
            ],
            // 禁止未知的伪元素选择器
            'selector-pseudo-element-no-unknown': [
                true,
                {
                    ignorePseudoElements: ['v-deep'],
                },
            ],
            'order/properties-order': [
                'position',
                'top',
                'right',
                'bottom',
                'left',
                'z-index',
                'display',
                'justify-content',
                'align-items',
                'float',
                'clear',
                'overflow',
                'overflow-x',
                'overflow-y',
                'margin',
                'margin-top',
                'margin-right',
                'margin-bottom',
                'margin-left',
                'padding',
                'padding-top',
                'padding-right',
                'padding-bottom',
                'padding-left',
                'width',
                'min-width',
                'max-width',
                'height',
                'min-height',
                'max-height',
                'font-size',
                'font-family',
                'font-weight',
                'border',
                'border-style',
                'border-width',
                'border-color',
                'border-top',
                'border-top-style',
                'border-top-width',
                'border-top-color',
                'border-right',
                'border-right-style',
                'border-right-width',
                'border-right-color',
                'border-bottom',
                'border-bottom-style',
                'border-bottom-width',
                'border-bottom-color',
                'border-left',
                'border-left-style',
                'border-left-width',
                'border-left-color',
                'border-radius',
                'text-align',
                'text-justify',
                'text-indent',
                'text-overflow',
                'text-decoration',
                'white-space',
                'color',
                'background',
                'background-position',
                'background-repeat',
                'background-size',
                'background-color',
                'background-clip',
                'opacity',
                'filter',
                'list-style',
                'outline',
                'visibility',
                'box-shadow',
                'text-shadow',
                'resize',
                'transition',
            ],
        },
        overrides: [
            {
                files: ['*.vue', '**/*.vue', '*.html', '**/*.html'],
                extends: ['stylelint-config-html'],
                rules: {
                    // 指定关键帧名称的模式
                    'keyframes-name-pattern': null,
                    // 禁止未知的伪类选择器
                    'selector-pseudo-class-no-unknown': [
                        true,
                        {
                            ignorePseudoClasses: ['deep', 'global'],
                        },
                    ],
                    // 禁止未知的伪元素选择器
                    'selector-pseudo-element-no-unknown': [
                        true,
                        {
                            ignorePseudoElements: ['v-deep', 'v-global', 'v-slotted'],
                        },
                    ],
                },
            },
            {
                files: ['*.less', '**/*.less'],
                customSyntax: 'postcss-less',
                extends: ['stylelint-config-standard', 'stylelint-config-recommended-vue'],
            },
        ],
    }
    
  3. 忽略检测( .stylelintignore

    # .stylelintignore
    # 旧的不需打包的样式库
    *.min.css
    
    # 其他类型文件
    *.js
    *.jpg
    *.woff
    
    # 测试和打包目录
    /test/
    /dist/*
    /public/*
    public/*
    /node_modules/
    
  4. VSCode 安装插件 Stylelint


husky

You can use it to lint your commit messages, run tests, lint code, etc… when you commit or push. Husky supports all Git hooks.

您可以使用它来检测提交消息、运行测试、检测代码等。当你承诺或推动的时候。Husky支持所有Git钩子。

如果没有 npx 命令,执行 cnpm install -g npx 安装

  1. 安装(自动):pnpm dlx husky-init && pnpm install

  2. lint-staged

    只需要用 ESLint 修复此次写的代码,而不去影响其他的代码,此时需要借助 lint-staged 工具。

    lint-staged 一般结合 husky 来使用,它可以让 husky 的 hook 触发的命令只作用于 git 暂存区的文件,而不会影响到其他文件。

    1. 安装:pnpm add -w lint-staged -D

    2. 配置( package.json

      {
          // "husky": {
          //     "hooks": {
          //         "pre-commit": "lint-staged",
          //         "commit-msg": "npx --no-install commitlint --edit $1"
          //     }
          // },
          "lint-staged": {
              "*.{js,jsx,ts,tsx}": [
                  "prettier --write",
                  "eslint --fix"
              ],
              "*.vue": [
                  "prettier --write",
                  "eslint --fix",
                  "stylelint --fix"
              ],
              "*.{html,vue,vss,sass,less}": [
                  "prettier --write",
                  "stylelint --fix"
              ],
              "package.json": [
                  "prettier --write"
              ],
              "*.md": [
                  "prettier --write"
              ]
          }
      }
      
    3. Hook(pre-commit)

      npx husky add .husky/pre-commit  'npx lint-staged'
      
  3. git-cz

    规范提交

    1. 安装:
      cnpm install -g git-cz commitizen
      pnpm add -w git-cz -D
      
    2. 配置( package.json
    {
        "config": {
            "commitizen": {
                "path": "git-cz"
            }
        }
    }
    
    1. 配置 script( package.json
    {
        "scripts": {
            "commit": "git-cz"
        }
    }
    
    1. 自定义git-cz配置(changelog.config.js
    /* 修改提示 */
    module.exports = {
        disableEmoji: false,
        format: '{type}{scope}: {emoji}{subject}',
        list: ['test', 'feat', 'fix', 'chore', 'docs', 'refactor', 'style', 'ci', 'perf'],
        maxMessageLength: 64,
        minMessageLength: 3,
        questions: ['type', 'scope', 'subject', 'body', 'breaking', 'issues', 'lerna'],
        scopes: [],
        types: {
            chore: {
                description: 'Build process or auxiliary tool changes',
                emoji: '🤖',
                value: 'chore',
            },
            ci: {
                description: 'CI related changes',
                emoji: '🎡',
                value: 'ci',
            },
            docs: {
                description: 'Documentation only changes',
                emoji: '✏️',
                value: 'docs',
            },
            feat: {
                description: 'A new feature',
                emoji: '🎸',
                value: 'feat',
            },
            fix: {
                description: 'A bug fix',
                emoji: '🐛',
                value: 'fix',
            },
            perf: {
                description: 'A code change that improves performance',
                emoji: '⚡️',
                value: 'perf',
            },
            refactor: {
                description: 'A code change that neither fixes a bug or adds a feature',
                emoji: '💡',
                value: 'refactor',
            },
            release: {
                description: 'Create a release commit',
                emoji: '🏹',
                value: 'release',
            },
            style: {
                description: 'Markup, white-space, formatting, missing semi-colons...',
                emoji: '💄',
                value: 'style',
            },
            test: {
                description: 'Adding missing tests',
                emoji: '💍',
                value: 'test',
            },
            messages: {
                type: "Select the type of change that you're committing:",
                customScope: 'Select the scope this component affects:',
                subject: 'Write a short, imperative mood description of the change:\n',
                body: 'Provide a longer description of the change:\n ',
                breaking: 'List any breaking changes:\n',
                footer: 'Issues this commit closes, e.g #123:',
                confirmCommit: 'The packages that this commit has affected\n',
            },
        },
    };
    
    1. 提交代码:pnpm commit

WARNING

参考文章
我的项目地址

商业转载请联系本人,非商业转载请注明出处。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值