从0到1搭建vue3+ts项目


前言

在自学 vue3 + vite + ts 项目时遇到的一些问题,都是一步一坑踩过来最终解决的,也借鉴了网上很多资料,特以此篇记录我的日常踩坑之路/(ㄒ o ㄒ)/~~

如果文章对你有帮助,可以点击链接关注我的掘金社区账号 更多技术分享请移步我的掘金哦~ 😀😀😀

点击链接 学习交流群(前端微信群) - 掘金 (juejin.cn) 加vx拉你进 前端学习交流群 让我们一起 好好学习(🐟🐟🐟)吧😎😎😎

从 0 到 1 搭建 vue3+ts 项目配置 eslint

  • 为什么要用 eslint?
    目的:为了规范团队成员代码格式,以及保持统一的代码风格,此项目采用当前业界最火的 Airbnb 规范,并引入代码风格管理工具 Prettier。

  • 为什么 ts 项目不用 tslint 而用于 eslint ?
    因为 tslint 已经不维护了!!!

  • 我的电脑本地环境版本:

    vscode: 1.68.1
    node:   16.13.2
    pnpm: 6.32.2
    vue-cli: 5.0.0-bate.3
    yarn: 1.22.10

    node 版本下载链接: https://nodejs.org/en/download/releases/

  • 项目开始:
    pnpm create vite 我这种创建项目方式一些配置文件需要手动创建配置如.eslintrc.js
    输入项目名称
    选择项目模板 vue -> vue-ts
    cd project 下载依赖 pnpm i

配置 eslint 以及相关依赖

eslint 只有开发阶段需要,因此添加到开发阶段的依赖中即可;根目录创建 .eslintrc.js 文件

eslint: eslint 的核心代码
eslint-plugin-vue :vue 官方 ESLint 插件,检查 .vue 文件中 template、script 中的语法错误、指令等
安装:pnpm i eslint eslint-plugin-vue -D

  • 配置 eslint 对.ts 文件的支持

    @typescript-eslint/eslint-plugin:这是一个 ESLint 插件,包含了各类定义好的检测 Typescript 代码的规范
    @typescript-eslint/parser eslint 解析器用于支持解析 typescript,从而检查和规范 Typescript 代码
    安装:
    pnpm i @typescript-eslint/eslint-plugin @typescript-eslint/parser -D

  • eslint 具体校验规则配置
    eslint 规则有很多,我们可以根据自己的需求自行配置,但是过于麻烦!目前业界有三个流行开源配置方案,分别是 Airbnb、 Standard、 Google,严格程度对比是 Airbnb > Google > Standard,所以普遍使用 Airbnb 较多,所有我这里使用安装 Airbnb
    pnpm i eslint-config-airbnb-base -D

prettier 配置以及解决 eslint 和 prettier 冲突

  • prettier 安装:pnpm i prettier -D
  • 解决 eslint 和 prettier 冲突
    eslint-config-prettier: 关闭所有和 prettier 冲突的 eslint 规则
    eslint-plugin-prettier: 告诉 eslint 应该怎么按照 prettier 的方式去格式化文档。
    pnpm i eslint-config-prettier eslint-plugin-prettier -D
  • 具体 prettierrc 规则配置,根目录创建.prettierrc.js 以及忽略文件.prettierignore
module.exports = {
  // printWidth: 100, // 一行最多 100 字符
  // tabWidth: 2, // 使用 4 个空格缩进
  // semi: false, // 行尾需要有分号
  semi: false, // 行尾需要有分号
  trailingComma: "none", // 末尾不需要逗号
  singleQuote: true, // 使用单引号而不是双引号
  // useTabs: false, // 用制表符而不是空格缩进行
  // quoteProps: 'as-needed', // 仅在需要时在对象属性两边添加引号
  // jsxSingleQuote: false, // 在 JSX 中使用单引号而不是双引号
  // bracketSpacing: true, // 大括号内的首尾需要空格
  // bracketSameLine: false, // 将多行 HTML(HTML、JSX、Vue、Angular)元素反尖括号需要换行
  // arrowParens: 'always', // 箭头函数,只有一个参数的时候,也需要括号 avoid
  // rangeStart: 0, // 每个文件格式化的范围是开头-结束
  // rangeEnd: Infinity, // 每个文件格式化的范围是文件的全部内容
  // requirePragma: false, // 不需要写文件开头的 @prettier
  // insertPragma: false, // 不需要自动在文件开头插入 @prettier
  // proseWrap: 'preserve', // 使用默认的折行标准 always
  // htmlWhitespaceSensitivity: 'css', // 根据显示样式决定 html 要不要折行
  // vueIndentScriptAndStyle: false, //(默认值)对于 .vue 文件,不缩进 <script> 和 <style> 里的内容
  // // endOfLine: 'lf', // 换行符使用 lf 在Linux和macOS以及git存储库内部通用\n
  // embeddedLanguageFormatting: 'auto' //(默认值)允许自动格式化内嵌的代码块
};

