vue项目搭建流程

1,644 阅读12分钟

1. 创建项目

这里推荐使用Vue脚手架创建项目模板

  • 创建vue3+vite版本模板
npm init vue
  • 创建vue2+vite版本模板
npm init vue@2

创建过程可以选择需要的功能:

image.png

创建完后目录:

image.png

2.代码检测和格式化插件

目前我比较喜欢的是选择eslint+stylelint进行代码的检测和格式化,可以选择自己喜欢的方式,比如eslint+prettier都是可以的。

ESLint

1.安装 eslint

-D 表示安装到 devDependencies, -D 是--save-dev 的缩写

不写默认安装到 dependencies

推荐使用pnpm进行安装

pnpm install eslint -D

npm install eslint -D

2.VSCode安装 ESLint 插件

image.png

3.自动生成 Eslint 配置文件

npx eslint --init  

没有 npx 可以先全局安装,在 npm 版本为 5.2 之后默认会给你安装 npx

npm install -g npx

根据命令提示,完成操作:

How would you like to use ESLint? 你想如何使用 eslint?

  • To check syntax only(只检查语法检查语法并发现问题
  • To check syntax and find problems(检查语法并发现问题

选择 To check syntax, find problems, and enforce code style检查语法,发现问题,并强制代码样式

What type of modules does your project use?您的项目使用什么类型的模块?

选择 JavaScript modules (import/export)

Which framework does your project use? 你的项目使用什么框架?

React Vue.js None of these

Does your project use TypeScript?你的项目中使用 Typescript 吗?

Yes/No

Where does your code run?你的代码运行在??

Browser(浏览器)Node(Node

选择Browser

How would you like to define a style for your project? 你想给你的项目定义什么风格?

选择Use a popular style guide使用一个流行的风格指南)Answer questions about your style(回答你关于风格的问题)Inspect your JavaScript file(检查你的 javascript 文件

Which style guide do you want to follow? 你想遵循是么样的风格指南?

Airbnb: github.com/airbnb/java…

Standard: github.com/standard/st…

Google: github.com/google/esli…

XO: github.com/xojs/eslint…

上面四种风格都是社区流行的 javascript 风格指南,选择Standard

What format do you want your config file to be in? 你希望配置文件的格式是什么?

JavaScript/YAML/JSON

选择javascript

eslint 根据上面我们选择的配置,来告诉我们安装哪些 npm 包,选择 Yes 即可。

4.个人常用配置

pnpm i eslint eslint-config-standard eslint-plugin-import eslint-plugin-n eslint-plugin-promise eslint-plugin-vue  -D

.eslintrc.js文件

module.exports = {
  env: {
    browser: true,
    es2021: true
  },
  extends: [
    'plugin:vue/vue3-strongly-recommended',
    'standard'
  ],
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module'
  },
  plugins: [
    'vue'
  ],
  rules: {
    'vue/multi-word-component-names': 'off',
    'import/no-absolute-path': 'off',
    'vue/require-default-prop': 'off',
    'vue/max-attributes-per-line': ['error', {
      singleline: {
        max: 3
      },
      multiline: {
        max: 1
      }
    }]
  }
}

Stylelint

使用stylelint对 css/scss进行代码格式化

1.安装stylelint

pnpm i stylelint stylelint-config-html stylelint-config-recommended-scss stylelint-config-recommended-vue stylelint-config-standard stylelint-config-standard-scss stylelint-order postcss postcss-html -D

2.vscode安装Stylelint插件

image.png

在 vscode 的 settings.json 中配置stylelint

    "stylelint.enable": true,    
    "editor.codeActionsOnSave": {        
        "source.fixAll.stylelint": true    
    },
    "stylelint.validate": ["css", "less", "postcss", "scss", "vue", "sass"]

3.个人常用配置

配置 .stylelintrc.js文件

module.exports = {
    extends: [
        'stylelint-config-standard',
        'stylelint-config-html/vue',
        'stylelint-config-standard-scss',
        'stylelint-config-recommended-vue/scss',
    ],
    plugins: ['stylelint-order'],
    rules: {
        'no-descending-specificity': null,
        'function-url-quotes': 'always',
        'string-quotes': 'double',
        indentation: 2,
        'unit-case': null,
        'color-hex-case': 'lower',
        'color-hex-length': 'long',
        'rule-empty-line-before': 'never',
        'font-family-no-missing-generic-family-keyword': null,
        'block-opening-brace-space-before': 'always',
        'property-no-unknown': null,
        'no-empty-source': null,
        'selector-pseudo-class-no-unknown': [
            true,
            {
                ignorePseudoClasses: ['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',
        ],
    },
}

Prettier

Prettier 是一款强大的代码格式化工具,支持 JavaScript、TypeScript、CSS、SCSS、Less、JSX、Angular、Vue、GraphQL、JSON、Markdown 等语言

1.安装 prettier

npm install prettier -D

2.配置 .prettierrc.js

module.exports = {
  printWidth: 160, // 单行输出(不折行)的(最大)长度
  tabWidth: 2, // 每个缩进级别的空格数
  semi: false, // 是否在语句末尾打印分号
  singleQuote: true, // 是否使用单引号
  quoteProps: 'as-needed', // 仅在需要时在对象属性周围添加引号
  bracketSpacing: true, // 是否在对象属性添加空格
  htmlWhitespaceSensitivity: 'ignore', // 指定 HTML 文件的全局空白区域敏感度, "ignore" - 空格被认为是不敏感的
  trailingComma: 'none', // 去除对象最末尾元素跟随的逗号
  useTabs: false, // 缩进不使用tab,使用空格
  jsxSingleQuote: false, // jsx 不使用单引号,而使用双引号
  arrowParens: 'avoid', // 箭头函数,只有一个参数的时候,也需要括号 always总是 avoid:省略括号
  rangeStart: 0, // 每个文件格式化的范围是文件的全部内容
  proseWrap: 'always', // 当超出print width(上面有这个参数)时就折行
  endOfLine: 'lf' // 换行符使用 lf
}

3.创建 .prettierignore 忽略文件

/dist/*
.local
.output.js
/node_modules/**

**/*.svg
**/*.sh

/public/*

4.VSCode安装prettier插件

image.png

5.测试 prettier 是否生效

  • 测试一:在代码中保存代码;
  • 测试二:配置一次性修改的命令;

package.json 的 scripts 对象中添加 prettier:执行 npm run prettier 可以对全部文件格式化

 "scripts": {
    "prettier": "prettier --write ."
  }

解决 eslintprettier 冲突

安装插件 eslint-plugin-prettiereslint-config-prettier

npm i eslint-plugin-prettier eslint-config-prettier -D

5.在 .eslintrc.js 中添加 prettier即可,代码第 9 行

  module.exports = {
  env: {
    browser: true,
    es2021: true
  },
  extends: [
    'plugin:vue/vue3-essential',
    'airbnb-base',
    'plugin:prettier/recommended' // 添加 prettier 插件
  ],
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module'
  },
  plugins: ['vue'],
  rules: {}
}

注意:

重启 vscode 后 eslint 的规则才会按照 prettier 的配置规则生效,不重启还是原先的规则。

配置 vscode 的 eslint,在设置中找到 ESLint,把这个勾打上

image.png

package.json 中添加格式化脚本,之后只需要执行 npm run lint 即可全局自动格式化所有需要格式化的文件

"scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
     ...
    "lint": "eslint ./src/**/*.{js,jsx,vue,ts,tsx} --fix"
  },

3. 代码规范

这个看个人需要,团队项目有这个会规范很多

1.集成 editorconfig 配置

EditorConfig 有助于为不同 IDE 编辑器上处理同一项目的多个开发人员维护一致的编码风格。

# 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

VSCode 需要安装一个插件:EditorConfig for VS Code

image.png

2.git commit 规范

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

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

image.png

image.png

Type作用
init项目初始化
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代码回退

3.代码提交验证

我们无法避免其他开发者会提交什么代码,所以需要进行统一的 git commit之前进行代码校验,如果校验不通过则不让提交。

  • 安装下面的插件

Plain Text npx mrm@2 lint-staged

该插件做了以下的事情,在 package.json 中增加了三行,创建了 husky 文件夹

image.png

image.png

在 package.json 中配置规则,该规则表示 commit 之前会先执行上面定义的 eslint 检查,如果不通过则无法提交

"lint-staged": {
    "*.{js,jsx,vue,ts,tsx}": [
      "npm run lint",
      "git add"
    ]
  }

4. 库集成

由于第一步已经选择vue-routerpinia,所以已安装了这两个库的可以跳过

1.vue-router

1.安装

@next 表示 vue-router 的最新版本

npm install vue-router@next

2.创建 router 对象

router/index.js

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

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

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

export default router

3.使用

main.js

import router from './router'

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

在 App.vue 中配置跳转

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

2.pinia

vue3 对于 vuex 兼容性差一些,可以使用更好用的 pinia

1. 安装

npm install pinia --save

2. 创建 Store

新建 src/store 目录并在其下面创建 index.js,导出 store

import { createPinia } from 'pinia'

const store = createPinia()

export default store

3. 使用

main.js 中引入

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

const app = createApp(App)
app.use(store)

4. 数据持久化插件

1.安装

pnpm install pinia-plugin-persist

2.注册使用

import { createPinia } from 'pinia'
import piniaPluginPersist from 'pinia-plugin-persist'

const store = createPinia()
store.use(piniaPluginPersist)

数据默认存在 sessionStorage 里,并且会以 store 的 id 作为 key。

export const useUserStore = defineStore({
  id: 'user',

  state: () => {
    return {
      name: '张三'
    }
  },

  // 开启数据缓存
  persist: {
    enabled: true
  }
})

3.自定义 key和默认存储位置

persist: {
  enabled: true,
  strategies: [
    {
      key: 'my_user',
      storage: localStorage,
    }
  ]
}

4.持久化部分 state

默认所有 state 都会进行缓存,你可以通过 paths 指定要持久化的字段,其他的则不会进行持久化。

state: () => {
  return {
    name: '张三',
    age: 18,
    gender: '男'
  }  
},

persist: {
  enabled: true,
  strategies: [
    {
      storage: localStorage,
      paths: ['name', 'age']
    }
  ]
}

上面我们只持久化 name 和 age,并将其改为 localStorage, 而 gender 不会被持久化,如果其状态发送更改,页面刷新时将会丢失,重新回到初始状态,而 name 和 age 则不会。

5. setup语法

在这种语法中,refstate 对应、computedgetters 对应、functionactions 对应。

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const doubleCount = computed(() => count.value * 2)
  function increment() {
    count.value++
  }

  return { count, doubleCount, increment }
})

6. 在setup语法外使用

如果准备在 Vue3 的 Setup 语法外引入 Pinia 的 Store,例如 useCounterStore。

直接 import { useCounterStore } from "@/store/modules/xxxxxx" 是不行的

正确用法:

将这个store导出后引入使用

import store from "@/store"

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const doubleCount = computed(() => count.value * 2)
  function increment() {
    count.value++
  }

  return { count, doubleCount, increment }
})

