⚠️Эта статья является первой подписанной статьей сообщества Nuggets, и её перепечатка без разрешения запрещена.
Привет всем, яЛуожу🎋, деревянный фронтенд, живущий в Ханчжоу 🧚🏻♀️, если вам понравилась моя статья 📚, вы можете помочь мне собрать духовную силу ⭐️ лайком.
Эта статья была впервые опубликована вКолонка самородков, синхронизированный с официальным аккаунтом «Program Life» иБлог Луожу.
У Луо Чжу есть друг Сяо Хэй, которого недавно спросили в интервью, как проектировать библиотеку компонентов интерфейса. Неопытный Xiao Hei отвечал за извлечение и инкапсуляцию бизнеса в библиотеку и вторичную инкапсуляцию бизнеса на основе antd. В конце концов, Сяо Хэй был убит HR из-за недостаточной духовной силы. На самом деле этот вопрос исследует не концепцию ложного и пустого пространства, а об управлении складом разработчика, проектировании компонентов, модульном тестировании, непрерывной интеграции, управлении совместной работой и других возможностях. Поэтому, чтобы дать Xiaohei возможность идеально ответить на этот вопрос, я решил привести Xiaohei к созданию библиотеки компонентов React Native шаг за шагом.
Это практическое руководство по созданию библиотеки компонентов с большим количеством сухих товаров, которое не только охватывает общие спецификации кода, спецификации отправки, обслуживание документов, модульное тестирование и объяснения конфигурации GitHub Action, но также включает в себя управление несколькими пакетами на основе lerna. Архитектура и библиотека иконок React Native Построение, разработка и отладка библиотеки компонентов React Native, принцип и реализация загрузки по требованию. Идея инженерии общая, поэтому независимо от того, какой фреймворк вы используете, эту статью стоит прочитать.
Если вы заинтересованы в разработке библиотеки компонентов перед компьютером, вы можете сначала поставить лайк, а затем продолжить следить за развитием библиотеки компонентов Luozhu и Xiaohei. ПС: сотрудничатьсклада такжеДокументация библиотеки компонентовЛучше прочтите эту статью!
Стоя на плечах Vant Design
Поддержание и развитие библиотеки компонентов, несомненно, требует много времени и энергии. Можно сказать что вначале все сложно.Прежде всего надо иметь самопознание.Ввиду отсутствия дизайнеров и любительской разработки,я выбрал вариант реализации React Native для существующего UI Design для запуска библиотеки компонентов путь развития. под следствиемvant,fishd-mobileа такжеantd-mobileТогда я выбрал вант. Вот сравнение статус-кво нескольких складов:
Библиотека компонентов | команда | Github Star | Еженедельные загрузки NPM | Обслуживание |
---|---|---|---|---|
vant | Понравилось | 17.7K | 27,789 | Большой размер и высокая популярность |
antd-mobile | Ant Design Team | 8.9K | 31,470 | Почти никакого обслуживания, говорят, что муравьи не используются внутри |
fishd-mobile | Интерфейс облачного бизнеса NetEase | 29 | 22 | Похоже на проект KPI без сомнений |
Определено направление движения, которое заключается в том, чтобы дать нашей библиотеке компонентов подходящее имя и слоган, который выражается в образе фронтенд-инженеров.package.json
изname
а такжеdescription
Поле:
// package.json
{
"name": "vant-react-native",
"description": "Lightweight React Native UI Components inspired on Vant"
}
Поскольку наша библиотека компонентов находится в RN версии vant, ссылаясь на метод именования lottie-react-native, styled-react-native и jpush-react-native, мы называем библиотеку компонентов vant-react-native, и так же надеюсь, что библиотека компонентов по доработке будет доступна официальная поддержка от vant.
Многопакетная архитектура управления на основе Lerna
Lerna — это инструмент администрирования для управления проектами JavaScript, которые содержат несколько пакетов. Склады, которыми управляет Lerna, обычно называются монорепо. Преимущества многопакетной архитектуры управления на основе Lerna:
- Разделение на уровне компонентов, независимый контроль версий, и каждый компонент имеет записи версий для отслеживаемости.
- Компоненты выпускаются отдельно, поддерживая оттенки серого, откат версии и плавное обновление и обновление.
- Ссылка по требованию, пользователь устанавливает определенный пакет компонентов, и эффект загрузки по требованию может быть достигнут без настройки.
- Разделение задач, уменьшение масштабной сложности, четкие и контролируемые зависимости между компонентами
- Принцип единой ответственности снижает сложность участия и вклада друзей с открытым исходным кодом.
.
└── packages
├── button # @vant-react-native/button
└── icons # @vant-react-native/icon
Инициализировать проект lerna
$ mkdir vant-react-native && lerna init --independent
yarn workspaces
использоватьyarn workspacesОбъединить ЛернуuseWorkspaces
может быть реализованLerna Hoisting. Это не лишнее, это позволяет управлять зависимостями в едином месте (корневом каталоге), что экономит время и место.
настроитьlerna.json
:
{
...
"npmClient": "yarn",
"useWorkspaces": true
}
После размещения на воркспейсе пряжи, lerna'spackages
будет топpackage.json
изworkspaces
покрытие:
{
"private": true,
...
"workspaces": [
"packages/*"
],
}
lerna publish config
Если ты совсем не хочешь бытьpackage.json
Явно задайте конфигурацию реестра отдельно в файле, например, при использовании частного реестра установитеcommand.publish.registry
Очень полезно. настроитьignoreChanges
Это сделано для того, чтобы избежать ненужных обновлений версии.
"ignoreChanges": [
"ignored-file",
"**/__tests__/**",
"**/*.md"
],
"command": {
"publish": {
"registry": "https://registry.npmjs.org"
}
}
Кроме того, если имя вашего пакета ограничено, оно должно быть в этом пакете.
package.json
установить вpublishConfig.access
для"public"
.
lerna version config
При настройкеconventionalCommits
дляtrue
, версия lerna будет использоватьConventional Commits Specificationдля подтверждения обновления версии иСоздайте файл CHANGELOG.md.
"command": {
"version": {
"conventionalCommits": true,
"message": "chore(release): publish"
}
}
канонический коммит
нормализоватьgit commit
для улучшенияgit log
Удобочитаемость, контролируемый контроль версий и генерация журнала изменений играют важную роль. Луожу был вОдна статья, чтобы получить нормализованный Git CommitКонцепция обычных коммитов и настройка таких инструментов, как commitizen, cz-customizable, @commitlint/cli, yorkie и commitlint-config-cz, подробно описаны в .
Из-за громоздкой конфигурации я@youngjuning/cliдобавлено вinit-commit
Команда настраивает обычную фиксацию одним щелчком мыши. могу открыть этоcommitПросмотр информации о конфигурации.
Примечание: использование версии Husky High не имеет обратной совместимости, я в этомcommitЗаменил хаски на йорка.
нормализация кода
Важность нормализации кода очевидна.Инструменты, используемые для нормализации кода, включают editorconfig, eslint, prettier и т. д.Установите его | Никогда больше не беспокойтесь о конфигурации ESLintВ этой статье я рассказал, как шаг за шагом создать свой собственный плагин конфигурации eslint и вывести@youngjuning/eslint-configа также@youngjuning/prettier-config.
vant-react-native временно использует @youngjuning/eslint-config, @youngjuning/prettier-config для ограничения спецификаций кода проекта. Соответствующая конфигурация выглядит следующим образом.
eslint
Сначала установите плагины, необходимые для react-native.
yarn add -D eslint-plugin-react \
eslint-plugin-react-hooks \
eslint-plugin-jsx-a11y \
eslint-plugin-import \
eslint-plugin-react-native
затем настройте.eslintrc.js
// .eslintrc.js
module.exports = {
extends: ['@youngjuning/eslint-config/react-native']
}
prettier
// .prettierrc.js
module.exports = require('@youngjuning/prettier-config');
План @youngjuning/eslint-config также управляется lerna, которая создает @youngjuning/eslint-config-react, @youngjuning/eslint-config-react-native, @youngjuning/eslint-config-vue, чтобы разработчики не слишком много нужно настраивать.из коробки.
editorconfig
# .editorconfig
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[*.gradle]
indent_size = 4
[BUCK]
indent_size = 4
yorkie & lint-staged
$ yarn add -D yorkie lint-staged
{
"gitHooks": {
"commit-msg": "commitlint -e -V",
"pre-commit": "lint-staged"
},
"lint-staged": {
"**/*.{js,jsx,ts,tsx}": [
"eslint --fix",
"git add ."
]
},
}
Первый компонент начинается с Icon
Библиотека зрелых компонентов будет иметь свой собственный набор иконок.Иконки обычно создаются дизайнерами через Sketch, а затем экспортируются в виде файлов svg.
Файл svg для значков ant-design:сохранить локально, который затем генерируется скриптомреактивный компонент,vue-компонента такжеicons-react-nativeи другие компоненты, т.к. поддерживаемый фреймворк относительно полный, нам не нужно реализовывать его самим, мы используем RN напрямуюicons-react-native.
vant и fishd-mobile поддерживают файлы svg через Iconfont, а затем устанавливают@font-face
способ реализации компонента Icon, как показано на рисунке:
С файлом ttf мы можем использовать скрипт для создания компонента Icon на основе файла ttf, такого как @ant-design/icons-react-native, но использование шрифта ttf имеет недостаток, то есть каждый раз, когда значок обновляется, файл ttf должен быть обновлен соответствующим образом.Затем снова упаковать и выпустить приложение. И ttf не поддерживает значки нескольких цветов, в результате чего все значки становятся монохромными. Если вы используете react-native-vector-icons, в библиотеку встроено более 10 наборов файлов ttf, которые вместе составляют около 2M; вы можете их не использовать, но они все равно будут упакованы в ваше приложение, что также me Одна из причин, почему я считаю, что react-native-elements — сильная библиотека.
Итак, как нам реализовать React Native версию vant-icons только со ссылками на Iconfont? Здесь Луожу не писал свой собственный скрипт, а использовал инструмент под названием react-native-iconfont-cli.fwh1990Для решения вышеуказанных проблем большой парень использует чистый Javascript для реализации преобразования iconfont в компоненты React, не полагаясь на файлы шрифтов ttf и не загружая значки вручную на локальный сервер.
Создайте подпакет lerna
# 创建主包,主包用来统一导出所有的组件
$ lerna create vant-react-native -y
# 创建 icons 包,我们的第一个组件!
$ lerna create @vant-react-native/icons -y
Наша структура каталогов выглядит так:
.
└── packages
├── icons
│ ├── README.md
│ └── package.json
└── vant-react-native
├── README.md
└── package.json
генерировать иконки
Установить плагин
yarn workspace @vant-react-native/icons add -D react-native-svg react-native-iconfont-cli
Создать файл конфигурации
мы вpackages/icons
использовать в каталогеnpx iconfont-init
команда будет генерироватьiconfont.json
файл, содержимое после настройки выглядит следующим образом:
{
"symbol_url": "https://at.alicdn.com/t/font_2553510_7cds497uxwn.js",
"use_typescript": false,
"save_dir": "./lib",
"trim_icon_prefix": "van-icon",
"default_icon_size": 18
}
Создание стандартных компонентов React Native
воплощать в жизньnpx iconfont-rn
команда для создания стандартных компонентов React Native. Из-за большого количества файлов значков мы не добавляем продукты значков в управление git. Поэтому нам нужно выполнить команду сборки перед публикацией npm:
{
"build": "npx iconfont-rn",
"prepublishOnly": "yarn build"
}
Настроить реактивный натив-вант
мы упоминали ранееpackages/vant-react-native
это каталог основного пакета, нам нужно поместить@vant-react-native/icons
Пакет добавляется в зависимости основного пакета и экспортируется.
добавить зависимости
$ lerna add @vant-react-native/icons --scope vant-react-native
Компонент «Экспорт значка»
// packages/vant-react-native/src/index.ts
export { default as Icon } from '@vant-react-native/icons';
export * from '@vant-react-native/icons';
конфигурация tsconfig
Мы ожидаем одинаковую конфигурацию для каждого подпакета, поэтому сначала создадим новый в корневом каталоге всего проекта.tsconfig. base.json, вы можете наследовать его в подпакете.
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "lib",
},
"include": ["src/**/*"]
}
Настройте сценарий публикации
а также@vant-react-native/icons
Как и подпакеты, нам нужно добавитьbuild
а такжеprepublishOnly
сценарий:
{
"build": "tsc",
"prepublishOnly": "yarn build"
}
выпуск пакета
Для первого выпуска обратите внимание на использованиеlerna publish 0.0.1
, т.к. команда выпуска lerna не освобождает этот параметр в первый раз, необходимо явно указать начальную версию. Или первоначальная версия может быть установлена на0.0.0
затем выполнитьlerna publish
.
Совет: Если вы хотите просмотреть содержимое пакета после публикации, вы можете пройти черезjsdelivrПроверить. например, только что выпущенныйvant-react-nativeа также@vant-react-native/icons
Разработка и отладка
Полный и проверенный процесс отладки может не только обеспечить проверку того, соответствуют ли компоненты ожиданиям на этапе разработки, но и уменьшить сложность участия членов сообщества открытого исходного кода. Отладка библиотеки компонентов React Native в основном такая же, как и другие процессы стека технологий, но посколькуMetro не поддерживает программные ссылкиА vant-react-native — это единый складской проект на базе lerna, наша конфигурация будет другой.
Инициализировать приложение React Native
Поскольку это проект React Native, нам нужно инициализировать проект React Native. Сначала найдите место для использованияreact-native init vantapp --template react-native-template-typescript
Создайте новое приложение React Native. Затем объедините получившееся приложение с нашим основным проектом. Общая структура проекта выглядит следующим образом:
.
├── App.tsx
├── __tests__
│ └── App-test.tsx
├── android
│ ├── app
│ ├── build.gradle
│ ├── gradle
│ ├── gradle.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── settings.gradle
├── app.json
├── babel.config.js
├── commitlint.config.js
├── index.js
├── ios
│ ├── Podfile
│ ├── Podfile.lock
│ ├── Pods
│ ├── vantapp
│ ├── vantapp.xcodeproj
│ ├── vantapp.xcworkspace
│ └── vantappTests
├── lerna.json
├── metro.config.js
├── package.json
├── packages
│ ├── icons
│ └── vant-react-native
├── tsconfig.base.json
├── tsconfig.json
└── yarn.lock
Основной конфликт заключается в настройке таких инструментов, как Prettier и eslint, слияние не так уж и сложно. Перед запуском проекта нам обычно нужно скомпилировать проект. мы можем использоватьlerna run build
Пакет команд запускает подпакеты вbuild
нпм скрипты.
Примечание 📢: из-за зависимостей между подпакетами не используйте
--parallel
параметр для параллельного выполнения сценария упаковки.
Теперь давайте напишем демонстрацию Jiugongge для проверки:
// App.tsx
import React, { Component } from 'react';
import { View, Text, SafeAreaView, ScrollView } from 'react-native';
import { Icon } from 'vant-react-native';
// 我们也可以只安装 @vant-react-native/icons 包
// import { VanIconAdd } from '@vant-react-native/icons'
type IconNameType = React.ComponentProps<typeof Icon>['name'];
export default class App extends Component {
render() {
return (
<SafeAreaView>
<ScrollView>
<Text
style={{ textAlign: 'center', paddingVertical: 20, fontSize: 25, color: '#007fff' }}
>
vant-react-native
</Text>
<View style={{ flexWrap: 'wrap', flexDirection: 'row' }}>
{data.map((item, index) => {
const lastLineLength = data.length % 4 || 4;
return (
<View
key={item}
style={{
width: '25%',
marginBottom: index < data.length - lastLineLength ? 40 : 0,
alignItems: 'center',
}}
>
<Icon name={item} size={40} />
<Text style={{ color: '#646566', marginTop: 10 }}>{item}</Text>
</View>
);
})}
</View>
</ScrollView>
</SafeAreaView>
);
}
}
const data: IconNameType[] = ['location-o', 'like-o', 'star-o', 'phone-o', 'setting-o', 'fire-o', 'coupon-o', 'cart-o', 'shopping-cart-o', 'cart-circle-o', 'friends-o', 'comment-o', 'gem-o', 'gift-o', 'point-gift-o', 'send-gift-o', 'service-o', 'bag-o', 'todo-list-o', 'balance-list-o', 'close', 'clock-o', 'question-o', 'passed'];
затем выполнитьyarn ios
Посмотрите его в действии (затем мы можем выполнитьyarn start --reset-cache
Быстрый старт отладки):
В приведенном выше примере кода мы видим, что мы напрямую используемimport { Icon } from 'vant-react-native';
Вместо относительных путей ссылайтесь на модули в пакетах. Но наш проект не установил эту зависимость, как компилятор ее нашел? Здесь также нет серебряной пули, потому что lerna будет программно связывать подпакеты в node_modules, мы можем использоватьls -al
Найдено, чтобы увидеть фактическую точку пакета:
Мы также можем видеть в подсказке типа, что она на самом деле указывает на файлы в пакетах:
Примечание 📢:Metro не поддерживает символические ссылкиЭто означает, что каталог мягкой ссылки не находится в корневом каталоге проекта.Здесь место, на которое указывает наша мягкая ссылка, все еще находится в корневом каталоге, поэтому оно может работать правильно ✅. Эта функция обеспечивает согласованность и простоту отладки и разработки продукции.
Своевременная компиляция
Теперь наш поток отладки:
- Изменить код
- воплощать в жизнь
lerna run build
Скомпилируйте каждый подпакет - воплощать в жизнь
yarn ios
Отладка проекта - Изменить код
- воплощать в жизнь
lerna run build
перекомпилировать - воплощать в жизнь
yarn start --reset-cache
запустить проект - Петля 4, 5, 6.
Хотя React Native имеет функцию быстрого обновления, поскольку наш код необходимо скомпилировать, нам нужно повторить действие компиляции и запуска.
Любую повторяющуюся работу можно заменить скриптами. Прежде всего, нам нужно добавить скрипты, компилируемые в реальном времени, в каждый подпакет, такие как rollup, babel, webpack и typescript, имеющие параметры для достижения компиляции в реальном времени:
{
"scripts": {
"dev": "tsc -w",
"build": "tsc",
"prepublishOnly": "yarn build"
},
}
И наш пакет @vant-react-native/icons используетnpx iconfont
Варианта компиляции в реальном времени нет.После исследований я представилonchangeЭта библиотека может выполнять команду на основе шаблона глобуса, прослушивая изменения файла:
{
"scripts": {
"dev": "onchange -i 'iconfont.json' -- yarn build",
}
}
Затем нам нужно использоватьlerna run dev --parallel
Пакетное выполнение сценариев компиляции в реальном времени, добавьте сюда--parallel
Это потому, что если подпакет скомпилирован в реальном времени, процесс зависнет. Чтобы исправить это, нам пришлось предварительно скомпилировать@vant-react-native/icons
package, то по той же причине я ввелnpm-run-all
выполнять параллельноlerna run dev
а такжеreact-native start
, полный скрипт выглядит следующим образом:
{
"predev": "lerna run build --scope @vant-react-native/icons",
"dev": "lerna run dev --parallel",
"start": "react-native start",
"debug": "run-p dev start",
}
нагрузка по требованию
Сяо Хей: «Брат Луожу, я представил всю библиотеку компонентов, чтобы использовать несколько компонентов react-native-elements. Поскольку эта библиотека компонентов зависит от react-native-vector-icons, пакет пакета становится больше. Если я просто хотите использовать весь набор vant-react-native, как решить эту проблему?»
Как мы все знаем, инструмент упаковки React Native Metroвстряхивание дерева не поддерживается. Способ решить эту проблему на самом деле очень прост, вы можете знать, как сотрудничатьbabel-plugin-importМожно выполнить требования по загрузке по требованию. Но поскольку у нас многопакетная архитектура управления, нам нужно разработать решение для многопакетной архитектуры.
реактивный пакет
Чтобы сравнить размер пакета до и после оптимизации, нам нужно использоватьreact-native bundle
Команда, чтобы увидеть размер чистого пакета JS, давайте кратко рассмотрим эту команду:
react-native bundle --platform ios --entry-file index.js --bundle-output ./bundle/ios/index.ios.jsbundle --assets-dest ./bundle/ios --dev false --reset-cache
-
--entry
: входной файл js -
--bundle-output
: Путь к сгенерированному файлу пакета -
--platform
:Платформа -
--assets-dest
: Выходной каталог для ресурсов изображения -
--dev
: Является ли это версией разработки или нет, мы присваиваем ей значение false при печати официальной версии установочного пакета. -
--reset-cache
: сброс кеша, избегайте упаковки старого кеша
Принцип загрузки по требованию
Ранее мы упоминалиpackages/vant-react-native
только один файлsrc/index.ts
Используется для экспорта всех подпакетов, теперь мы добавляем новую кнопку пакета, которая выглядит так:
export { default as Icon } from '@vant-react-native/icons';
export * from '@vant-react-native/icons';
export { default as Button } from '@vant-react-native/icons';
При таком способе экспорта пользователи могут толькоimport Button from '@vant-react-native/button';
илиimport Button from 'vant-react-native/lib/button';
Способ ручной реализации загрузки по требованию не только неудобен для использования разработчиками, но и добавляет много байтов от упаковки продукта. Итак, вопрос в том, какая организационная форма может удовлетворить нагрузку по требованию? Ответ находится в документации плагина babel-plugin-import:
Из рисунка видно, что плагин babel-plugin-import указывает ссылку на папку, в которой находится модуль, на этапе компиляции. Когда пользователи используют его, установите подключаемый модуль и выполните следующую настройку, чтобы завершить загрузку по требованию.
"plugins": [
["import", { libraryName: "antd", style: true }]
]
Серебряной пули по-прежнему нет, плагин работает как раз на месте вашей правой руки. Зная принцип, мы можем реорганизовать наш пакет vant-react-native в формате, требуемом документацией:
.
├── CHANGELOG.md
├── lib # 上传到 NPM 的编译产物
│ ├── button # 符合 babel-plugin-import 的默认配置要求
│ │ ├── index.d.ts
│ │ └── index.js
│ ├── icon
│ │ ├── index.d.ts
│ │ └── index.js
│ ├── index.d.ts
│ └── index.js # export * from './button';
├── package.json
├── src # 源码目录
│ ├── button
│ │ └── index.ts
│ ├── icon
│ │ └── index.ts
│ └── index.ts
└── tsconfig.json # 编译配置,将 ts 文件编译到 lib 文件夹下
вант-реагировать-родной/src/кнопка/index.ts:
import Button from '@vant-react-native/button';
export default Button;
export { Button };
вант-реагировать-родной/src/icon/index.ts:
import Icon from '@vant-react-native/icons';
export default Icon;
export { Icon };
export * from '@vant-react-native/icons';
вант-реагировать-родной/src/index.ts:
export * from './icon';
export * from './button';
Затем измените babel.config.js в проекте:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
["import", {libraryName: 'vant-react-native'}]
],
};
Пишете плагин для Babel?
Хотя требования можно выполнить, изменив метод экспорта основного пакета, это значительно увеличивает сложность самого проекта. Мы уже знаем, что принцип babel-plugin-import заключается в преобразовании эталонного пути. Так можем ли мы динамически поставить его через плагин?import {Button} from 'vant-react-native'
Превратиться вimport Button from '@vant-react-native/button'
Шерстяная ткань? Ответ да, вот что у меня есть на основе babel-plugin-importcustomName
Configuration записывает набор конфигураций и инкапсулирует их в пакет babel-plugin-import-vant:
import camelCase from 'camelcase';
export default (): any[] => [
[
'import',
{
libraryName: 'vant-react-native',
customName: (name: string) => {
if (name === 'icon') {
return '@vant-react-native/icons';
}
if (name.match(/^van-icon-/)) {
return `@vant-react-native/icons/lib/${camelCase(name, { pascalCase: true })}`;
}
return `@vant-react-native/${name}`;
},
},
'vant-react-native',
],
[
'import',
{
libraryName: '@vant-react-native/icons',
customName: (name: string) => {
return `@vant-react-native/icons/lib/${camelCase(name, { pascalCase: true })}`;
},
},
'@vant-react-native/icons',
],
];
в проектеbabel.config.js
добавить в конфигурациюplugins: [...require('babel-plugin-import-vant').default()]
Его можно загрузить по запросу.
Есть ли что-то еще, что можно оптимизировать? Вы можете обнаружить, что я только что экспортировал конфигурацию через функцию, а не настоящий плагин, поэтому в будущем я настрою собственный плагин загрузки Babel по требованию vant-react-native.
name.match(/^van-icon-/)
Это условие суждения связано с тем, что@vant-react-native/icons
В дополнение к экспортируемому по умолчанию компоненту значка пакет также экспортирует множество отдельных компонентов значка.Чтобы еще больше уменьшить размер пакета, мы также загружаем этот подпакет по запросу.Мы уже знаем, что принцип загрузки по требованию заключается в том, что нет посредника, который зарабатывает разницу и напрямую общается с продавцом., поэтому мы можем вернуться к адресу продавца, конвертировав его, когда мы столкнемся с аналогичными потребностями позже. Никаких деструктивных изменений в структуре проекта не требуется.
Дисплей достижений
начальный размер пакета | Загрузка по запросу не настроена (представляем кнопку) | Загрузка по требованию (представляем кнопку) | Загрузка по запросу (представить Icon) | Загрузка по требованию (представляем VanIconAdd) |
---|---|---|---|---|
723KB | 1.8M | 725KB | 1.8M | 1.22M |
Причина, по которой пакет Icon большой, заключается в том, что библиотека react-native-svg велика, поэтому не рекомендуется использовать компонент Icon напрямую, а использовать отдельный компонент значка, такой как VanIconAdd и VanIconEye, который довольно ароматен без 593 КБ.
Документация библиотеки компонентов
Самое важное в документации библиотеки компонентов — это интерактивная демонстрация.Я старший пользователь Dumi.С помощью dumi-theme-mobile иumi-plugin-react-nativeМы вполне можем встретить построение документации библиотеки компонентов React Native.
Интегрировать Думи в проект
Установите зависимости:
$ yarn add dumi dumi-theme-mobile umi-plugin-react-native -D
Конфигурационный файл:
Добавьте в корневой каталог проекта.umirc.ts
import { defineConfig, IConfig } from 'dumi';
export default defineConfig({
title: 'vant-react-native',
mode: 'site',
logo: 'https://img01.yzcdn.cn/vant/logo.png',
favicon: 'https://img01.yzcdn.cn/vant/logo.png',
resolve: {
includes: ['docs', 'packages/button', 'packages/icons'],
},
// more config: https://d.umijs.org/config
} as IConfig);
Стоит отметить, что Dumi поддерживает репозиторий Lerna и по умолчаниюpackages/[包名]/src
Ищет базовый путь в документации Markdown всех подпакетов и создает маршрут. пройти черезresolve.includes
Каталог документов, который нюхает dumi, можно настроить, и dumi попытается рекурсивно найти файлы уценки в настроенном каталоге.
Добавьте npm-скрипт:
Примечание 📢: поскольку фактическими зависимостями являются пакеты в пакетах, мы должны сначала скомпилировать все пакеты, иначе развертывание сообщит
This dependency was not found:
ошибка.
{
"scripts": {
"start:dumi": "dumi dev",
"build:dumi": "lerna run build && dumi build"
}
}
Игнорировать файлы (.gitignore):
# umi
.umi
.umi-production
.env.local
dist/
Развертывание на страницах GitHub
Новое в корневом каталоге.github/workflows/gh-pages
:
name: github pages
on:
push:
branches:
- main # default branch
jobs:
deploy:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- run: yarn install
- run: yarn build:dumi
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
предварительный просмотр
Теперь мы можем получить доступЭто гигантский Нин, это .org/van T-react-…Оцените эффект:
Оптимизация конфигурации
Сейчас сайт документации на базе думи только инициализирован, многие конфигурации (.umirc.ts) можно оптимизировать, например:
- Настроить ускорение CDN на основе jsdeliver
const isProd = process.env.NODE_ENV === 'production';
...
publicPath: isProd ? 'https://cdn.jsdelivr.net/gh/youngjuning/vant-react-native@gh-pages/': '/',
- Добавочная публикация и предотвращение кэширования загрузки в браузере
{
hash: true
}
{
scripts: ['https://s9.cnzz.com/z_stat.php?id=1280093214&web_id=1280093214'],
styles: ['a[title=站长统计] { display: none; }'],
}
- настроить
exportStatic: {}
Выведите все маршруты в виде структуры каталогов HTML, чтобы избежать ошибки 404 при обновлении страницы.
Предварительная версия запроса на вытягивание
Учитывая, что сообщество внесет код и документацию позже. Прежде чем pr будет объединен с основной веткой, нам нужно предварительно просмотреть документ или компонент. Удовлетворением этой потребности является статическая служба хостинга под названием surf.sh. Surge поддерживает бесплатную публикацию файлов HTML, CSS и JS в Интернете с помощью простых команд из командной строки.
Подать заявку на Surge Token
Установите всплеск-cli:
npm install --global surge
Зарегистрируйтесь для увеличения учетной записи:
suerge login
Получить токен:
suerge token
Настроить ЭК
Из-за проблем с безопасностью GitHub нельзя использовать подключаемый модуль действия для предварительного просмотра.Мы настроили CI, сославшись на официальную конфигурацию dumi.Сначала мы скопировали три файла на рисунке ниже в проект.
затем изменитьpreview-build.yml
серединаbuild step
:
- NODE_OPTIONS='--max-old-space-size=4096' yarn build
+ NODE_OPTIONS='--max-old-space-size=4096' PREVIEW_PR=true yarn build:dumi
добавить переменную окруженияPREVIEW_PR=true
Это сделано для того, чтобы dumi распознал, что он не упакован в производственной среде, когда он упакован..umirc.ts
Его необходимо соответствующим образом изменить, чтобы:
const isProd =
process.env.NODE_ENV === 'production' && process.env.PREVIEW_PR !== "true";
...
publicPath: isProd ? 'https://cdn.jsdelivr.net/gh/youngjuning/vant-react-native@gh-pages/': '/',
...
Затем изменитеpreview-deploy.yml
Имя домена развертывания в файлеdumi-preview
дляvant-react-native-preview
.
Наконец, мы можем добавить Surge Token, полученный ранее, к Секретам склада.
Дисплей достижений
Статус предварительного просмотра развертывания PR:
Статус успешного развертывания:
доступvant-react-native-preview-pr-1.surge.sh/Вы можете проверить правильность документа ✅.
модульный тест
я здесьМодульное тестирование React Native с помощью Jest и Enzyme | Технический обзорМодульный тест, представленный в этой статье, как и документация, является важной частью обеспечения качества наименьшего модуля программы. Это правда, что зрелая библиотека компонентов обязательно должна иметь модульные тесты. В этой главе речь пойдет не о модульном тестировании, а в основном о том, как vant-react-native настраивает модульное тестирование.
Установить зависимости
Зависимости jest, babel-jest и @types/jest были установлены.Что нам нужно установить, так это энзим, фреймворк модульного тестирования, основанный на jest.
$ yarn add enzyme jest-enzyme enzyme-adapter-react-16 enzyme-to-json @types/enzyme react-native-mock-render -DW
Enzyme — это утилита для тестирования JavaScript для React, которая упрощает тестирование вывода компонентов React. Вы также можете воздействовать на заданный вывод, перебирать и каким-то образом имитировать среду выполнения.
настроить
jest.config.js:
module.exports = {
preset: 'react-native',
verbose: true,
collectCoverage: true, // 生成测试覆盖率报告
moduleNameMapper: {
// for https://github.com/facebook/jest/issues/919
'^image![a-zA-Z0-9$_-]+$': 'GlobalImageStub',
'^[@./a-zA-Z0-9$_-]+\\.(png|gif)$': 'RelativeImageStub',
},
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'], // 使用 Jest 运行安装文件以配置 Enzyme 和适配器(如下文jest.setup.js中所示),之前是setupTestFrameworkScriptFile,也可以使用setupFiles
snapshotSerializers: ['enzyme-to-json/serializer'], // 推荐使用序列化程序使用 enzyme-to-json,它的安装和使用非常简单,并允许您编写简洁的快照测试。
};
jest.setup.js:
import 'react-native';
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });
Простой пример:
// packages/button/__test__/index.tsx
import React from 'react';
import { shallow } from 'enzyme';
import Button from '../src/index';
function setup(props = {}) {
const wrapper = shallow(<Button />);
const instance = wrapper.instance();
return { wrapper, instance };
}
describe('Button Component', () => {
it('renders correctly', () => {
const { wrapper } = setup();
expect(wrapper).toMatchSnapshot();
});
});
воплощать в жизньjest
После команды можно просмотреть покрытие следующим образом:
написать воинам
Те, кто может писать длинные эссе, — не воины, те, кто может настойчиво видеть здесь, — воины. Луо Чжу хотел бы поблагодарить вас за чтение. Однако разработка библиотеки компонентов — это только отправная точка.Если отзывы на эту статью будут положительными, Луожу расскажет о разработке и реализации конкретных компонентов библиотеки компонентов, о полном руководстве по модульному тестированию React Native и т. д. в последующих статьях.
Рекомендуемые библиотеки пользовательского интерфейса
Конечно, vant-react-native — не единственный ваш выбор.Следующие UI-библиотеки — отличные проекты. При реализации vant-react-native я также позаимствовал некоторые превосходные разработки своих предшественников.