zoukankan      html  css  js  c++  java
  • 你在寻找Vue3移动端项目框架嘛?请看这里

    现在web开发变得更加美妙高效,在于开发工具设计得更好了,丰富性与易用性,都有所提高。丰富性带来了一个幸福的烦恼,就是针对实际应用场景,如何选择工具 ?

    1. Vue Cli和Vite之间的选择

    Vite的开发环境体验好,基于浏览器原生ES6 Modules提供的功能,不对ES高版本语法进行转译,省略掉耗时的打包流程, 可是考虑到:

    1) 项目要用到真机调试功能,开发环境下调试代码时不能使用ES高版本的语法,用着不顺畅。

    后面发现可用@vitejs/plugin-legacy解决此问题。

    import legacy from '@vitejs/plugin-legacy';

    2) 受制于历史项目包袱,感受到Vite的一些痛点:

    • Vite最新版2.7.x版本自带的less-loader, 将背景色的rgba属性转换成四位16进制在有些手机上存在兼容性问题。
    • 与某些第三方工具库(比如说Cache-Router)不兼容,编译会报错。
    • Vite的缓存机制,有时候让人有些困惑,代码修改了,重启之后都不生效,要手动删除node_modules下的.vite文件夹才生效。 
    • 给命令行动态添加自定义参数不太方便。
    • Vite不支持装饰器语法,而有的第三方库用到了装饰器语法

    3) Vite脚手架默认不集成TypeScript,Vue-Router,Vuex功能,使用起来不太方便

    4) Vue Cli作为久经考验的成熟构建工具,稳定坑少,使用者众多,在生态环境和插件数量方面更好。

    所以最终选择vue-cli最为Vue项目的脚手架。若是新项目,个人还是比较推荐使用Vite,构建速度确实快。

    安装最新版本vue脚手架

    npm install -g @vue/cli@next

    安装成功后通过查看版本命令,确认是否安装成功

    vue -V
    @vue/cli 5.0.0-rc.1

    2 创建vue3项目

    vue create vue3-demo

    Vue CLI v5.0.0-rc.1
    ? Please pick a preset:
      Default ([Vue 2] babel, eslint)
      Default (Vue 3) ([Vue 3] babel, eslint) // 不选择默认的vue3配置,是因为没有vue-router+typescript功能,需要自己引入
    > Manually select features // 手动选择特性

    Vue CLI v5.0.0-rc.1
    ? Please pick a preset: Manually select features
    ? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed)
    >(*) Choose Vue version
     (*) Babel               // 添加babel
     (*) TypeScript          // 添加类型约束功能
     ( ) Progressive Web App (PWA) Support
     (*) Router              // 添加路由功能
     (*) Vuex                // 添加状态管理功能
     (*) CSS Pre-processors  // 添加样式预编译功能  
     (*) Linter / Formatter  // 添加代码质量校验提示和格式化功能
     ( ) Unit Testing
     ( ) E2E Testing
    Vue CLI v5.0.0-rc.1
    ? Please pick a preset: Manually select features
    ? Check the features needed for your project: Choose Vue version, Babel, TS, Router, Vuex, CSS Pre-processors, Linter
    ? Choose a version of Vue.js that you want to start the project with
      2.x
    > 3.x    // 选择vue3
    Vue CLI v5.0.0-rc.1
    ? Please pick a preset: Manually select features
    ? Check the features needed for your project: Choose Vue version, Babel, TS, Router, Vuex, CSS Pre-processors, Linter
    ? Choose a version of Vue.js that you want to start the project with 3.x
    ? Use class-style component syntax? (y/N) N  // 是否使用class组件语法, ,选N  项目中用Composition API

     为了在Vue中使用TypeScript中,许多开发者选择了Class-Style Component 解决方案,时至今日,还有另外一个方案,Composition API 撰写的代码会完美享用类型推导,并且也不用做太多额外的类型标注。这也同样意味着你写出的 JavaScript 代码几乎就是 TypeScript 的代码。即使是非 TypeScript 开发者也会因此得到更好的 IDE 类型支持而获益。

    常规风格

    export default {
        data(){
            return {
                selectOptions: ['A1', 'A2'],
                results: [],
                // ...
            }
        }
    }

    class 组件风格

    import { Vue, Component } from 'vue-property-decorator'
    @Component
    export default class Game extends Vue {
        // 定义data
      private selectOptions = ['A1', 'A2']
      private results: string[] = []
        ...
    }
    ? Use class-style component syntax? Yes
    
    ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes  // 是否使用babel工具自动为转换后的 TypeScript 代码注入 polyfiills,此处选择 Y 
    
    ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes   // 使用history网址路径风格,hash路径有点丑陋
    
    ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Less    // sass在国内安装经常出错,所以选less
    
    ? Pick a linter / formatter config: Prettier  // 校验配置选择 eslint+prettier组合,沿袭项目使用习惯
    
    ? Pick additional lint features: Lint on save // 保存代码时校验代码质量, 提交代码时才去校验代码质量有些滞后
    
    ? Where do you prefer placing config for Babel, ESLint, etc. In dedicated config files // 将Babel,ESlint等配置文件从package.json中独立出来,因为json文件不能写注释
    
    ? Save this as a preset for future projects? Y // 将此配置保存起来,用于将来的项目 ,下次用vue-cli生成项目时,可以看到之前保存的配置项

    启动服务

    cd vue3-demo && yarn serve

    在VSCode中打开app.vue发现文件中有许多红色的告警波浪线,安装Volar扩展,,绝大多数语法报错消失。顺便说一下为什么要使用Volar扩展,Vetur对<script setup>里面定义的响应式变量支持度不够好。

    <script setup>
    // ...
    // 仅用于template,未在script中被使用,会报 count is declared but its value is never read.Vetur(6133)
    const count = ref(1)
    //...
    </script>

    3 配置vue文件保存时自动格式化

    代码美化功能,是一个重要的影响开发体验的指标。书写潦草的代码,按下Ctrl+S保存之后,瞬间变成整洁有序, 这种视觉感受,让人神清气爽。

    在项目下新建.vscode/settings.json,内容如下: 

    {
      // ...
      "editor.formatOnSave": true,
      "editor.defaultFormatter": "esbenp.prettier-vscode",
      "[vue]": {
        "editor.defaultFormatter": "johnsoncodehk.volar"
      },
      "[json]": {
        "editor.defaultFormatter": "vscode.json-language-features"
      },
      // ...
    }

    修改项目下的.prettierrc文件为.prettierrc.js, 内容如下:

    module.exports = {
      // 1.一行代码的最大字符数,默认是80(printWidth: <int>)
      printWidth: 120,
      // 2.tab宽度为2空格(tabWidth: <int>)
      tabWidth: 2,
      // 3.是否使用tab来缩进,我们使用空格(useTabs: <bool>)
      useTabs: false,
      // 4.结尾是否添加分号
      semi: true,
      // 5.使用单引号(singleQuote: <bool>)
      singleQuote: true,
      // 6.object对象中key值是否加引号(quoteProps: "<as-needed|consistent|preserve>")as-needed只有在需求要的情况下加引号,consistent是有一个需要引号就统一加,preserve是保留用户输入的引号
      quoteProps: 'as-needed',
      // 7.在jsx文件中的引号需要单独设置(jsxSingleQuote: <bool>)
      jsxSingleQuote: false,
      // 8.尾部逗号设置,es5是尾部逗号兼容es5,none就是没有尾部逗号,all是指所有可能的情况,需要node8和es2017以上的环境。(trailingComma: "<es5|none|all>")
      trailingComma: 'all',
      // 9.object对象里面的key和value值和括号间的空格(bracketSpacing: <bool>)
      bracketSpacing: true,// 10.箭头函数单个参数的情况是否省略括号,默认always是总是带括号(arrowParens: "<always|avoid>")
      arrowParens: 'always',
      // 11.range是format执行的范围,可以选执行一个文件的一部分,默认的设置是整个文件(rangeStart: <int>  rangeEnd: <int>)
      rangeStart: 0,
      rangeEnd: Infinity,
      // 12. requirePragma: <bool>,格式化有特定开头编译指示的文件 比如下面两种
      /**
       * @prettier
       */
      // or
      /**
       * @format
       */
      requirePragma: false,
      // 13.insertPragma: <bool> 自动插入pragma到已经完成的format的文件开头
      insertPragma: false,
      // 14. proseWrap: "<always|never|preserve>" 文章换行,默认情况下会对你的markdown文件换行 进行format会控制在printwidth以内
      proseWrap: 'always',
      // 15. htmlWhitespaceSensitivity: "<css|strict|ignore>" html中的空格敏感性
      // html文档片段 1<b>2</b>3 原本显示为123, 不设置忽略空格的话格式化后会变成 1<b> 2 </b>3 显示为1 2 3
      htmlWhitespaceSensitivity: 'ignore',
      // 16. vue script和style标签中是否缩进,开启可能会破坏编辑器的代码折叠
      vueIndentScriptAndStyle: false,
      // 17. endOfLine: "<lf|crlf|cr|auto>" 行尾换行符,默认是lf,
      endOfLine: 'lf',
      // 18. 控制被引号包裹的代码是否进行格式化, 默认是auto,
      embeddedLanguageFormatting: 'off'
    }

    4 配置移动端UI库

    做移动端开发,虽然定制性比较强。绝大多数UI库组件都用不到,但像Toast,Modal,Picker,Form,PullRefresh等组件几乎是必用,所以需要引入移动端UI库。

    vue3移动端UI库的选择:

    antd-mobile-vue-next 移入项目之后,编译报错
    Vux UI风格是绿色系,与现有项目使用的蓝色系风格UI不符,  所以没用
    Vant 是业界主流的移动端组件库之一,UI色系风格与历史项目相符,支持vue3,组件功能优于Vux,已Toast为例,Vant提供了网络加载的Toast, Vux未提供。Vant总共提供了69个(不含组合api)涵盖基础,表单,反馈,展示,导航,业务六大类组件。
     yarn add vant@3

    按需引入

    按需加载需要借助babel-plugin-import, 这样就可以只引入需要的组件,以减小项目体积

    yarn add babel-plugin-import -D

     对babel.config.js进行配置

    module.exports = {
      presets: ["@vue/cli-plugin-babel/preset"],
      plugins: [
        [
          "import",
          {
            libraryName: "vant",
            libraryDirectory: "es",
            style: true,
          },
          "vant",
        ],
      ],
    };

     main.js中引入vant的样式

    import { createApp } from "vue";
    import App from "./App.vue";
    import "vant/lib/index.css";
    createApp(App).mount("#app");

    在App.vue中引入组件

    <template>
      <div>
        <Button type="primary">主要按钮</Button>
        <img alt="Vue logo" src="./assets/logo.png" />
        <HelloWorld msg="Welcome to Your Vue.js App" />
      </div>
    </template>
    
    <script>
    import HelloWorld from "./components/HelloWorld.vue";
    import { Button } from "vant";
    export default {
      name: "App",
      components: {
        HelloWorld,
        Button,
      },
    };
    </script>

     5 配置开发环境请求代理

    请求代理是解决本地开发请求跨域的最佳方式之一,对前后端代码都没有侵入性。  在vue.config.js中添加代理转发配置:

    const { defineConfig } = require("@vue/cli-service");
    module.exports = defineConfig({
      transpileDependencies: true,
      devServer: {
        port: 9000,
        host: "localhost",
        https: false,
        open: "/",
        proxy: {
          "/api": {
            target: "http://192.168.xx.xx:50000",
            secure: false,
            changeOrigin: true,
            logLevel: "debug",
          },
        },
      },
      // ....
    });

    6 配置路径别名

    项目统一使用路径别名,好处是在代码中不用写../../../之类让人看着有些云里雾里的文件引用路径,此外用短路径替代长路径,书写也更方便。而且编辑器对于别名路径也有提示,可以跳转。

    需要注意的是,如果使用了TypeScript,除了要在vue.config.js中配置路径别名之外,还需要在tsconfig.json配置路径别名,否则虽然打包编译不报错,但是代码编辑器却会提示引用路径有错误。

    vue.config.js路径别名配置

    const path = require('path');
    
    module.exports = {
        configureWebpack: {
            resolve: {
                alias: {
                    '@': path.join(__dirname, 'src/')
                }
            }
        }
    }

     tsconfig.json路径别名配置

    {
      "compilerOptions": {
        // ...
        "baseUrl": ".",
        "paths": {
          "@/*": ["src/*"],
        }
      },
      "include": [
        "src/**/*.ts",
        "src/**/*.tsx",
        "src/**/*.vue",
        // 包含自定义声明文件
        "typings/**/*.d.ts",
      ],
      // ...
    }

    7 设置自定义环境变量

    开发调试的时候,需要动态在命令行添加动态参数,用以执行开发环境的调试逻辑,将自定义的命令行参数传到业务文件的方法是:

    在package.json中传入自定义环境变量

    {
      // ...
      "scripts": {
        "start:wx": "ytt && vue-cli-service serve --mode local --wx true",
      // ...
      },
    }

    在vue.config.js中设置自定义环境变量

    // ...
    const webpack = require('webpack');
    const { defineConfig } = require('@vue/cli-service');
    const { wx, mode } = require('minimist')(process.argv.slice(2));
    console.log({ wx, mode });
    
    // console.log(process.env.VITE_API_HOST);
    module.exports = defineConfig({
      // ...
      configureWebpack: {
        plugins: [
          // 定义环境变量
          new webpack.DefinePlugin({
            'process.env.WX_JS_SDK_ENABLED': wx, // 是否真机调试SDK模式
            'process.env.CURRENT_ENV': JSON.stringify(mode),
          }),
        ],
      },
    });

    在业务文件中接收自定义环境变量

    import { createApp } from 'vue';
    import 'vant/lib/index.css';
    import App from './App.vue';
    import router from './router';
    import store from './store';
    
    console.log(process.env.WX_JS_SDK_ENABLED, process.env.CURRENT_ENV);
    
    createApp(App).use(store).use(router).mount('#app');

    8 配置stylelint校验规则

    stylelint的好处:

    • 可以发现样式书写问题,如无效的十六进制值;重复的选择器;未命名的动画名称;错误的线性渐变语法;后面的属性覆盖前面的属性;前面的选择器优先级更高,覆盖后面的属性;选择器下未设置任何属性等。
    • 能使所有人写的样式风格都一致,按照业内知名公司 (GitHub、Google、Airbnb)的样式规范要求写样式。
    • 保存时自动对样式书写进行优化(如采用样式的简写形式,删除无意义小数点前面的0,调整样式顺序等),修复可以修复的样式错误。

    1.安装依赖

    yarn  add -D stylelint stylelint-config-recess-order  stylelint-order stylelint-config-standard stylelint-less  stylelint-webpack-plugin postcss-html

    2. 创建.stylelintrc.js 样式校验规则

    module.exports = {
      plugins: ['stylelint-less'],
      extends: ['stylelint-order', 'stylelint-config-standard', 'stylelint-config-recess-order'],
      rules: {
        indentation: 2,
        'at-rule-no-unknown': [true, { ignoreAtRules: ['mixin', 'extend', 'content', 'include'] }],
        'no-empty-source': null, //  null是关闭规则的意思--less文件内容可以为空
        'no-descending-specificity': null, //禁止特异性较低的选择器在特异性较高的选择器之后重写
        'font-family-no-missing-generic-family-keyword': null, // 关闭必须设置通用字体的规则
        'property-no-unknown': [
          true,
          {
            ignoreProperties: ['box-flex'], // 忽略某些未知属性的检测
          },
        ],
        'selector-pseudo-element-no-unknown': [
          true,
          {
            ignorePseudoElements: ['ng-deep'], // 忽略ng-deep这种合法的伪元素选择器报警
          },
        ],
        'declaration-colon-newline-after': null, //一个属性过长的话可以写成多行
        'media-feature-name-no-unknown': null, // 关闭禁止未知的媒体功能名
        // 下面的排序规则是stylelint-config-recess-order的css排序规则,
        // 要对某个属性排序进行调整,这个属性之前的样式排序都要配置在自定义属性排序中
        'order/properties-order': [
          {
            // Must be first.
            properties: ['all'],
          },
          {
            // Position.
            properties: ['position', 'top', 'right', 'bottom', 'left', 'z-index'],
          },
          {
            // Display mode.
            properties: ['box-sizing', 'display'],
          },
          {
            // Flexible boxes.
            properties: ['flex', 'flex-basis', 'flex-direction', 'flex-flow', 'flex-grow', 'flex-shrink', 'flex-wrap'],
          },
          {
            // Grid layout.
            properties: [
              'grid',
              'grid-area',
              'grid-template',
              'grid-template-areas',
              'grid-template-rows',
              'grid-template-columns',
              'grid-row',
              'grid-row-start',
              'grid-row-end',
              'grid-column',
              'grid-column-start',
              'grid-column-end',
              'grid-auto-rows',
              'grid-auto-columns',
              'grid-auto-flow',
              'grid-gap',
              'grid-row-gap',
              'grid-column-gap',
            ],
          },
          {
            // Align.
            properties: ['align-content', 'align-items', 'align-self'],
          },
          {
            // Justify.
            properties: ['justify-content', 'justify-items', 'justify-self'],
          },
          {
            // Order.
            properties: ['order'],
          },
          {
            // Box model.
            properties: [
              'float',
              'width',
              'min-width',
              'max-width',
              'height',
              'line-height',
              'min-height',
              'max-height',
              'padding',
              'padding-top',
              'padding-right',
              'padding-bottom',
              'padding-left',
              'margin',
              'margin-top',
              'margin-right',
              'margin-bottom',
              'margin-left',
              'overflow',
              'overflow-x',
              'overflow-y',
              '-webkit-overflow-scrolling',
              '-ms-overflow-x',
              '-ms-overflow-y',
              '-ms-overflow-style',
              'clip',
              'clear',
            ],
          },
          {
            // Typography.
            properties: [
              'font',
              'font-family',
              'font-size',
              'font-style',
              'font-weight',
              'font-variant',
              'font-size-adjust',
              'font-stretch',
              'font-effect',
              'font-emphasize',
              'font-emphasize-position',
              'font-emphasize-style',
              '-webkit-font-smoothing',
              '-moz-osx-font-smoothing',
              'font-smooth',
              'hyphens',
              'color',
              'text-align',
              'text-align-last',
              'text-emphasis',
              'text-emphasis-color',
              'text-emphasis-style',
              'text-emphasis-position',
              'text-decoration',
              'text-indent',
              'text-justify',
              'text-outline',
              '-ms-text-overflow',
              'text-overflow',
              'text-overflow-ellipsis',
              'text-overflow-mode',
              'text-shadow',
              'text-transform',
              'text-wrap',
              '-webkit-text-size-adjust',
              '-ms-text-size-adjust',
              'letter-spacing',
              'word-break',
              'word-spacing',
              'word-wrap', // Legacy name for `overflow-wrap`
              'overflow-wrap',
              'tab-size',
              'white-space',
              'vertical-align',
              'list-style',
              'list-style-position',
              'list-style-type',
              'list-style-image',
            ],
          },
          {
            // Accessibility & Interactions.
            properties: [
              'pointer-events',
              '-ms-touch-action',
              'touch-action',
              'cursor',
              'visibility',
              'zoom',
              'table-layout',
              'empty-cells',
              'caption-side',
              'border-spacing',
              'border-collapse',
              'content',
              'quotes',
              'counter-reset',
              'counter-increment',
              'resize',
              'user-select',
              'nav-index',
              'nav-up',
              'nav-right',
              'nav-down',
              'nav-left',
            ],
          },
          {
            // Background & Borders.
            properties: [
              'background',
              'background-color',
              'background-image',
              "-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient",
              'filter:progid:DXImageTransform.Microsoft.gradient',
              'filter:progid:DXImageTransform.Microsoft.AlphaImageLoader',
              'filter',
              'background-repeat',
              'background-attachment',
              'background-position',
              'background-position-x',
              'background-position-y',
              'background-clip',
              'background-origin',
              'background-size',
              'background-blend-mode',
              'isolation',
              'border',
              'border-color',
              'border-style',
              'border-width',
              'border-top',
              'border-top-color',
              'border-top-style',
              'border-top-width',
              'border-right',
              'border-right-color',
              'border-right-style',
              'border-right-width',
              'border-bottom',
              'border-bottom-color',
              'border-bottom-style',
              'border-bottom-width',
              'border-left',
              'border-left-color',
              'border-left-style',
              'border-left-width',
              'border-radius',
              'border-top-left-radius',
              'border-top-right-radius',
              'border-bottom-right-radius',
              'border-bottom-left-radius',
              'border-image',
              'border-image-source',
              'border-image-slice',
              'border-image-width',
              'border-image-outset',
              'border-image-repeat',
              'outline',
              'outline-width',
              'outline-style',
              'outline-color',
              'outline-offset',
              'box-shadow',
              'mix-blend-mode',
              'filter:progid:DXImageTransform.Microsoft.Alpha(Opacity',
              "-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha",
              'opacity',
              '-ms-interpolation-mode',
            ],
          },
          {
            // SVG Presentation Attributes.
            properties: [
              'alignment-baseline',
              'baseline-shift',
              'dominant-baseline',
              'text-anchor',
              'word-spacing',
              'writing-mode',
    
              'fill',
              'fill-opacity',
              'fill-rule',
              'stroke',
              'stroke-dasharray',
              'stroke-dashoffset',
              'stroke-linecap',
              'stroke-linejoin',
              'stroke-miterlimit',
              'stroke-opacity',
              'stroke-width',
    
              'color-interpolation',
              'color-interpolation-filters',
              'color-profile',
              'color-rendering',
              'flood-color',
              'flood-opacity',
              'image-rendering',
              'lighting-color',
              'marker-start',
              'marker-mid',
              'marker-end',
              'mask',
              'shape-rendering',
              'stop-color',
              'stop-opacity',
            ],
          },
          {
            // Transitions & Animation.
            properties: [
              'transition',
              'transition-delay',
              'transition-timing-function',
              'transition-duration',
              'transition-property',
              'transform',
              'transform-origin',
              'animation',
              'animation-name',
              'animation-duration',
              'animation-play-state',
              'animation-timing-function',
              'animation-delay',
              'animation-iteration-count',
              'animation-direction',
            ],
          },
        ],
      },
    };

    编译时自动修复

    // ...
    const { defineConfig } = require('@vue/cli-service');
    const StylelintPlugin = require('stylelint-webpack-plugin');
    
    module.exports = defineConfig({
      // ...
      configureWebpack: {
        plugins: [
          // ...
          new StylelintPlugin({
            files: ['src/**/*.vue'],
            // 编译时自动修复
            fix: true,
            // 这样配才能修复vue文件style片段中的less语法
            customSyntax: 'postcss-html',
          }),
        ],
      },
    });

    安装VSCode stylelint扩展

    在.vscode/settings.json中配置保存代码时自动修复样式错误

    {
      "editor.codeActionsOnSave": {
        // ...
        "source.fixAll.stylelint": true
      },
      // 关闭vscode自带的css,less,scss报错提示
      "css.validate": false,
      "less.validate": false,
      "scss.validate": false,
      "stylelint.validate": ["css", "less"]
    }

    9 配置yapi-to-typescript

    typescript面世以来,经历了一个从厌烦到喜欢的过程,厌恶的是要在原来开发的基础上,多做一些繁杂数据类型定义的工作,喜欢的是确实帮助开发者发现了许多语法错误,享受到接口和传参的便利提示, 综合起来,还是利大于弊,所以 越来越多的开发者开始加入ts大家庭。yapi-to-typescript这个工具,可以帮我们省去接口数据类型定义的工作量。让我们更愉快的与ts玩耍。

    安装依赖

    yarn add -D yapi-to-typescript

    创建ytt.config.ts配置文件

    import { defineConfig } from 'yapi-to-typescript';
    
    /**
     * 生成Api接口名称  Interface和ChangeCase数据类型参见node_modules\yapi-to-typescript\lib\esm\index.d.ts定义
     * @param interfaceInfo : Interface
     * @param changeCase:ChangeCase
     * @returns 请求响应接口名称--pascal命名
     */
    function genApiInterfaceName(interfaceInfo, changeCase) {
      // 取解析路径dir最尾部的路径作为前缀路径
      const lastPath = interfaceInfo.parsedPath.dir.split('/').pop();
      // 拼接前缀路径+文件名称
      return `${changeCase.pascalCase(lastPath)}${changeCase.pascalCase(interfaceInfo.parsedPath.name)}`;
    }
    
    export default defineConfig([
      {
        serverUrl: 'https://yapi.xxx.com',
        typesOnly: true,
        target: 'typescript',
        reactHooks: {
          enabled: false,
        },
        prodEnvName: '项目名称',
        // 将生成文件路径转化成小驼峰命名方式
        outputFilePath: (interfaceInfo, changeCase) => {
          // 文件夹名称取api-url路径末尾2个
          const filePathArr = interfaceInfo.path.split('/').slice(-2);
          const filePath = filePathArr.map((item) => changeCase.camelCase(item)).join('/');
          return `typings/httpTypes/${filePath}.ts`;
        },
        // 生成ts文件中请求参数interface名称,将下划线命名转换成pascal命名
        getRequestDataTypeName: (interfaceInfo, changeCase) => {
          return `${genApiInterfaceName(interfaceInfo, changeCase)}Request`;
        },
        // 生成ts文件中请求响应数据interface名称,将下划线命名转换成pascal命名
        getResponseDataTypeName: (interfaceInfo, changeCase) => {
          return `${genApiInterfaceName(interfaceInfo, changeCase)}Response`;
        },
        // 响应数据中要生成ts数据类型的键名
        dataKey: 'retdata',
        projects: [
          {
            // token获取方式: 在yapi-设置-token配置中查看
            token: 'xxx',
            // 分类id查找方式: 点击接口左侧的分类菜单,查看url地址栏最后面的数字获取
            // 分类id配置特别重要,配置错了无法生成对应的ts数据类型定义文件
            categories: [
              {
                id: [xxx], // 民生立减金API分类id
              },
            ],
          },
        ],
      },
    ]);

    3.在package.json中配置ytt指令

    {
      // ...
      "scripts": {
        "start": "ytt && vue-cli-service serve --mode local",
        "build": "ytt && vue-cli-service build --mode local",
        "ytt": "ytt",
      },
    }

    4.在.gitignore中添加对httpTypes下文件的忽略

    # ...
    /typings/httpTypes/*
    # ...

    10 配置commitlint

    commit message 是程序员开发的日常高频操作,自然状态下commit message 呈现五花八门的书写风格,不利于阅读和维护,规范的 commit message 有助于团队做 code review, 输出清晰明了的 CHANGELOG, 有利于项目的长期维护。

    安装依赖包

    yarn add -D husky conventional-changelog-cli @commitlint/{cli,config-conventional}

    创建提交校验配置文件commitlint.config.js

    /**
     *  git commit最佳实践
     *  1.经常commit,One Thing,One Commit
     *  2.commit之前测试,不要commit一半工作;
     *  3.编写规范的commit message
     */
    
    /**
     * Commit message 包括三个部分:Header,Body 和 Footer
     * <type>(<scope>): <subject>
     * 空一行
     * <body>
     * 空一行
     * <footer>
     */
    module.exports = {
      extends: ['@commitlint/config-conventional'],
      rules: {
        // Header包括三个字段:type(必需)、scope(可选)和subject(必需)。最多200字
        'header-max-length': [2, 'always', 200],
        // 提交类型<type>枚举
        'type-enum': [
          2,
          'always',
          [
            'init', // 项目初始化
            'clean', // 清理过时无用文件
            'merge', // 合并代码
            'style', //  修改样式文件(包括css/less/sass,图片,字体文件)
            'format', // 格式化,不影响代码含义的修改,比如空格、格式缩进、缺失的分号等
            'build', // 改变构建流程、或者增加依赖库、工具等 如webpack.config.js,package.json yarn.lock
            'chore', // 各种配置文件的修改,  如.gitignore,tsconfig.json,.vscode,.tenone, eslint/stylelint,envConfig
            'ci', // 对CI配置文件或脚本进行了修改
            'docs', // 修改项目说明文档
            'feat', // 新增功能
            'fix', // 修复bug
            'perf', // 性能优化
            'refactor', // 既不是修复bug也不是添加功能的代码重构
            'revert', // 版本回退
            'test', // 修改测试用例
          ],
        ],
        // 格式-可选值
        // 'lower-case' 小写 lowercase
        // 'upper-case' 大写 UPPERCASE
        // 'camel-case' 小驼峰 camelCase
        // 'kebab-case' 短横线 kebab-case
        // 'pascal-case' 大驼峰 PascalCase
        // 'sentence-case' 首字母大写 Sentence case
        // 'snake-case' 下划线 snake_case
        // 'start-case' 所有首字母大写 start-case
        // <type> 不能为空
        'type-empty': [2, 'never'],
        // <type> 格式 小写
        'type-case': [2, 'always', 'lower-case'],
        // <scope> 关闭改动范围不能为空规则
        'scope-empty': [0, 'never'],
        // <scope> 格式 小写
        'scope-case': [2, 'always', 'lower-case'],
        // <subject> 不能为空
        'subject-empty': [2, 'never'],
        // <subject> 关闭 以.为结束标志
        'subject-full-stop': [0, 'never', '.'],
        // <subject> 格式
        'subject-case': [2, 'never', []],
        // <body> 以空行开头
        'body-leading-blank': [1, 'always'],
        // <footer> 以空行开头
        'footer-leading-blank': [1, 'always'],
      },
    };

    3. 创建提交校验shell脚本 husky.sh和commit-msg

    yarn husky install

    在.husky文件夹下创建commit-msg文件

    npx husky add .husky/commit-msg

    在.husky/commit-msg文件中写入

    #!/bin/sh
    . "$(dirname "$0")/_/husky.sh"
    # 提交记录检查
    yarn commitlint --edit $1
    # 代码重复率检测
    yarn jscpd
    # 格式化检查
    yarn format:check
    # eslint检查
    yarn lint:check

    11 配置代码重复率检测工具jscpd

    代码的简洁之道有一条铁律是 Don't Repeat Yourself,那么如何快速地检测出项目出是否存在着大段的重复代码,靠人工检查显然不可取,这种重复体力活应该交给工具。

    检测前端代码重复率的工具有jsinspectjscpdPMD-CPD(PMD's Copy/Paste Detector)

    • jsinspect工具支持js和jsx格式的文件,基于抽象语法树,可以检测出结构类似的代码块
    • PMD-CPD工具支持js文件检测,也可以自己开发扩展包来解析指定的语言
    • jscpd工具支持文件格式广泛,如js、jsx、vue、ts、less,java、oc等。其重复率判定依据为一定长度标识符的MD5值是否相同

    每个工具各有其优缺点,若只需要检测js或jsx文件,且对检测结果要求较高,可以选择jsinspect或者PMD-CPD工具,若考虑检测工具的通用性,可以选择jscpd工具。

    安装:
    npm install -g jscpd
    用法:
    jscpd  src/*
    在项目下创建.jscpd.json配置文件
    { 
    // 重复率阈值
    "threshold": 0.1,
    // 报告输出格式
    "reporters": [ "html", "console" ], "ignore": [ "dist/**", "node_modules/**" ],
    // 文件路径使用相对路径
    "absolute": false }
     --min-tokens  -k:代码的最小块大小。小于的代码块min-tokens将被跳过,默认为50;
     --min-lines  -l:最小代码行数,默认为5;
     --max-lines  -x: 最大代码行数,默认为1000;
     --max-size  -z:最大文件大小,单位为kb,默认100;
     --threshold  -t:重复级别的阈值,当项目重复级别大于该阈值时报错退出,默认为空;
     --ignore  -i:忽略的文件类型;
     --reporters  -r:输出类型


    参考文献

  • 相关阅读:
    Python学习笔记
    Python学习笔记
    不定宽高垂直居中分析
    PhoneGap安装配置
    Mongoose学习参考资料
    我的node+express小例子
    node+express+mongodb初体验
    stylie工具轻松搞定css3抛物线动画
    fis前端开发框架
    Fiddler实现手机的抓包(转载园友小坦克)
  • 原文地址:https://www.cnblogs.com/wangpenghui522/p/15688555.html
Copyright © 2011-2022 走看看