/** 在 setup 外使用 */
export function useCounterStoreHook() {
  return useCounterStore(store)
}

然后引入

import { useCounterStoreHook } from "@/store/modules/xxxxxx" 即可!

3.vuex

1.安装

npm install vuex@next

2.创建 store 对象

import { createStore } from 'vuex'

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

export default store

3.使用 store

main.js

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

4. element-plus

Element Plus,一套为开发者、设计师和产品经理准备的基于 Vue 3.0 的桌面端组件库。

1.安装

npm install element-plus --save

2.引入

完整引入

如果你对打包后的文件大小不是很在乎,那么使用完整导入会更方便。

// main.ts
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'

const app = createApp(App)

app.use(ElementPlus)
app.mount('#app')

按需引入

首先你需要安装 unplugin-vue-componentsunplugin-auto-import 这两款插件

npm install -D unplugin-vue-components unplugin-auto-import

3.配置

vite 中配置 vite.config.js

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 {
  plugins: [
    // ...
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
}

webpack 中配置 vue.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()],
    }),
  ],
}

通过以上步骤即可随用随加载对应组件。

5. axios

1.安装

npm install axios

2.封装

import axios from 'axios'
import QS from 'qs' //用于序列化body内容,后端有配置可以不用这个库
import { ElLoading, ElMessage } from 'element-plus' //用于请求成功与否的弹框提醒和等待
import store from '@/store'
import router from '@/router'

