0.0.5 • Published 1 year ago

yu-el-ui v0.0.5

Weekly downloads
-
License
MIT
Repository
-
Last release
1 year ago

Vue 3 + TypeScript + Vite + Eslint + prettier

安装pnpm ,node版本16.18.1

npm i -g pnpm 

用vite创建vue3+ts项目

pnpm create vite

安装@types/node

pnpm add @types/node -D

vite.config.ts设置别名

resolve: {
   alias: {
     '@': resolve(__dirname, 'src'),
     components: resolve(__dirname, 'src/components'),
   },
   extensions: ['.js', '.ts', '.jsx', '.tsx', '.json', '.vue', 'mjs'],
 },

tsconfig.json设置别名,不然vscode识别不了

"compilerOptions": {
  "baseUrl": "./",
   "paths": {
      "@/*": ["./src/*"],
      "components/*": ["./src/components/*"]
      }
   }

安装vue-router

pnpm add vue-roter

在src目录创建router文件夹,新建index.ts文件

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

import Home from '@/views/index.vue'

const routes: Array = { path: '', name: 'Home页面', component: Home, },

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

export default router

>在main.ts文件引入

import { createApp } from 'vue' import './style.css' import App from './App.vue' import router from './router'

const app = createApp(App)

// 注册路由 app.use(router) app.mount('#app')

## 安装element-plus

pnpm add element-plus @element-plus/icons-vue

> 在main.ts文件引入
> >1.全局引用

import { createApp } from 'vue' import './style.css' import App from './App.vue' import router from './router' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' import locale from 'element-plus/lib/locale/lang/zh-cn' import * as ElementPlusIconsVue from '@element-plus/icons-vue'

const app = createApp(App)

app.use(ElementPlus, { locale, })

for (const key, component of Object.entries(ElementPlusIconsVue)) { app.component(key, component) }

// 注册路由 app.use(router) app.mount('#app')

> 修改主题,创建样式并修改main.ts的引入

/ 只需要重写你需要的即可 / @forward 'element-plus/theme-chalk/src/common/var.scss' with ( $colors: ( 'primary': ( 'base': green, ), ), );

// 如果只是按需导入,则可以忽略以下内容。 // 如果你想导入所有样式: @use "element-plus/theme-chalk/src/index.scss" as *;

## 安装sass

pnpm add sass sass-loader -D

## 安装js-cookies

pnpm add @types/js-cookie js-cookie -D

## 安装axios并封装

pnpm add axios

>新建service文件夹,创建request.ts

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios' import { Result } from './types' import Cookies from 'js-cookie'

