从零开始搭Vue项目-01创建一个Vue项目

278 阅读8分钟

初始化项目篇

创建本地项目

安装pnpm/cnpm/npm/yarn

npm install -g pnpm/cnpm/npm/yarn

cmd转到项目workspace路径 , 创建项目

pnpm create vite
vue create xxxx

安装依赖 测试运行

pnpm i

pnpm ren dev

npm i

npm run serve

git远程仓库

  • 安装git(此处忽略)

初始化本地项目 提交到本地队列

git init
git add -A
git commit -m "first commit"

链接github 远程仓库

  1. 创建SSHkey(需要使用GIt bash操作,桌面右键即可)

    shh keygen -t rsa -C "xxxxxxx@163.com"
    

image-20220707095105755.png

  1. 查看SSHkey

image-20220707095203563.png

image-20220707095212434.png

  1. github配置SSHkey

    点击头像 -> 设置

image-20220707095416071.png

  1. 本地验证

    ssh -T git@github.com
    

image-20220707095552188.png

github创建仓库

选择Create a new repository

按照默认创建即可

关联远程仓库

复制 remote 命令

image-20220707095804934.png

本地内容提交

首次提交需要加上-u

git push -u origin master

仓库不是空的之后

git push origin master

配置项目

代码风格

统一代码风格,安装editorconfig插件

image-20220315182913415.png

  1. 根目录右键创建.editorconfig文件

  2. 配置文件

    # http://editorconfig.org
    
    root = true
    
    [*] # 表示所有文件适用
    charset = utf-8 # 设置文件字符集为 utf-8
    indent_style = space # 缩进风格(tab | space)
    indent_size = 2 # 缩进大小
    end_of_line = lf # 控制换行类型(lf | cr | crlf)
    trim_trailing_whitespace = true # 去除行首的任意空白字符
    insert_final_newline = true # 始终在文件末尾插入一个新行
    
    [*.md] # 表示仅 md 文件适用以下规则
    max_line_length = off
    trim_trailing_whitespace = false
    

