Введение
что заставляет меня готовитьсяCreate React App[1](далее именуемый CRA) для разработки библиотеки компонентов пользовательского интерфейса? Поскольку команда выбрала Vue в качестве основного стека технологий, они привыкли к официальному стандартномуVue-CLIОчень удобно настроить производственную среду, необходимую для сборки библиотеки компонентов, например, этот набор, который мы используем внутри.wooui-pro, На основе конфигурации соглашения CLI компоненты, соответствующие стандартам группы, создаются быстро. Итак, используя CRA, официально предоставленный React, можем ли мы быстро создать стандартизированную библиотеку компонентов? Начал путешествие с вопросов.
Цель
Я резюмировал руководство по настройке среды с использованием стека технологий Vue, если вам интересно, вы можете ткнуть 👉здесь
Наша основная цель — настроить библиотеку компонентов пользовательского интерфейса React на основе CRA с интерфейсом, подобным Vue-CLI.
нужно
Теперь, когда мы поставили цель, мы должны уточнить наши потребности для достижения этой цели (да, каждый является менеджером продукта, 🐶 спасает жизни)
- CRA в качестве базовых строительных лесов, а не извлекаемый
- использоватьCSS ModulesУправление именами классов CSS
- Настраиваемыйpostcssпредварительно скомпилированный плагин
- Настройте инструменты проверки кода, чтобы обеспечить стандартизацию кода
- Примеры и документация компонентов быстрого генерации
- Пакет библиотеки может быть собран для публикации
Основываясь на этих требованиях, мы будем решать проблемы, возникающие при выполнении этих требований, одну за другой.
Начинать
Инициализация проекта CRA
Первое, что нужно сделать, это использовать CRA для создания проекта, и одна строка кода завершает инициализацию проекта.
npx create-react-app my-app
Структура файла проекта выглядит следующим образом, что довольно лаконично, и я даже подозреваю, что зашел не в ту директорию...
my-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
└── src
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
└── serviceWorker.js
Создайте приложение React, как следует из названия, для создания приложения React, полностью стандартизированного каркаса.
Итак, попробуйте ввести CSS-модули, согласно документации
Button.module.css
.error {
background-color: red;
}
Button.js
import React, { Component } from 'react';
import styles from './Button.module.css'; // Import css modules
class Button extends Component {
render() {
// reference as a js object
return <button className={styles.error}>Error Button</button>;
}
}
результат
<button class="Button_error_ax7yz">Error Button</button>
Button_error_ax7yzчерный вопросительный знак.jpg! Терпеть не могу имя класса CSS библиотеки компонентов с md5. После долгого поиска документации я обнаружил, что вам негде менять правила именования модулей CSS. Так что, если вы хотите изменить это правило? Те, кто знает, могут знать, что CSS-модулиcss-loaderОбеспечьте поддержку, так что теперь вам нужно не извлекать CRA, а также изменять элементы конфигурации css-loader.Есть ли какая-то хитрость?
React App Rewired Rewired Настройка Webpack
В соответствии с целью использовать то, что уже доступно, не делайте это сами🤦, Google здесьReact App RewiredЭтот артефакт, но и китайское объяснение:
Этот инструмент может изменить встроенную конфигурацию веб-пакета create-реагировать-приложение без «извлечения» и создания дополнительных реагирующих сценариев, тогда у вас будут все функции создания-реагирования-приложения, и вы сможете настроить его в соответствии с вашими потребностями. плагины, загрузчики и т.д.
Это именно то, что нам нужно, полагаясь на них для изменения конфигурации css-loader.
Установить приложение-реакция, перемонтированное
yarn add react-app-rewired --dev
Создайте файл config-overrides.js в корневом каталоге проекта.
/* config-overrides.js */
module.exports = {
webpack: function(config, env) {
// 这里修改config
// react-app-rewired拦截后修改配置,然后按照配置进行脚本构建
return config;
}
}
Измените директивы сценария в package.json.
/* package.json */
"scripts": {
- "start": "react-scripts start",
+ "start": "react-app-rewired start",
}
Изменить конфигурацию css-загрузчика
Найдите документы, перемонтированные в приложении, и найденные модули CSS, имеющие соответствующий загрузчик:
Однако кажется, что эти два расширения загрузчика не подходят для текущей версии CRA (текущая версия CRA уже поддерживает модули CSS, мой призыв изменить конфигурацию).
Тем не менее, мы можем извлечь уроки из кода.Изучая код, мы также можем увидеть, как выглядит конфигурация веб-пакета наших угнанных реактивных скриптов.Файл находится вnode_modules/react-scripts/config/webpack.config.js
.
- Создайте новый каталог scripts в корневом каталоге проекта для хранения скрипта cssModuleConfig.js для изменения модулей CSS и вставьте исходный код напрямую:
/* scripts/cssModuleConfig.js */
const path = require('path');
const ruleChildren = loader =>
loader.use || loader.oneOf || (Array.isArray(loader.loader) && loader.loader) || [];
const findIndexAndRules = (rulesSource, ruleMatcher) => {
let result = undefined;
const rules = Array.isArray(rulesSource) ? rulesSource : ruleChildren(rulesSource);
rules.some(
(rule, index) =>
(result = ruleMatcher(rule)
? { index, rules }
: findIndexAndRules(ruleChildren(rule), ruleMatcher))
);
return result;
};
const findRule = (rulesSource, ruleMatcher) => {
const { index, rules } = findIndexAndRules(rulesSource, ruleMatcher);
return rules[index];
};
const cssRuleMatcher = rule =>
rule.test && String(rule.test) === String(/\.module\.css$/);
const sassRuleMatcher = rule =>
rule.test && String(rule.test) === String(/\.module\.(scss|sass)$/);
const createLoaderMatcher = loader => rule =>
rule.loader && rule.loader.indexOf(`${path.sep}${loader}${path.sep}`) !== -1;
const cssLoaderMatcher = createLoaderMatcher('css-loader');
const sassLoaderMatcher = createLoaderMatcher('sass-loader');
module.exports = function(config, env, options) {
const cssRule = findRule(config.module.rules, cssRuleMatcher);
let cssModulesRuleCssLoader = findRule(cssRule, cssLoaderMatcher);
const sassRule = findRule(config.module.rules, sassRuleMatcher);
let sassModulesRuleCssLoader = findRule(sassRule, sassLoaderMatcher);
cssModulesRuleCssLoader.options = { ...cssModulesRuleCssLoader.options, ...options };
sassModulesRuleCssLoader.options = { ...sassModulesRuleCssLoader.options, ...options };
return config;
};
Такой фрагмент кода на самом деле должен найти соответствующий загрузчик, а затем изменить свойство options внутри.
- Измените конфигурацию модулей CSS в config-overrides.js:
/* config-overrides.js */
const cssModuleConfig = require('./scripts/cssModuleConfig');
const loaderUtils = require('loader-utils');
module.exports = {
webpack: function(config, env) {
// 配置className按照namespace-folderName-localName的形式输出
config = cssModuleConfig(config, env, {
modules: {
getLocalIdent: (context, localIdentName, localName, options) => {
const folderName = loaderUtils.interpolateName(context, '[folder]', options);
const className =
process.env.LIB_NAMESPACE + '-' + folderName + '-' + localName;
return className.toLowerCase();
}
}
});
return config;
}
};
Принятие результатов
Button.module.css
.main {
border: 1px solid;
}
Button.js
import styles from './Button.module.css'; // Import css modules
<button className={styles.main}>Button</button>
результат
<button class="woo-button-main">Button</button>
Первый шаг — выразить это! Следующим шагом должно быть построение каждого компонента.Компонентов много, и необходимо их вывести по одному и перечислить.Если выполнять пошагово, то это будет потреблять много энергии. Есть ли способ упростить этот процесс? Вот еще артефакт:
Пример компонента, сгенерированного React Styleguidist
🐙Стилист ReactЭто может помочь нам легко решить такие проблемы, как автоматическая генерация свойств, отображение состояния компонентов, документация и т. д., чтобы мы могли полностью сосредоточиться на разработке компонентов.
Установите реагирующий стиль-руководитель
yarn add react-styleguidist --dev
каталог src для установки каталога компонентов
...
└── src
├── components
├── Button
├── Button.module.css //CSS
├── index.js //Button组件入口
├── Readme.md //示例说明
...
Измените инструкции в package.json.
/* package.json */
"scripts": {
- "start": "react-app-rewired start",
+ "start": "styleguidist server",
}
🚀 Запустить
запуск из командной строкиyarn start
, жду когда произойдет "чудо"...
(Результат работы основан на том, что компонент Button был написанчасть кода)
Живописный~ Нет, подождите, почему правило имени класса, которое я только что настроил, изменилось обратно при проверке элемента? Тщательно обдумав это, я обнаружил, что конфигурация веб-пакета, загруженная Styleguidist, предоставляется CRA, так что мне делать? Мы должны придумать, как заставить Styleguidist вызывать Rewired работать, так чтоreact-app-rewired start
все, что произойдет, будетstyleguidist server
случиться на. Могу я? Конечно!
Настроить StyleGuidist
Создав новый файл styleguide.config.js, вызовите конфигурацию react-app-rewired
/* styleguide.config.js */
const { paths } = require('react-app-rewired');
const overrides = require('react-app-rewired/config-overrides');
const config = require(paths.scriptVersion + '/config/webpack.config');
module.exports = {
webpackConfig: overrides.webpack(config(process.env.NODE_ENV), process.env.NODE_ENV)
};
🚀 запустить снова
запуск из командной строкиyarn start
, польщена конфигурация модулей CSS, чтобы она вступила в силу.
настроить postcss
Последние два года я использую postcss, инструмент для прекомпиляции CSS. С одной стороны, postcss ориентирован на будущие стандарты CSS, а с другой стороны, плагины можно устанавливать по мере необходимости, что намного быстрее, чем установка node-sass за один раз. Существует N способов настройки файлов postcss, обычно создается новый в корневом каталоге проекта.postcss.config.js
,postcss-loaderПрочитайте конфигурацию и завершите процесс компиляции в порядке плагинов. Итак, настройтеpostcss-pxtorem.
postcss.config.js
/* postcss.config.js */
module.exports = {
plugins: {
'postcss-pxtorem': {
rootValue: 16,
propWhiteList: [
'*',
'!border',
'!border-top',
'!border-right',
'!border-bottom',
'!border-left',
'!border-width'
],
selectorBlackList: ['html'],
mediaQuery: false
}
}
};
Button.module.css
.main {
font-size: 16px;
}
результат
.woo-button-main {
font-size: 16px;
}
Ожидаемый результат не произошел. Оказывается, у CRA не имеет опции Postcss-Loader. Кажется, что Reware все еще нужно.
Rewired Postcss
Установите приложение-реакция-перепрошивка-postcss
react-app-rewire-postcssПопробовал, можно нормально использовать, настроим config-override.js по документации
/* config-override.js */
...
const rewirePostcss = require('react-app-rewire-postcss');
module.exports = {
webpack: function(config, env) {
...
config = rewirePostcss(config, true);
return config;
}
};
Button.module.css
.main {
font-size: 16px;
}
результат
.woo-button-main {
font-size: 1rem;
}
Готово! Теперь вы можете продолжить счастливое кодирование~, чтобы сделать стандарт кодирования стандартным, вам нужно использовать инструменты для его ограничения.
канонический код
проверка кодаPrettierтак же какESLintрасширение,eslint-config-prettierВсе ненужные или потенциально конфликтующие правила Prettier будут отключены.eslint-plugin-prettierЭто плагин, который добавляет правила форматирования Prettier.
Установить
yarn add prettier eslint-config-prettier eslint-plugin-prettier --dev
Конфигурация ESLint
Создайте новый файл .eslintrc
{
"extends": ["react-app", "plugin:prettier/recommended"]
}
Более красивая конфигурация
Создайте новый файл .prettierrc
{
"printWidth": 90,
"singleQuote": true,
"semi": true
}
Настроить проверку фиксации git
Следующая настройкаHuskyа такжеLint Stagedдля обеспечения правильности каждого коммита
yarn add husky lint-staged --dev
Изменить package.json
{
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{js,jsx,json,css,md}": [
"prettier --write",
"git add"
]
}
}
Оглянитесь на начало целей разработки, оставив только самый важный последний шаг — создание библиотеки компонентов пользовательского интерфейса.
Библиотека сборки
CRA обеспечивает только функцию разработки и сборки приложений и не имеет возможности создавать библиотеки. На данный момент нам приходится прибегать к React App Rewired, который можно найти в документации.react-app-rewire-create-react-libraryЭто привлекает внимание, но, к сожалению, его нелегко использовать, поэтому мне приходится модифицировать собственный код, чтобы создать библиотеку компонентов.
Настроить переменные среды
Создайте пользовательскую переменную среды библиотеки
- Установить первымenv-cmd
yarn add env-cmd --dev
- Создайте файл переменной среды .env.library
REACT_APP_NODE_ENV = "library"
- Изменить package.json
{
"scripts": {
"build:library": "rm -rf build && env-cmd -f .env.library react-app-rewired build"
}
}
- Файл записи конфигурации
/* src/index.js */
import Button from './components/Button';;
export { Button };
- package.json указывает запись модуля es и основную запись
{
"module": "./src/index.js",
"main": "./build/wooui-react.js"
}
скрипт сборки
Основная идея построения конфигурации библиотеки заключается в том, чтобы пропустить все шаги, такие как разделение кода, имя файла md5 и изменение html-шаблона для построения производственной среды, а затем настроить параметры выходных атрибутов.
- Сохраните новый упакованный скрипт reactLibraryConfig.js в директорию scripts:
/* scripts/reactLibraryConfig.js */
module.exports = function(config, env, options) {
// 当值为library的时候,修改配置
if (env === 'library') {
const srcFile = process.env.npm_package_module || options.module;
const libName = process.env.npm_package_name || options.name;
config.entry = srcFile;
// 构件库信息
config.output = {
path: path.resolve('./', 'build'),
filename: libName + '.js',
library: libName,
libraryTarget: 'umd'
};
// 修改webpack optimization属性,删除代码分割逻辑
delete config.optimization.splitChunks;
delete config.optimization.runtimeChunk;
// 清空plugin只保留构建CSS命名
config.plugins = [];
config.plugins.push(
new MiniCssExtractPlugin({
filename: libName + '.css'
})
);
// 代码来自 react-app-rewire-create-react-library
// 生成externals属性值,排除外部扩展,比如React
let externals = {};
Object.keys(process.env).forEach(key => {
if (key.includes('npm_package_dependencies_')) {
let pkgName = key.replace('npm_package_dependencies_', '');
pkgName = pkgName.replace(/_/g, '-');
// below if condition addresses scoped packages : eg: @storybook/react
if (pkgName.startsWith('-')) {
const scopeName = pkgName.substr(1, pkgName.indexOf('-', 1) - 1);
const remainingPackageName = pkgName.substr(
pkgName.indexOf('-', 1) + 1,
pkgName.length
);
pkgName = `@${scopeName}/${remainingPackageName}`;
}
externals[pkgName] = `${pkgName}`;
}
});
config.externals = externals;
}
return config;
};
вызвать скрипт сборки
Далее приложение Time Out React Rewared, используя только что завершил ReactlibraryConfig, возьмите в конфигурацию модифицированных свойств. Наконец, текущий полный код выглядит следующим образом
/* config-overrides.js */
const cssModuleConfig = require('./scripts/cssModuleConfig');
const loaderUtils = require('loader-utils');
const reactLibraryConfig = require('./scripts/reactLibraryConfig');
const rewirePostcss = require('react-app-rewire-postcss');
module.exports = {
webpack: function(config, env) {
// 配置CSS Modules
config = cssModuleConfig(config, env, {
modules: {
getLocalIdent: (context, localIdentName, localName, options) => {
const folderName = loaderUtils.interpolateName(context, '[folder]', options);
const className =
process.env.LIB_NAMESPACE + '-' + folderName + '-' + localName;
return className.toLowerCase();
}
}
});
// 配置Postcss
config = rewirePostcss(config, true);
// 配置构建信息
// 当执行 yarn build:library时 process.env.REACT_APP_NODE_ENV值为library
config = reactLibraryConfig(config, process.env.REACT_APP_NODE_ENV);
// 传给 react-app-rewired 的最终配置清单
return config;
}
};
Очистите общедоступный каталог
CRA скопирует все содержимое общедоступного каталога в каталог сборки во время производственных сборок, поэтому в этой папке нужно сохранить только index.html.
🛰️👨🚀 Мягкая посадка
yarn build:library
Creating an optimized production build...
Compiled successfully.
File sizes after gzip:
2.83 KB build/wooui-react.js
684 B build/wooui-react.css
build
В каталоге с файлами я увидел двух друзей, машущих нам рукой~
Суммировать
Наконец, в соответствии с поставленными целями, все требования, выдвинутые перед стартом, были реализованы. Одна из них заключается в том, можно ли быстро создать библиотеку компонентов пользовательского интерфейса на основе React в соответствии с процессом построения Vue-CLI. В соответствии с первоначальными потребностями, шаг за шагом, чтобы найти решения, столкнуться с трудностями, прояснить основные проблемы, с которыми нужно иметь дело, прояснить идеи решения, найти решения, а затем выполнить дальнейшие потребности, чтобы, наконец, реализовать построение пользовательского интерфейса без отклонение цели компонента CRA.
Если подумать еще раз, много ли вещей можно оптимизировать? Например, создание одного файла компонента, генерация всего файла записи, построение одного компонента и т. д.
Это вопрос так, жизнь, работа и учеба многие другие, почему бы и нет?
Хорошо, спасибо за просмотр, увидимся в следующий раз.
Да, кстати, здесь размещен исходный код проекта:
-
именуемый в дальнейшем КРА↩︎