从0开始搭建vue3+vite+ts+pinia项目

5 篇文章 0 订阅

目录

项目搭建选项

项目搭建步骤

本地开发环境

Vite脚手架构建项目

关联Git仓库

开发工具

安装pinia

安装Sass

安装Vant-UI

安装postcss-pxtorem(移动端项目)

安装axios

本地调试

环境变量

本地代理

全局UI组件

路由中间件

项目部署

nginx配置

jenkins自动化部署

自由风格配置

流水线配置

灰度部署方案


项目搭建选项

  • Vue3
  • Vite
  • TypeScript
  • axios
  • Pinia
  • Sass
  • Vant-UI(M)、Element-UI(PC)
  • Eslint
  • postcss-pxtorem(M)

项目搭建步骤

本地开发环境

安装nodejs,node版本建议大于16.0.0

Download | Node.js

Vite脚手架构建项目

官网:https://cn.vitejs.dev/guide/

关联Git仓库

初始化后的项目关联远程git仓库

开发工具

Visual Studio Code

配置.vscode/setting.json,自动校验eslint并修复

{
  // 开启保存自动格式化
  "editor.formatOnSave": true,
  // 开启eslint校验
  "eslint.enable": true,
  "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"],
  "editor.fontSize": 14,
  // vscode默认启用了根据文件类型自动设置tabsize的选项
  "editor.detectIndentation": false,
  // 重新设定tabsize
  "editor.tabSize": 2,
  // #每次保存的时候将代码按eslint格式进行修复
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  // 校验文件类型
  "eslint.validate": ["html", "vue", "javascript", "jsx"],
  //  #让prettier使用eslint的代码格式进行校验
  "prettier.eslintIntegration": true,
  //  #去掉代码结尾的分号
  "prettier.semi": true,
  //  #使用带引号替代双引号
  "prettier.singleQuote": true,
  //  #让函数(名)和后面的括号之间加个空格
  "javascript.format.insertSpaceBeforeFunctionParenthesis": true,
  // #让vue中的js按编辑器自带的ts格式进行格式化
  "vetur.format.defaultFormatter.js": "vscode-typescript",
  "vetur.format.defaultFormatterOptions": {
    "js-beautify-html": {
      "wrap_attributes": "force-aligned"
      // #vue组件中html代码格式化样式
    },
    "prettier": {
      "semi": false,
      "singleQuote": true,
      "eslintIntegration": true,
      "stylelintIntegration": true,
      "tabWidth": 2,
      "vetur.format.defaultFormatter.html": "prettier"
    }
  },
  "explorer.confirmDelete": false,
  "explorer.confirmDragAndDrop": false,
  "editor.renderControlCharacters": true,
  // "editor.renderWhitespace": "all",
  "files.associations": {
    "*.cjson": "jsonc",
    "*.wxss": "css",
    "*.wxs": "javascript"
  },
  "emmet.includeLanguages": {
    "wxml": "html"
  },
  "minapp-vscode.disableAutoConfig": true,
  "bald.config": false,
  "files.autoSave": "off",
  "diffEditor.ignoreTrimWhitespace": false,
  "editor.foldingStrategy": "indentation",
  "git.path": "",
  "editor.foldingMaximumRegions": 50000,
  "security.workspace.trust.untrustedFiles": "newWindow",
  "editor.unicodeHighlight.nonBasicASCII": false,
  // 以下是格式化插件配置
  "[html]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[less]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[vue]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[css]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[scss]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[jsonc]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  }
}

安装pinia与持久化封装

官网:安装 | Pinia 中文文档

项目构建时已选择安装pinia,下面是使用方法以及持久化存储配置

官网:快速开始 | pinia-plugin-persistedstate

1、安装持久化存储插件 pinia-plugin-persistedstate

npm i pinia-plugin-persistedstate -S

2、main.ts

import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const app = createApp(App)

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

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

3、在/src/store/目录下新建user.ts

import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    name: 'Tom', // 用户名
    age: 18, // 年龄
    weight: 60 // 公斤
  }),
  getters: {
    // 获取体重市斤
    getWeight: (state) => {
      return state.weight * 2
    }
  },
  actions: {
    // 修改用户名
    changeUserName(name: string) {
      this.name = name
    }
  },
  // 持久化插件配置
  persist: {
    key: 'store-user', // 本地存储key名称
    // storage: sessionStorage // 不设置默认存储localStorage
    paths: ['name'] // 指定持久化的值
  }
})

4、页面调用

<template>
  <div>
    <p>pinia-name: {{ name }}</p>
    <p>pinia-age: {{ age }}</p>
    <p>pinia-市斤: {{ storeUser.getWeight }}</p>
    <button @click="changeName">修改用户名称</button>
    <button @click="changeUser">批量修改</button>
    <button @click="changeNameFun">修改用户名称方法</button>
  </div>
</template>

<script setup lang="ts">
import { useUserStore } from '../store/user'
import { storeToRefs } from 'pinia';
const storeUser = useUserStore()
const { name, age } = storeToRefs(storeUser) // 将pinia的值响应式

// 单个修改state
const changeName = () => {
  storeUser.name = 'Jack'
}
// 批量修改
const changeUser = () => {
  storeUser.$patch({
    name: 'LiuTao',
    age: 10,
    weight: 80
  })
}
// 调用action
const changeNameFun = ()=> {
  storeUser.changeUserName('Alex')
}
</script>

安装Sass

npm i sass -D

使用

<style lang="scss">
</style>

安装Vant-UI

官网:Vant 4 - A lightweight, customizable Vue UI library for mobile web apps.

npm i vant -S

安装postcss-pxtorem(移动端项目)

移动端适配,兼容不同分辨率的手机

npm i postcss-pxtorem amfe-flexible -D