代码格式化 工具 prettier 工具

  1. 安装prettier

    pnpm install prettier -D
    
  2. 配置 .prettierrc文件

    {
      "useTabs": false,
      "tabWidth": 2,
      "printWidth": 80,
      "singleQuote": true,
      "trailingComma": "none",
      "semi": false
    }
    
    // useTabs:使用tab缩进还是空格缩进,选择false;
    // tabWidth:tab是空格的情况下,是几个空格,选择2个;
    // printWidth:当行字符的长度,推荐80,也有人喜欢100或者120;
    // singleQuote:使用单引号还是双引号,选择true,使用单引号;
    // trailingComma:在多行输入的尾逗号是否添加,设置为 `none`;
    // semi:语句末尾是否要加分号,默认值true,选择false表示不加;
    
  3. 创建.prettierignore忽略文件

    /dist/*
    .local
    .output.js
    /node_modules/**
    
    **/*.svg
    **/*.sh
    
    /public/*
    
  4. VSCode需要安装prettier的插件

image-20220315182900355.png

  1. 在package.json中配置scripts

    "prettier": "prettier --write ."
    

代码检测ESLint

  1. 安装ESLint插件 image-20220315185754903.png

  2. 解决eslint和prettier的冲突

    npm i eslint-plugin-prettier eslint-config-prettier -D
    
  3. 配置.eslintrc.js,添加prettier插件:

    module.exports = {
      root: true,
      env: {
        node: true
      },
      extends: [
        'plugin:vue/vue3-essential',
        'eslint:recommended',
        '@vue/typescript/recommended',
        '@vue/prettier',
        '@vue/prettier/@typescript-eslint',
        'plugin:prettier/recommended'
      ],
      parserOptions: {
        ecmaVersion: 2020
      },
      rules: {
        'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
        'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
        '@typescript-eslint/no-var-requires': 'off',
        '@typescript-eslint/no-explicit-any': 'off',
        '@typescript-eslint/explicit-module-boundary-types': 'off'
      }
    }
    

提交规范(选配)

代码提交验证 git Husky 和 eslint(选配)

虽然我们已经要求项目使用eslint了,但是不能保证组员提交代码之前都将eslint中的问题解决掉了:

  • 也就是我们希望保证代码仓库中的代码都是符合eslint规范的;

  • 那么我们需要在组员执行 git commit 命令的时候对其进行校验,如果不符合eslint规范,那么自动通过规范进行修复;

那么如何做到这一点呢?可以通过Husky工具:

  • husky是一个git hook工具,可以帮助我们触发git提交的各个阶段:pre-commit、commit-msg、pre-push

如何使用husky呢?

这里我们可以使用自动配置命令:

npx husky-init && npm install

这里会做三件事:

1.安装husky相关的依赖:

008i3skNgy1gsqq0o5jxmj30bb04qwen.jpg

2.在项目目录下创建 .husky 文件夹:

npx huksy install

008i3skNgy1gsqq16zo75j307703mt8m.jpg

3.在package.json中添加一个脚本: 008i3skNgy1gsqq26phpxj30dj06fgm3.jpg

接下来,我们需要去完成一个操作:在进行commit时,执行lint脚本: 008i3skNgy1gsqq3hn229j30nf04z74q.jpg

这个时候我们执行git commit的时候会自动对代码进行lint校验。

代码提交规范

通常我们的git commit会按照统一的风格来提交,这样可以快速定位每次提交的内容,方便之后对版本进行控制。

008i3skNgy1gsqw17gaqjj30to0cj3zp.jpg

但是如果每次手动来编写这些是比较麻烦的事情,我们可以使用一个工具:Commitizen

  • Commitizen 是一个帮助我们编写规范 commit message 的工具;

1.安装Commitizen

npm install commitizen -D

2.安装cz-conventional-changelog,并且初始化cz-conventional-changelog:

npx commitizen init cz-conventional-changelog --save-dev --save-exact

这个命令会帮助我们安装cz-conventional-changelog: 008i3skNgy1gsqvz2odi4j30ek00zmx2.jpg

并且在package.json中进行配置:

"config": {
    "commitizen": {
      "path": "./node_modules/cz-conventional-changelog"
    }
  }

这个时候我们提交代码需要使用 npx cz

  • 第一步是选择type,本次更新的类型
Type作用
feat新增特性 (feature)
fix修复 Bug(bug fix)
docs修改文档 (documentation)
style代码格式修改(white-space, formatting, missing semi colons, etc)
refactor代码重构(refactor)
perf改善性能(A code change that improves performance)
test测试(when adding missing tests)
build变更项目构建或外部依赖(例如 scopes: webpack、gulp、npm 等)
ci更改持续集成软件的配置文件和 package 中的 scripts 命令,例如 scopes: Travis, Circle 等
chore变更构建流程或辅助工具(比如更改测试环境)
revert代码回退
  • 第二步选择本次修改的范围(作用域)

008i3skNgy1gsqw8ca15oj30r600wmx4.jpg

  • 第三步选择提交的信息

008i3skNgy1gsqw8mq3zlj60ni01hmx402.jpg

  • 第四步提交详细的描述信息 008i3skNgy1gsqw8y05bjj30kt01fjrb.jpg

  • 第五步是否是一次重大的更改 008i3skNgy1gsqw9z5vbij30bm00q744.jpg

  • 第六步是否影响某个open issue

008i3skNgy1gsqwar8xp1j30fq00ya9x.jpg

我们也可以在scripts中构建一个命令来执行 cz: 008i3skNgy1gsqwc4gtkxj30e207174t.jpg

代码commit验证

如果我们按照cz来规范了提交风格,但是依然有同事通过 git commit 按照不规范的格式提交应该怎么办呢?

  • 我们可以通过commitlint来限制提交;

1.安装 @commitlint/config-conventional 和 @commitlint/cli

npm i @commitlint/config-conventional @commitlint/cli -D

2.在根目录创建commitlint.config.js文件,配置commitlint

module.exports = {
  extends: ['@commitlint/config-conventional']
}

3.使用husky生成commit-msg文件,验证提交信息:

npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"
  • cmd环境下执行失败

    • 手动创建commit-msg文件,修改内部文件

      #!/bin/sh
      . "$(dirname "$0")/_/husky.sh"
      
      npx --no-install commitlint --edit $1
      

运行环境

三种环境

  • 默认环境

  • 开发环境: development

    根目录下创建.env.development文件

    VUE_APP_BASE_URL=https://codermjjh.org/dev
    VUE_APP_BASE_NAME=codermjjh
    
  • 生成环境: production

    VUE_APP_BASE_URL=https://codermjjh.org/pore
    VUE_APP_BASE_NAME=kobe
    

第三方库集成

配置Vue.config.js

作用配置一些公用路径属性等

vue.config.js有三种配置方式:

  • 方式一:直接通过CLI提供给我们的选项来配置:
    • 比如publicPath:配置应用程序部署的子目录(默认是 /,相当于部署在 https://www.my-app.com/);
    • 比如outputDir:修改输出的文件夹;
  • 方式二:通过configureWebpack修改webpack的配置:
    • 可以是一个对象,直接会被合并;
    • 可以是一个函数,会接收一个config,可以通过config来修改配置;
  • 方式三:通过chainWebpack修改webpack的配置:
    • 是一个函数,会接收一个基于 webpack-chain 的config对象,可以对配置进行修改;
const path = require('path')

module.exports = {
  outputDir: './build',
  // configureWebpack: {
  //   resolve: {
  //     alias: {
  //       views: '@/views'
  //     }
  //   }
  // }
  // configureWebpack: (config) => {
  //   config.resolve.alias = {
  //     '@': path.resolve(__dirname, 'src'),
  //     views: '@/views'
  //   }
  // },
  chainWebpack: (config) => {
    config.resolve.alias.set('@', path.resolve(__dirname, 'src')).set('views', '@/views')
  }
}

安装Vue-Router

安装

npm install vue-router@next

创建rotuer文件夹

创建index文件 , 配置路由

import { createRouter, createWebHashHistory } from 'vue-router'
import { RouteRecordRaw } from 'vue-router'

const routes: RouteRecordRaw[] = [
  {
    path: '/',
    redirect: '/login'
  },
  {
    path: '/login',
    component: () => import('@/views/login/login.vue')
  },
  {
    path: '/main',
    component: () => import('@/views/main/main.vue')
  }
]

const router = createRouter({
  routes,
  history: createWebHashHistory()
})

export default router

在main中引入

import { createApp } from 'vue'
import App from './App.vue'

import router from './router'
import { store, key } from './store'

createApp(App).use(router).mount('#app')

测试

在views文件夹下创建main和login两个文件夹,并且在文件夹中新建vue文件

在app.vue中创建路由链接以及路由占位

<router-link to="/login">登录</router-link>
<router-link to="/main">首页</router-link>
<router-view></router-view>

安装Vuex

vuex对ts的支持不太行 , 推荐使用pinia , 由于兼容性原因暂时选择使用vuex

安装

npm install vuex@next 

创建store文件夹

创建index文件

import { createStore } from 'vuex'

const store = createStore({
  state: () => {
    return {
      name: 'codermjjh'
    }
  }
})

export default store

如果需要对vuex的类型进行限制

可以查看这篇文章thenightmarex.github.io/blogs/2021/…

// store.ts
import { InjectionKey } from 'vue'
import { createStore, Store } from 'vuex'

// 为 store state 声明类型
export interface State {
  name: string
}

// 定义 injection key
export const key: InjectionKey<Store<State>> = Symbol()

export const store = createStore<State>({
  state: {
    name: 'codermjjh'
  }
})

在main中引入

默认状态

import { createApp } from 'vue'
import App from './App.vue'

import router from './router'
import store from './store'

createApp(App).use(router).use(store).mount('#app')

需要类型限制状态

import { createApp } from 'vue'
import App from './App.vue'

import router from './router'
import { store, key } from './store'

createApp(App).use(router).use(store, key).mount('#app')

测试

在app.vue中引用字段

<h2>{{ store.state.name }}</h2>

element-plus集成

安装

npm install element-plus --save

引入

具体可查看中文镜相官网element-plus.gitee.io/zh-CN/guide…

这里我们选择按需引入

  1. 安装unplugin-vue-componentsunplugin-auto-import这两款插件

    npm install -D unplugin-vue-components unplugin-auto-import
    
  2. 将下列代码插入到vite或者webpack配置中

    // 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()],
        }),
      ],
    })
    
    // webpack.config.js
    const AutoImport = require('unplugin-auto-import/webpack')
    const Components = require('unplugin-vue-components/webpack')
    const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
    
    module.exports = {
      // ...
      plugins: [
        AutoImport({
          resolvers: [ElementPlusResolver()],
        }),
        Components({
          resolvers: [ElementPlusResolver()],
        }),
      ],
    }
    

测试

在app.vue中使用element-plus组件

<el-row class="mb-4">
  <el-button>Default</el-button>
  <el-button type="primary">Primary</el-button>
  <el-button type="success">Success</el-button>
  <el-button type="info">Info</el-button>
  <el-button type="warning">Warning</el-button>
  <el-button type="danger">Danger</el-button>
  <el-button>中文</el-button>
</el-row>

axios集成

安装axios:

npm install axios

封装axios:

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import { Result } from './types'
import { useUserStore } from '/@/store/modules/user'

class MJRequest {
  private instance: AxiosInstance

  private readonly options: AxiosRequestConfig

  constructor(options: AxiosRequestConfig) {
    this.options = options
    this.instance = axios.create(options)

    this.instance.interceptors.request.use(
      (config) => {
        const token = useUserStore().getToken
        if (token) {
          config.headers.Authorization = `Bearer ${token}`
        }
        return config
      },
      (err) => {
        return err
      }
    )

    this.instance.interceptors.response.use(
      (res) => {
        // 拦截响应的数据
        if (res.data.code === 0) {
          return res.data.data
        }
        return res.data
      },
      (err) => {
        return err
      }
    )
  }

  request<T = any>(config: AxiosRequestConfig): Promise<T> {
    return new Promise((resolve, reject) => {
      this.instance
        .request<any, AxiosResponse<Result<T>>>(config)
        .then((res) => {
          resolve((res as unknown) as Promise<T>)
        })
        .catch((err) => {
          reject(err)
        })
    })
  }

  get<T = any>(config: AxiosRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'GET' })
  }

  post<T = any>(config: AxiosRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'POST' })
  }

  patch<T = any>(config: AxiosRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'PATCH' })
  }

  delete<T = any>(config: AxiosRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'DELETE' })
  }
}

export default HYRequest