docs: init document

This commit is contained in:
fonghehe 2022-08-19 18:23:00 +08:00
commit 36613cd17b
42 changed files with 2917 additions and 0 deletions

25
.github/workflows/deploy.yml vendored Normal file
View File

@ -0,0 +1,25 @@
name: deployment
on:
push:
branches: ["docs"]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: 16
cache: yarn
- run: yarn install --frozen-lockfile
- name: Build
run: yarn docs:build
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: docs/.vitepress/dist

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

496
README.md Normal file
View File

@ -0,0 +1,496 @@
# vue-h5-template
基于 vue3 + vite + nutui or varlet or vant + sass + viewport 适配方案 +axios 封装,构建手机端模板脚手架
如果你不熟悉 vue3想继续使用 vue2 开发的,可以[点这里](https://github.com/sunniejs/vue-h5-template/tree/vue2-h5-template)来获取 vue2-h5-template
掘金: [移动端适配方案](https://juejin.cn/post/7018433228591595550)
<p>
<img src="https://cdn.jsdelivr.net/gh/fonghehe/picture/vue-h5-template/screen.png" width="320" style="display:inline; ">
</p>
### Node 版本要求
推荐你使用 NodeJs 14+的版本,毕竟技术日新月异。你可以使用 [nvm](https://github.com/nvm-sh/nvm) 或 [nvm-windows](https://github.com/coreybutler/nvm-windows) 在同一台电脑中管理多个 Node 版本。
本示例 Node.js 14.19.0
### 启动项目(强烈推荐使用 yarn)
```bash
git clone https://github.com/sunniejs/vue-h5-template.git
cd vue-h5-template
yarn install
yarn dev
```
<span id="top">目录</span>
- [√ vite](#vite)
- [√ 配置多环境变量](#env)
- [√ viewport 适配方案](#viewport)
- [√ 多 UI 组件库供选择](#ui)
- [√ Pinia 状态管理](#Pinia)
- [√ vue-router 4](#router)
- [√ axios 封装及接口管理](#axios)
- [√ vite.config.ts 基础配置](#base)
- [√ alias](#alias)
- [√ proxy 跨域](#proxy)
- [√ Eslint+Pettier+stylelint 统一开发规范 ](#lint)
### <span id="vite">✅ vite </span>
基于原生 ES 模块提供了丰富的内建功能如速度快到惊人的模块热更新HMR使用 Rollup 打包你的代码,并且它是预配置的,可输出用于生产环境的高度优化过的静态资源。更多关于[vite](https://cn.vitejs.dev/guide/)
模版集成了如下的 vite 插件
- unplugin-auto-import按需加载自动引入
- unplugin-vue-components按需加载自动引入组件
- vite-plugin-compression开启.gz 压缩)
- vite-plugin-eruda控制台方便移动端调试
- vite-plugin-imagemin图片压缩
- vite-plugin-mock引入 mockjs本地模拟接口
- vite-plugin-pages动态生成路由
- vite-plugin-progress构建显示进度条
- vite-plugin-restart监听配置文件修改自动重启 Vite
- vite-plugin-style-import按需引入样式文件
- vite-plugin-svg-icons加载 SVG 文件,自动引入)
### <span id="env">✅ 配置多环境变量 </span>
`package.json` 里的 `scripts` 配置 `dev` `dev:test` `dev:prod` ,通过 `--mode xxx` 来执行不同环境
- 通过 `yarn dev` 启动本地环境参数 , 执行 `development`
- 通过 `yarn dev:test` 启动测试环境参数 , 执行 `test`
- 通过 `yarn dev:prod` 启动正式环境参数 , 执行 `prod`
```javascript
"scripts": {
"dev": "vite",
"dev:test": "vite --mode test",
"dev:prod": "vite --mode production",
}
```
[▲ 回顶部](#top)
### <span id="viewport">✅ viewport 适配方案 </span>
不用担心,项目已经配置好了 `viewport` 适配,下面仅做介绍:
- [cnjm-postcss-px-to-viewport](https://github.com/cnjm/postcss-px-to-viewport) 是一款 `postcss` 插件,用于将单位转化为 `vw` 现在很多浏览器对`vw`的支持都很好,适配首选方案。
##### PostCSS 配置
下面提供了一份基本的 `postcss` 配置,可以在此配置的基础上根据项目需求进行修改
```javascript
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
plugins: {
autoprefixer: { overrideBrowserslist: ['Android 4.1', 'iOS 7.1', 'Chrome > 31', 'ff > 31', 'ie >= 8'] },
'cnjm-postcss-px-to-viewport': {
unitToConvert: 'px', // 要转化的单位
viewportWidth: 750, // UI设计稿的宽度
unitPrecision: 6, // 转换后的精度,即小数点位数
propList: ['*'], // 指定转换的css属性的单位*代表全部css属性的单位都进行转换
viewportUnit: 'vw', // 指定需要转换成的视窗单位默认vw
fontViewportUnit: 'vw', // 指定字体需要转换成的视窗单位默认vw
minPixelValue: 1, // 默认值1小于或等于1px则不进行转换
mediaQuery: true, // 是否在媒体查询的css代码中也进行转换默认false
replace: true, // 是否转换后直接更换属性值
include: [],
exclude: [], // 设置忽略文件,用正则做目录名匹配
customFun: ({ file }) => {
// 这个自定义的方法是针对处理vant组件下的设计稿为375问题
const designWidth = judgeComponent(file) ? 375 : 750;
return designWidth;
},
},
};
```
**新手必看,老鸟跳过**
很多小伙伴会问我,适配的问题, 因为我们使用的是 Vant UI所以必须根据 Vant UI 375 的设计规范走,一般我们的设计会将 UI 图上传到蓝湖,我们就可以需要的尺寸了。下面就大搞普及一下 rem。
我们知道 `1rem` 等于 `html` 根元素设定的 `font-size``px` 值。Vant UI 设置 `rootValue: 37.5` , 你可以看到在 iPhone 6 下看到 `1rem 等于 37.5px`
```html
<html data-dpr="1" style="font-size: 37.5px;"> </html>
```
切换不同的机型,根元素可能会有不同的 `font-size` 。当你写 css px 样式时,会被程序换算成 `rem` 达到适配。
因为我们用了 Vant 的组件,需要按照 `rootValue: 37.5` 来写样式。
举个例子:设计给了你一张 750px \* 1334px 图片,在 iPhone6 上铺满屏幕, 其他机型适配。
- 当`rootValue: 75` , 样式 `width: 750px;height: 1334px;` 图片会撑满 iPhone6 屏幕,这个时候切换其他机型,图片也会跟着撑满。
- 当`rootValue: 37.5` 的时候,样式 `width: 375px;height: 667px;` 图片会撑满 iPhone6 屏幕。
也就是 iphone 6 下 375px 宽度写 CSS。其他的你就可以根据你设计图去写对应的样式就可以了。
当然,想要撑满屏幕你可以使用 100%,这里只是举例说明。
```html
<img class="image" src="https://www.sunniejs.cn/static/weapp/logo.png" />
<style>
/* rootValue: 75 */
.image {
width: 750px;
height: 1334px;
}
/* rootValue: 37.5 */
.image {
width: 375px;
height: 667px;
}
</style>
```
[▲ 回顶部](#top)
### <span id="ui">✅ 多 UI 组件库供选择 </span>
Vite 构建工具,使用 vite-plugin-style-import 和 unplugin-vue-components/vite 实现按需引入。
#### 安装插件
```bash
yarn add vite-plugin-style-import -D
yarn add unplugin-vue-components/vite -D
```
#### 使用组件库
nutUI 没有按需加载的 resolversstyle 需要自己配置按需加载
`config/vite/plugins/styleImport.ts` 设置
```javascript
// 按需加载样式文件
...
createStyleImportPlugin({
resolves: [NutuiResolve()],
}),
...
```
项目在 `src/plugins/nutUI.ts` 下统一管理组件,用哪个引入哪个,无需在页面里重复引用
```javascript
// 按需全局引入nutUI组件
import Vue from 'vue';
import { Button, Cell, CellGroup } from '@nutui/nutui';
export const nutUiComponents = [Button, Cell, CellGroup];
// 在main.ts文件中引入
nutUiComponents.forEach((item) => {
app.use(item);
});
```
vant 和 varlet 可以使用组件按需加载
`config/vite/plugins/component.ts`
```javascript
import { VueUseComponentsResolver, VantResolver, VarletUIResolver } from 'unplugin-vue-components/resolvers';
...
resolvers: [VantResolver(), VarletUIResolver()],
...
```
#### 不需要某个组件库
nutUI 需删除`src/plugins/nutUI.ts``main.ts`文件下的引入
vant 和 varlet 只需删除对应的 resolvers 即可
删除后需全局搜索删除不需要的组件,避免报错
[▲ 回顶部](#top)
### <span id="Pinia">✅ Pinia 状态管理</span>
下一代 vuex使用极其方便ts 兼容好
目录结构
```bash
├── store
│ ├── modules
│ │ └── user.js
│ ├── index.js
```
使用
```html
<script lang="ts" setup>
import { useUserStore } from '@/store/modules/user';
const userStore = useUserStore();
userStore.login();
</script>
```
[▲ 回顶部](#top)
### <span id="router">✅ Vue-router </span>
本案例采用 `hash` 模式,开发者根据需求修改 `mode` `base`
**注意**:如果你使用了 `history` 模式, `vue.config.js` 中的 `publicPath` 要做对应的**修改**
前往:[vue.config.js 基础配置](#base)
```javascript
import Vue from 'vue';
import { createRouter, createWebHistory, Router } from 'vue-router';
Vue.use(Router);
export const router = [
{
name: 'root',
path: '/',
redirect: '/home',
component: () => import('@/layout/basic/index.vue'),
},
];
const router: Router = createRouter({
history: createWebHistory(),
routes: routes,
});
export default router;
```
更多:[Vue Router](https://router.vuejs.org/zh/introduction.html)
[▲ 回顶部](#top)
### <span id="axios">✅ Axios 封装及接口管理</span>
`utils/request.js` 封装 axios , 开发者需要根据后台接口做修改。
- `service.interceptors.request.use` 里可以设置请求头,比如设置 `token`
- `config.hideloading` 是在 api 文件夹下的接口参数里设置,下文会讲
- `service.interceptors.response.use` 里可以对接口返回数据处理,比如 401 删除本地信息,重新登录
```javascript
import axios from 'axios';
import store from '@/store';
import { Toast } from 'vant';
// 根据环境不同引入不同api地址
import { baseApi } from '@/config';
// create an axios instance
const service = axios.create({
baseURL: baseApi, // url = base api url + request url
withCredentials: true, // send cookies when cross-domain requests
timeout: 5000, // request timeout
});
// request 拦截器 request interceptor
service.interceptors.request.use(
(config) => {
// 不传递默认开启loading
if (!config.hideloading) {
// loading
Toast.loading({
forbidClick: true,
});
}
if (store.getters.token) {
config.headers['X-Token'] = '';
}
return config;
},
(error) => {
// do something with request error
console.log(error); // for debug
return Promise.reject(error);
},
);
// respone拦截器
service.interceptors.response.use(
(response) => {
Toast.clear();
const res = response.data;
if (res.status && res.status !== 200) {
// 登录超时,重新登录
if (res.status === 401) {
store.dispatch('FedLogOut').then(() => {
location.reload();
});
}
return Promise.reject(res || 'error');
} else {
return Promise.resolve(res);
}
},
(error) => {
Toast.clear();
console.log('err' + error); // for debug
return Promise.reject(error);
},
);
export default service;
```
#### 接口管理
`src/api` 文件夹下统一管理接口
- 你可以建立多个模块对接接口, 比如 `home.js` 里是首页的接口这里讲解 `user.js`
- `url` 接口地址,请求的时候会拼接上 `config` 下的 `baseApi`
- `method` 请求方法
- `data` 请求参数 `qs.stringify(params)` 是对数据系列化操作
- `hideloading` 默认 `false`, 设置为 `true` 后,不显示 loading ui 交互中有些接口不需要让用户感知
```javascript
import qs from 'qs';
// axios
import request from '@/utils/request';
//user api
// 用户信息
export function getUserInfo(params) {
return request({
url: '/user/userinfo',
method: 'post',
data: qs.stringify(params),
hideloading: true, // 隐藏 loading 组件
});
}
```
#### 如何调用
```javascript
// 请求接口
import { getUserInfo } from '@/api/user.js';
const params = {
user: 'sunnie',
};
getUserInfo(params)
.then(() => {})
.catch(() => {});
```
[▲ 回顶部](#top)
### <span id="base">✅ vite.config.ts 基础配置 </span>
如果你的 `Vue Router` 模式是 hash
```javascript
publicPath: './',
```
如果你的 `Vue Router` 模式是 history 这里的 publicPath 和你的 `Vue Router` `base` **保持一致**
```javascript
publicPath: '/app/',
```
```javascript
export default function ({ command }: ConfigEnv): UserConfigExport {
const isProduction = command === 'build';
return {
server: {
host: '0.0.0.0',
},
plugins: [
vue(),
vueJsx(),
createStyleImportPlugin({
resolves: [NutuiResolve()],
}),
eruda(),
viteMockServe({
mockPath: './src/mock',
localEnabled: command === 'serve',
logger: true,
}),
],
css: {
preprocessorOptions: {
scss: {
// 配置 nutui 全局 scss 变量
additionalData: `@import "@nutui/nutui/dist/styles/variables.scss";`,
},
},
},
};
}
```
[▲ 回顶部](#top)
### <span id="alias">✅ 配置 alias 别名 </span>
```javascript
resolve: {
alias: [{
find: 'vue-i18n',
replacement: 'vue-i18n/dist/vue-i18n.cjs.js',
},
// /@/xxxx => src/xxxx
{
find: /\/@\//,
replacement: pathResolve('src') + '/',
},
// /#/xxxx => types/xxxx
{
find: /\/#\//,
replacement: pathResolve('types') + '/',
},
],
},
```
[▲ 回顶部](#top)
### <span id="proxy">✅ 配置 proxy 跨域 </span>
```javascript
server: {
proxy: {
'/api': {
target: 'https://baidu.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
},
```
[▲ 回顶部](#top)
### <span id="lint">✅ Eslint+Pettier+stylelint 统 ˜ 开发规范 </span>
根目录下的`.eslintrc.js``.stylelint.config.js``.prettier.config.js`内置了 lint 规则,帮助你规范地开发代码,有助于提高团队的代码质量和协作性,可以根据团队的规则进行修改
# 关于我
扫描添加下方的微信并备注加交流群,交流学习,及时获取代码最新动态。
<p>
<img src="https://cdn.jsdelivr.net/gh/fonghehe/picture/personal/account.jpg" width="256" style="display:inline; ">
</p>
<p>
<img src="https://cdn.jsdelivr.net/gh/fonghehe/picture/personal/group.jpg" width="256" style="display:inline; ">
</p>
如果对你有帮助送我一颗珍贵的小星星づ ̄3 ̄づ╭❤

99
docs/.vitepress/config.js Normal file
View File

@ -0,0 +1,99 @@
module.exports = {
lang: "zh-CN",
title: "Vue-H5-Template",
base: "/fastool/",
description: "一个开箱即用的vue h5脚手架",
lastUpdated: true,
head: [
// 添加图标
["link", { rel: "icon", href: "/favicon.ico" }],
],
themeConfig: {
nav: nav(),
sidebar: {
"/guide/": sidebarGuide(),
},
socialLinks: [
{ icon: "github", link: "https://github.com/tobe-fe-dalao/fastool" },
],
editLink: {
pattern: "https://github.com/tobe-fe-dalao/fastool/tree/doc/docs/:path",
text: "在GitHub编辑此页",
},
footer: {
message: "Released under the MIT License.",
copyright: "Copyright © 2022-present Fonghehe",
},
algolia: {
appId: "5ZHOMUV2DI",
apiKey: "d1de686f0fd4404abc0897093c246ffb",
indexName: "vue-h5-template",
},
},
};
function nav() {
return [
{ text: "介绍", link: "/guide/" },
{ text: "掘金", link: "https://juejin.cn/user/3016715636842622" },
{ text: "加入我们", link: "https://github.com/tobe-fe-dalao/fastool" },
];
}
function sidebarGuide() {
return [
{
text: "介绍",
collapsible: true,
items: [
{ text: "介绍", link: "/guide/" },
{ text: "快速上手", link: "/guide/start" },
{ text: "参与编辑", link: "/guide/edit" },
],
},
{
text: "vue3-template",
collapsible: true,
items: [
{ text: "vite", link: "/guide/vue3/vite" },
{ text: "配置多环境变量", link: "/guide/vue3/env" },
{ text: "viewport 适配方案", link: "/guide/vue3/viewport" },
{ text: "多UI组件库供选择", link: "/guide/vue3/ui" },
{ text: "Pinia 状态管理", link: "/guide/vue3/pinia" },
{ text: "vue-router", link: "/guide/vue3/router" },
{ text: "axios 封装及接口管理", link: "/guide/vue3/axios" },
{ text: "vite.config.ts 基础配置", link: "/guide/vue3/base" },
{ text: "alias", link: "/guide/vue3/base" },
{ text: "proxy 跨域", link: "/guide/vue3/base" },
{
text: "Eslint+Pettier+stylelint 统一开发规范",
link: "/guide/vue3/lint",
},
],
},
{
text: "vue2-template",
collapsible: false,
items: [
{ text: "启动项目", link: "/guide//vue2/start" },
{ text: "配置多环境变量", link: "/guide/vue2/env" },
{ text: "rem 适配方案", link: "/guide/vue2/rem" },
{ text: "vw 适配方案", link: "/guide/vue2/vw" },
{ text: "VantUI 组件按需加载", link: "/guide/vue2/vant" },
{ text: "Sass 全局样式", link: "/guide/vue2/sass" },
{ text: "Vuex 状态管理", link: "/guide/vue2/vuex" },
{ text: "Vue-router", link: "/guide/vue2/router" },
{ text: "Axios 封装及接口管理", link: "/guide/vue2/axios" },
{ text: "vue.config.js 基础配置", link: "/guide/vue2/base" },
{ text: "配置 alias 别名", link: "/guide/vue2/alias" },
{ text: "配置 proxy 跨域", link: "/guide/vue2/proxy" },
{ text: "配置 打包分析", link: "/guide/vue2/bundle" },
{ text: "配置 externals 引入 cdn 资源", link: "/guide/vue2/externals" },
{ text: "去掉 console.log", link: "/guide/vue2/console" },
{ text: "splitChunks 单独打包第三方模块", link: "/guide/vue2/chunks" },
{ text: "添加 IE 兼容", link: "/guide/vue2/ie" },
{ text: "Eslint+Pettier 统一开发规范", link: "/guide/vue2/lint" },
],
},
];
}

View File

@ -0,0 +1,61 @@
:root {
--vp-c-brand: #16c5fe;
--vp-c-green: #16c5fe;
--vp-c-green-light: #109ef7;
--vp-c-green-lighter: #109ef7;
--vp-c-green-dark: #109ef7;
--vp-c-green-darker: #109ef7;
}
.dark {
--vp-c-bg: #000;
--vp-code-block-bg: #111;
--vp-c-bg-alt: rgba(0, 0, 0, 0.5);
}
@media (min-width: 960px) {
.dark .VPNavBar.has-sidebar .content[data-v-d84f2262] {
background: rgba(36, 36, 36, 0.1);
}
}
.Layout::before {
content: "";
background-size: 100% 100%;
background-position: right;
background-repeat: no-repeat;
opacity: 1;
max-width: 100%;
height: 100%;
width: 50%;
position: fixed;
top: -20%;
right: -10%;
display: block;
}
.Layout::after {
content: "";
background-size: 100% 100%;
background-position: right;
background-repeat: no-repeat;
opacity: 1;
max-width: 100%;
height: 100%;
width: 50%;
position: fixed;
bottom: -20%;
left: -10%;
display: block;
z-index: -1;
}
@media (min-width: 960px) {
.title {
font-size: 24px !important;
}
}
.image-src {
max-width: 220px !important;
}

View File

@ -0,0 +1,4 @@
import DefaultTheme from "vitepress/theme";
import "./custom.css";
export default DefaultTheme;

19
docs/guide/edit.md Normal file
View File

@ -0,0 +1,19 @@
# 参与编辑
欢迎各位有意愿参与到开源当中的朋友加入文档的编写,书写文档不仅是教会别人知识,更是用自己的表达方式概括自己所学习的知识,这对个人来说是一种不多的成长机会
```js
// 拉取项目
git clone https://github.com/sunniejs/vue-h5-template
// 切换分支
git checkout -b docs origin/docs
// 安装依赖
yarn install
// 启动项目
yarn start
```

23
docs/guide/index.md Normal file
View File

@ -0,0 +1,23 @@
# Vue-H5-Template
[Vue-H5-Template](https://github.com/sunniejs/vue-h5-template),是基于 vite + vue3 + pinia + ( Vant or Varlet or NutUI ) + viewport 适配方案 ,构建移动端开发脚手架
## 特点
### 最新技术栈
- 框架选型基于当下流行的 vue + vite + ts 模式,精选社区经典的 ui 框架和 vite 插件
### 基于 TypeScript
- typescript 越来越被大型的 js 项目所需要,明确的类型定义可以省下不少的维护成本
### 轻量级
- 不同于集成解决方案,尽量做到轻量不冗杂,只引入高频次、需求高的插件和清晰的示例
- 轻装上阵,便于拓展开发
### 通俗易懂的文档
- 基于最新 VitePress 构建的文档,更快,更便捷
- 更快的热更新

17
docs/guide/start.md Normal file
View File

@ -0,0 +1,17 @@
# 快速上手
## node 版本要求
推荐 14.19.0+以上的版本,毕竟 2022 年了,别掐着 12+的版本了,你也可以使用[nvm](https://github.com/nvm-sh/nvm)或[nvm-windows](https://github.com/coreybutler/nvm-windows)在同一台电脑上管理多个 node 版本
## 包管理器
尽量使用 yarn 或者 pnpm本项目仅保证在 yarn 或 pnpm 下正确运行npm 涉及到网络环境等各种情况的限制不做过多考虑。
## 启动项目
项目中包含 vue2 和 vue3 两套模版
如你使用的是 vue2-template请参考[vue2 项目启动]()
如你使用的是 vue3-template请参考[vue3 项目启动]()

19
docs/guide/vue2/alias.md Normal file
View File

@ -0,0 +1,19 @@
# 配置 alias 别名
```javascript
const path = require("path");
const resolve = (dir) => path.join(__dirname, dir);
const IS_PROD = ["production", "prod"].includes(process.env.NODE_ENV);
module.exports = {
chainWebpack: (config) => {
// 添加别名
config.resolve.alias
.set("@", resolve("src"))
.set("assets", resolve("src/assets"))
.set("api", resolve("src/api"))
.set("views", resolve("src/views"))
.set("components", resolve("src/components"));
},
};
```

106
docs/guide/vue2/axios.md Normal file
View File

@ -0,0 +1,106 @@
### <span id="axios">✅ Axios 封装及接口管理</span>
`utils/request.js` 封装 axios ,开发者需要根据后台接口做修改。
- `service.interceptors.request.use` 里可以设置请求头,比如设置 `token`
- `config.hideloading` 是在 api 文件夹下的接口参数里设置,下文会讲
- `service.interceptors.response.use` 里可以对接口返回数据处理,比如 401 删除本地信息,重新登录
```javascript
import axios from 'axios'
import store from '@/store'
import { Toast } from 'vant'
// 根据环境不同引入不同api地址
import { baseApi } from '@/config'
// create an axios instance
const service = axios.create({
baseURL: baseApi, // url = base api url + request url
withCredentials: true, // send cookies when cross-domain requests
timeout: 5000, // request timeout
})
// request 拦截器 request interceptor
service.interceptors.request.use(
config => {
// 不传递默认开启loading
if (!config.hideloading) {
// loading
Toast.loading({
forbidClick: true,
})
}
if (store.getters.token) {
config.headers['X-Token'] = ''
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
// respone拦截器
service.interceptors.response.use(
response => {
Toast.clear()
const res = response.data
if (res.status && res.status !== 200) {
// 登录超时,重新登录
if (res.status === 401) {
store.dispatch('FedLogOut').then(() => {
location.reload()
})
}
return Promise.reject(res || 'error')
} else {
return Promise.resolve(res)
}
},
error => {
Toast.clear()
console.log('err' + error) // for debug
return Promise.reject(error)
}
)
export default service
```
#### 接口管理
`src/api` 文件夹下统一管理接口
- 你可以建立多个模块对接接口, 比如 `home.js` 里是首页的接口这里讲解 `user.js`
- `url` 接口地址,请求的时候会拼接上 `config` 下的 `baseApi`
- `method` 请求方法
- `data` 请求参数 `qs.stringify(params)` 是对数据系列化操作
- `hideloading` 默认 `false`,设置为 `true` 后,不显示 loading ui 交互中有些接口不需要让用户感知
```javascript
import qs from 'qs'
// axios
import request from '@/utils/request'
//user api
// 用户信息
export function getUserInfo(params) {
return request({
url: '/user/userinfo',
method: 'post',
data: qs.stringify(params),
hideloading: true, // 隐藏 loading 组件
})
}
```
#### 如何调用
```javascript
// 请求接口
import { getUserInfo } from '@/api/user.js'
const params = { user: 'sunnie' }
getUserInfo(params)
.then(() => {})
.catch(() => {})
```

36
docs/guide/vue2/base.md Normal file
View File

@ -0,0 +1,36 @@
### <span id="base">✅ Webpack 4 vue.config.js 基础配置 </span>
如果你的 `Vue Router` 模式是 hash
```javascript
publicPath: './',
```
如果你的 `Vue Router` 模式是 history 这里的 publicPath 和你的 `Vue Router` `base` **保持一直**
```javascript
publicPath: '/app/',
```
```javascript
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
module.exports = {
publicPath: './', // 署应用包时的基本 URL。 vue-router hash 模式使用
// publicPath: '/app/', // 署应用包时的基本 URL。 vue-router history模式使用
outputDir: 'dist', // 生产环境构建文件的目录
assetsDir: 'static', // outputDir的静态资源(js、css、img、fonts)目录
lintOnSave: !IS_PROD,
productionSourceMap: false, // 如果你不需要生产环境的 source map可以将其设置为 false 以加速生产环境构建。
devServer: {
port: 9020, // 端口号
open: false, // 启动后打开浏览器
overlay: {
// 当出现编译器错误或警告时,在浏览器中显示全屏覆盖层
warnings: false,
errors: true,
},
// ...
},
}
```

22
docs/guide/vue2/bundle.md Normal file
View File

@ -0,0 +1,22 @@
### <span id="bundle">✅ 配置 打包分析 </span>
```javascript
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = {
chainWebpack: config => {
// 打包分析
if (IS_PROD) {
config.plugin('webpack-report').use(BundleAnalyzerPlugin, [
{
analyzerMode: 'static',
},
])
}
},
}
```
```bash
npm run build
```

45
docs/guide/vue2/chunks.md Normal file
View File

@ -0,0 +1,45 @@
### <span id="chunks">✅ splitChunks 单独打包第三方模块</span>
```javascript
module.exports = {
chainWebpack: config => {
config.when(IS_PROD, config => {
config
.plugin('ScriptExtHtmlWebpackPlugin')
.after('html')
.use('script-ext-html-webpack-plugin', [
{
// 将 runtime 作为内联引入不单独存在
inline: /runtime\..*\.js$/,
},
])
.end()
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
// cacheGroups 下可以可以配置多个组每个组根据test设置条件符合test条件的模块
commons: {
name: 'chunk-commons',
test: resolve('src/components'),
minChunks: 3, // 被至少用三次以上打包分离
priority: 5, // 优先级
reuseExistingChunk: true, // 表示是否使用已有的 chunk如果为 true 则表示如果当前的 chunk 包含的模块已经被抽取出去了,那么将不会重新生成新的。
},
node_vendors: {
name: 'chunk-libs',
chunks: 'initial', // 只打包初始时依赖的第三方
test: /[\\/]node_modules[\\/]/,
priority: 10,
},
vantUI: {
name: 'chunk-vantUI', // 单独将 vantUI 拆包
priority: 20, // 数字大权重到,满足多个 cacheGroups 的条件时候分到权重高的
test: /[\\/]node_modules[\\/]_?vant(.*)/,
},
},
})
config.optimization.runtimeChunk('single')
})
},
}
```

View File

@ -0,0 +1,34 @@
### <span id="console">✅ 去掉 console.log </span>
保留了测试环境和本地环境的 `console.log`
```bash
npm i -D babel-plugin-transform-remove-console
```
在 babel.config.js 中配置
```javascript
// 获取 VUE_APP_ENV 非 NODE_ENV测试环境依然 console
const IS_PROD = ['production', 'prod'].includes(process.env.VUE_APP_ENV)
const plugins = [
[
'import',
{
libraryName: 'vant',
libraryDirectory: 'es',
style: true,
},
'vant',
],
]
// 去除 console.log
if (IS_PROD) {
plugins.push('transform-remove-console')
}
module.exports = {
presets: [['@vue/cli-plugin-babel/preset', { useBuiltIns: 'entry' }]],
plugins,
}
```

84
docs/guide/vue2/env.md Normal file
View File

@ -0,0 +1,84 @@
### <span id="env">✅ 配置多环境变量 </span>
`package.json` 里的 `scripts` 配置 `serve` `stage` `build`,通过 `--mode xxx` 来执行不同环境
- 通过 `npm run serve` 启动本地 , 执行 `development`
- 通过 `npm run stage` 打包测试 , 执行 `staging`
- 通过 `npm run build` 打包正式 , 执行 `production`
```javascript
"scripts": {
"serve": "vue-cli-service serve --open",
"stage": "vue-cli-service build --mode staging",
"build": "vue-cli-service build",
}
```
##### 配置介绍
&emsp;&emsp;`VUE_APP_` 开头的变量,在代码中可以通过 `process.env.VUE_APP_` 访问。
&emsp;&emsp;比如,`VUE_APP_ENV = 'development'` 通过`process.env.VUE_APP_ENV` 访问。
&emsp;&emsp;除了 `VUE_APP_*` 变量之外,在你的应用代码中始终可用的还有两个特殊的变量`NODE_ENV``BASE_URL`
在项目根目录中新建`.env.*`
- .env.development 本地开发环境配置
```bash
NODE_ENV='development'
# must start with VUE_APP_
VUE_APP_ENV = 'development'
```
- .env.staging 测试环境配置
```bash
NODE_ENV='production'
# must start with VUE_APP_
VUE_APP_ENV = 'staging'
```
- .env.production 正式环境配置
```bash
NODE_ENV='production'
# must start with VUE_APP_
VUE_APP_ENV = 'production'
```
这里我们并没有定义很多变量,只定义了基础的 VUE_APP_ENV `development` `staging` `production`
变量我们统一在 `src/config/env.*.js` 里进行管理。
这里有个问题,既然这里有了根据不同环境设置变量的文件,为什么还要去 config 下新建三个对应的文件呢?
**修改起来方便,不需
要重启项目,符合开发习惯。**
config/index.js
```javascript
// 根据环境引入不同配置 process.env.NODE_ENV
const config = require('./env.' + process.env.VUE_APP_ENV)
module.exports = config
```
配置对应环境的变量,拿本地环境文件 `env.development.js` 举例,用户可以根据需求修改
```javascript
// 本地环境配置
module.exports = {
title: 'vue-h5-template',
baseUrl: 'http://localhost:9018', // 项目地址
baseApi: 'https://test.xxx.com/api', // 本地api请求地址
APPID: 'xxx',
APPSECRET: 'xxx',
}
```
根据环境不同,变量就会不同了
```javascript
// 根据环境不同引入不同baseApi地址
import { baseApi } from '@/config'
console.log(baseApi)
```

View File

@ -0,0 +1,84 @@
### <span id="externals">✅ 配置 externals 引入 cdn 资源 </span>
这个版本 CDN 不再引入,我测试了一下使用引入 CDN 和不使用,不使用会比使用时间少。网上不少文章测试 CDN 速度块,这个开发者可
以实际测试一下。
另外项目中使用的是公共 CDN 不稳定,域名解析也是需要时间的(如果你要使用请尽量使用同一个域名)
因为页面每次遇到`<script>`标签都会停下来解析执行,所以应该尽可能减少`<script>`标签的数量 `HTTP`请求存在一定的开销100K
的文件比 5 个 20K 的文件下载的更快,所以较少脚本数量也是很有必要的
暂时还没有研究放到自己的 cdn 服务器上。
```javascript
const defaultSettings = require('./src/config/index.js')
const name = defaultSettings.title || 'vue mobile template'
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
// externals
const externals = {
vue: 'Vue',
'vue-router': 'VueRouter',
vuex: 'Vuex',
vant: 'vant',
axios: 'axios',
}
// CDN外链会插入到index.html中
const cdn = {
// 开发环境
dev: {
css: [],
js: [],
},
// 生产环境
build: {
css: ['https://cdn.jsdelivr.net/npm/vant@2.4.7/lib/index.css'],
js: [
'https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js',
'https://cdn.jsdelivr.net/npm/vue-router@3.1.5/dist/vue-router.min.js',
'https://cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js',
'https://cdn.jsdelivr.net/npm/vuex@3.1.2/dist/vuex.min.js',
'https://cdn.jsdelivr.net/npm/vant@2.4.7/lib/index.min.js',
],
},
}
module.exports = {
configureWebpack: config => {
config.name = name
// 为生产环境修改配置...
if (IS_PROD) {
// externals
config.externals = externals
}
},
chainWebpack: config => {
/**
* 添加CDN参数到htmlWebpackPlugin配置中
*/
config.plugin('html').tap(args => {
if (IS_PROD) {
args[0].cdn = cdn.build
} else {
args[0].cdn = cdn.dev
}
return args
})
},
}
```
在 public/index.html 中添加
```javascript
<!-- 使用CDN的CSS文件 -->
<% for (var i in
htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %>
<link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style" />
<link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet" />
<% } %>
<!-- 使用CDN加速的JS文件配置在vue.config.js下 -->
<% for (var i in
htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %>
```

30
docs/guide/vue2/ie.md Normal file
View File

@ -0,0 +1,30 @@
### <span id="ie">✅ 添加 IE 兼容 </span>
之前的方式 会报 `@babel/polyfill` is deprecated. Please, use required parts of `core-js` and
`regenerator-runtime/runtime` separately
`@babel/polyfill` 废弃,使用 `core-js``regenerator-runtime`
```bash
npm i --save core-js regenerator-runtime
```
`main.js` 中添加
```javascript
// 兼容 IE
// https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md#babelpolyfill
import 'core-js/stable'
import 'regenerator-runtime/runtime'
```
配置 `babel.config.js`
```javascript
const plugins = []
module.exports = {
presets: [['@vue/cli-plugin-babel/preset', { useBuiltIns: 'usage', corejs: 3 }]],
plugins,
}
```

165
docs/guide/vue2/lint.md Normal file
View File

@ -0,0 +1,165 @@
### <span id="pettier">✅ Eslint + Pettier 统一开发规范 </span>
VScode (版本 1.47.3)安装 `eslint` `prettier` `vetur` 插件 `.vue` 文件使用 vetur 进行格式化,其他使用`prettier`,后面会
专门写个如何使用配合使用这三个玩意
在文件 `.prettierrc` 里写 属于你的 pettier 规则
```bash
{
"printWidth": 120,
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "none",
"semi": false,
"wrap_line_length": 120,
"wrap_attributes": "auto",
"proseWrap": "always",
"arrowParens": "avoid",
"bracketSpacing": false,
"jsxBracketSameLine": true,
"useTabs": false,
"overrides": [{
"files": ".prettierrc",
"options": {
"parser": "json"
}
}]
}
```
Vscode setting.json 设置
```bash
{
// 将设置放入此文件中以覆盖默认设置
"files.autoSave": "off",
// 控制字体系列。
"editor.fontFamily": "Consolas, 'Courier New', monospace,'宋体'",
"terminal.integrated.shell.windows": "C:\\Program Files\\Git\\bin\\bash.exe",
// 以像素为单位控制字号。
"editor.fontSize": 16,
// 控制选取范围是否有圆角
"editor.roundedSelection": false,
// 建议小组件的字号
"editor.suggestFontSize": 16,
// 在“打开的编辑器”窗格中显示的编辑器数量。将其设置为 0 可隐藏窗格。
"explorer.openEditors.visible": 0,
// 是否已启用自动刷新
"git.autorefresh": true,
// 以像素为单位控制终端的字号,这是 editor.fontSize 的默认值。
"terminal.integrated.fontSize": 14,
// 控制终端游标是否闪烁。
"terminal.integrated.cursorBlinking": true,
// 一个制表符等于的空格数。该设置在 `editor.detectIndentation` 启用时根据文件内容进行重写。
// Tab Size
"editor.tabSize": 2,
// By default, common template. Do not modify it!!!!!
"editor.formatOnType": true,
"window.zoomLevel": 0,
"editor.detectIndentation": false,
"css.fileExtensions": ["css", "scss"],
"files.associations": {
"*.string": "html",
"*.vue": "vue",
"*.wxss": "css",
"*.wxml": "wxml",
"*.wxs": "javascript",
"*.cjson": "jsonc",
"*.js": "javascript"
},
// 为指定的语法定义配置文件或使用带有特定规则的配置文件。
"emmet.syntaxProfiles": {
"vue-html": "html",
"vue": "html"
},
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true
},
//保存时eslint自动修复错误
"editor.formatOnSave": true,
// Enable per-language
//配置 ESLint 检查的文件类型
"editor.quickSuggestions": {
"strings": true
},
// 添加 vue 支持
// 这里是针对vue文件的格式化设置vue的规则在这里生效
"vetur.format.options.tabSize": 2,
"vetur.format.options.useTabs": false,
"vetur.format.defaultFormatter.html": "js-beautify-html",
"vetur.format.defaultFormatter.css": "prettier",
"vetur.format.defaultFormatter.scss": "prettier",
"vetur.format.defaultFormatter.postcss": "prettier",
"vetur.format.defaultFormatter.less": "prettier",
"vetur.format.defaultFormatter.js": "vscode-typescript",
"vetur.format.defaultFormatter.sass": "sass-formatter",
"vetur.format.defaultFormatter.ts": "prettier",
"vetur.format.defaultFormatterOptions": {
"js-beautify-html": {
"wrap_attributes": "aligned-multiple", // 超过150折行
"wrap-line-length": 150
},
// #vue组件中html代码格式化样式
"prettier": {
"printWidth": 120,
"tabWidth": 2,
"singleQuote": false,
"trailingComma": "none",
"semi": false,
"wrap_line_length": 120,
"wrap_attributes": "aligned-multiple", // 超过150折行
"proseWrap": "always",
"arrowParens": "avoid",
"bracketSpacing": true,
"jsxBracketSameLine": true,
"useTabs": false,
"overrides": [
{
"files": ".prettierrc",
"options": {
"parser": "json"
}
}
]
}
},
// Enable per-language
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"vetur.validation.template": false,
"html.format.enable": false,
"json.format.enable": false,
"javascript.format.enable": false,
"typescript.format.enable": false,
"javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[vue]": {
"editor.defaultFormatter": "octref.vetur"
},
"emmet.includeLanguages": {
"wxml": "html"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// 开启eslint自动修复js/ts功能
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"minapp-vscode.disableAutoConfig": true,
"javascript.implicitProjectConfig.experimentalDecorators": true,
"editor.maxTokenizationLineLength": 200000
}
```

36
docs/guide/vue2/proxy.md Normal file
View File

@ -0,0 +1,36 @@
### <span id="proxy">✅ 配置 proxy 跨域 </span>
如果你的项目需要跨域设置,你需要打来 `vue.config.js` `proxy` 注释 并且配置相应参数
<u>**!!!注意:你还需要将 `src/config/env.development.js` 里的 `baseApi` 设置成 '/'**</u>
```javascript
module.exports = {
devServer: {
// ....
proxy: {
//配置跨域
'/api': {
target: 'https://test.xxx.com', // 接口的域名
// ws: true, // 是否启用websockets
changOrigin: true, // 开启代理,在本地创建一个虚拟服务端
pathRewrite: {
'^/api': '/',
},
},
},
},
}
```
使用 例如: `src/api/home.js`
```javascript
export function getUserInfo(params) {
return request({
url: '/api/userinfo',
method: 'post',
data: qs.stringify(params),
})
}
```

69
docs/guide/vue2/rem.md Normal file
View File

@ -0,0 +1,69 @@
### <span id="rem">✅ rem 适配方案 </span>
不用担心,项目已经配置好了 `rem` 适配, 下面仅做介绍:
Vant 中的样式默认使用`px`作为单位,如果需要使用`rem`单位,推荐使用以下两个工具:
- [postcss-pxtorem](https://github.com/cuth/postcss-pxtorem) 是一款 `postcss` 插件,用于将单位转化为 `rem`
- [lib-flexible](https://github.com/amfe/lib-flexible) 用于设置 `rem` 基准值
##### PostCSS 配置
下面提供了一份基本的 `postcss` 配置,可以在此配置的基础上根据项目需求进行修改
```javascript
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
plugins: {
autoprefixer: {
overrideBrowserslist: ['Android 4.1', 'iOS 7.1', 'Chrome > 31', 'ff > 31', 'ie >= 8']
},
'postcss-pxtorem': {
rootValue: 37.5,
propList: ['*']
}
}
}
```
更多详细信息: [vant](https://youzan.github.io/vant/#/zh-CN/quickstart#jin-jie-yong-fa)
**新手必看,老鸟跳过**
很多小伙伴会问我,适配的问题,因为我们使用的是 Vant UI所以必须根据 Vant UI 375 的设计规范走,一般我们的设计会将 UI 图上传到蓝湖,我们就可以需要的尺寸了。下面就大搞普及一下 rem。
我们知道 `1rem` 等于`html` 根元素设定的 `font-size``px` 值。Vant UI 设置 `rootValue: 37.5`,你可以看到在 iPhone 6 下看到 `1rem 等于 37.5px`
```html
<html data-dpr="1" style="font-size: 37.5px;"></html>
```
切换不同的机型,根元素可能会有不同的`font-size`。当你写 css px 样式时,会被程序换算成 `rem` 达到适配。
因为我们用了 Vant 的组件,需要按照 `rootValue: 37.5` 来写样式。
举个例子:设计给了你一张 750px \* 1334px 图片,在 iPhone6 上铺满屏幕,其他机型适配。
- 当`rootValue: 70` , 样式 `width: 750px;height: 1334px;` 图片会撑满 iPhone6 屏幕,这个时候切换其他机型,图片也会跟着撑满。
- 当`rootValue: 37.5` 的时候,样式 `width: 375px;height: 667px;` 图片会撑满 iPhone6 屏幕。
也就是 iphone 6 下 375px 宽度写 CSS。其他的你就可以根据你设计图去写对应的样式就可以了。
当然,想要撑满屏幕你可以使用 100%,这里只是举例说明。
```html
<img class="image" src="https://www.sunniejs.cn/static/weapp/logo.png" />
<style>
/* rootValue: 75 */
.image {
width: 750px;
height: 1334px;
}
/* rootValue: 37.5 */
.image {
width: 375px;
height: 667px;
}
</style>
```

34
docs/guide/vue2/router.md Normal file
View File

@ -0,0 +1,34 @@
### <span id="router">✅ Vue-router </span>
本案例采用 `hash` 模式,开发者根据需求修改 `mode` `base`
**注意**:如果你使用了 `history` 模式,`vue.config.js` 中的 `publicPath` 要做对应的**修改**
前往:[vue.config.js 基础配置](#base)
```javascript
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export const router = [
{
path: '/',
name: 'index',
component: () => import('@/views/home/index'), // 路由懒加载
meta: {
title: '首页', // 页面标题
keepAlive: false, // keep-alive 标识
},
},
]
const createRouter = () =>
new Router({
// mode: 'history', // 如果你是 history模式 需要配置 vue.config.js publicPath
// base: '/app/',
scrollBehavior: () => ({ y: 0 }),
routes: router,
})
export default createRouter()
```

104
docs/guide/vue2/sass.md Normal file
View File

@ -0,0 +1,104 @@
### <span id="sass">✅ Sass 全局样式</span>
首先 你可能会遇到 `node-sass` 安装不成功,别放弃多试几次!!!
每个页面自己对应的样式都写在自己的 .vue 文件之中 `scoped` 它顾名思义给 css 加了一个域的概念。
```html
<style lang="scss">
/* global styles */
</style>
<style lang="scss" scoped>
/* local styles */
</style>
```
#### 目录结构
vue-h5-template 所有全局样式都在 `@/src/assets/css` 目录下设置
```bash
├── assets
│ ├── css
│ │ ├── index.scss # 全局通用样式
│ │ ├── mixin.scss # 全局mixin
│ │ └── variables.scss # 全局变量
```
#### 自定义 vant-ui 样式
现在我们来说说怎么重写 `vant-ui` 样式。由于 `vant-ui` 的样式我们是在全局引入的,所以你想在某个页面里面覆盖它的样式就不能加 `scoped`,但你又想只覆盖这个页面的 `vant` 样式,你就可在它的父级加一个 `class`,用命名空间来解决问题。
```css
.about-container {
/* 你的命名空间 */
.van-button {
/* vant-ui 元素*/
margin-right: 0px;
}
}
```
#### 父组件改变子组件样式 深度选择器
当你子组件使用了 `scoped` 但在父组件又想修改子组件的样式可以 通过 `>>>` 来实现:
```css
<style scoped>
.a >>> .b { /* ... */ }
</style>
```
#### 全局变量
`vue.config.js` 配置使用 `css.loaderOptions` 选项,注入 `sass``mixin` `variables` 到全局,不需要手动引入 ,配置`$cdn`通过变量形式引入 cdn 地址,这样向所有 Sass/Less 样式传入共享的全局变量:
```javascript
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
const defaultSettings = require('./src/config/index.js')
module.exports = {
css: {
extract: IS_PROD,
sourceMap: false,
loaderOptions: {
// 给 scss-loader 传递选项
scss: {
// 注入 `sass``mixin` `variables` 到全局, $cdn可以配置图片cdn
// 详情: https://cli.vuejs.org/guide/css.html#passing-options-to-pre-processor-loaders
prependData: `
@import "assets/css/mixin.scss";
@import "assets/css/variables.scss";
$cdn: "${defaultSettings.$cdn}";
`,
},
},
},
}
```
设置 js 中可以访问 `$cdn`,`.vue` 文件中使用`this.$cdn`访问
```javascript
// 引入全局样式
import '@/assets/css/index.scss'
// 设置 js中可以访问 $cdn
// 引入cdn
import { $cdn } from '@/config'
Vue.prototype.$cdn = $cdn
```
在 css 和 js 使用
```html
<script>
console.log(this.$cdn)
</script>
<style lang="scss" scoped>
.logo {
width: 120px;
height: 120px;
background: url($cdn+'/weapp/logo.png') center / contain no-repeat;
}
</style>
```

17
docs/guide/vue2/start.md Normal file
View File

@ -0,0 +1,17 @@
# 启动项目
```js
// 拉取项目
git clone https://github.com/sunniejs/vue-h5-template
// 切换分支
git checkout -b vue2-h5-template origin/vue2-h5-template
// 安装依赖
yarn install
// 启动项目
yarn serve
```

49
docs/guide/vue2/vant.md Normal file
View File

@ -0,0 +1,49 @@
### <span id="vant">✅ VantUI 组件按需加载 </span>
项目采
用[Vant 自动按需引入组件 (推荐)](https://youzan.github.io/vant/#/zh-CN/quickstart#fang-shi-yi.-zi-dong-an-xu-yin-ru-zu-jian-tui-jian)下
面安装插件介绍:
[babel-plugin-import](https://github.com/ant-design/babel-plugin-import) 是一款 `babel` 插件,它会在编译过程中将
`import` 的写法自动转换为按需引入的方式
#### 安装插件
```bash
npm i babel-plugin-import -D
```
`babel.config.js` 设置
```javascript
// 对于使用 babel7 的用户,可以在 babel.config.js 中配置
const plugins = [
[
'import',
{
libraryName: 'vant',
libraryDirectory: 'es',
style: true,
},
'vant',
],
]
module.exports = {
presets: [['@vue/cli-plugin-babel/preset', { useBuiltIns: 'usage', corejs: 3 }]],
plugins,
}
```
#### 使用组件
项目在 `src/plugins/vant.js` 下统一管理组件,用哪个引入哪个,无需在页面里重复引用
```javascript
// 按需全局引入 vant组件
import Vue from 'vue'
import { Button, List, Cell, Tabbar, TabbarItem } from 'vant'
Vue.use(Button)
Vue.use(Cell)
Vue.use(List)
Vue.use(Tabbar).use(TabbarItem)
```

45
docs/guide/vue2/vuex.md Normal file
View File

@ -0,0 +1,45 @@
### <span id="vuex">✅ Vuex 状态管理</span>
目录结构
```bash
├── store
│ ├── modules
│ │ └── app.js
│ ├── index.js
│ ├── getters.js
```
`main.js` 引入
```javascript
import Vue from 'vue'
import App from './App.vue'
import store from './store'
new Vue({
el: '#app',
router,
store,
render: h => h(App),
})
```
使用
```html
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['userName']),
},
methods: {
// Action 通过 store.dispatch 方法触发
doDispatch() {
this.$store.dispatch('setUserName', '真乖,赶紧关注公众号,组织都在等你~')
},
},
}
</script>
```

61
docs/guide/vue2/vw.md Normal file
View File

@ -0,0 +1,61 @@
### <span id="vw">✅ vm 适配方案 </span>
本项目使用的是 `rem` 的 适配方案,其实无论你使用哪种方案,都不需要你去计算 12px 是多少 `rem` 或者 `vw`, 会有专门的工具去帮你做
。如果你想用 `vw`,你可以按照下面的方式切换。
#### 1.安装依赖
```bash
npm install postcss-px-to-viewport -D
```
#### 2.修改 .postcssrc.js
将根目录下 .postcssrc.js 文件修改如下
```javascript
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
plugins: {
autoprefixer: {
overrideBrowserslist: [
"Android 4.1",
"iOS 7.1",
"Chrome > 31",
"ff > 31",
"ie >= 8",
],
},
"postcss-px-to-viewport": {
viewportWidth: 375, // 视窗的宽度对应的是我们设计稿的宽度一般是750
unitPrecision: 3, // 指定`px`转换为视窗单位值的小数位数(很多时候无法整除)
viewportUnit: "vw", // 指定需要转换成的视窗单位建议使用vw
selectorBlackList: [".ignore", ".hairlines"], // 指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名
minPixelValue: 1, // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值
mediaQuery: false, // 允许在媒体查询中转换`px`
},
},
};
```
#### 3.删除原来的 rem 相关代码
src/main.js 删除如下代码
```javascript
// 移动端适配
import "lib-flexible/flexible.js";
```
package.json 删除如下代码
```javascript
"lib-flexible": "^0.3.2",
"postcss-pxtorem": "^5.1.1",
```
运行起来F12 元素 css style 就是 vw 单位了
[▲ 回顶部](#top)

21
docs/guide/vue3/alias.md Normal file
View File

@ -0,0 +1,21 @@
# alias
```javascript
resolve: {
alias: [{
find: 'vue-i18n',
replacement: 'vue-i18n/dist/vue-i18n.cjs.js',
},
// /@/xxxx => src/xxxx
{
find: /\/@\//,
replacement: pathResolve('src') + '/',
},
// /#/xxxx => types/xxxx
{
find: /\/#\//,
replacement: pathResolve('types') + '/',
},
],
},
```

67
docs/guide/vue3/axios.md Normal file
View File

@ -0,0 +1,67 @@
# axios 封装及接口管理
`utils/request.js` 封装 axios , 开发者需要根据后台接口做修改。
- `service.interceptors.request.use` 里可以设置请求头,比如设置 `token`
- `config.hideloading` 是在 api 文件夹下的接口参数里设置,下文会讲
- `service.interceptors.response.use` 里可以对接口返回数据处理,比如 401 删除本地信息,重新登录
```javascript
import axios from "axios";
import store from "@/store";
import { Toast } from "vant";
// 根据环境不同引入不同api地址
import { baseApi } from "@/config";
// create an axios instance
const service = axios.create({
baseURL: baseApi, // url = base api url + request url
withCredentials: true, // send cookies when cross-domain requests
timeout: 5000, // request timeout
});
// request 拦截器 request interceptor
service.interceptors.request.use(
(config) => {
// 不传递默认开启loading
if (!config.hideloading) {
// loading
Toast.loading({
forbidClick: true,
});
}
if (store.getters.token) {
config.headers["X-Token"] = "";
}
return config;
},
(error) => {
// do something with request error
console.log(error); // for debug
return Promise.reject(error);
}
);
// respone拦截器
service.interceptors.response.use(
(response) => {
Toast.clear();
const res = response.data;
if (res.status && res.status !== 200) {
// 登录超时,重新登录
if (res.status === 401) {
store.dispatch("FedLogOut").then(() => {
location.reload();
});
}
return Promise.reject(res || "error");
} else {
return Promise.resolve(res);
}
},
(error) => {
Toast.clear();
console.log("err" + error); // for debug
return Promise.reject(error);
}
);
export default service;
```

45
docs/guide/vue3/base.md Normal file
View File

@ -0,0 +1,45 @@
# vite.config.ts 基础配置
如果你的 `Vue Router` 模式是 hash
```javascript
publicPath: './',
```
如果你的 `Vue Router` 模式是 history 这里的 publicPath 和你的 `Vue Router` `base` **保持一致**
```javascript
publicPath: '/app/',
```
```javascript
export default function ({ command }: ConfigEnv): UserConfigExport {
const isProduction = command === "build";
return {
server: {
host: "0.0.0.0",
},
plugins: [
vue(),
vueJsx(),
createStyleImportPlugin({
resolves: [NutuiResolve()],
}),
eruda(),
viteMockServe({
mockPath: "./src/mock",
localEnabled: command === "serve",
logger: true,
}),
],
css: {
preprocessorOptions: {
scss: {
// 配置 nutui 全局 scss 变量
additionalData: `@import "@nutui/nutui/dist/styles/variables.scss";`,
},
},
},
};
}
```

13
docs/guide/vue3/env.md Normal file
View File

@ -0,0 +1,13 @@
`package.json` 里的 `scripts` 配置 `dev` `dev:test` `dev:prod` ,通过 `--mode xxx` 来执行不同环境
- 通过 `yarn dev` 启动本地环境参数 , 执行 `development`
- 通过 `yarn dev:test` 启动测试环境参数 , 执行 `test`
- 通过 `yarn dev:prod` 启动正式环境参数 , 执行 `prod`
```javascript
"scripts": {
"dev": "vite",
"dev:test": "vite --mode test",
"dev:prod": "vite --mode production",
}
```

3
docs/guide/vue3/lint.md Normal file
View File

@ -0,0 +1,3 @@
# Eslint+Pettier+stylelint 统一开发规范
根目录下的.eslintrc.js、.stylelint.config.js、.prettier.config.js 内置了 lint 规则,帮助你规范地开发代码,有助于提高团队的代码质量和协作性,可以根据团队的规则进行修改

22
docs/guide/vue3/pinia.md Normal file
View File

@ -0,0 +1,22 @@
# Pinia 状态管理
下一代 vuex使用极其方便ts 兼容好
目录结构
```bash
├── store
│ ├── modules
│ │ └── user.js
│ ├── index.js
```
使用
```html
<script lang="ts" setup>
import { useUserStore } from "@/store/modules/user";
const userStore = useUserStore();
userStore.login();
</script>
```

13
docs/guide/vue3/proxy.md Normal file
View File

@ -0,0 +1,13 @@
# proxy 跨域
```javascript
server: {
proxy: {
'/api': {
target: 'https://baidu.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
},
```

29
docs/guide/vue3/router.md Normal file
View File

@ -0,0 +1,29 @@
# vue-router
本案例采用 `hash` 模式,开发者根据需求修改 `mode` `base`
**注意**:如果你使用了 `history` 模式, `vue.config.js` 中的 `publicPath` 要做对应的**修改**
前往:[vue.config.js 基础配置](#base)
```javascript
import Vue from "vue";
import { createRouter, createWebHistory, Router } from "vue-router";
Vue.use(Router);
export const router = [
{
name: "root",
path: "/",
redirect: "/home",
component: () => import("@/layout/basic/index.vue"),
},
];
const router: Router = createRouter({
history: createWebHistory(),
routes: routes,
});
export default router;
```

14
docs/guide/vue3/start.md Normal file
View File

@ -0,0 +1,14 @@
# 启动项目
```js
// 拉取项目
git clone https://github.com/sunniejs/vue-h5-template
// 安装依赖
yarn install
// 启动项目
yarn dev
```

58
docs/guide/vue3/ui.md Normal file
View File

@ -0,0 +1,58 @@
# 多 UI 组件库供选择
Vite 构建工具,使用 vite-plugin-style-import 和 unplugin-vue-components/vite 实现按需引入。
## 安装插件
```bash
yarn add vite-plugin-style-import -D
yarn add unplugin-vue-components/vite -D
```
## 使用组件库
nutUI 没有按需加载的 resolversstyle 需要自己配置按需加载
`config/vite/plugins/styleImport.ts` 设置
```javascript
// 按需加载样式文件
...
createStyleImportPlugin({
resolves: [NutuiResolve()],
}),
...
```
项目在 `src/plugins/nutUI.ts` 下统一管理组件,用哪个引入哪个,无需在页面里重复引用
```javascript
// 按需全局引入nutUI组件
import Vue from "vue";
import { Button, Cell, CellGroup } from "@nutui/nutui";
export const nutUiComponents = [Button, Cell, CellGroup];
// 在main.ts文件中引入
nutUiComponents.forEach((item) => {
app.use(item);
});
```
vant 和 varlet 可以使用组件按需加载
`config/vite/plugins/component.ts`
```javascript
import { VueUseComponentsResolver, VantResolver, VarletUIResolver } from 'unplugin-vue-components/resolvers';
...
resolvers: [VantResolver(), VarletUIResolver()],
...
```
## 不需要某个组件库
nutUI 需删除`src/plugins/nutUI.ts``main.ts`文件下的引入
vant 和 varlet 只需删除对应的 resolvers 即可
删除后需全局搜索删除不需要的组件,避免报错

View File

@ -0,0 +1,76 @@
# viewport 适配方案
不用担心,项目已经配置好了 `viewport` 适配,下面仅做介绍:
- [cnjm-postcss-px-to-viewport](https://github.com/cnjm/postcss-px-to-viewport) 是一款 `postcss` 插件,用于将单位转化为 `vw` 现在很多浏览器对`vw`的支持都很好,适配首选方案。
## PostCSS 配置
下面提供了一份基本的 `postcss` 配置,可以在此配置的基础上根据项目需求进行修改
```javascript
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
plugins: {
autoprefixer: { overrideBrowserslist: ['Android 4.1', 'iOS 7.1', 'Chrome > 31', 'ff > 31', 'ie >= 8'] },
'cnjm-postcss-px-to-viewport': {
unitToConvert: 'px', // 要转化的单位
viewportWidth: 750, // UI设计稿的宽度
unitPrecision: 6, // 转换后的精度,即小数点位数
propList: ['*'], // 指定转换的css属性的单位*代表全部css属性的单位都进行转换
viewportUnit: 'vw', // 指定需要转换成的视窗单位默认vw
fontViewportUnit: 'vw', // 指定字体需要转换成的视窗单位默认vw
minPixelValue: 1, // 默认值1小于或等于1px则不进行转换
mediaQuery: true, // 是否在媒体查询的css代码中也进行转换默认false
replace: true, // 是否转换后直接更换属性值
include: [],
exclude: [], // 设置忽略文件,用正则做目录名匹配
customFun: ({ file }) => {
// 这个自定义的方法是针对处理vant组件下的设计稿为375问题
const designWidth = judgeComponent(file) ? 375 : 750;
return designWidth;
},
},
};
```
**新手必看,老鸟跳过**
很多小伙伴会问我,适配的问题, 因为我们使用的是 Vant UI所以必须根据 Vant UI 375 的设计规范走,一般我们的设计会将 UI 图上传到蓝湖,我们就可以需要的尺寸了。下面就大搞普及一下 rem。
我们知道 `1rem` 等于 `html` 根元素设定的 `font-size``px` 值。Vant UI 设置 `rootValue: 37.5` , 你可以看到在 iPhone 6 下看到 `1rem 等于 37.5px`
```html
<html data-dpr="1" style="font-size: 37.5px;"></html>
```
切换不同的机型,根元素可能会有不同的 `font-size` 。当你写 css px 样式时,会被程序换算成 `rem` 达到适配。
因为我们用了 Vant 的组件,需要按照 `rootValue: 37.5` 来写样式。
举个例子:设计给了你一张 750px \* 1334px 图片,在 iPhone6 上铺满屏幕, 其他机型适配。
- 当`rootValue: 75` , 样式 `width: 750px;height: 1334px;` 图片会撑满 iPhone6 屏幕,这个时候切换其他机型,图片也会跟着撑满。
- 当`rootValue: 37.5` 的时候,样式 `width: 375px;height: 667px;` 图片会撑满 iPhone6 屏幕。
也就是 iphone 6 下 375px 宽度写 CSS。其他的你就可以根据你设计图去写对应的样式就可以了。
当然,想要撑满屏幕你可以使用 100%,这里只是举例说明。
```html
<img class="image" src="https://www.sunniejs.cn/static/weapp/logo.png" />
<style>
/* rootValue: 75 */
.image {
width: 750px;
height: 1334px;
}
/* rootValue: 37.5 */
.image {
width: 375px;
height: 667px;
}
</style>
```

17
docs/guide/vue3/vite.md Normal file
View File

@ -0,0 +1,17 @@
# vite
基于原生 ES 模块提供了丰富的内建功能如速度快到惊人的模块热更新HMR使用 Rollup 打包你的代码,并且它是预配置的,可输出用于生产环境的高度优化过的静态资源。更多关于[vite](https://cn.vitejs.dev/guide/)
模版集成了如下的 vite 插件
- unplugin-auto-import按需加载自动引入
- unplugin-vue-components按需加载自动引入组件
- vite-plugin-compression开启.gz 压缩)
- vite-plugin-eruda控制台方便移动端调试
- vite-plugin-imagemin图片压缩
- vite-plugin-mock引入 mockjs本地模拟接口
- vite-plugin-pages动态生成路由
- vite-plugin-progress构建显示进度条
- vite-plugin-restart监听配置文件修改自动重启 Vite
- vite-plugin-style-import按需引入样式文件
- vite-plugin-svg-icons加载 SVG 文件,自动引入)

34
docs/index.md Normal file
View File

@ -0,0 +1,34 @@
---
layout: home
title: Vue-H5-Template
titleTemplate: 一个快速开发的vue h5移动端脚手架
hero:
name: Vue-H5-Template
text: 一个快速开发的Vue H5移动端脚手架
image:
src: http://www.sunniejs.cn/static/weapp/logo.png
alt: sunnie
actions:
- theme: brand
text: 开始
link: /guide/
- theme: alt
text: Github仓库
link: https://github.com/sunniejs/vue-h5-template
features:
- icon: 💡
title: 开箱即用
details: 集成vue2、vue3的移动端快速开发模版学习成本低易上手
- icon: 📦
title: 代码规范
details: 完整的eslint、prettier、stylelint规范加上husky帮助你更好的管理代码
- icon: 🛠️
title: 配置优化
details: 完整配置的vue脚手架插件和优化让你专注于业务开发更高效
- icon: ⚙️
title: More
details: 加入我们,更多能力等你挖掘....
---

10
package.json Normal file
View File

@ -0,0 +1,10 @@
{
"devDependencies": {
"vitepress": "^1.0.0-alpha.8",
"vue": "^3.2.37"
},
"scripts": {
"start": "vitepress dev docs --host 0.0.0.0",
"build": "vitepress build docs"
}
}

710
pnpm-lock.yaml generated Normal file
View File

@ -0,0 +1,710 @@
lockfileVersion: 5.3
specifiers:
vitepress: ^1.0.0-alpha.8
vue: ^3.2.37
devDependencies:
vitepress: 1.0.0-alpha.8
vue: 3.2.37
packages:
/@algolia/autocomplete-core/1.7.1:
resolution: {integrity: sha512-eiZw+fxMzNQn01S8dA/hcCpoWCOCwcIIEUtHHdzN5TGB3IpzLbuhqFeTfh2OUhhgkE8Uo17+wH+QJ/wYyQmmzg==}
dependencies:
'@algolia/autocomplete-shared': 1.7.1
dev: true
/@algolia/autocomplete-preset-algolia/1.7.1_algoliasearch@4.14.2:
resolution: {integrity: sha512-pJwmIxeJCymU1M6cGujnaIYcY3QPOVYZOXhFkWVM7IxKzy272BwCvMFMyc5NpG/QmiObBxjo7myd060OeTNJXg==}
peerDependencies:
'@algolia/client-search': ^4.9.1
algoliasearch: ^4.9.1
dependencies:
'@algolia/autocomplete-shared': 1.7.1
algoliasearch: 4.14.2
dev: true
/@algolia/autocomplete-shared/1.7.1:
resolution: {integrity: sha512-eTmGVqY3GeyBTT8IWiB2K5EuURAqhnumfktAEoHxfDY2o7vg2rSnO16ZtIG0fMgt3py28Vwgq42/bVEuaQV7pg==}
dev: true
/@algolia/cache-browser-local-storage/4.14.2:
resolution: {integrity: sha512-FRweBkK/ywO+GKYfAWbrepewQsPTIEirhi1BdykX9mxvBPtGNKccYAxvGdDCumU1jL4r3cayio4psfzKMejBlA==}
dependencies:
'@algolia/cache-common': 4.14.2
dev: true
/@algolia/cache-common/4.14.2:
resolution: {integrity: sha512-SbvAlG9VqNanCErr44q6lEKD2qoK4XtFNx9Qn8FK26ePCI8I9yU7pYB+eM/cZdS9SzQCRJBbHUumVr4bsQ4uxg==}
dev: true
/@algolia/cache-in-memory/4.14.2:
resolution: {integrity: sha512-HrOukWoop9XB/VFojPv1R5SVXowgI56T9pmezd/djh2JnVN/vXswhXV51RKy4nCpqxyHt/aGFSq2qkDvj6KiuQ==}
dependencies:
'@algolia/cache-common': 4.14.2
dev: true
/@algolia/client-account/4.14.2:
resolution: {integrity: sha512-WHtriQqGyibbb/Rx71YY43T0cXqyelEU0lB2QMBRXvD2X0iyeGl4qMxocgEIcbHyK7uqE7hKgjT8aBrHqhgc1w==}
dependencies:
'@algolia/client-common': 4.14.2
'@algolia/client-search': 4.14.2
'@algolia/transporter': 4.14.2
dev: true
/@algolia/client-analytics/4.14.2:
resolution: {integrity: sha512-yBvBv2mw+HX5a+aeR0dkvUbFZsiC4FKSnfqk9rrfX+QrlNOKEhCG0tJzjiOggRW4EcNqRmaTULIYvIzQVL2KYQ==}
dependencies:
'@algolia/client-common': 4.14.2
'@algolia/client-search': 4.14.2
'@algolia/requester-common': 4.14.2
'@algolia/transporter': 4.14.2
dev: true
/@algolia/client-common/4.14.2:
resolution: {integrity: sha512-43o4fslNLcktgtDMVaT5XwlzsDPzlqvqesRi4MjQz2x4/Sxm7zYg5LRYFol1BIhG6EwxKvSUq8HcC/KxJu3J0Q==}
dependencies:
'@algolia/requester-common': 4.14.2
'@algolia/transporter': 4.14.2
dev: true
/@algolia/client-personalization/4.14.2:
resolution: {integrity: sha512-ACCoLi0cL8CBZ1W/2juehSltrw2iqsQBnfiu/Rbl9W2yE6o2ZUb97+sqN/jBqYNQBS+o0ekTMKNkQjHHAcEXNw==}
dependencies:
'@algolia/client-common': 4.14.2
'@algolia/requester-common': 4.14.2
'@algolia/transporter': 4.14.2
dev: true
/@algolia/client-search/4.14.2:
resolution: {integrity: sha512-L5zScdOmcZ6NGiVbLKTvP02UbxZ0njd5Vq9nJAmPFtjffUSOGEp11BmD2oMJ5QvARgx2XbX4KzTTNS5ECYIMWw==}
dependencies:
'@algolia/client-common': 4.14.2
'@algolia/requester-common': 4.14.2
'@algolia/transporter': 4.14.2
dev: true
/@algolia/logger-common/4.14.2:
resolution: {integrity: sha512-/JGlYvdV++IcMHBnVFsqEisTiOeEr6cUJtpjz8zc0A9c31JrtLm318Njc72p14Pnkw3A/5lHHh+QxpJ6WFTmsA==}
dev: true
/@algolia/logger-console/4.14.2:
resolution: {integrity: sha512-8S2PlpdshbkwlLCSAB5f8c91xyc84VM9Ar9EdfE9UmX+NrKNYnWR1maXXVDQQoto07G1Ol/tYFnFVhUZq0xV/g==}
dependencies:
'@algolia/logger-common': 4.14.2
dev: true
/@algolia/requester-browser-xhr/4.14.2:
resolution: {integrity: sha512-CEh//xYz/WfxHFh7pcMjQNWgpl4wFB85lUMRyVwaDPibNzQRVcV33YS+63fShFWc2+42YEipFGH2iPzlpszmDw==}
dependencies:
'@algolia/requester-common': 4.14.2
dev: true
/@algolia/requester-common/4.14.2:
resolution: {integrity: sha512-73YQsBOKa5fvVV3My7iZHu1sUqmjjfs9TteFWwPwDmnad7T0VTCopttcsM3OjLxZFtBnX61Xxl2T2gmG2O4ehg==}
dev: true
/@algolia/requester-node-http/4.14.2:
resolution: {integrity: sha512-oDbb02kd1o5GTEld4pETlPZLY0e+gOSWjWMJHWTgDXbv9rm/o2cF7japO6Vj1ENnrqWvLBmW1OzV9g6FUFhFXg==}
dependencies:
'@algolia/requester-common': 4.14.2
dev: true
/@algolia/transporter/4.14.2:
resolution: {integrity: sha512-t89dfQb2T9MFQHidjHcfhh6iGMNwvuKUvojAj+JsrHAGbuSy7yE4BylhLX6R0Q1xYRoC4Vvv+O5qIw/LdnQfsQ==}
dependencies:
'@algolia/cache-common': 4.14.2
'@algolia/logger-common': 4.14.2
'@algolia/requester-common': 4.14.2
dev: true
/@babel/parser/7.18.11:
resolution: {integrity: sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==}
engines: {node: '>=6.0.0'}
hasBin: true
dev: true
/@docsearch/css/3.2.1:
resolution: {integrity: sha512-gaP6TxxwQC+K8D6TRx5WULUWKrcbzECOPA2KCVMuI+6C7dNiGUk5yXXzVhc5sld79XKYLnO9DRTI4mjXDYkh+g==}
dev: true
/@docsearch/js/3.2.1:
resolution: {integrity: sha512-H1PekEtSeS0msetR2YGGey2w7jQ2wAKfGODJvQTygSwMgUZ+2DHpzUgeDyEBIXRIfaBcoQneqrzsljM62pm6Xg==}
dependencies:
'@docsearch/react': 3.2.1
preact: 10.10.3
transitivePeerDependencies:
- '@algolia/client-search'
- '@types/react'
- react
- react-dom
dev: true
/@docsearch/react/3.2.1:
resolution: {integrity: sha512-EzTQ/y82s14IQC5XVestiK/kFFMe2aagoYFuTAIfIb/e+4FU7kSMKonRtLwsCiLQHmjvNQq+HO+33giJ5YVtaQ==}
peerDependencies:
'@types/react': '>= 16.8.0 < 19.0.0'
react: '>= 16.8.0 < 19.0.0'
react-dom: '>= 16.8.0 < 19.0.0'
peerDependenciesMeta:
'@types/react':
optional: true
react:
optional: true
react-dom:
optional: true
dependencies:
'@algolia/autocomplete-core': 1.7.1
'@algolia/autocomplete-preset-algolia': 1.7.1_algoliasearch@4.14.2
'@docsearch/css': 3.2.1
algoliasearch: 4.14.2
transitivePeerDependencies:
- '@algolia/client-search'
dev: true
/@esbuild/linux-loong64/0.14.54:
resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
dev: true
optional: true
/@types/web-bluetooth/0.0.15:
resolution: {integrity: sha512-w7hEHXnPMEZ+4nGKl/KDRVpxkwYxYExuHOYXyzIzCDzEZ9ZCGMAewulr9IqJu2LR4N37fcnb1XVeuZ09qgOxhA==}
dev: true
/@vitejs/plugin-vue/3.0.3_vite@3.0.8+vue@3.2.37:
resolution: {integrity: sha512-U4zNBlz9mg+TA+i+5QPc3N5lQvdUXENZLO2h0Wdzp56gI1MWhqJOv+6R+d4kOzoaSSq6TnGPBdZAXKOe4lXy6g==}
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
vite: ^3.0.0
vue: ^3.2.25
dependencies:
vite: 3.0.8
vue: 3.2.37
dev: true
/@vue/compiler-core/3.2.37:
resolution: {integrity: sha512-81KhEjo7YAOh0vQJoSmAD68wLfYqJvoiD4ulyedzF+OEk/bk6/hx3fTNVfuzugIIaTrOx4PGx6pAiBRe5e9Zmg==}
dependencies:
'@babel/parser': 7.18.11
'@vue/shared': 3.2.37
estree-walker: 2.0.2
source-map: 0.6.1
dev: true
/@vue/compiler-dom/3.2.37:
resolution: {integrity: sha512-yxJLH167fucHKxaqXpYk7x8z7mMEnXOw3G2q62FTkmsvNxu4FQSu5+3UMb+L7fjKa26DEzhrmCxAgFLLIzVfqQ==}
dependencies:
'@vue/compiler-core': 3.2.37
'@vue/shared': 3.2.37
dev: true
/@vue/compiler-sfc/3.2.37:
resolution: {integrity: sha512-+7i/2+9LYlpqDv+KTtWhOZH+pa8/HnX/905MdVmAcI/mPQOBwkHHIzrsEsucyOIZQYMkXUiTkmZq5am/NyXKkg==}
dependencies:
'@babel/parser': 7.18.11
'@vue/compiler-core': 3.2.37
'@vue/compiler-dom': 3.2.37
'@vue/compiler-ssr': 3.2.37
'@vue/reactivity-transform': 3.2.37
'@vue/shared': 3.2.37
estree-walker: 2.0.2
magic-string: 0.25.9
postcss: 8.4.16
source-map: 0.6.1
dev: true
/@vue/compiler-ssr/3.2.37:
resolution: {integrity: sha512-7mQJD7HdXxQjktmsWp/J67lThEIcxLemz1Vb5I6rYJHR5vI+lON3nPGOH3ubmbvYGt8xEUaAr1j7/tIFWiEOqw==}
dependencies:
'@vue/compiler-dom': 3.2.37
'@vue/shared': 3.2.37
dev: true
/@vue/devtools-api/6.2.1:
resolution: {integrity: sha512-OEgAMeQXvCoJ+1x8WyQuVZzFo0wcyCmUR3baRVLmKBo1LmYZWMlRiXlux5jd0fqVJu6PfDbOrZItVqUEzLobeQ==}
dev: true
/@vue/reactivity-transform/3.2.37:
resolution: {integrity: sha512-IWopkKEb+8qpu/1eMKVeXrK0NLw9HicGviJzhJDEyfxTR9e1WtpnnbYkJWurX6WwoFP0sz10xQg8yL8lgskAZg==}
dependencies:
'@babel/parser': 7.18.11
'@vue/compiler-core': 3.2.37
'@vue/shared': 3.2.37
estree-walker: 2.0.2
magic-string: 0.25.9
dev: true
/@vue/reactivity/3.2.37:
resolution: {integrity: sha512-/7WRafBOshOc6m3F7plwzPeCu/RCVv9uMpOwa/5PiY1Zz+WLVRWiy0MYKwmg19KBdGtFWsmZ4cD+LOdVPcs52A==}
dependencies:
'@vue/shared': 3.2.37
dev: true
/@vue/runtime-core/3.2.37:
resolution: {integrity: sha512-JPcd9kFyEdXLl/i0ClS7lwgcs0QpUAWj+SKX2ZC3ANKi1U4DOtiEr6cRqFXsPwY5u1L9fAjkinIdB8Rz3FoYNQ==}
dependencies:
'@vue/reactivity': 3.2.37
'@vue/shared': 3.2.37
dev: true
/@vue/runtime-dom/3.2.37:
resolution: {integrity: sha512-HimKdh9BepShW6YozwRKAYjYQWg9mQn63RGEiSswMbW+ssIht1MILYlVGkAGGQbkhSh31PCdoUcfiu4apXJoPw==}
dependencies:
'@vue/runtime-core': 3.2.37
'@vue/shared': 3.2.37
csstype: 2.6.20
dev: true
/@vue/server-renderer/3.2.37_vue@3.2.37:
resolution: {integrity: sha512-kLITEJvaYgZQ2h47hIzPh2K3jG8c1zCVbp/o/bzQOyvzaKiCquKS7AaioPI28GNxIsE/zSx+EwWYsNxDCX95MA==}
peerDependencies:
vue: 3.2.37
dependencies:
'@vue/compiler-ssr': 3.2.37
'@vue/shared': 3.2.37
vue: 3.2.37
dev: true
/@vue/shared/3.2.37:
resolution: {integrity: sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw==}
dev: true
/@vueuse/core/9.1.0_vue@3.2.37:
resolution: {integrity: sha512-BIroqvXEqt826aE9r3K5cox1zobuPuAzdYJ36kouC2TVhlXvFKIILgFVWrpp9HZPwB3aLzasmG3K87q7TSyXZg==}
dependencies:
'@types/web-bluetooth': 0.0.15
'@vueuse/metadata': 9.1.0
'@vueuse/shared': 9.1.0_vue@3.2.37
vue-demi: 0.13.8_vue@3.2.37
transitivePeerDependencies:
- '@vue/composition-api'
- vue
dev: true
/@vueuse/metadata/9.1.0:
resolution: {integrity: sha512-8OEhlog1iaAGTD3LICZ8oBGQdYeMwByvXetOtAOZCJOzyCRSwqwdggTsmVZZ1rkgYIEqgUBk942AsAPwM21s6A==}
dev: true
/@vueuse/shared/9.1.0_vue@3.2.37:
resolution: {integrity: sha512-pB/3njQu4tfJJ78ajELNda0yMG6lKfpToQW7Soe09CprF1k3QuyoNi1tBNvo75wBDJWD+LOnr+c4B5HZ39jY/Q==}
dependencies:
vue-demi: 0.13.8_vue@3.2.37
transitivePeerDependencies:
- '@vue/composition-api'
- vue
dev: true
/algoliasearch/4.14.2:
resolution: {integrity: sha512-ngbEQonGEmf8dyEh5f+uOIihv4176dgbuOZspiuhmTTBRBuzWu3KCGHre6uHj5YyuC7pNvQGzB6ZNJyZi0z+Sg==}
dependencies:
'@algolia/cache-browser-local-storage': 4.14.2
'@algolia/cache-common': 4.14.2
'@algolia/cache-in-memory': 4.14.2
'@algolia/client-account': 4.14.2
'@algolia/client-analytics': 4.14.2
'@algolia/client-common': 4.14.2
'@algolia/client-personalization': 4.14.2
'@algolia/client-search': 4.14.2
'@algolia/logger-common': 4.14.2
'@algolia/logger-console': 4.14.2
'@algolia/requester-browser-xhr': 4.14.2
'@algolia/requester-common': 4.14.2
'@algolia/requester-node-http': 4.14.2
'@algolia/transporter': 4.14.2
dev: true
/body-scroll-lock/4.0.0-beta.0:
resolution: {integrity: sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==}
dev: true
/csstype/2.6.20:
resolution: {integrity: sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==}
dev: true
/esbuild-android-64/0.14.54:
resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
dev: true
optional: true
/esbuild-android-arm64/0.14.54:
resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
dev: true
optional: true
/esbuild-darwin-64/0.14.54:
resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
dev: true
optional: true
/esbuild-darwin-arm64/0.14.54:
resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
dev: true
optional: true
/esbuild-freebsd-64/0.14.54:
resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
dev: true
optional: true
/esbuild-freebsd-arm64/0.14.54:
resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
dev: true
optional: true
/esbuild-linux-32/0.14.54:
resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
dev: true
optional: true
/esbuild-linux-64/0.14.54:
resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
dev: true
optional: true
/esbuild-linux-arm/0.14.54:
resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
dev: true
optional: true
/esbuild-linux-arm64/0.14.54:
resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
dev: true
optional: true
/esbuild-linux-mips64le/0.14.54:
resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
dev: true
optional: true
/esbuild-linux-ppc64le/0.14.54:
resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
dev: true
optional: true
/esbuild-linux-riscv64/0.14.54:
resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
dev: true
optional: true
/esbuild-linux-s390x/0.14.54:
resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
dev: true
optional: true
/esbuild-netbsd-64/0.14.54:
resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
dev: true
optional: true
/esbuild-openbsd-64/0.14.54:
resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
dev: true
optional: true
/esbuild-sunos-64/0.14.54:
resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
dev: true
optional: true
/esbuild-windows-32/0.14.54:
resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
dev: true
optional: true
/esbuild-windows-64/0.14.54:
resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
dev: true
optional: true
/esbuild-windows-arm64/0.14.54:
resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
dev: true
optional: true
/esbuild/0.14.54:
resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
'@esbuild/linux-loong64': 0.14.54
esbuild-android-64: 0.14.54
esbuild-android-arm64: 0.14.54
esbuild-darwin-64: 0.14.54
esbuild-darwin-arm64: 0.14.54
esbuild-freebsd-64: 0.14.54
esbuild-freebsd-arm64: 0.14.54
esbuild-linux-32: 0.14.54
esbuild-linux-64: 0.14.54
esbuild-linux-arm: 0.14.54
esbuild-linux-arm64: 0.14.54
esbuild-linux-mips64le: 0.14.54
esbuild-linux-ppc64le: 0.14.54
esbuild-linux-riscv64: 0.14.54
esbuild-linux-s390x: 0.14.54
esbuild-netbsd-64: 0.14.54
esbuild-openbsd-64: 0.14.54
esbuild-sunos-64: 0.14.54
esbuild-windows-32: 0.14.54
esbuild-windows-64: 0.14.54
esbuild-windows-arm64: 0.14.54
dev: true
/estree-walker/2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
dev: true
/fsevents/2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
dev: true
optional: true
/function-bind/1.1.1:
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
dev: true
/has/1.0.3:
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
engines: {node: '>= 0.4.0'}
dependencies:
function-bind: 1.1.1
dev: true
/is-core-module/2.10.0:
resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==}
dependencies:
has: 1.0.3
dev: true
/jsonc-parser/3.1.0:
resolution: {integrity: sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==}
dev: true
/magic-string/0.25.9:
resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
dependencies:
sourcemap-codec: 1.4.8
dev: true
/nanoid/3.3.4:
resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
dev: true
/path-parse/1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
dev: true
/picocolors/1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
dev: true
/postcss/8.4.16:
resolution: {integrity: sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==}
engines: {node: ^10 || ^12 || >=14}
dependencies:
nanoid: 3.3.4
picocolors: 1.0.0
source-map-js: 1.0.2
dev: true
/preact/10.10.3:
resolution: {integrity: sha512-Gwwh0o531izatQQZu0yEX4mtfxVYsZJ4TT/o2VK3UZ/UuAWAWFnzsEfpZvad32vY3TKoRnSY2WqiDz2rH/viWQ==}
dev: true
/resolve/1.22.1:
resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
hasBin: true
dependencies:
is-core-module: 2.10.0
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
dev: true
/rollup/2.77.3:
resolution: {integrity: sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==}
engines: {node: '>=10.0.0'}
hasBin: true
optionalDependencies:
fsevents: 2.3.2
dev: true
/shiki/0.11.1:
resolution: {integrity: sha512-EugY9VASFuDqOexOgXR18ZV+TbFrQHeCpEYaXamO+SZlsnT/2LxuLBX25GGtIrwaEVFXUAbUQ601SWE2rMwWHA==}
dependencies:
jsonc-parser: 3.1.0
vscode-oniguruma: 1.6.2
vscode-textmate: 6.0.0
dev: true
/source-map-js/1.0.2:
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
engines: {node: '>=0.10.0'}
dev: true
/source-map/0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
dev: true
/sourcemap-codec/1.4.8:
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
dev: true
/supports-preserve-symlinks-flag/1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
dev: true
/vite/3.0.8:
resolution: {integrity: sha512-AOZ4eN7mrkJiOLuw8IA7piS4IdOQyQCA81GxGsAQvAZzMRi9ZwGB3TOaYsj4uLAWK46T5L4AfQ6InNGlxX30IQ==}
engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true
peerDependencies:
less: '*'
sass: '*'
stylus: '*'
terser: ^5.4.0
peerDependenciesMeta:
less:
optional: true
sass:
optional: true
stylus:
optional: true
terser:
optional: true
dependencies:
esbuild: 0.14.54
postcss: 8.4.16
resolve: 1.22.1
rollup: 2.77.3
optionalDependencies:
fsevents: 2.3.2
dev: true
/vitepress/1.0.0-alpha.8:
resolution: {integrity: sha512-kTRN5DCagvMqr9OjylSV9/waGg0IHrxL0hBVuJoz7ykleZq2qR02n5CaiFq5QrSB/VRBGqiVsFQzet9vJsXS8g==}
hasBin: true
dependencies:
'@docsearch/css': 3.2.1
'@docsearch/js': 3.2.1
'@vitejs/plugin-vue': 3.0.3_vite@3.0.8+vue@3.2.37
'@vue/devtools-api': 6.2.1
'@vueuse/core': 9.1.0_vue@3.2.37
body-scroll-lock: 4.0.0-beta.0
shiki: 0.11.1
vite: 3.0.8
vue: 3.2.37
transitivePeerDependencies:
- '@algolia/client-search'
- '@types/react'
- '@vue/composition-api'
- less
- react
- react-dom
- sass
- stylus
- terser
dev: true
/vscode-oniguruma/1.6.2:
resolution: {integrity: sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==}
dev: true
/vscode-textmate/6.0.0:
resolution: {integrity: sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==}
dev: true
/vue-demi/0.13.8_vue@3.2.37:
resolution: {integrity: sha512-Vy1zbZhCOdsmvGR6tJhAvO5vhP7eiS8xkbYQSoVa7o6KlIy3W8Rc53ED4qI4qpeRDjv3mLfXSEpYU6Yq4pgXRg==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
peerDependencies:
'@vue/composition-api': ^1.0.0-rc.1
vue: ^3.0.0-0 || ^2.6.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
dependencies:
vue: 3.2.37
dev: true
/vue/3.2.37:
resolution: {integrity: sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ==}
dependencies:
'@vue/compiler-dom': 3.2.37
'@vue/compiler-sfc': 3.2.37
'@vue/runtime-dom': 3.2.37
'@vue/server-renderer': 3.2.37_vue@3.2.37
'@vue/shared': 3.2.37
dev: true