保证 plugin:prettier/recommended 放在.eslintrc extends 中最后

  • 运行时对代码进行 eslint 校验
    这样配置完重启编辑器项目应该不会有报错,因为需要执行 eslint 命令去检测文件中不符合规则的代码这不是我们期望的
    我们期望的是代码运行期间如果不符合 eslint 规范就报错提示。这里使用的是 rollup 的 eslint 插件
    pnpm i @rollup/plugin-eslint -D
    vite 配置文件里 plugins 开启 eslint:

    // ...,
      {
          // 开启eslint
          ...eslint({
            // include: ['src/**/*.vue', 'src/**/*.js'],
            // fix: true, // 自动修复
            include: ['src/**/*.js', 'src/**/*.ts', 'src/**/*.vue'], // 需要检查的文件
            // exclude: ['src/**/*.js',  'src/**/*.vue'], // 忽略文件
            throwOnError: true, // 有错误抛出
            throwOnWarning: true, // 有警告抛出
          }),
          enforce: 'pre',
      },
    

这时重启项目,运行时某个文件代码不符合 eslint 规则就会直接报错,必须修复后才可以运行成功,至此到达了我们预期的效果。

packge.josn 所有依赖

  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "preview": "vite preview",
    // 环境变量
    "dev1": "vite --mode development",
    "test": "vite --mode test",
    "prod": "vite --mode production",
    // lint 检查./src下所有这些结尾的文件
    "lint": "eslint --ext .js,.jsx,.ts,.tsx,.vue ./src",
    // eslint  fix修复问题(只能修复部分)
    "fix": "eslint --ext .js,.jsx,.ts,.tsx,.vue ./src --fix"
  },
  "dependencies": {
    "@element-plus/icons-vue": "^2.0.4", // 饿了么plus-icon
    "@types/node": "^17.0.42",
    "axios": "^0.27.2",
    "element-plus": "^2.2.5",
    "mockjs": "^1.1.0",
    "pinia": "^2.0.14",
    "vue": "^3.2.25",
    "vue-router": "^4.0.16",
    "vuex": "^4.0.2"
  },

 "devDependencies": {
    // rollup插件开启eslint检查
    "@rollup/plugin-eslint": "^8.0.2",
    // ts解析器 让eslint支持对ts文件检查
    "@typescript-eslint/eslint-plugin": "^5.28.0",
    "@typescript-eslint/parser": "^5.28.0",
    "@vitejs/plugin-vue": "^2.3.3",
    "consola": "^2.15.3",
    // airbnb 比较火的eslint开源配置方案
    "eslint-config-airbnb-base": "^15.0.0",
    // "eslint-import-resolver-typescript": "^2.7.1",
    // 对 mport/export的语法进行linting,并防止文件路径和导入名称拼写错误的问题
    "eslint-plugin-import": "^2.26.0",
    // prettier 以及 解决prettier和eslint冲突
    "prettier": "^2.7.0",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-prettier": "^4.0.0",
    // 基础eslint
    "eslint": "^8.17.0",
    "eslint-plugin-vue": "^9.1.1",
    "less": "^4.1.3",
    "less-loader": "^11.0.0",
    "typescript": "^4.5.4",
    // 饿了么css样式按需引入
    "vite-plugin-style-import": "^2.0.0",
    // 饿了么plus 组件按需引入
    "unplugin-auto-import": "^0.8.8",
    "unplugin-vue-components": "^0.19.6",
    "vite": "^2.9.9",
    "vue-tsc": "^0.34.7"
}

vue3+ts 项目配置 eslint 遇到的具体问题

