上記は、一連のユーティリティとコンポーネント情報を作成し、新しいコンポーネント モジュールに関連するディレクトリとファイルの作成を実装します。この記事では引き続き以下の内容を実装していきます。
1 コンポーネント スタイル ファイルとインポート
initScss関数をエクスポートするinit-scss.tsファイルをsrc/serviceディレクトリに作成します。
.vue タイプのコンポーネントのスタイルはstyleに直接記述されているため、最初にコンポーネントのタイプがtsxであるかどうかが判断されます。このステップは tsx タイプのコンポーネントに対してのみ実行されます。
- コンポーネントの scss ファイル_xxx.module.scssをscss/components/ディレクトリに作成します。
- scss/components/index.scssに_xxx.module.scssをインポートします。
1.1 init-scss.ts
コードは次のように実装されます。
import {
ComponentInfo } from '../domain/component-info'
import path from 'path'
import {
scssTemplate } from '../util/template-utils'
import fs from 'fs'
import {
g } from '../util/log-utils'
const updateComponentScssIndex = (scssRootPath: string, lineName: string) => {
const indexScssPath = path.resolve(scssRootPath, 'components/index.scss')
const content = fs.readFileSync(indexScssPath).toString()
const newContent = content.substring(0, content.length) + `@use "${
lineName}.module";\n`
fs.writeFileSync(indexScssPath, newContent)
}
/**
* 创建组件库 scss 文件,并在 scss/components/index.scss 中引入该文件
*/
export const initScss = (componentInfo: ComponentInfo) => new Promise((resolve, reject) => {
// tsx 类型需要创建scss文件
if (componentInfo.type === 'tsx') {
const {
parentPath, lineName, lineNameWithPrefix } = componentInfo
// scss 根目录(packages/scss)
const scssRootPath = path.resolve(parentPath, 'scss')
// 1. 创建组件的 scss 文件
const componentScssPath = path.resolve(scssRootPath, `components/_${
lineName}.module.scss`)
fs.writeFileSync(componentScssPath, scssTemplate(lineNameWithPrefix))
// 2. 在组件库 scss 入口文件 (packages/components/index.scss)引入上面创建的文件
updateComponentScssIndex(scssRootPath, lineName)
g('component scss init success')
}
resolve(componentInfo)
})
1.2 テンプレート-utils.ts
上記のinit-scss.ts は、 scss ファイルの作成時にtemplate-utils.tsのscssTemplate関数を呼び出してテンプレートを取得します。したがって、この関数をutil/template-utils.tsに追加する必要があります。
/**
* scss 文件模板
*/
export const scssTemplate = (lineNameWithPrefix: string): string => {
return `@import "../tools";
@import "../acss/mp";
@import "../base/var.module";
@include b('${
lineNameWithPrefix}') {
}
`
}
2 コンポーネントライブラリエントリモジュールに追加
新しいコンポーネントとスタイルの作成が完了したら、次のステップは、新しいコンポーネント モジュールをコンポーネント ライブラリ エントリ モジュールの依存関係にインストールすることです。src/serviceディレクトリにupdate-component-lib.tsファイルを作成し、関数updateComponentLibをエクスポートします。この関数は次の 2 つのことを行う必要があります。
- 新しいコンポーネントをコンポーネント ライブラリ エントリ モジュールに依存関係としてインストールします。
- コンポーネント ライブラリ エントリ モジュールのindex.ts ファイルを更新し、新しいコンポーネントを導入します。
コードは次のように実装されます。
import {
ComponentInfo } from '../domain/component-info'
import {
execCmd } from '../util/cmd-utils'
import path from 'path'
import {
Config } from '../config'
import fs from 'fs'
import {
g } from '../util/log-utils'
const updateComponentLibIndex = (libPath: string, componentInfo: ComponentInfo) => {
const indexPath = path.join(libPath, 'index.ts')
const content = fs.readFileSync(indexPath).toString()
const index1 = content.indexOf('// import component end')
const index2 = content.indexOf('] // components')
const result = `${
content.substring(0, index1)}` +
`import ${
componentInfo.upCamelName} from '${
componentInfo.nameWithLib}'\n` +
content.substring(index1, index2 - 1) +
`,\n ${
componentInfo.upCamelName}\n` +
content.substring(index2)
fs.writeFileSync(indexPath, result)
}
/**
* 更新组件库入口
*/
export const updateComponentLib = async (componentInfo: ComponentInfo) => {
// 组件库入口的路径
const libPath = path.resolve(componentInfo.parentPath, Config.COMPONENT_LIB_NAME)
// 1. 添加新创建的组件到依赖中
await execCmd(`cd ${
libPath} && pnpm install ${
componentInfo.nameWithLib}`)
// 2. 更新入口 index.ts
updateComponentLibIndex(libPath, componentInfo)
g('component library update success')
}
3 コンポーネントライブラリドキュメント関連ファイル
3.1 init-doc.ts
src/serviceディレクトリにinit-doc.tsファイルを作成し、関数initDocをエクスポートします。この関数は次の 3 つのことを行う必要があります。
- コンポーネントの MarkDown ドキュメントを作成します。
- コンポーネント MD ドキュメントでデモを作成します。
- コンポーネント ライブラリのドキュメント メニューを更新しました。
コードは次のように実装されます。
import {
ComponentInfo } from '../domain/component-info'
import {
g } from '../util/log-utils'
import path from 'path'
import fs from 'fs'
import {
demoTemplate, mdTemplate } from '../util/template-utils'
/**
* 创建组件文档、demo及更新菜单
*/
export const initDoc = (componentInfo: ComponentInfo) => {
// 组件库文档根路径
const docRootPath = path.resolve(componentInfo.parentPath, '../docs')
const {
lineName, lineNameWithPrefix, upCamelName, zhName } = componentInfo
// 1. 创建组件的 MD 文档
fs.writeFileSync(path.resolve(docRootPath, `components/${
lineName}.md`), mdTemplate(componentInfo))
// 2. 创建组件文档中的 Demo
fs.mkdirSync(path.resolve(docRootPath, `demos/${
lineName}`))
fs.writeFileSync(path.resolve(docRootPath, `demos/${
lineName}/${
lineName}-1.vue`), demoTemplate(lineNameWithPrefix))
// 3. 更新组件库文档菜单
const menuPath = path.resolve(docRootPath, 'components.ts')
const content = fs.readFileSync(menuPath).toString()
const index = content.indexOf('] // end')
const result = content.substring(0, index - 1) +
`,\n { text: '${
upCamelName} ${
zhName}', link: '/components/${
lineName}' }\n` +
content.substring(index)
fs.writeFileSync(menuPath, result)
g('component document init success')
}
3.2 テンプレート-utils.ts
上記の init-doc.ts は2 つの関数mdTemplateとdemoTemplateを呼び出します。これらの 2 つの関数をtemplate-utils.tsに追加します。
export const mdTemplate = (componentInfo: ComponentInfo) => {
return `
# ${
componentInfo.upCamelName} ${
componentInfo.zhName}
## 基本使用
<preview path="../demos/${
componentInfo.lineName}/${
componentInfo.lineName}-1.vue" title="基本使用" description=" "></preview>
## 组件 API
### Attributes 属性
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---- | ---- | ---- | ---- | ---- |
| | | | | |
### Methods 方法
| 方法名 | 说明 | 参数 | 返回值 |
| ---- | ---- | ---- | ---- |
| | | | |
### Events 事件
| 事件名 | 说明 | 参数 | 返回值 |
| ---- | ---- | ---- | ---- |
| | | | |
### Slots 插槽
| 插槽名 | 说明 | 参数 |
| ---- | ---- | ---- |
| | | |
`
}
export const demoTemplate = (lineNameWithPrefix: string) => {
return `<template>
<${
lineNameWithPrefix}></${
lineNameWithPrefix}>
</template>
<script lang="ts" setup>
</script>
<style scoped lang="scss">
</style>
`
}
これら 2 つの関数のテンプレートは自分で定義できます。
4 コンポーネントの作成.ts
4 つのステップが実装され、最後に、src/command/create-component.tsファイルのcreateNewComponent関数で上記の 4 つのサービス呼び出しを完了する必要があります。
4.1 インポート
使用される 4 つのサービスとその他の機能をインポートします。
import {
ComponentInfo } from '../domain/component-info'
import {
closeLoading, showLoading } from '../util/loading-utils'
import {
g, r } from '../util/log-utils'
import {
initComponent } from '../service/init-component'
import {
initScss } from '../service/init-scss'
import {
updateComponentLib } from '../service/update-component-lib'
import {
initDoc } from '../service/init-doc'
4.2 新しいコンポーネントの作成
この関数は、まずユーザー入力に基づいて ComponentInfo オブジェクトを構築し、次に導入された 4 つのサービスを順番に呼び出して、コンポーネント作成のプロセス全体を完了します。
const createNewComponent = async (componentName: string, description: string, componentType: string) => {
console.log(componentName, description, componentType)
showLoading('Generating, please wait...')
try {
// 1. 构造 ComponentInfo 对象
const componentInfo = new ComponentInfo(componentName, description, componentType)
// 2. 创建组件目录及文件
await initComponent(componentInfo)
// 3. 创建样式
await initScss(componentInfo)
// 4. 更新组件库入口
await updateComponentLib(componentInfo)
// 5. 组件库文档
initDoc(componentInfo)
closeLoading()
g(`component [${
componentInfo.lineName} ${
componentInfo.zhName}] created done!`)
} catch (e: any) {
closeLoading()
r(e.message)
}
}
コンポーネントライブラリcliが完成しました。pnpm run genを実行し、コンポーネント名、コンポーネントの中国語名を入力し、コンポーネントの種類を選択すると、コンポーネントの作成、登録、ドキュメントの作成が自動的に完了します。Yaya 兄弟は cli の開発について多くのスペースを割いて紹介しましたが、これはここでのみ使用できるものではありません。この事例の実装を通じて、この方法を github からのコード テンプレートのプルや自動 CI/ など、他の場所にも移植できることを願っています。 CDなど
次の記事では、コンポーネント ライブラリのパッケージ化、構築、リリースについて紹介します。
この記事をお読みいただきありがとうございます。この記事が少しでも助けやインスピレーションを与えた場合は、Gongwei アカウント「Brother Elegant Programmer」についてさらに詳しく知るために 3 回サポートしてください。