class YBRequest { private instance: AxiosInstance private options: AxiosRequestConfig constructor(options: AxiosRequestConfig) { this.options = options this.instance = axios.create(this.options)

this.instance.interceptors.request.use(
  (config: any) => {
    const token = Cookies.get('token')
    if (token) {
      config.headers.Authorization = token
    }
    return config
  },
  (err) => {
    return err
  },
)

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

}

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

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

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

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

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

export default YBRequest

>创建types.d.ts

export interface Result<T = any> { code: number data: T }

>创建index.ts

import YBRequest from './request'

export default new YBRequest({ baseURL: '/api', timeout: 10000, })

>在service建立对应模块的api文件夹进行分类
>>main/login/index.ts

import ybRequest from '@/service' import { GetDepartmentListParams } from './types'

enum DepartmentAPI { DepartmentList = '/department/list', }

export function getDepartmentList(params: GetDepartmentListParams) { return ybRequest.post({ url: DepartmentAPI.DepartmentList, data: params, }) }

>>main/login/types.d.ts

export interface GetDepartmentListParams { offset: number size: number } //可继承 // export interface GetDepartmentListParams extends ParamsPagination {}

## 安装eslint

pnpm add eslint -D

>初始化eslint
>> 执行npx eslint --init命令初始化eslint

You can also run this command directly using 'npm init @eslint/config'.

? How would you like to use ESLint? ... To check syntax and find problems

? What type of modules does your project use? ... JavaScript modules (import/export)

? Which framework does your project use? ... Vue.js

? Does your project use TypeScript? » No / Yes Yes

? Where does your code run? ... (用空格选中两个,回车确定) √ Browser √ Node

? What format do you want your config file to be in? ... JavaScript

The config that you've selected requires the following dependencies: eslint-plugin-vue@latest @typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest ? Would you like to install them now? No

>>最后一个提示我们选择No,然后手动npm安装提示的依赖

pnpm add eslint-plugin-vue@latest @typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest -D

>>在packeage.json添加命令

"scripts": { // 执行该命令eslint会检测当前项目下所有的.vue,.js,.ts,.jsx,.tsx文件是否符合eslint的代码规范,并尝试自动修复 "lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx --fix" },

>建立.eslintignore文件

.sh node_modules .md .woff .ttf .vscode .idea dist /public /docs .husky .local /bin .eslintrc.js prettier.config.js /src/mock/*

## 安装prettier

pnpm add prettier -D

> 配置.prettier.cjs

/*

  • @Author: yubb
  • @Date: 2023-04-26 15:37:48
  • @LastEditTime: 2023-04-26 15:52:49
  • @LastEditors: yubb
  • @Description:
  • @FilePath: \yubb-el-ui.prettierrc.cjs */ module.exports = { // 一行最多 100 字符 printWidth: 100, // 使用 2 个空格缩进 tabWidth: 2, // 不使用缩进符,而使用空格 useTabs: false, // 行尾不需要有分号 semi: false, // 使用单引号 singleQuote: true, // 对象的 key 仅在必要时用引号 quoteProps: 'as-needed', // jsx 不使用单引号,而使用双引号 jsxSingleQuote: false, // 尾随逗号 trailingComma: 'all', // 大括号内的首尾需要空格 bracketSpacing: true, // jsx 标签的反尖括号需要换行 jsxBracketSameLine: false, // 箭头函数,只有一个参数的时候,也需要括号 arrowParens: 'always', // 每个文件格式化的范围是文件的全部内容 rangeStart: 0, rangeEnd: Infinity, // 不需要写文件开头的 @prettier requirePragma: false, // 不需要自动在文件开头插入 @prettier insertPragma: false, // 使用默认的折行标准 proseWrap: 'preserve', // 根据显示样式决定 html 要不要折行 htmlWhitespaceSensitivity: 'css', // 换行符使用 lf endOfLine: 'lf', }
>建立.prettierignore

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

/*.svg /*.sh

/public/*

## vscode安装eslint,prettier插件

{ // vscode默认启用了根据文件类型自动设置tabsize的选项 "editor.detectIndentation": false, // 重新设定tabsize "editor.tabSize": 2, // 每次保存的时候自动格式化 "editor.formatOnSave": true, "editor.codeActionsOnSave": { // 使用eslint来fix,包括格式化会自动fix和代码质量检查会给出错误提示 "source.fixAll.eslint": true }, // 把prettier设置为vscode默认的代码格式化工具 "editor.defaultFormatter": "esbenp.prettier-vscode", // vue文件的默认格式化工具选择prettier "vue": { "editor.defaultFormatter": "esbenp.prettier-vscode" } }

## ESLint与Prettier会有冲突,和vue的一些语法冲突

pnpm add eslint-config-prettier eslint-plugin-prettier vue-eslint-parser -D

>eslint-config-prettier 会关闭ESLint中有关代码格式化的配置
>eslint-plugin-prettier 把Prettier配置成ESLint的一个插件,让其当做一个linter规则来运行
>去掉驼峰写法,index
>修改.eslint.cjs

extends: 'eslint:recommended', 'plugin:vue/vue3-essential', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended', , overrides: [], parser: 'vue-eslint-parser', parserOptions: { ecmaVersion: 'latest', sourceType: 'module', parser: '@typescript-eslint/parser', },

rules: { '@typescript-eslint/ban-types': 'error', { extendDefaults: true, types: { '{}': false, }, }, , 'vue/multi-word-component-names': [ 'error', { ignores: 'index', //需要忽略的组件名 }, ], },

## 在运行时,检测

pnpm add vite-plugin-eslint -D

> 修改vite.config.ts配置

import eslintPlugin from 'vite-plugin-eslint' import vueSetupExtend from 'vite-plugin-vue-setup-extend' import { resolve } from 'path' export default defineConfig({ plugins: [ vue(), vueSetupExtend(), eslintPlugin({ include: 'src//*.ts', 'src//.js', 'src/**/.vue', 'src/.ts', 'src/.js', 'src/*.vue', }), ], })

## 加些插件
### vite-plugin-vue-setup-extend 
>此插件解决了:使用setup语法糖的时候没办法直接为组件定义name(页面缓存需要name属性)

pnpm add vite-plugin-vue-setup-extend -D

> 在vite.config.ts配置

import vueSetupExtend from 'vite-plugin-vue-setup-extend' plugins: vueSetupExtend ()

> 在页面中使用
### unplugin-auto-import
>自动引入vue等的api

pnpm add unplugin-auto-import -D

>在vite.config.ts配置

import AutoImport from 'unplugin-auto-import/vite' plugins: [ AutoImport({ imports: 'vue', 'vue-router', 'pinia', // 自动导入vue、vue-router、pinia相关API dts: 'src/auto-import.d.ts', // 生成 auto-import.d.ts 全局声明 eslintrc: { enabled: true, // Default false }, }), ]

>在eslintrc.cjs配置'./.eslintrc-auto-import.json',重启

extends: 'eslint:recommended', 'plugin:vue/vue3-essential', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended', './.eslintrc-auto-import.json', ,

### vite-plugin-compression
> 静态文件压缩

pnpm install vite-plugin-compression -D

>配置

import viteCompression from 'vite-plugin-compression' plugins: viteCompression({ verbose: true, disable: false, // 不禁用压缩 deleteOriginFile: false, // 压缩后是否删除原文件 threshold: 10240, // 压缩前最小文件大小 algorithm: 'gzip', // 压缩算法 ext: '.gz' // 文件类型 })

### rollup-plugin-visualizer
>打包后的视图文件——生成一个stats.html文件

pnpm install rollup-plugin-visualizer -D

>配置

import {visualizer} from 'rollup-plugin-visualizer' plugins: visualizer({ open:true, //注意这里要设置为true,否则无效 gzipSize:true, brotliSize:true }),

## 安装pinia

pnpm add pinia

>在src目录新建store文件夹,新建index.ts文件,代码如下:

// 因为用了“unplugin-auto-import”插件 可以不需要再import Pinia的API // import { createPinia } from 'pinia' // 创建pinia状态管理对象 const pinia = createPinia() export default pinia

>在main.ts文件中引入,代码如下:

import pinia from './store' app.use(pinia)

>在store文件夹中新建modules文件夹(当然也可以不建,我这是为了区分管理),新建user.ts文件,代码如下:

const useUserStore = defineStore('user', { state: () => { return { token: '', name: '', avatar: '', nickName: '', userId: null, dept: {}, permissions: [], permBtn: [], permCode: [], } }, getters: {}, actions: {}, })

export default useUserStore

>>使用 defineStore() 定义一个 Store ;defineStore() 第一个参数是 storeId (必须要),第二个参数是一个选项对象:中有state(是一个函数返回一个对象)、getters、actions
>>store 是一个用 reactive 包裹的对象,如果直接解构会失去响应性。我们可以使用 storeToRefs() 对其进行解构:

import useUserStore from '@/store/modules/user' const userStore= useUserStore() const { hello: myHello } = storeToRefs(userStore)

## 集成qiankun(微前端)父级项目

pnpm install qiankun

> 修改main.ts

import { registerMicroApps, start } from 'qiankun' registerMicroApps( { name: 'subApp', // 必须与微应用注册名字相同 entry: 'http://192.168.8.50:3301', // 入口路径,开发时为微应用所启本地服务,上线时为微应用线上路径 container: '#sub-app-container', // app.vue 配置的挂载容器 id activeRule: '/subapp', // 当访问路由为 home 时加载微应用 props: { // 主应用向微应用传递参数 }, }, , { //生命周期钩子函数 beforeLoad: async (app) => { console.log('beforeLoad', app) }, beforeMount: async (app) => { console.log('beforeMount ', app) }, afterMount: async (app) => { console.log('afterMount', app) }, beforeUnmount: async (app) => { console.log('beforeUnmount ', app) }, afterUnmount: async (app) => { console.log('afterUnmount', app) }, }, )

// 启动 qiankun start()

## 集成qiankun(微前端)子级项目
> 安装vite-plugin-qiankun

pnpm add vite-plugin-qiankun

>修改vite.config.ts

import qiankun from 'vite-plugin-qiankun' plugins: qiankun('subApp', { // 微应用名字,与主应用注册的微应用名字保持一致 useDevMode: true, }), , server: { headers: { 'Access-Control-Allow-Origin': '*', }, host: '0.0.0.0', port: 3301, },

> 修改router.ts

import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper' const router = createRouter({ history: createWebHistory(qiankunWindow.POWERED_BY_QIANKUN ? '/subApp/' : '/'), routes: routes, })

> 修改main.ts

import { createApp } from 'vue' import './style.css' import App from './App.vue' import pinia from './store' import router from './router' import ElementPlus from 'element-plus' import './style/element/index.scss' import Cookies from 'js-cookie' import locale from 'element-plus/lib/locale/lang/zh-cn' import * as ElementPlusIconsVue from '@element-plus/icons-vue'

import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper' let instance: any = null function render(props: any = {}) { const { container } = props instance = createApp(App) instance.use(router) instance.use(pinia) // 注册全局api方法 // 注册所有图标 for (const key, component of Object.entries(ElementPlusIconsVue)) { instance.component(key, component) } // 注册ElementPlus instance.use(ElementPlus, { locale, // 语言设置 // size: Cookies.get('size') || 'medium' // 尺寸设置 }) instance?.mount(container ? container.querySelector('#app') : '#app') console.log('开始加载相关内容') } renderWithQiankun({ mount(props: any) { render(props) }, bootstrap() { console.log('%c', 'color:green;', ' ChildOne bootstrap') }, update() { console.log('%c', 'color:green;', ' ChildOne update') }, unmount(props: any) { console.log('unmount', props) instance.unmount() instance._container.innerHTML = '' instance = null }, }) if (!qiankunWindow.POWERED_BY_QIANKUN) { console.log('并不是qiankun渲染') render() }

## 封装自己的组件
> 给各自的组件都加上install

import YuButton from './src/index.vue'

YuButton.install = (App) => { App.component(YuButton.name, YuButton) }

export default YuButton

>统一暴露给外部

import YuButton from './button'

//按需引入 export { YuButton }

const components = YuButton

const YuUI = { install(App) { components.forEach((item) => { App.component(item.name, item) }) }, }

export default YuUI

## 安装vitepress
> 一个md和vue都可以使用的文档

pnpm add vitepress vitepress-theme-demoblock -D

>新建doces文件夹,创建首页

layout: home

title: Yu-el-ui

titleTemplate: 选项卡描述

editLink: true lastUpdated: true hero: name: Yu-el-ui text: vue3基础组件 tagline: Vue3 中基于Element-plus二次封装基础组件文档 image: src: /img/wocwin.jpg alt: Yu-el-ui actions: - theme: brand text: 安装指南 link: /components/ - theme: brand text: 组件预览 link: /components/TSelect/base.md features:

  • icon: 🔨 title: 实际项目 details: 实际项目中碰到的疑点、难点,致力于更优的自我。。
  • icon: 🧩 title: 基础组件 details: 基于Element-plus二次封装;使用组件 Demo 快速体验交互细节。。
  • icon: ✈️ title: Vue驱动。 details: 享受 Vue3 + vite3 的开发体验,在 Markdown 中使用 Vue 组件,同时可以使用 Vue 来开发自定义主题。

>新建components,放对应的组件说明和示例
>新建.vitepress文件夹config.ts

import { defineConfig } from 'vitepress' import { demoBlockPlugin } from 'vitepress-theme-demoblock' export default defineConfig({ title: 'yuui基础组件文档', description: '基于Element-plus基础组件封装使用', lang: 'cn-ZH', base: '/yuui/', lastUpdated: true, themeConfig: { logo: '/favicon.ico', siteTitle: 'yuui基础组件文档', outline: 3, nav: { text: '基础组件', link: '/components/Yubutton/base.md' }, , sidebar:{ '/components': [ // { // text: '常用组件', // items: // { text: '下拉选择组件', link: '/components/TSelect/base.md' }, // { text: '下拉选择表格组件', link: '/components/TSelectTable/base.md' }, // // }, ] } }, markdown: { config(md) { md.use(demoBlockPlugin, { customClass: 'demoblock-custom' }) } } })

>新增命令

"docs:dev": "pnpm run register:components && vitepress dev docs",

"docs:build": "pnpm run register:components && vitepress build docs",

"register:components": "vitepress-rc"

## 通过github预览页面
> 修改config.ts里面的base

base: '/yu-el-ui/',

> 添加命令,deploy.sh

确保脚本抛出遇到的错误

set -e

生成静态文件

pnpm run docs:build

进入生成的文件夹

cd ./docs/.vitepress/dist

git init git add -A git commit -m 'deploy'

如果发布到 https://.github.io/

git push -f https://github.com/onewebstudy/yu-el-ui.git master:gh-pages

cd -

"deploy": "deploy.sh"