eslint 问题所有相关配置都在根目录 .eslintrc.js 文件下配置
此项目 eslint 使用的是 @rollup/plugin-eslint 这个插件依赖

  • vue3 一直报错 error: Parsing error: Unexpected token ?
    我在引入 element-plus 类型时 type 这里 eslint 一直报这个错
    import type { FormInstance, FormRules } from 'element-plus'
    vue3+ts 解决方法
    需要先安装 ts 解析器依赖: yarn add @typescript-eslint/parser -D

    parserOptions: [
        parser: '@typescript-eslint/parser',
    ]
  • vue3+ts 解决 The template root requires exactly one element.eslintvue/no-multiple-template-root 问题?

    extends: [
        // 解决根元素报错问题
        'plugin:vue/vue3-essential',
        //  vue3 推使用这个规则支持.vue文件校验
        'plugin:vue/vue3-recommended'
    ]
  • error Parsing error: ‘>‘ expected ?
    让 eslint 检测.vue 代码
    解决
    parser: 'vue-eslint-parser',

  • Missing file extension “ts” for “xxx” import/extensions ?
    导入/扩展缺少文件扩展名“ts”
    使用了 airbnb-base 规则后,如引入 import components from './components' 文件报错,必须写到 components 下的 index.ts
    解决:rulse 规则配置忽略

    rules: {
      'import/extensions': [
      'error',
      'ignorePackages',
        {
        js: 'never',
        jsx: 'never',
        ts: 'never',
        tsx: 'never'
        }
      ]
    }
  • Unable to resolve path to module xxx import/no-unresolved ?
    配置别名后:无法解析模块 xxx 导入的路径/未解析路径
    解决
    vite.config 里配置别名
    网上说还需要在 ts.config.json paths 配置同上的别名,但是配置了 eslint 还是会不通过;
    安装: pnpm i eslint-import-resolver-alias 这个包是一个配合 eslint-plugin-import 使用的 resolver,用来 resolve 带别名的路径。
    配置 eslint

    // .eslomtrc.js
    settings: {
      'import/resolver': {
        // 别名同vite.config
        alias: {
          map: [
            ['@', './src'],
            ['@mock', './src/mock'],
            //...
          ],
          extensions: ['js', '.ts', '.jsx', '.tsx']
        }
      }
    },

其他报错问题

  • 找不到模块“xxx”或其相应的类型声明?
    没有相关的声明文件,在 ts 项目里面,.ts 文件是识别不了.vue 文件,.vue 文件也识别不了.ts 文件,这时候就需要在 src 下 创建 env.d.ts 声明文件来解决:

      /// <reference types="vite/client" />
      declare module '*.vue' {
        import type { DefineComponent } from 'vue'
        // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
        const component: DefineComponent<{}, {}, any>
        export default component
      }

    但是我遇到的问题是自己写的 ts 文件: import { getProducts, IProduct } from '@mock/pages/shop' 也提示找不到模块“@mock/pages/shop”或其相应的类型声明。 但不影响运行
    在 ts 文件中定义好有关的 interface 接口使用,在其他文件中引入的时候出现了该问题
    一般出现这个问题都是路径问题!!!建议别名只配置一个 [‘@’, ‘./src’]

vue3+vite 项目中遇到的代码问题

Element Plus 官网推荐的自动引入组件方式部分组件 css 无法引入

官网推荐使用这个两个插件 npm install -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()],
    }),
  ],
});

如:引入 ElMessage 为例
import { ElMessage } from 'element-plus'
ElMessage.warning('warning')
如果不采用 import 的方式引入,会直接报错:ElMessage 没有定义,所以这个 import 是省不了的,但是 import 了之后,消息弹窗是出来了,但此时发现没有对应的样式!

  • 解决方案 1 (不推荐):
    使用官网说的手动导入的 unplugin-element-plus的插件,但是很麻烦,不同组件需要手动引入不同的 css
import "element-plus/es/components/message/style/css";
// import 'element-plus/es/components/用到的组件/style/css'
import { ElMessage } from "element-plus";
  • 解决方案 2 (推荐):
    使用 vite-plugin-style-import 插件可以实现按需引入 css;
    安装完成后在 vite.config.js 下 plugins: [] 使用。
    该插件可以按需引入 VantResolve、 ElementPlusResolve 等 ui 样式
    因为该插件的使用了 consola 包,所以还需要安装 npm i consola -D OR yarn add consola -D

