При разработке интерфейсных проектов некоторые компоненты пользовательского интерфейса/функциональные модули в проекте часто ускоряются в соответствии с бизнес-требованиями (далее именуемыекомпоненты) и т. д.; изначально эти компоненты поддерживаются только в одном проекте и повторно используются на разных страницах или модулях проекта. В настоящее время компоненты постепенно улучшаются, что является периодом роста, который фокусируется только на функциональности и надежности. .
По мере развития бизнеса первоначальный проект, возможно, придется разделить и превратить в несколько похожих, но разных проектов — например, после накопления опыта в начальном проекте его необходимо расширить на аналогичные бизнес-форматы или в соответствии с потребностями разных крупных клиентов.В этом случае часто трудно идеально поддерживать синхронизацию основных версий каждого проекта или последующего хода разработки, и можно развиваться только постепенно. В это время те «многоразовые компоненты», которые поначалу кажутся изысканными, часто нужно обслуживать отдельно в каждом проекте в спешке, или возникают непредвиденные проблемы, которые необходимо перепланировать.
В этой статье в качестве примера используется интерфейсный проект стека технологий Vue и делается попытка кратко обсудить метод абстрагирования и извлечения повторно используемых компонентов в разных проектах.
Общая ситуация с повторно используемыми компонентами
- Повторное использование компонентов ограничено одним проектом
- Одна разработка, n раз
использоватьсистема - Разделение проекта увеличивает проблему в геометрической прогрессии, и каждое исправление/изменение нужно синхронизировать n раз.
- Зависимые библиотеки одноуровневых проектов могут быть похожими, но разными, или разница версий велика.
- Различия в средах или версиях модульного тестирования также вызывают проблемы при повторном использовании компонентов.
Что касается различий одного и того же компонента в разных проектах, инкапсулируйте el-date-picker в element-ui с помощью вторичного пакета.DateRange.vueПример компонента:
| Проект | библиотека базовых компонентов | Обнаруженные репрезентативные проблемы |
|---|---|---|
| A | element-ui@v1.x |
|
| B | ||
| C | ||
| D | ||
| E | element-ui@v2.x |
|
| F |
По разным причинам библиотеки пользовательского интерфейса, от которых зависят несколько проектов, похожи, но не одинаковы; размер проекта слишком велик, команда поддержки отличается и т. д., что делает практически невозможной унификацию базовой библиотеки компонентов~🐔 Ты такая красивая,Это так стыдно~
Как совместить точки обслуживания?
- Для нескольких проектов в примере есть 6 точек обслуживания и рабочая нагрузка × 6
- еслиОбъединение в единую библиотеку, то точка обслуживания становится 2, и нужно различать только разницу между библиотекой базовой версии
- Для большинства более простых компонентов разные версии базовой библиотеки компонентов не будут вызывать различий, или для простых компонентов, которые вообще не ссылаются на библиотеку компонентов element-ui, точка обслуживания может быть напрямую уменьшена до 1.
Какие компоненты являются универсальными?
- Достаточно абстрактный, не содержащий бизнес-логики или достаточно расширяемый
- попробуй не включать
$t,$routerи другие зависимости, связанные со средой проекта - Имеются юнит-тесты с достаточным покрытием
- Иметь необходимую документацию или описать достаточно полную функциональность с помощью модульных тестов.
- Желательно также предоставить рабочий пример
Опубликовать в нпм
В конкретном проекте достаточно обратиться к исходному коду компонента;
Один из подходов к общей библиотеке компонентов для проектов состоит в том, чтобы поддерживать в каждом проекте подмодуль, указывающий на исходный код библиотеки компонентов (git поддерево или подмодуль), но этот метод сложнее поддерживать, поэтому он обычно не используется.
Другой способ, к которому мы больше привыкли, — это прямое обращение к зарегистрированному имени компонента после его установки через npm (package.jsonсерединаname).
Конечно, если ваши собственные компоненты более-менее связаны с бизнес-логикой и не так распространены во внешних проектах, а компания поддерживает образ npm внутри, то вы можете выбрать его публикацию в эту внутреннюю среду.
Основные шаги для публикации компонентов npm:
Зарегистрируйте пользователя на npmjs.com или через командную строку:
npm adduser
Подтвердите вход перед публикацией:
npm login
Вручную измените package.json перед публикацией или используйте командную строку для обновления номера версии проекта. Обратите внимание, что номер версии не может быть одинаковым для каждого выпуска:
npm version x.x.x
Выполнить выпуск:
npm publish
Откройте домашнюю страницу проекта прямо из командной строки, чтобы просмотреть:
npm home [name]
Дополнительные команды см. в официальной полной документации:docs.thathorseplus.com/handle-doc_door…
Следует также отметить, что правильная конфигурация в package.jsonrepositoryполе для отображения ссылки на репозиторий на домашней странице компонента npm.
Компоненты пакета с накопительным пакетом вместо веб-пакета
В этом примере в качестве инструмента упаковки выбран накопительный пакет:
- Хотя веб-пакет является мощным, его конфигурация сложна, а сгенерированный код избыточен.
- rollup больше подходит для компиляции исходного кода таких типов, как библиотеки и компоненты
- накопительный пакет расширяет функцию упаковки на основе подключаемых модулей, а конфигурация относительно проста.
- Элементы конфигурации свертки очень похожи на webpack, что упрощает миграцию и адаптацию.
Базовый набор конфигураций
Предположим, что структура библиотеки компонентов запланирована следующим образом:
├─.babelrc
├─.eslintignore
├─.eslintrc.js
├─.gitignore
├─CHANGELOG.md
├─jest.config.js
├─package.json
├─README.md
├─postcss.config.js
├─rollup.config.js
├─dist/
├─example/
├─node_modules/
├─src/
├─__mocks__/
└─__tests__/
Минимальные сценарии npm следующие:
// package.json
"scripts": {
"build": "rollup --config"
},
Более базовая конфигурация свертки выглядит следующим образом:
// rollup.config.js
import path from 'path';
import json from 'rollup-plugin-json';
import { uglify } from 'rollup-plugin-uglify';
import alias from 'rollup-plugin-alias';
import vue from 'rollup-plugin-vue';
import babel from 'rollup-plugin-babel';
import commonjs from 'rollup-plugin-commonjs';
import resolve from 'rollup-plugin-node-resolve';
import nodeGlobals from 'rollup-plugin-node-globals';
import bundleSize from 'rollup-plugin-filesize';
import { eslint } from 'rollup-plugin-eslint';
import pkg from './package.json';
const pathResolve = p => path.resolve(__dirname, p);
const extensions = ['.js', '.vue'];
module.exports = {
input: 'src/index.js',
output: {
file: 'dist/bundle.min.js',
format: 'umd',
name: 'MyComponents',
globals: {
vue: 'Vue',
echarts: 'echarts',
lodash: 'lodash'
},
sourcemap: true
},
external: Object.keys(pkg.dependencies),
plugins: [
resolve({
extensions,
browser: true
}),
eslint({
extensions,
exclude: ['**/*.json'],
cache: true,
throwOnError: true
}),
bundleSize(),
commonjs(),
nodeGlobals(),
vue({
template: {
isProduction: !process.env.ROLLUP_WATCH,
compilerOptions: { preserveWhitespace: false }
},
css: true
}),
babel({
exclude: 'node_modules/**'
}),
alias({
'@': pathResolve('src')
}),
json(),
uglify()
]
};
Краткое описание этой конфигурации выглядит следующим образом:
- Порядок плагинов в приведенном выше примере важен
- Плагин node-globals будет вводить переменные, такие как процесс, в упакованный файл.
- Плагин eslint проверит синтаксис перед упаковкой и может повторно использовать файл конфигурации .eslintrc.js в обычном проекте.
- Плагин bundleSize используется для отображения размера целевого файла после упаковки.
- Поле css в плагине vue, указывающее, следует ли упаковывать встроенные стили в целевой js.
- Продолжайте использовать babel вместо более легкого buble, который часто сочетается с rollup для компиляции кода ES6, а также для повторного использования с шуткой.
- Компонент json решает ситуацию, когда файл json может быть напрямую импортирован в исходный код.
- Внешняя конфигурация означает: зависимости, содержащиеся в зависимостях в package.json, не упаковываются в компоненты, а должны быть установлены в конкретных проектах.
Связанное преобразование синтаксиса и настройка проверки синтаксиса:
// .babelrc
{
"presets": [["env", { "modules": false }]],
"env": {
"test": {
"presets": [["env", { "targets": { "node": "current" } }]]
}
}
}
// .eslintignore
__tests__/*
*.css
// .eslintrc.js
module.exports = {
extends: [
"airbnb-base",
'plugin:vue/essential'
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': 'error',
'space-before-function-paren': 'off',
'no-underscore-dangle': 'off',
'no-param-reassign': 'off',
'func-names': 'off',
'no-bitwise': 'off',
'prefer-rest-params': 'off',
'no-trailing-spaces': 'off',
'comma-dangle': 'off',
'quote-props': 'off',
'consistent-return': 'off',
'no-plusplus': 'off',
'prefer-spread': 'warn',
semi: 'warn',
indent: 'warn',
'no-tabs': 'warn',
'no-unused-vars': 'warn',
quotes: 'warn',
'no-void': 'off',
'no-nested-ternary': 'off',
'import/no-unresolved': 'off',
'no-return-assign': 'warn',
'linebreak-style': 'off',
'prefer-destructuring': 'off',
'no-restricted-syntax': 'warn'
},
parserOptions: {
parser: 'babel-eslint'
}
}
Настройка среды модульного тестирования
Точки обслуживания объединены в библиотеку, следует отметить высокую концентрацию соответствующих рисков.
Поэтому модульное тестирование становится все более и более важным.Компоненты или модули в библиотеке все условны (например, директивы во Vue не так просто сделать модульное тестирование, а чистые функции фильтров легко), и разработчики из различных проектов хотят друзья, если вы уверены и смелы, вы должны безоговорочно купить один получить один бесплатно, с идеальным модульным тестированием.
Здесь мы возьмем jest в качестве примера, чтобы перечислить его основную конфигурацию:
// jest.config.js
module.exports = {
modulePaths: [
'<rootDir>/src/'
],
moduleFileExtensions: [
'js',
'json',
'vue'
],
transform: {
'^.+\\.vue$': 'vue-jest',
'^.+\\.jsx?$': 'babel-jest'
},
transformIgnorePatterns: [
'/node_modules/'
],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
'\\.(css|less|scss)$': '<rootDir>/__mocks__/emptyMock.js'
},
snapshotSerializers: [
'jest-serializer-vue'
],
collectCoverage: true,
collectCoverageFrom: [
'<rootDir>/src/**/*.{js,vue}',
'!**/node_modules/**'
],
coveragePathIgnorePatterns: [
'<rootDir>/__tests__/'
],
coverageReporters: [
'text'
]
};
вemptyMock.jsиспользуется для игнорирования ссылок на стили в вариантах использования:
// __mocks__/emptyMock.js
module.exports = {};
Соответствующие сценарии npm:
"scripts": {
// ...
"test": "jest"
},
"pre-commit": [
"test"
],
Здесь пакет pre-commit используется для реализации функции ловушки модульного тестирования перед фиксацией.
Для получения дополнительной информации о модульном тестировании Vue см.эта статья.
Предварительный просмотр фактического эффекта компонента
Если вы просто говорите и не тренируетесь с поддельным дескриптором, хотя статическая грамматика также была проверена и модульный тест пройден, более практично видеть то, что видно, и это более интуитивно понятно другим разработчикам. с помощью плагинов, таких как rollup-plugin-serve, вы можете запустить минимальную конфигурацию операционной среды браузера, живую плоть, чтобы увидеть реальную производительность компонентов.
Задайте параметры среды в сценариях npm, чтобы запустить службу демонстрационной страницы для полностью универсальных компонентов и компонентов, подходящих для определенных типов проектов:
"scripts": {
// ...
"dev:common": "rollup --watch --config rollup.config.dev.js --environment PROJ_ENV:common",
"dev:A": "rollup --watch --config rollup.config.dev.js --environment PROJ_ENV:A",
"dev:B": "rollup --watch --config rollup.config.dev.js --environment PROJ_ENV:B",
},
Соответствующим образом измените исходную конфигурацию объединения, добавьте отдельный файл rollup.config.dev.js и запустите службу в соответствии с параметрами среды:
import serve from 'rollup-plugin-serve';
import postcss from 'rollup-plugin-postcss';
import baseConfig, {
pathResolve,
browserGlobals
} from './rollup.config.base';
...
const PORT = 3001;
const PROJECT = process.env.PROJ_ENV;
export default {
input: pathResolve(`example/${PROJECT}/main.js`),
output: {
file: pathResolve(`example/${PROJECT}/dist/example.bundle.${PROJECT}.js`),
format: 'umd',
name: 'exampleApp',
globals: browserGlobals,
sourcemap: false
},
plugins: [
postcss(),
...baseConfig.plugins,
serve({
port: PORT,
contentBase: [
pathResolve(`example/${PROJECT}`)
]
})
]
};
Здесь предполагается, что компоненты ссылаются на App.vue просто и грубо.Пока что, независимо от маршрутизации и других ситуаций, структура соответствующего каталога примера может быть следующей:
+---A
| | App.vue
| | index.html
| | main.js
| |
| \---dist
| example.bundle.A.js
|
+---B
| | App.vue
| | index.html
| | foo.css
| | main.js
| |
| \---dist
| example.bundle.B.js
|
\---common
| App.vue
| index.html
| main.js
|
+---dist
| example.bundle.common.js
|
\---fonts
Суммировать
При одновременном сопровождении нескольких однородных интерфейсных проектов неизбежно задействование некоторых более общих компонентов/функциональных модулей пользовательского интерфейса, которые собираются и публикуются в npm, дополняются идеальными модульными тестами и готовыми к запуску демонстрационными примерами. Отображение и необходимая документация могут значительно сократить объем работ по обслуживанию компонентов.
--End--
Поиск FemmeLife Подпишитесь на официальный аккаунт
Пожалуйста, укажите источник