//可以通过下面这个来获取vite中的环境是开发环境还是生产环境
//let { VITE_NORMALURL: normalUrl, MODE } = import.meta.env
//console.log('vite', import.meta.env)

//如果为开发模式
//let baseURL = MODE == 'development' ? String(normalUrl) : String(normalUrl)
let baseURL ='http://localhost:3000/'
const instance = axios.create({
  baseURL, //基础url
  timeout: 30000, //请求超时时间
})

// 请求拦截器
instance.interceptors.request.use(
  (config) => {
    /* 
    *将token放在请求头里就不需要每次都手动添加token。
    *即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断。
    */
    //const token = store.state.token;
    //token && (config.headers.Authorization = token);

    //如果公司的token是直接放在请求参数里面的,那么可以使用以下的配置
    let token = store.state.token
    if (token) {
      if (config.params) {
        config.params.token = token
      } else {
        config.params = {
          token,
        }
      }
    }
    return config
  },
  (error) => {
    return Promise.error(error)
  }
)

// 响应拦截器
instance.interceptors.response.use(
  (response) => {
    if (response.status === 200) {
      return Promise.resolve(response)
    } else {
      return Promise.reject(response)
    }
  },
  // 服务器状态码不是200的情况
  (error) => {
    if (error.response.status) {
      switch (error.response.status) {
        //无权限,直接回到登录页
        case 401:
          ElMessage({
            message: '登录过期,请重新登录',
            type: 'error',
          })
          // 清除token
          store.commit('setUserInfo', { token: '' })
          // 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
          setTimeout(() => {
            router.replace({
              path: '/',
              query: {
                redirect: router.currentRoute.fullPath,
              },
            })
          }, 1000)
          break
        // 404请求不存在
        case 404:
          ElMessage({
            message: '网络请求不存在',
            type: 'error',
          })
          break
        // 其他错误,直接抛出错误提示
        default:
          ElMessage({
            message: error.response.data.message,
            type: 'error',
          })
      }
      return Promise.reject(error.response)
    }
  }
)

