предисловие
С тех пор, как недавно открылись работы по реконструкции, Vue3 вернулся в нашу разработку. С тех пор, как открыта библиотека компонентов Vue, второй пакет будет основан на vue3.x + element-plus, общих универсальных компонентах упаковки. В этом исследовании выбор технологии библиотеки компонентов Vue в большей степени не представляет собой окончательный выбор, который является лучшим, но на данном этапе я думаю, что это должен быть наиболее подходящий выбор технологии сцены, на самом деле, написание библиотеки компонентов не сложный, весь технологический процесс исследования и выбор технологии вниз, различные методы имеют свои преимущества и недостатки, несколько широкое понимание цели этой статьи состоит в том, чтобы записать этот выбор до окончательного завершения всего процесса. Базовая конфигурация не повторяется, документ для записи по существу только развитие по существу одной структуры и измерения пакета и только для справочных целей. Не хочу видеть статью, хочу увидеть кодкликните сюдаЯ хочу сначала увидеть эффект интерактивного документакликните сюда
Цель
Зачем создавать библиотеку компонентов? Эта проблема тоже банальна.В сценарии системы управления background xx на стороне ПК общие вещи можно легко абстрагировать, так что нет необходимости каждый раз писать в проекте набор базовых компонентов открыты, и базовые компоненты можно использовать напрямую.Разработка на основе компонентов может сэкономить много времени.На этот раз из компонентов извлекаются только несколько npm-пакетов с высокой интеграцией и универсальностью, а также реализуются общие общие функции во-первых, а последующее расширение может осуществляться без изменения исходной архитектуры на основе добавления функций. Эти компоненты включают в себя компоненты общего макета, общие компоненты таблицы, общие компоненты формы, общие компоненты загрузки файлов и изображений и т. д.
В частности, для таблиц и компонентов формы, если они используются непосредственно на странице, будет много повторяющегося кода, а код будет избыточным при написании, поэтому в общих проектах эти базовые компоненты будут инкапсулированы для достижения общей цели. конфигурация может быть использована на странице, как правило, они в основном одинаковы, это также является первоначальным намерением разработки такой базовой библиотеки компонентов, нет необходимости писать набор в каждом проекте, напрямую кидайте библиотеку компонентов в управление npm. была впоследствии модернизирована. Таким образом, собственный уникальный фонд и библиотека бизнес-компонентов компании могут быть постепенно ускорены, а последующие новые проекты могут быть использованы «из коробки».
до начала
Перед началом, в дополнение к технологическому стеку Vue 3.x + ElementPlus, необходимо уточнить принципы развития компонентной библиотеки: Краткое, эффективное, гибкое и расширяемое. Прежде всего, должна быть читаемая библиотека документов с примерами для взаимодействия; во-вторых, повторяющаяся работа, которая может быть автоматизирована, никогда не копируется вручную, и библиотека документов автоматически развернута; наконец-то лучше всего иметь тестирование компонентов для обеспечения правильность и полнота компонентов.
Структура проекта
├── docs /* 组件库文档 */
│ .vuepress /* vuepress 配置 */
│ ├── clientAppEnhance.ts /* 注册全局组件 */
│ ├── config.ts /* vuepress配置文件 */
│ index.md /* 文档 */
└── packages /* 包 */
│ ├── layout /* 布局组件 */
│ │ ├── src /* vue组件 */
│ │ ├── package.json /* 组件配置文件 */
│ │ ├── typings /* 组件声明文件 */
│ ├── form /* 表单组件 */
│ ├── table /* 表格组件 */
├── templates /* plop 配置clone的模板文件夹 */
├── typings /* 声明文件夹 */
├── .eslintrc.js /* eslint 配置 */
├── .gitignore /* gitignore 配置 */
├── .prettierrc /* prettier 配置 */
├── .stylelintrc /* stylelint 配置 */
├── babel.config.js /* babel 配置 */
├── jest.config.js /* jest 配置 */
├── LICENSE /* license */
├── package.json /* package.json */
├── plopfile.js /* plop 配置 */
├── tsconfig.json /* ts 配置 */
├── rollup.config.js /* rollup 打包配置 */
└── README.md /* 文档说明文件 */
режим управления пакетами
Поскольку это библиотека компонентов, несколько пакетов компонентов будут иметь общие зависимости.Чтобы уменьшить дублирование кода, рабочее пространство lerna + yarn используется для управления пакетами, что также является выбором большинства библиотек компонентов сегодня.
Упаковка компонентов
Упаковка компонентов выбирает rollup, потому что этот компонент предназначен для упаковки компонентов для нескольких общих сценариев, и им планируется управлять отдельно.Пакетирование Rollup может упаковывать esm, cjs, umd и т. д. в различных режимах, а esm поставляется с древовидной структурой. , полученный пакет имеет четкую семантику и его легче отлаживать. Файл конфигурации накопительной упаковки размещается на самом внешнем уровне для единообразной настройки упаковки компонентов.
Следующая конфигурация имеет несколько ключевых моментов:
- Мультивход, каждый компонент упаковывается отдельно, а файл index.js в формате umd и файл index.module.js в формате esm упаковываются отдельно
- При настройке babel вам необходимо вручную добавить расширения .ts и .vue для нормальной компиляции файлов ts и vue.
- В package.json под каждым пакетом объявляется основной модуль и типизация.Если поддерживается загрузка в режиме esm, по умолчанию загружается index.module.js, в противном случае загружается index.js.
- При настройке добавьте peerDependencies во внешний элемент конфигурации и не упаковывайте пакет peerDependencies, уменьшите размер пакета и улучшите эффективность упаковки
- esm поддерживает tree-shaking, поэтому css не упаковывается отдельно, поэтому прямое использование формата esm будет загружаться по запросу без необходимости использования плагинов.
rollup.config.js
/* eslint-disable @typescript-eslint/no-var-requires */
import fs from 'fs'
import path from 'path'
import json from '@rollup/plugin-json'
import postcss from 'rollup-plugin-postcss'
import vue from '@vitejs/plugin-vue'
import { terser } from 'rollup-plugin-terser'
import { nodeResolve } from '@rollup/plugin-node-resolve'
import typescript from '@rollup/plugin-typescript'
import babel from '@rollup/plugin-babel'
import commonjs from '@rollup/plugin-commonjs'
import { DEFAULT_EXTENSIONS } from '@babel/core'
const isDev = process.env.NODE_ENV !== 'production'
// packages 文件夹路径
const root = path.resolve(__dirname, 'packages')
// 公共插件配置
const getPlugins = () => {
return [
vue(),
typescript({
tsconfig: './tsconfig.json'
}),
nodeResolve({
mainField: ['jsnext:main', 'browser', 'module', 'main'],
browser: true
}),
commonjs(),
json(),
postcss({
plugins: [require('autoprefixer')],
// 把 css 插入到 style 中
inject: true,
// 把 css 放到和js同一目录
// extract: true
// Minimize CSS, boolean or options for cssnano.
minimize: !isDev,
// Enable sourceMap.
sourceMap: isDev,
// This plugin will process files ending with these extensions and the extensions supported by custom loaders.
extensions: ['.sass', '.less', '.scss', '.css']
}),
babel({
exclude: 'node_modules/**',
babelHelpers: 'runtime',
// babel 默认不支持 ts 需要手动添加
extensions: [...DEFAULT_EXTENSIONS, '.ts', '.tsx', '.vue']
}),
// 如果不是开发环境,开启压缩
!isDev && terser({ toplevel: true })
]
}
module.exports = fs
.readdirSync(root)
// 过滤,只保留文件夹
.filter(item => fs.statSync(path.resolve(root, item)).isDirectory())
// 为每一个文件夹创建对应的配置
.map(item => {
const pkg = require(path.resolve(root, item, 'package.json'))
return {
input: path.resolve(root, item, 'src/main.ts'),
output: [
{
name: 'index',
file: path.resolve(root, item, pkg.main),
format: 'umd',
sourcemap: isDev,
globals: {
vue: 'vue',
'element-plus': 'element-plus'
}
},
{
name: 'index.module',
file: path.join(root, item, pkg.module),
format: 'es',
sourcemap: isDev,
globals: {
vue: 'vue',
'element-plus': 'element-plus'
}
}
],
onwarn: function (warning) {
if (warning.code === 'THIS_IS_UNDEFINED' || warning.code === 'CIRCULAR_DEPENDENCY') {
return
}
console.error(`(!) ${warning.message}`)
},
plugins: getPlugins(),
external: Object.keys(require(path.join(root, item, 'package.json'))?.peerDependencies || {})
}
})
Документация библиотеки компонентов
документация по библиотеке компонентов sum-uiПо сравнению с предыдущей библиотекой документов рассмотрение другое.Используется Vuepress.Одной из причин выбора является то, что страница проста и гибкая.С помощью плагинов можно не только настроить инструкции взаимодействия компонентов, но и настроить другие инструкции для Руководство по документации.Vue рассматривался ранее.-styleguidst, но его ограничения относительно сильны. Он может только настраивать документы взаимодействия компонентов, а стиль страницы не такой простой и красивый, как vuepress. WIP и многие конфигурации, такие как плагины в vuepress, были удалены. Если это чистая документация, этого достаточно, но нам нужны инструкции по взаимодействию компонентов, поэтому мы наконец выбрали vuepress@next, поддерживающий Vue3.
vuepress упаковка
В дополнение к веб-пакету vuepress@next также добавляет способ разработки и упаковки vite, который можно настроить в .vuepress/config.ts.
Следующая конфигурация имеет несколько ключевых моментов:
- Прочитайте имя папки в папке пакетов и добавьте псевдоним к указанному пакету.
- Поскольку в компоненте поддерживается синтаксис jsx, добавлен плагин @vitejs/plugin-vue-jsx
- Конфигурация сборщика (@vuepress/webpack / @vuepress/vite), если не задано, вебпак по умолчанию, если установлен vuepress-vite, то упаковка vite по умолчанию
- Добавить плагин vuepressvuepress-plugin-demoblock-plus, плагин делает интерактивный рендеринг компонента со ссылкой на реализацию рендеринга документа element-plus
- Поскольку GitHub Actions используется для автоматического развертывания документов на страницах GitHub, конфигурация базовой опции должна соответствовать имени проекта github, поскольку путь загруженного статического ресурса находится в этой папке.
.vuepress/config.js
const { readdirSync } = require('fs')
const { join } = require('path')
const chalk = require('chalk')
const headPkgList = []; // 非 @sum-ui/开头的组件
const pkgList = readdirSync(join(__dirname, '../../packages')).filter(
(pkg) => pkg.charAt(0) !== '.' && !headPkgList.includes(pkg),
);
const alias = pkgList.reduce((pre, pkg) => {
pre[`@sum-ui/${pkg}`] = join(__dirname, '../../packages', pkg, 'src/Index.vue');
return {
...pre,
};
}, {});
console.log(`🌼 alias list \n${chalk.blue(Object.keys(alias).join('\n'))}`);
module.exports = {
title: "sum-ui", // 顶部左侧标题
description: 'Vue3 + ElementPlus 组件库',
base: '/sum-ui/',
bundler: '@vuepress/vite',
bundlerConfig: {
viteOptions: {
plugins: [
vueJsx()
]
}
},
alias,
head: [
// 设置 描述 和 关键词
[
"meta",
{ name: "keywords", content: "Vue3 UI 组件库" },
]
],
themeConfig: {
sidebar: {
// 侧边栏
"/": [
{
text: "介绍",
children: [
{ text: "安装", link: "/guide/install" },
{ text: "快速上手", link: "/guide/start" },
],
},
{
text: "组件",
children: [
{ text: "Layout 布局", link: "/components/layout" },
{ text: "Table 表格", link: "/components/table" }
],
},
],
},
nav: [
// 顶部右侧导航栏
{ text: "介绍", link: "/", activeMatch: "^/$|^/guide/" },
{
text: "组件",
link: "/components/layout.html",
activeMatch: "^/$|^/components/"
}
],
// page meta
editLinkText: '在 GitHub 上编辑此页',
lastUpdatedText: '上次更新',
contributorsText: '贡献者',
},
plugins: ['demoblock-plus'] // vuepress-plugin-demoblock-plus 插件,作用是展示交互文档和代码展开
};
.vuepress/clientAppEnhance.ts
В дополнение к настройке config.ts для вступления в силу требуется глобальная регистрация компонентов, а для настройки необходимо добавить clientAppEnhance.ts.
import { defineClientAppEnhance } from '@vuepress/client'
import 'element-plus/theme-chalk/src/index.scss' // 全量引入样式文件 scss TODO: 这里如果用element-plus 文档里的方法 vite-plugin-element-plus 插件按需引入的话,dev 正常但是 vuepress build 打包 scss @import 就会报错
import SumTable from '@sum-ui/table'
import SumLayout from '@sum-ui/layout'
export default defineClientAppEnhance(({ app }) => {
app.component('SumTable', SumTable)
app.component('SumLayout', SumLayout)
})
Предварительный просмотр разработки компонентов
После завершения настройки интерактивной библиотеки документов вы можете разрабатывать библиотеку компонентов, наблюдая за окончательным эффектом компонента.
yarn docs:dev // vuepress 文档库开发模式
yarn docs:build // vuepress 文档库打包成静态资源文件
Упакованные файлы ресурсов могут быть автоматически развернуты на страницах GitHub с помощью действий Github.адрес документов библиотеки компонентов sum-ui
тестирование компонентов
Тесты компонентов помещаются в каталог каждого компонента.После написания компонента модульный тест vue можно написать с помощью @vue/test-utils.Кроме того, когда компоненты импортируются в тесты компонентов, ts и vue не могут быть напрямую идентифицированы. файл, обязательныйts-jest vue-jest babel-jestсделать преобразование
настроить jest.config.js
const alias = require('./alias')
module.exports = {
globals: {
// work around: https://github.com/kulshekhar/ts-jest/issues/748#issuecomment-423528659
'ts-jest': {
diagnostics: {
ignoreCodes: [151001]
}
}
},
testEnvironment: 'jsdom',
transform: {
'^.+\.vue$': 'vue-jest',
'^.+\.(t|j)sx?$': [
'babel-jest',
{
presets: [
[
'@babel/preset-env',
{
targets: {
node: true
}
}
],
[
'@babel/preset-typescript',
{
isTSX: true,
allExtensions: true
}
]
]
}
]
},
moduleNameMapper: alias, // 声明别名以便于在jest中导入文件加载的时候能够正确加载文件
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
// u can change this option to a more specific folder for test single component or util when dev
// for example, ['<rootDir>/packages/input']
roots: ['<rootDir>']
}
vue поддерживает тсх
Предустановка Babel настраивает два параметра: isTSX: true, allExtensions: true, allExtensions — true для поддержки всех расширений, в основном для поддержки разбора файлов .vue, isTSX — true для поддержки разбора синтаксиса jsx.
babel.config.js
module.exports = {
// ATTENTION!!
// Preset ordering is reversed, so `@babel/typescript` will called first
// Do not put `@babel/typescript` before `@babel/env`, otherwise will cause a compile error
// See https://github.com/babel/babel/issues/12066
presets: [
'@vue/cli-plugin-babel/preset',
[
'@babel/typescript',
{
isTSX: true,
allExtensions: true
}
]
],
plugins: ['@babel/transform-runtime']
}
Связанный с цветом темы
Поскольку элемент-плюс используют CSS-переменные могут быть переопределены путем изменения темы Color Priment CSS
main.js
import { themeVarsKey } from 'element-plus'
const themeVars = {
'--el-color-primary': '#29b6b0'
}
const app = createApp(App)
app.provide(themeVarsKey, themeVars)
Другие возможные проблемы
Cannot read property 'isCE' of nullсообщить об ошибкеGitHub.com/v UE JS/v UE-вы…
После того, как я упакую компонент локальноyarn linkДля глобального, а затем столкнуться с этой ошибкой при ссылке в других проектах, это связано с несколькими проблемами со ссылками на пакеты Vue, после публикации в npm нормально устанавливать и ссылаться из npm