修改vite.config.ts

import postCssPxToRem from 'postcss-pxtorem'
export default defineConfig({
  ...
  css: {
    postcss: {
      plugins: [
        postCssPxToRem({
          rootValue: 75, // 1rem的大小
          propList: ['*'], // 需要转换的属性,这里选择全部都进行转换
          minPixelValue: 2 // 最小px为2,如果设置1px则不转rem
        })
      ]
    }
  }
  ...
})

在main.ts引入amfe-flexible

import 'amfe-flexible'

安装axios与请求封装

官网:axios

npm i axios -S

封装axios方法,新建/src/utils/request.ts文件

import axios from 'axios'
import type { AxiosInstance, AxiosError, AxiosResponse } from 'axios'
import { showToast } from 'vant'

const service: AxiosInstance = axios.create({
  // import.meta.env.DEV 判断是否为本地环境
  baseURL: import.meta.env.DEV ? '/api' : 'http://www.baidu.com',
  timeout: 30000
})

/* 请求拦截器 */
service.interceptors.request.use(
  (config) => {
    // 登录状态鉴权
    // if (token) {
    //   config.headers.Authorization = `Bearer ${token}`;
    // }
    return config
  },
  (error: AxiosError) => {
    showToast(error.message)
    return Promise.reject(error)
  }
)

/* 响应拦截器 */
service.interceptors.response.use(
  (response: AxiosResponse) => {
    const { code, message, data } = response.data
    // 根据自定义错误码判断请求是否成功
    if (code === '0') {
      // 将组件用的数据返回
      return data
    } else {
      // 处理业务错误。
      showToast(message)
      return Promise.reject(new Error(message))
    }
  },
  (error: AxiosError) => {
    // 处理 HTTP 网络错误
    let message = ''
    // HTTP 状态码
    const status = error.response?.status
    switch (status) {
      case 401:
        message = 'token 失效,请重新登录'
        // 这里可以触发退出的 action
        break
      case 403:
        message = '拒绝访问'
        break
      case 404:
        message = '请求地址错误'
        break
      case 500:
        message = '服务器故障'
        break
      default:
        message = '网络连接故障'
    }

    showToast(message)
    return Promise.reject(error)
  }
)

/* 导出封装的请求方法 */
export const http = (options: any) => {
  return new Promise((resolve, reject) => {
    // 方法一:get和delete请求,将请求体转换为queryString形式拼接在url
    // if (!options.method || options.method === 'get' || options.method === 'delete') {
    //   if (options.data) {
    //     options.url = options.url + '?' + new URLSearchParams(options.data).toString()
    //   }
    // }

    // 方法二:get和delete请求,使用params参数传参,post和put使用data参数
    const serviceOpt: any = {}
    if (!options.method || options.method === 'get' || options.method === 'delete') {
      serviceOpt.params = options.data
    } else {
      serviceOpt.data = options.data
    }
    service({
      method: options.method || 'get',
      url: options.url,
      ...serviceOpt
    })
      .then((res) => {
        resolve(res)
      })
      .catch((err) => {
        reject(err)
      })
  })
}

将封装的http方法绑定到全局变量

打开/src/mian.ts

import { http } from '@/utils/request'

app.config.globalProperties.$http = http

在vue文件使用

<script setup lang="ts">
import { onMounted, getCurrentInstance } from 'vue'
const { proxy: { $http } } = getCurrentInstance() as any
onMounted (async() => {
  const res: object = await $http({
    url: '/get/product/list',
    // method: 'get',
    data: {
      id: 1
    }
  })
  console.log(res)
})
</script>

本地调试

npm run dev执行后,只显示了Local: http://localhost:5173/,没有显示局域网ip地址,不方便局域网真机调试,需要配置启动host为0.0.0.0

打开vite.config.ts

export default defineConfig({
  server: {
    // port: 8080, // 启动端口号
    host: '0.0.0.0' // 启动显示局域网ip
  }
})

测试环境真机调试请参考:

H5移动端调试工具_不求甚解bc的博客-CSDN博客

环境变量

1、获取系统环境变量

import.meta.env.DEV // 开发环境:true
import.meta.env.PROD // 生产环境:true
import.meta.env.MODE // 开发环境:development  生产环境:production
...

2、获取命令行自定义环境变量

npm run dev --env=test

打开vite.config.ts

const env = process.env.npm_config_env || 'dev'
export default defineConfig({
  define: {
    app_env: JSON.stringify(env)
  }
})

在项目代码中使用,比如main.ts / index.vue

console.log(app_env) // 打印结果:test

注意:直接使用环境变量会提示变量未声明,需要在 env.d.ts 或 vite-env.d.ts 文件中添加类型声明

declare const app_env: string

本地代理

vite.config.ts

export default defineConfig({
  server: {
    proxy: {
      // 带选项写法:http://localhost:5173/api/bar -> http://jsonplaceholder.typicode.com/bar
      '/api': {
        target: 'http://jsonplaceholder.typicode.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
})

全局UI组件

vue3全局api组件_vue3 全局弹窗_不求甚解bc的博客-CSDN博客

路由中间件

vue路由中间件_不求甚解bc的博客-CSDN博客

项目部署

nginx配置

Apache,Nginx部署vue/react项目_apached发布 react_不求甚解bc的博客-CSDN博客

jenkins自动化部署

自由风格配置

jenkins部署vue/react项目_jenkins部署vue项目_不求甚解bc的博客-CSDN博客

jenkins分环境部署vue/react项目_不求甚解bc的博客-CSDN博客

流水线配置

jenkins流水线部署H5项目_jenkins部署h5_不求甚解bc的博客-CSDN博客

灰度部署方案

web前端灰度部署_不求甚解bc的博客-CSDN博客

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值