/**
 * get方法,对应get请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 */
export function get(url, params) {
  return new Promise((resolve, reject) => {
    instance
      .get(url, {
        params: params,
      })
      .then((res) => {
        resolve(res.data)
      })
      .catch((err) => {
        reject(err.data)
      })
  })
}
/**
 * post方法,对应post请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 */
export function post(url, params) {
  return new Promise((resolve, reject) => {
    instance
      .post(url, QS.stringify(params))
      .then((res) => {
        resolve(res.data)
      })
      .catch((err) => {
        reject(err.data)
      })
  })
}

export { instance }

6. normalize.css

作用:

  • 保护有用的浏览器样式而不是去掉他们。
  • 为大部分 HTML 元素提供一般化的样式。
  • 修复浏览器自身的 bug 并保证各浏览器的一致性。
  • 优化 css 可用性。
  • 用注释和详细的文档来解释代码。
  • Normalize 支持包括手机浏览器在内的超多浏览器,同时对 HTML5 元素、排版、列表、嵌入的内容、表单和表格都进行了一般化。

1.安装

npm install --save normalize.css 

2.使用

main.js中引入

import 'normalize.css'

7. scss

npm i -D sass

8. unocss

1.安装

pnpm i unocss -D

2.配置

创建uno.config.js文件

import { presetMini, presetAttributify, presetIcons, defineConfig } from 'unocss'

export default defineConfig({
  presets: [presetAttributify(), presetMini(), presetIcons()],
  rules: [
    [
      'base',
      {
        width: '100%',
        height: '100%',
        display: 'flex',
        'flex-direction': 'column'
      }
    ],
    [
      'ellipsis',
      {
        overflow: 'hidden',
        'text-overflow': 'ellipsis',
        'white-space': 'nowrap'
      }
    ],
    [/^ellipsis-(\d+)$/, ([, d]) => ({
      'word-break': 'break-all',
      'text-overflow': 'ellipsis',
      display: '-webkit-box',
      '-webkit-box-orient': 'vertical',
      '-webkit-line-clamp': d,
      overflow: 'hidden'
    })]
  ]
})

vite.config.js中使用unocss

import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx' // 引入jsx
import Unocss from 'unocss/vite'

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd())
  return {
    plugins: [
      vue(),
      vueJsx({
      // 配置选项
      }),
      Unocss()
    ],
    resolve: {
      extensions: ['.vue', '.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'],
      alias: {
        '@': path.join(__dirname, 'src')
      }
    }
  }
})

3.安装vscode unocss 插件

image.png

有这种效果即可以正常使用unocss

image.png

5. 个人后台模板

这是自己使用vue3+vite+element-plus+unocss搭建的后台管理模板,欢迎体验

github地址:

github.com/monsterxwx/…

在线体验:

Vite App