感谢

感谢作者Kagol的无私分享,Vue DevUI即将发布1.0,欢迎大家关注,使用!


视频教程

【我要做开源】华为大佬亲授,vue devui开源指南04:[组件库工程化]搭建一个支持TS/JSX的Vite工程_json


上一次直播内容回顾

  • 先是停下来,给上上次的tree组件(渲染嵌套的多层节点)增加单元测试
  • 然后完善tree组件,实现展开/收起功能
  • 并使用vue3的组合式API,对该功能进行重构,实现useToggle方法,将该功能从setup中抽离出来

最终实现的效果:

【我要做开源】华为大佬亲授,vue devui开源指南04:[组件库工程化]搭建一个支持TS/JSX的Vite工程_json_02img

1 创建基础项目工程

yarn create vite vite-demo --template vue-ts

# or
# npm init vite@latest vite-demo -- --template vue-ts
$ yarn create vite vite-demo --template vue-ts
yarn create v1.22.10
[1/4] 🔍 Resolving packages...
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
[4/4] 🔨 Building fresh packages...
success Installed "create-vite@2.6.6" with binaries:
- create-vite
- cva

Scaffolding project in /kagol/vite-demo...

Done. Now run:

cd vite-demo
yarn
yarn dev

✨ Done in 5.46s.

非常友好地提示了下一步要做什么

  cd vite-demo
yarn
yarn dev

安装依赖

$ yarn
yarn install v1.22.10
warning package.json: No license field
info No lockfile found.
warning vite-demo@0.0.0: No license field
[1/4] 🔍 Resolving packages...
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
[4/4] 🔨 Building fresh packages...
success Saved lockfile.
✨ Done in 7.33s.

本地启动

"dev": "vite",
$ yarn dev
yarn run v1.22.10
warning package.json: No license field
$ vite
Pre-bundling dependencies:
vue
(this will be run only when your dependencies or config have changed)

vite v2.6.5 dev server running at:

> Local: http://localhost:3000/
> Network: use `--host` to expose

ready in 402ms.

浏览器看效果

在浏览器地址栏输入以下链接查看效果:

​http://localhost:3000/​

【我要做开源】华为大佬亲授,vue devui开源指南04:[组件库工程化]搭建一个支持TS/JSX的Vite工程_json_03img

构建生产包

"build": "vue-tsc --noEmit && vite build",
$ yarn build
yarn run v1.22.10
warning package.json: No license field
$ vue-tsc --noEmit && vite build
vite v2.6.5 building for production...
✓ 14 modules transformed.
dist/assets/logo.03d6d6da.png 6.69 KiB
dist/index.html 0.48 KiB
dist/assets/index.31b3d229.js 1.95 KiB / gzip: 1.03 KiB
dist/assets/index.459f8680.css 0.34 KiB / gzip: 0.24 KiB
dist/assets/vendor.2acfe60d.js 49.61 KiB / gzip: 19.93 KiB
✨ Done in 11.09s.

2 一些关键文件

使用​​tree​​命令看下目录结构

$ tree -l 3
/kagol/vite-demo
├── README.md
├── index.html
├── package.json
├── public
| └── favicon.ico
├── src
| ├── App.vue
| ├── assets
| | └── logo.png
| ├── components
| | └── HelloWorld.vue
| ├── env.d.ts // vue-ts模板
| └── main.ts
├── tsconfig.json // vue-ts模板
└── vite.config.ts

directory: 4 file: 11

package.json

{
"name": "vite-demo",
"version": "0.0.0",
"scripts": {
"dev": "vite", // 本地启动
"build": "vue-tsc --noEmit && vite build", // 构建生产包,增加了vue-tsc类型检查 vue模板为 vite build
"serve": "vite preview" // 预览生产包效果
},
"dependencies": {
"vue": "^3.2.16"
},
"devDependencies": {
"@vitejs/plugin-vue": "^1.9.3", // 提供 Vue 3 单文件组件支持
"typescript": "^4.4.3", // vue-ts模板
"vite": "^2.6.4",
"vue-tsc": "^0.3.0" // volar的子包,vue3的ts类型检查工具(可选) vue-ts模板
}
}

一共有5个依赖

运行态依赖:vue 开发态依赖:

  • vite
  • @vitejs/plugin-vue 提供 Vue 3 单文件组件支持的vite插件
  • typescript
  • vue-tsc vue3的类型检查工具,可选

vite.config.ts

vite.config.ts/vite.config.js

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()]
})

tsconfig.json

{
// 编译选项 https://www.tslang.cn/docs/handbook/compiler-options.html
"compilerOptions": {
"target": "esnext", // 目标语言的版本
"useDefineForClassFields": true, // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#the-usedefineforclassfields-flag-and-the-declare-property-modifier
"module": "esnext", // 指定生成代码的模块标准
"moduleResolution": "node", // 决定如何处理模块
"strict": true, // 启用所有严格类型检查选项
"jsx": "preserve", // 在.tsx文件里支持JSX https://www.tslang.cn/docs/handbook/jsx.html
"sourceMap": true, // 生成目标文件的sourceMap文件
"resolveJsonModule": true, // 为了import json文件方便
"esModuleInterop": true, // 为了import cjs文件方便 https://zhuanlan.zhihu.com/p/148081795
"lib": ["esnext", "dom"] // 编译过程中需要引入的库文件的列表
},

// 指定编译器需要编译的文件或文件夹
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>



### env.d.ts



vue组件的类型声明,不添加该文件会提示



```plain
找不到模块“./App.vue”或其相应的类型声明。

3 添加 jsx 支持

希望能在项目中使用jsx编写的组件。

HelloWorld.tsx

export const HelloWorld = () => <div>Hello World jsx</div>

App.vue

import { HelloWorld } from './components/HelloWorld'

<HelloWorld />

报错:Uncaught ReferenceError: React is not defined

Uncaught ReferenceError: React is not defined
at HelloWorld (HelloWorld.tsx:1)

引入vite插件:@vitejs/plugin-vue-jsx

安装插件

yarn add -D @vitejs/plugin-vue-jsx

引入插件

vite.config.ts

import vueJsx from '@vitejs/plugin-vue-jsx'
plugins: [vue(), vueJsx()]

接上第一次直播的tree组件

tree.tsx

import { defineComponent, ExtractPropTypes, PropType } from 'vue'

interface TreeItem {
label: string
children?: TreeData
}

type TreeData = Array<TreeItem>

const treeProps = {
data: {
type: Array as PropType<TreeData>,
default: () => [],
}
}

type TreeProps = ExtractPropTypes<typeof treeProps>

export default defineComponent({
name: 'DTree',
props: treeProps,
setup(props: TreeProps) {
console.log('props:', props, props.data)
return () => {
return <div class="devui-tree">
{ props.data.map(item => <div>{ item.label }</div>) }
</div>
}
}
})

App.vue

import { ref } from 'vue'

import DTree from './components/tree'

const data = ref([{
label: '一级 1',
children: [{
label: '二级 1-1',
children: [{
label: '三级 1-1-1'
}]
}]
}, ...])

<d-tree :data="data"></d-tree>