使用 Vite 快速搭建脚手架

命令行选项直接指定项目名称和想要使用的模板,Vite + Vue 项目,运行(推荐使用yarn)

# npm 6.x
npm init vite@latest my-vue-app --template vue # npm 7+, 需要额外的双横线:
npm init vite@latest my-vue-app -- --template vue # yarn
yarn create vite my-vue-app --template vue # pnpm
pnpm create vite my-vue-app -- --template vue

这里我们想要直接生成一个Vue3+Vite2+ts的项目模板,因此我们执行的命令是: yarn create vite my-vue-app --template vue-ts,这样我们就不需要你单独的再去安装配置ts了。

cd 到项目文件夹,安装node_modules依赖,运行项目

# cd进入my-vue-app项目文件夹
cd my-vue-app
# 安装依赖
yarn
# 运行项目
yarn dev

至此,一个最纯净的vue3.0+vite2+typescript项目就完成了。在浏览地址栏中输入http://localhost:3000/,就看到了如下的启动页,然后就可以安装所需的插件了。

配置文件路径引用别名 alias

修改vite.config.ts中的reslove的配置

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path' // https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
})

在修改tsconfig.json文件的配置

{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"baseUrl": ".",
"paths": {
"@/*":["src/*"]
}
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue"
]
}

配置路由

安装

# npm
npm install vue-router@4 # yarn
yarn add vue-router@4

在src下新建router文件夹,用来集中管理路由,在router文件夹下新建 index.ts文件。

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

const routes: RouteRecordRaw[] = [
{
path: '/',
name: 'Login',
// 注意这里要带上文件后缀.vue
component: () => import('@/pages/login/Login.vue'),
meta: {
title: '登录',
},
},
] const router = createRouter({
history: createWebHistory(),
routes,
strict: true,
// 期望滚动到哪个的位置
scrollBehavior(to, from, savedPosition) {
return new Promise(resolve => {
if (savedPosition) {
return savedPosition;
} else {
if (from.meta.saveSrollTop) {
const top: number =
document.documentElement.scrollTop || document.body.scrollTop;
resolve({ left: 0, top });
}
}
});
}
}) export function setupRouter(app: App) {
app.use(router);
} export default router

修改入口文件 mian.ts

import { createApp } from "vue";
import App from "./App.vue";
import router, { setupRouter } from './router'; const app = createApp(App);
// 挂在路由
setupRouter(app);
// 路由准备就绪后挂载APP实例
await router.isReady(); app.mount('#app', true);