1.x 写法

import styleImport from 'vite-plugin-style-import'
styleImport({
      libs: [{
        libraryName: 'element-plus',
        esModule: true,
        resolveStyle: (name) => {
          return `element-plus/theme-chalk/${name}.css`
        },
        // resolveComponent: (name) => {
        //   return `element-plus/lib/components/${name}`
        // },
      }]
    }),

2.x 写法

import { createStyleImportPlugin, VantResolve } from 'vite-plugin-style-import';
createStyleImportPlugin({
            resolves: [VantResolve()],
        }),

引入 Element Plus 遇到的其他问题

本地环境无任何报错,部署上线后报错

  • 报错 Cannot read properties of null (reading ‘insertBefore‘)
    本地项目启动操作无任何报错,部署后开始报这个错, 经过排查上网查资料原因总结如下:

v-if 导致
在 v-if 值为 false 时,如果操作了 v-if 控制的 DOM,可能会因为该 DOM 元素不存在而报错。
解决方:v-show 替换 v-if

el-table 组件导致
el-table-column 渲染时报错,若 scope.row.xxx (xxx 为任意字段值)不存在,对其直接执行 split、toString() 等方法时报错。
我是因为这个报错
解决方
可选链操作符: scope.row.field?.split

el-dialog 组件导致
默认弹框是关闭的,DOM 中没有弹框中的内容。打开弹框再关闭后,弹框中的 DOM 元素没有被销毁,可能会因为不该存在的 DOM 元素而报错
解决方:给 el-dialog 组件增加 destroy-on-close 属性

jsx 使用

  • 安装
    npm i @vitejs/plugin-vue-jsx

    // vite.config.ts
    import { defineConfig } from "vite";
    export default defineConfig({
      // ...
      plugins: [
        // ...
        vueJsx(),
      ],
    });
  • 然后就可以创建.jsx 文件使用 jsx 语法

    import { defineComponent, ref } from "vue";
    export default defineComponent({
      props: {
        params: {
          type: Object,
          default: () => {},
        },
      },
      setup(props) {
        const str = ref("tsx的使用");
        const clickFunc1 = () => {
          console.log("没有参数");
        };
        const clickFunc2 = (msg = "默认值") => {
          console.log(msg);
          console.log("接收到的:", props);
        };
        return () => (
          <>
            <div class="async">{str.value}</div>
            <button onClick={clickFunc1}>不传参数点击</button>
            <button onClick={() => clickFunc2("额外参数")}>传参数点击</button>
          </>
        );
      },
    });

    或者 .vue 里 script 写 jsx

    <!-- lang=jsx  tsx好像都可以 -->
    <script lang="jsx" >
    import { defineComponent, ref } from 'vue'
    export default defineComponent({
      props: {
        params: {
          type: Object,
          default: () => {}
        }
      },
      setup (props) {
        const str = ref('script lang=jsx写法')
        const clickFunc1 = () => {
          alert('没有参数')
        }
        const clickFunc2 = (msg = '默认值') => {
          alert('接收到的:' + msg)
        }
        return () => (
          <>
            <div class='jsxBox'>
            <div>{str.value}</div>
            <button onClick={() => clickFunc1()}>点击</button>
            <button onClick={() => clickFunc2('额外参数')}>传参数点击</button>
            </div>
          </>
        )
      }
    })
    </script>
    <style lang="less">
      .jsxBox{
        border:1px solid red;
      }
    </style>
    

文章作者: 尖椒土豆sss
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 尖椒土豆sss !
 上一篇
macOs开发环境配置 macOs开发环境配置
记录个人使用 macOs 时配置开发环境mac 环境变量相关Mac 系统的环境变量,加载顺序为:系统级别:/etc/profile/etc/paths用户级别:~/.bash_profile~/.bash_login~/.profile ~
2022-05-02
下一篇 
搭建自己的图床 搭建自己的图床
什么是图床?简单理解为将图片上传存储到服务器,同时可以在公网中通过 url 访问图片。 为什么要搭建图床?我们在写 Markdown 文档时对于文档里面的图片,如果不使用图床,图片都是存放在本地,其他地方要用的话还得复制来复制去很不方便,也
2021-07-28
  目录
L
O
A
D
I
N
G