更多的路由配置可以移步vue-router(https://next.router.vuejs.org/zh/introduction.html)。 vue-router4.x支持typescript,路由的类型为RouteRecordRaw。meta字段可以让我们根据不同的业务需求扩展 RouteMeta 接口来输入它的多样性。以下的meta中的配置仅供参考:

// typings.d.ts or router.ts
import 'vue-router' declare module 'vue-router' {
interface RouteMeta {
// 页面标题,通常必选。
title: string;
// 菜单图标
icon?: string;
// 配置菜单的权限
permission: string[];
// 是否开启页面缓存
keepAlive?: boolean;
// 二级页面我们并不想在菜单中显示
hidden?: boolean;
// 菜单排序
order?: number;
// 嵌套外链
frameUrl?: string;
}
}

配置 css 预处理器 scss

安装

yarn add sass-loader --dev
yarn add dart-sass --dev
yarn add sass --dev

配置全局 scss 样式文件 在 src文件夹下新增 styles 文件夹,用于存放全局样式文件,新建一个 varibles.scss文件,用于统一管理声明的颜色变量:

$white: #FFFFFF;
$primary-color: #1890ff;
$success-color: #67C23A;
$warning-color: #E6A23C;
$danger-color: #F56C6C;
$info-color: #909399;

组件中使用在vite.config.ts中将这个样式文件全局注入到项目即可全局使用,不需要在任何组件中再次引入这个文件或者颜色变量。

css: {
preprocessorOptions: {
scss: {
modifyVars: {},
javascriptEnabled: true,
// 注意这里的引入的书写
additionalData: '@import "@/style/varibles.scss";'
}
}
},

在组件中使用

.div {
color: $primary-color;
background-color: $success-color;
}

统一请求封装

在src文件夹下,新建http文件夹,在http文件夹下新增index.ts,config.ts,core.ts,types.d.ts,utils.ts

core.ts

import Axios, { AxiosRequestConfig, CancelTokenStatic, AxiosInstance } from "axios";
import NProgress from 'nprogress'
import { genConfig } from "./config";
import { transformConfigByMethod } from "./utils";
import {
cancelTokenType,
RequestMethods,
HttpRequestConfig,
HttpResoponse,
HttpError
} from "./types.d"; class Http {
constructor() {
this.httpInterceptorsRequest();
this.httpInterceptorsResponse();
}
// 初始化配置对象
private static initConfig: HttpRequestConfig = {}; // 保存当前Axios实例对象
private static axiosInstance: AxiosInstance = Axios.create(genConfig()); // 保存 Http实例
private static HttpInstance: Http; // axios取消对象
private CancelToken: CancelTokenStatic = Axios.CancelToken; // 取消的凭证数组
private sourceTokenList: Array<cancelTokenType> = []; // 记录当前这一次cancelToken的key
private currentCancelTokenKey = ""; public get cancelTokenList(): Array<cancelTokenType> {
return this.sourceTokenList;
} // eslint-disable-next-line class-methods-use-this
public set cancelTokenList(value) {
throw new Error("cancelTokenList不允许赋值");
} /**
* @description 私有构造不允许实例化
* @returns void 0
*/
// constructor() {} /**
* @description 生成唯一取消key
* @param config axios配置
* @returns string
*/
// eslint-disable-next-line class-methods-use-this
private static genUniqueKey(config: HttpRequestConfig): string {
return `${config.url}--${JSON.stringify(config.data)}`;
} /**
* @description 取消重复请求
* @returns void 0
*/
private cancelRepeatRequest(): void {
const temp: { [key: string]: boolean } = {}; this.sourceTokenList = this.sourceTokenList.reduce<Array<cancelTokenType>>(
(res: Array<cancelTokenType>, cancelToken: cancelTokenType) => {
const { cancelKey, cancelExecutor } = cancelToken;
if (!temp[cancelKey]) {
temp[cancelKey] = true;
res.push(cancelToken);
} else {
cancelExecutor();
}
return res;
},
[]
);
} /**
* @description 删除指定的CancelToken
* @returns void 0
*/
private deleteCancelTokenByCancelKey(cancelKey: string): void {
this.sourceTokenList =
this.sourceTokenList.length < 1
? this.sourceTokenList.filter(
cancelToken => cancelToken.cancelKey !== cancelKey
)
: [];
} /**
* @description 拦截请求
* @returns void 0
*/ private httpInterceptorsRequest(): void {
Http.axiosInstance.interceptors.request.use(
(config: HttpRequestConfig) => {
const $config = config;
NProgress.start(); // 每次切换页面时,调用进度条
const cancelKey = Http.genUniqueKey($config);
$config.cancelToken = new this.CancelToken(
(cancelExecutor: (cancel: any) => void) => {
this.sourceTokenList.push({ cancelKey, cancelExecutor });
}
);
this.cancelRepeatRequest();
this.currentCancelTokenKey = cancelKey;
// 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉
if (typeof config.beforeRequestCallback === "function") {
config.beforeRequestCallback($config);
return $config;
}
if (Http.initConfig.beforeRequestCallback) {
Http.initConfig.beforeRequestCallback($config);
return $config;
}
return $config;
},
error => {
return Promise.reject(error);
}
);
} /**
* @description 清空当前cancelTokenList
* @returns void 0
*/
public clearCancelTokenList(): void {
this.sourceTokenList.length = 0;
} /**
* @description 拦截响应
* @returns void 0
*/
private httpInterceptorsResponse(): void {
const instance = Http.axiosInstance;
instance.interceptors.response.use(
(response: HttpResoponse) => {
const $config = response.config;
// 请求每次成功一次就删除当前canceltoken标记
const cancelKey = Http.genUniqueKey($config);
this.deleteCancelTokenByCancelKey(cancelKey); NProgress.done();
// 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉
if (typeof $config.beforeResponseCallback === "function") {
$config.beforeResponseCallback(response);
return response.data;
}
if (Http.initConfig.beforeResponseCallback) {
Http.initConfig.beforeResponseCallback(response);
return response.data;
}
return response.data;
},
(error: HttpError) => {
const $error = error;
// 判断当前的请求中是否在 取消token数组理存在,如果存在则移除(单次请求流程)
if (this.currentCancelTokenKey) {
const haskey = this.sourceTokenList.filter(
cancelToken => cancelToken.cancelKey === this.currentCancelTokenKey
).length;
if (haskey) {
this.sourceTokenList = this.sourceTokenList.filter(
cancelToken =>
cancelToken.cancelKey !== this.currentCancelTokenKey
);
this.currentCancelTokenKey = "";
}
}
$error.isCancelRequest = Axios.isCancel($error);
NProgress.done();
// 所有的响应异常 区分来源为取消请求/非取消请求
return Promise.reject($error);
}
);
} public request<T>(
method: RequestMethods,
url: string,
param?: AxiosRequestConfig,
axiosConfig?: HttpRequestConfig
): Promise<T> {
const config = transformConfigByMethod(param, {
method,
url,
...axiosConfig
} as HttpRequestConfig);
// 单独处理自定义请求/响应回掉
return new Promise((resolve, reject) => {
Http.axiosInstance
.request(config)
.then((response: undefined) => {
resolve(response);
})
.catch((error: any) => {
reject(error);
});
});
} public post<T>(
url: string,
params?: T,
config?: HttpRequestConfig
): Promise<T> {
return this.request<T>("post", url, params, config);
} public get<T>(
url: string,
params?: T,
config?: HttpRequestConfig
): Promise<T> {
return this.request<T>("get", url, params, config);
}
} export default Http;

config.ts

import { AxiosRequestConfig } from "axios";
import { excludeProps } from "./utils";
/**
* 默认配置
*/
export const defaultConfig: AxiosRequestConfig = {
baseURL: "",
//10秒超时
timeout: 10000,
headers: {
Accept: "application/json, text/plain, */*",
"Content-Type": "application/json",
"X-Requested-With": "XMLHttpRequest"
}
}; export function genConfig(config?: AxiosRequestConfig): AxiosRequestConfig {
if (!config) {
return defaultConfig;
} const { headers } = config;
if (headers && typeof headers === "object") {
defaultConfig.headers = {
...defaultConfig.headers,
...headers
};
}
return { ...excludeProps(config!, "headers"), ...defaultConfig };
} export const METHODS = ["post", "get", "put", "delete", "option", "patch"];

utils.ts

import { HttpRequestConfig } from "./types.d";

export function excludeProps<T extends { [key: string]: any }>(
origin: T,
prop: string
): { [key: string]: T } {
return Object.keys(origin)
.filter(key => !prop.includes(key))
.reduce((res, key) => {
res[key] = origin[key];
return res;
}, {} as { [key: string]: T });
} export function transformConfigByMethod(
params: any,
config: HttpRequestConfig
): HttpRequestConfig {
const { method } = config;
const props = ["delete", "get", "head", "options"].includes(
method!.toLocaleLowerCase()
)
? "params"
: "data";
return {
...config,
[props]: params
};
}

types.d.ts

import Axios, {
AxiosRequestConfig,
Canceler,
AxiosResponse,
Method,
AxiosError
} from "axios"; import { METHODS } from "./config"; export type cancelTokenType = { cancelKey: string; cancelExecutor: Canceler }; export type RequestMethods = Extract<
Method,
"get" | "post" | "put" | "delete" | "patch" | "option" | "head"
>; export interface HttpRequestConfig extends AxiosRequestConfig {
// 请求发送之前
beforeRequestCallback?: (request: HttpRequestConfig) => void;
// 相应返回之前
beforeResponseCallback?: (response: HttpResoponse) => void;
} export interface HttpResoponse extends AxiosResponse {
config: HttpRequestConfig;
} export interface HttpError extends AxiosError {
isCancelRequest?: boolean;
} export default class Http {
cancelTokenList: Array<cancelTokenType>;
clearCancelTokenList(): void;
request<T>(
method: RequestMethods,
url: string,
param?: AxiosRequestConfig,
axiosConfig?: HttpRequestConfig
): Promise<T>;
post<T>(
url: string,
params?: T,
config?: HttpRequestConfig
): Promise<T>;
get<T>(
url: string,
params?: T,
config?: HttpRequestConfig
): Promise<T>;
}

index.ts

import Http from "./core";
export const http = new Http();

统一api管理

在src下新增api文件夹,对项目中接口做统一管理,按照模块来划分。

例如,在 api 文件下新增 user.ts和types.ts ,分别用于存放登录,注册等模块的请求接口和数据类型。

// login.ts
import { http } from "@/http/index";
import { ILoginReq, ILoginRes } from "./types"; export const getLogin = async(req: ILoginParams): Promise<ILoginRes> => {
const res:any = await http.post('/login/info', req)
return res as ILoginRes
}
# 或者
export const getLogin1 = async(req: ILoginParams): Promise<ILoginRes> => {
const res:any = await http.request('post', '/login/info', req)
return res as ILoginRes
}
// types.ts
export interface ILoginReq {
userName: string;
password: string;
} export interface ILoginRes {
access_token: string;
refresh_token: string;
scope: string
token_type: string
expires_in: string
}

除了自己手动封装 axios ,这里还推荐一个十分非常强大牛皮的 vue3 的请求库: VueRequest,里面的功能非常的丰富(偷偷告诉你我也在使用中)。官网地址:https://www.attojs.com/

状态管理 Pinia

Pinia 是 Vue.js 的轻量级状态管理库,最近很受欢迎。它使用 Vue 3 中的新反应系统来构建一个直观且完全类型化的状态管理库。

由于 vuex 4 对 typescript 的支持很不友好,所以状态管理弃用了 vuex 而采取了 pinia, pinia 的作者是 Vue 核心团队成员,并且pinia已经正式加入了Vue,成为了Vue中的一员。尤大佬 pinia 可能会代替 vuex,所以请放心使用(公司项目也在使用中)。

Pinia官网地址(https://pinia.vuejs.org

Pinia的一些优点:

(1)Pinia 的 API 设计非常接近 Vuex 5 的提案。

(2)无需像 Vuex 4 自定义复杂的类型来支持 typescript,天生具备完美的类型推断。

(3)模块化设计,你引入的每一个 store 在打包时都可以自动拆分他们。

(4)无嵌套结构,但你可以在任意的 store 之间交叉组合使用。

(5)Pinia 与 Vue devtools 挂钩,不会影响 Vue 3 开发体验。

Pinia的成功可以归功于其管理存储数据的独特功能(可扩展性、存储模块组织、状态变化分组、多存储创建等)。

另一方面,Vuex也是为Vue框架建立的一个流行的状态管理库,它也是Vue核心团队推荐的状态管理库。Vuex高度关注应用程序的可扩展性、开发人员的工效和信心。它基于与Redux相同的流量架构。

Pinia和Vuex都非常快,在某些情况下,使用Pinia的web应用程序会比使用Vuex更快。这种性能的提升可以归因于Pinia的极轻的体积,Pinia体积约1KB。

安装

# 安装
yarn add pinia@next

在src下新建store文件夹,在store文件夹下新建index.ts,mutation-types(变量集中管理),types.ts(类型)和modules文件夹(分模块管理状态)

// index.ts
import type { App } from "vue";
import { createPinia } from "pinia"; const store = createPinia();
export function setupStore(app: App<Element>) {
app.use(store)
} export { store }
// modules/user.ts
import { defineStore } from 'pinia';
import { store } from '@/store';
import { ACCESS_TOKEN } from '@/store/mutation-types';
import { IUserState } from '@/store/types' export const useUserStore = defineStore({
// 此处的id很重要
id: 'app-user',
state: (): IUserState => ({
token: localStorge.getItem(ACCESS_TOKEN)
}),
getters: {
getToken(): string {
return this.token;
}
},
actions: {
setToken(token: string) {
this.token = token;
},
// 登录
async login(userInfo) {
try {
const response = await login(userInfo);
const { result, code } = response;
if (code === ResultEnum.SUCCESS) {
localStorage.setItem(ACCESS_TOKEN, result.token);
this.setToken(result.token);
}
return Promise.resolve(response);
} catch (e) {
return Promise.reject(e);
}
},
}
}) // Need to be used outside the setup
export function useUserStoreHook() {
return useUserStore(store);
}
/// mutation-types.ts
// 对变量做统一管理
export const ACCESS_TOKEN = 'ACCESS-TOKEN'; // 用户token

修改main.ts

import { createApp } from 'vue'
import App from './App.vue'
import { setupStore } from '@/store'
import router from './router/index' const app = createApp(App)
// 挂载状态管理
setupStore(app); app.use(router) app.mount('#app')

在组件中使用

<template>
<div>{{userStore.token}}</div>
</template> <script lang="ts">
import { defineComponent } from 'vue'
import { useUserStoreHook } from "@/store/modules/user" export default defineComponent({
setup() {
const userStore = useUserStoreHook() return {
userStore
}
},
})
</script>

getters的用法介绍

// modules/user.ts
import { defineStore } from 'pinia';
import { store } from '@/store';
import { ACCESS_TOKEN } from '@/store/mutation-types';
import { IUserState } from '@/store/types' export const useUserStore = defineStore({
// 此处的id很重要
id: 'app-user',
state: (): IUserState => ({
token: localStorge.getItem(ACCESS_TOKEN),
name: ''
}),
getters: {
getToken(): string {
return this.token;
},
nameLength: (state) => state.name.length,
},
actions: {
setToken(token: string) {
this.token = token;
},
// 登录
async login(userInfo) {
// 调用接口,做逻辑处理
}
}
}) // Need to be used outside the setup
export function useUserStoreHook() {
return useUserStore(store);
}
<template>
<div>
<span>{{userStore.name}}</span>
<span>{{userStore.nameLength}}</span>
<buttton @click="changeName"></button>
</div>
</template> <script lang="ts">
import { defineComponent } from 'vue'
import { useUserStoreHook } from "@/store/modules/user" export default defineComponent({
setup() {
const userStore = useUserStoreHook() const changeName = ()=>{
// $patch 修改 store 中的数据
userStore.$patch({
name: '名称被修改了,nameLength也改变了'
})
} return {
userStore,
updateName
}
},
})
</script>

actions

这里与 Vuex 有极大的不同,Pinia 仅提供了一种方法来定义如何更改状态的规则,放弃 mutations 只依靠 Actions,这是一项重大的改变。

Pinia 让 Actions 更加的灵活

  • 可以通过组件或其他 action 调用

  • 可以从其他 store 的 action 中调用

  • 直接在商店实例上调用

  • 支持同步异步

  • 有任意数量的参数

  • 可以包含有关如何更改状态的逻辑(也就是 vuex 的 mutations 的作用)

  • 可以 $patch 方法直接更改状态属性

    更多详细的用法请参考Pinia中的actions官方网站:

    actions的用法(https://pinia.vuejs.org/core-concepts/actions.html)

环境变量配置

vite 提供了两种模式:具有开发服务器的开发模式(development)和生产模式(production)。在项目的根目录中我们新建开发配置文件.env.development和生产配置文件.env.production。

# 网站根目录
VITE_APP_BASE_URL= ''

组件中使用:

console.log(import.meta.env.VITE_APP_BASE_URL)

配置 package.json,打包区分开发环境和生产环境

"build:dev": "vue-tsc --noEmit && vite build --mode development",
"build:pro": "vue-tsc --noEmit && vite build --mode production",

使用组件库

根据自己的项目需要选择合适的组件库即可,这里推荐两个优秀的组件库Element-plus和Naive UI。下面简单介绍它们的使用方法。

使用element-plus(https://element-plus.gitee.io/zh-CN/)

yarn add element-plus

推荐按需引入的方式:

按需引入需要安装unplugin-vue-components和unplugin-auto-import两个插件。

yarn add -D unplugin-vue-components unplugin-auto-import

再将vite.config.ts写入一下配置,即可在项目中使用element plus组件,无需再引入。

// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' export default {
plugins: [
// ...
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
}

Naive UI(https://www.naiveui.com/zh-CN/os-theme)

# 安装naive-ui
npm i -D naive-ui # 安装字体
npm i -D vfonts

按需全局安装组件

import { createApp } from 'vue'
import {
// create naive ui
create,
// component
NButton
} from 'naive-ui' const naive = create({
components: [NButton]
}) const app = createApp()
app.use(naive)

安装后,你可以这样在 SFC 中使用你安装的组件。

<template>
<n-button>naive-ui</n-button>
</template>

Vite 常用基础配置

基础配置

运行代理和打包配置

server: {
host: '0.0.0.0',
port: 3000,
open: true,
https: false,
proxy: {}
},

生产环境去除 console debugger

build:{
...
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
}
}

生产环境生成 .gz 文件,开启 gzip 可以极大的压缩静态资源,对页面加载的速度起到了显著的作用。使用 vite-plugin-compression 可以 gzip 或 brotli 的方式来压缩资源,这一步需要服务器端的配合,vite 只能帮你打包出 .gz 文件。此插件使用简单,你甚至无需配置参数,引入即可。

# 安装
yarn add --dev vite-plugin-compression
// vite.config.ts中添加
import viteCompression from 'vite-plugin-compression' // gzip压缩 生产环境生成 .gz 文件
viteCompression({
verbose: true,
disable: false,
threshold: 10240,
algorithm: 'gzip',
ext: '.gz',
}),

最终 vite.config.ts文件配置如下(自己根据项目需求配置即可)

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
//@ts-ignore
import viteCompression from 'vite-plugin-compression' // https://vitejs.dev/config/
export default defineConfig({
base: './', //打包路径
plugins: [
vue(),
// gzip压缩 生产环境生成 .gz 文件
viteCompression({
verbose: true,
disable: false,
threshold: 10240,
algorithm: 'gzip',
ext: '.gz',
}),
],
// 配置别名
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
css:{
preprocessorOptions:{
scss:{
additionalData:'@import "@/assets/style/mian.scss";'
}
}
},
//启动服务配置
server: {
host: '0.0.0.0',
port: 8000,
open: true,
https: false,
proxy: {}
},
// 生产环境打包配置
//去除 console debugger
build: {
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
},
})

Vue3.0+typescript+Vite+Pinia+Element-plus搭建vue3框架!的更多相关文章

  1. vue3.0+typeScript项目

    https://segmentfault.com/a/1190000018720570#articleHeader15 https://segmentfault.com/a/1190000016423 ...

  2. Vue3.0+TypeScript

    序言 资料 https://www.cnblogs.com/chanwahfung/p/11968205.html

  3. Vue3 + Cesium + Typescript 集成搭建的快速启动模板(包含示例数据)

    开门见山 项目地址:https://github.com/tanghaojie/vue3-cesium-typescript-start-up-template 好用的话给个star呗,有更新可以第一 ...

  4. 快速进阶Vue3.0

    在2019.10.5日发布了Vue3.0预览版源码,但是预计最早需要等到 2020 年第一季度才有可能发布 3.0 正式版. 可以直接看 github源码. 新版Vue 3.0计划并已实现的主要架构改 ...

  5. VUE3.0发布,自己搞个文档网站

    9月19日,尤大神发表了VUE3.0版本的演说,强大且震撼,这两天一直在找网站文档,可能还未被百度收录,未找到文档网站.后来在github上面找到了中文代码. 地址为:https://github.c ...

  6. 【vue3-element-admin 】基于 Vue3 + Vite4 + TypeScript + Element-Plus 从0到1搭建后台管理系统(前后端开源@有来开源组织)

    vue3-element-admin 是基于 vue-element-admin 升级的 Vue3 + Element Plus 版本的后台管理前端解决方案,技术栈为 Vue3 + Vite4 + T ...

  7. vite + ts 快速搭建 vue3 项目 以及介绍相关特性

    博客地址:https://ainyi.com/98 Vue3.0,One Piece 接下来得抽空好好学习了 vite 尤大在 Vue 3.0 beta 直播中推荐了 vite 的工具,强调:针对Vu ...

  8. Vite+TS带你搭建一个属于自己的Vue3组件库

    theme: nico 前言 随着前端技术的发展,业界涌现出了许多的UI组件库.例如我们熟知的ElementUI,Vant,AntDesign等等.但是作为一个前端开发者,你知道一个UI组件库是如何被 ...

  9. 从0搭建Vue3组件库(三): 组件库的环境配置

    本篇文章将在项目中引入 typescript,以及手动搭建一个用于测试组件库组件 Vue3 项目 因为我们是使用 Vite+Ts 开发的是 Vue3 组件库,所以我们需要安装 typescript.v ...

  10. Vue3.0脚手架搭建

    https://www.jianshu.com/p/fbcad30031c2 vue3.0官网:https://cli.vuejs.org/zh/guide/ 介绍: notice: 这份文档是对应 ...

随机推荐

  1. sweetviz工具避坑和简单使用

    网上关于sweetviz的文章比较少,有些坑这里说一下给大家避坑. 使用sweetviz遇到的错误如下: KeyError: "None of ['index'] are in the co ...

  2. 使用EPLAN做项目的收获点

    收获点如下: 1.消息检查功能. 最具有代表性的EPLAN软件的辅助检查功能.通过自带检查可以发现设计的错误和警告. 2.导线表导出功能. 使用导入模版.宏设置,导出对应线号表. 此类接线通过一个导线 ...

  3. kubernetes集群最新版安装

    原文地址:https://haiyux.cc/2022/09/21/k8s-install/ 虚拟机准备 我这里准备了三台虚拟机,分别部署一个master和两个node,操作系统位ubuntu 20. ...

  4. 贝壳基于 Flink 的实时计算演进之路

    简介: 贝壳找房在实时计算之路上的平台建设以及实时数仓应用. 摘要:贝壳找房大数据平台实时计算负责人刘力云带来的分享内容是贝壳找房的实时计算演进之路,内容如下: 发展历程 平台建设 实时数仓及其应用场 ...

  5. 使用 DISM 安全清理 C 盘 WinSxS 文件夹空间

    本文将介绍如何使用系统内置 DISM 工具进行安全清理 C 盘空间,清理 WinSxS 文件夹里面的可回收删除的程序包空间 开始之前,先使用管理员权限打开 CMD 或 PowerShell 命令行窗口 ...

  6. 支持 dotnet 6 的 dnSpy 神器版本

    官方的 dnSpy 在 2021 时,由于某些吃瓜的原因 wtfsck 将 dnSpy 给 Archived 掉,在大佬被哄好之前,预计是不再更新.最新官方版本对 dotnet 6 的支持较弱,对于很 ...

  7. 零侵入!试试这款Api接口文档生成器!

    大家好,我是 Java陈序员. 作为一名合格的程序员,不仅代码要写好,而且文档要写好. 虽然目前有成熟的框架可以快速生成接口文档,如大名鼎鼎的 Swagger.但是 Swagger 需要编写大量的注解 ...

  8. 通过AMDP调用HANA的PAL函数

    SAP预测分析库(SAP Predictive Analysis Library,PAL)是SAP HANA中的一项功能,它允许我们在SAP HANA SQLScript过程中执行分析算法. 基于AB ...

  9. 三、Prophecis 一站式云原生机器学习平台

    Prophecis 是微众银行自研大数据平台套件 WeDataSphere 的核心应用工具之一,为用户提供了全栈的机器学习应用开发与部署解决方案.作为WeDataSphere 功能工具应用系统,Pro ...

  10. 二:大数据架构回顾-Kappa架构

    Kappa 架构是由 LinkedIn 的前首席工程师杰伊·克雷普斯(Jay Kreps)提出的一种架构思想.克雷普斯是几个著名开源项目(包括 Apache Kafka 和 Apache Samza ...