начало
Много раз, чтобы повторно использовать или суммировать, мы будем извлекать компоненты и отправлять их вnpm
начальство. Но в этом процессе вы обнаружите проблему, заключающуюся в том, как сделать это лучше.发布
а также管理
сохранить эти компоненты. В конце концов вы обнаружите, что другие учебники в Интернете либо слишком разбросаны, либо некоторые детали не на месте. Здесь я пользуюсь этой возможностью, чтобы подвести итог. Если вы сочтете это полезным после прочтения, вы также можете赞
, обратите внимание, ха-ха.
После понимания мы можем
- Напишите и опубликуйте полезную библиотеку компонентов
- способен
import { demoComponent } from 'xxxUI'
способ представить - так же может быть
import demoComponent from xxxUI/component/demoComponent
способ представить - отдельные компоненты
打包相对独立
, не мешая друг другу - Выходной компонент может
简单易用
и имеет хороший兼容性
- Библиотека компонентов может быть реализована в соответствии с конфигурацией пользователя.
按需加载
- Библиотека компонентов может быть реализована в соответствии с конфигурацией пользователя.
Tree Shaking
- компоненты проходят
单元测试
- упаковать и опубликовать в
npm
Вот так, хе-хе.
Ниже в качестве примера взята библиотека компонентов реакции.На самом деле vue тот же самый, но конфигурация babel другая.
Структура проекта
Структурный анализ
Давайте сначала посмотрим на структуру проекта библиотеки компонентов.
Ну, это выглядит очень сложно. Первое впечатление должно быть связано с какими-то грязными файлами. Давайте сначала объясним это.
-
src
сохранить основной код -
dist
Сохраните окончательный упакованный выходной код -
sass
Стили разделены и размещены отдельно (конечно, их можно ставить вместе с компонентами. Цель здесь в том, что даже если связанные компоненты не используются, не проблема использовать связанные стили отдельно) -
__mocks__
(ложный объект),coverage
(покрытие),test,jest.config.js
(конфигурация шутки) Все они связаны с модульным тестированием и будут подробно рассмотрены в следующей главе. -
.npmignore
а также.gitignore
Аналогичный эффект -
.babelrc
Знаменитый Вавилон должен знать каждый - Другие должны быть очень знакомы, и если вы введете это дальше, вас заподозрят в том, что вы составляете количество слов.
ключевой каталог
Давайте сосредоточимся наsrc
В каталоге основного кода сначала мы сохраняем компоненты вcomponent
во внешнем слоеindex
Цитироватьcomponent
компоненты в , так как не указан конкретный путь,import
При импорте он будет найден по умолчаниюindex
. Таким образом, после упаковки и вывода вы можете пройтиimport { demoComponent } from 'xxxUI'
Это способ ссылки на компоненты.
// index.jsx
import demoComponent from './component/demoComponent';
export {
demoComponent
};
// demoComponent.jsx
export default class demoComponent extends Component {
render() {
return (
<div>
hello world
</div>
);
}
}
Затем используйте эту форму для экспорта компонентов, вы можете передатьimport demoComponent from xxxUI/component/demoComponent
Эта форма вводит компоненты отдельно.
Библиотеки компонентов загружаются по запросу
Согласно приведенной выше структуре каталогов и методу импорта, мы можем узнать, что черезimport { demoComponent } from 'xxxUI'
Эта форма введения заставит всю библиотеку компонентов быть введена в проект разработки, а иногда нужно использовать только два или три компонента, чего мы не хотим видеть. и черезimport demoComponent from xxxUI/component/demoComponent
Ссылаясь в таком виде, можно ввести только определенный компонент, который необходимо использовать, что как раз и решает эту проблему. Но писать такую длинную строку каждый раз при импорте очень неудобно. В это время необходимо использоватьbabel-plugin-import
этот плагин.
import { demoComponent, demoComponent1, demoComponent2 } from 'xxxUI'
// 使用babel-plugin-import插件能自动将以上这种调用形式在AST(抽象语法树)中改写成以下形式。
// 这样就能方便地引入相关组件,又不用担心一次全部引入导致包过大的问题
import demoComponent from xxxUI/component/demoComponent
import demoComponent1 from xxxUI/component/demoComponent
import demoComponent2 from xxxUI/component/demoComponent
Наконец в.babelrc
Настройте путь, который необходимо преобразовать в
// .babelrc
{
...
"plugins":[
"import", {
"libraryName": "xxxUI",
"libraryDirectory": "component",
}
]
}
Если загрузка по требованию не установлена, упаковывается вся библиотека компонентов. Установлена загрузка по требованию, и загружаются только используемые компоненты.Следует отметить, что настраивать здесь должен пользователь библиотеки компонентов, а не тот, который прописан в библиотеке компонентов
.babelrc
середина. Если библиотека компонентов поддерживает загрузку по требованию, эта конфигурация должна быть записана наREADME.md
Выбор остается за пользователем библиотеки компонентов. Плюсы и минусы загрузки по требованию зависят от конкретной среды проекта.需要具体情况具体分析
.
И вот так, с продуманной файловой структурой, цель2,3,6
достигнуто.
войти
После уточнения структуры проекта следующим шагом будет сбор исходного кода компонента. Вообще говоря, необходимо толькоwebpack
изentry
Только входной файл должен быть установлен в конфигурацииindex
Именно такentry: path.resolve(__dirname, 'src', 'index.jsx')
. Однако, поскольку нам нужно, чтобы каждый компонент был упакован независимо друг от друга, нам нужно импортировать компоненты один за другим, сохраняя при этом соответствующую файловую структуру.
function getFileCollection() {
const globPath = './src/**/*.*(jsx|js)';
const files = glob.sync(globPath);
return files;
}
function entryConfig() {
let entryObj = {};
getFileCollection().forEach(item => {
const filePath = item.replace('./src', '');
entryObj[filePath] = path.resolve(__dirname, item);
});
return entryObj;
}
используется здесьglob
Этот очень полезный инструмент может легко сопоставить соответствующие файлы. Окончательный результат — это объект сопоставления пути к файлу, мы можем видеть, какие файлы вводятся в консоли.
Хорошо, следующий шаг — как поступить с этими исходными файлами.
Обработка компиляции и библиотека компонентов Tree Shaking
Процесс обработки здесь очень прост, логика заключается в конфигурацииbabel
Будуes6+
Исходный код обрабатывается вes5
совместимый код, кстати тожеsvg
Маленькие значки превращаются вbase64
Формат встроенный. Это больше сделано для того, чтобы пользователи могли использовать эту библиотеку компонентов с минимально возможной настройкой и минимальными начальными затратами. Вот если бы при этом держатьes6
код, который позволяет разработчикам свободно настраиватьTree Shaking
(Например, в сценарии, где разработчик использует только метод в компоненте, нет необходимости представлять весь компонент). О том, как разработчики настраиваютTree Shaking
Расскажу об этом в конце.
Модули Es6 обеспечивают модульность на уровне синтаксиса,
Tree Shaking
Он основан на модульности ES6 и может быть скомпилирован и упакован на узле вAST
(Абстрактное синтаксическое дерево) статический анализ, удаление неиспользуемого кода. Наш скомпилированный и упакованный код es5 не может быть обработанTree Shaking
из.
// webpack.config中的loader配置
rules: [{
test: /.jsx|.js$/,
loader: 'babel-loader',
exclude: /node_modules/
}, {
test: /\.(jpg|png|gif|svg|jpeg)$/,
loader: 'url-loader',
exclude: /node_modules/
}]
// .babelrc
{
"presets": [
["@babel/preset-env", {
// 浏览器兼容方案配置
"targets": {
"browsers": [
">0.25%",
"not ie 11",
"not op_mini all"
]
}
}],
"@babel/preset-react",
],
"plugins": [
// 一些必备的转换插件
"@babel/plugin-proposal-function-bind",
"@babel/plugin-proposal-class-properties",
// 解决编译中产生的重复的工具函数
"@babel/plugin-transform-runtime",
"transform-remove-console"
]
}
Достигнут пункт 7 цели.
выход
пакет, скомпилированный вывод вdist
каталог, обратите внимание, чтоdist
Структура в каталоге должна быть такой же, какsrc
Каталог должен быть последовательным, чтобы путь ссылок между компонентами и компонентами не был хаотичным, как это,dist
структура каталогов сsrc
сходство.
посмотри сноваoutput
Dist можно вывести в следующей конфигурации, так как мы сохраняем информацию о пути к файлу во входном файле, поэтому здесь напрямую меняем суффикс.libraryTarget
Функция заключается в установке формата упаковки, который используется здесьumd
стандарт. если установленоlibrary
, то он будет экспортирован как однократная ссылочная формаimport xxxUI from 'xxxUI'
, чего мы не хотим.library
а такжеlibraryTarget
Значение отличается в зависимости от типа проекта.Подробнее см. здесь
output: {
filename: (chunkData) => {
let filePath = chunkData.chunk.name;
const filename = filePath.replace('.jsx', '.js');
return filename;
},
path: __dirname + '/dist',
libraryTarget: 'umd',
// library: 'xxxUI'
}
Все готово, но упаковав таким образом, вы узнаете, как может сторонний пакетreact,react-dom
Он также упакован, что приведет к тому, что библиотека компонентов будет очень большой после упаковки.
Нам нужно настроить так, отфильтроватьimport
Входящие сторонние пакеты
externals: [
function(context, request, callback) {
// 允许编译以下后缀文件
if (/.jsx|.jpg|.png|.gif|.svg|.jpeg$/g.test(request)) {
return callback();
}
callback(null, request);
}
]
Вы можете увидеть огромные изменения! Теперь весь размер упаковки составляет всего120kb
(удалить стили)
Так как стиль独立抽离
Выходи, просто скопируй стиль вdist
Каталог может быть, конечно, плагин может быть настроен на автоматическое завершение.
new CopyPlugin([{
from: './sass',
to: './sass'
}])
достижения цели4,5
точка
Окончательный релиз
- Перейти на официальный сайт для завершения регистрации
-
npm login
Авторизоваться - Добавить к
.npmignore
файл, перечислите файлы, которые необходимо игнорировать - Добавить к
README.md
, напишите необходимые инструкции, это хорошая привычка - существует
package.json
изscript
добавить команду вwebpack --mode production && npm publish ./dist
.这里意思是采用生产模式打包并将dist
Каталог опубликован наnpm
.
к концуREADME.md
Мануал можно написать так
// 安装
npm i -S xxxUI
// webpack配置处理样式
{
test: /\.scss$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', "postcss-loader", 'sass-loader'],
include: [
path.join(__dirname, 'node_modules/xxxUI/sass/')
]
}
// 在index.jsx中引入样式
import "xxxUI/sass/index.scss";
// 可选项---------------
// .babelrc 配置按需加载
"plugins": [
[
"import",
{
"libraryName": "xxxUI",
"libraryDirectory": "component",
}
],
// ...
]
// 可选项---------------
// 配置Tree Shaking
// webpack.config.js
// ...
{
test: /\.scss$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', "postcss-loader", 'sass-loader'],
include: [
path.join(__dirname, 'node_modules/xxxUI/sass/')
],
// 样式无需进行Tree Shaking
sideEffects: true
}
// ...
optimization: {
usedExports: true,
minimizer: [
new TerserPlugin({})
]
}
// .babelrc
"presets": [
[
"@babel/preset-env",
{
// 想达到Tree Shaking效果这里
"modules": false,
}
]
]
Варианты модулей в babel:
'amd' | 'umd' | 'systemjs' | 'commonjs' | false
Они, поскольку Tree Shaking основаны на модулях ES6, не могут быть преобразованы в другие стандарты здесь и могут быть выбраны толькоfalse
, то есть с помощью модуля стандартной компиляции исходного файла.
Готово, практичная библиотека компонентов выпущена, заходите и пробуйте.
модульный тест
Подождите, кажется, что юнит-теста не хватает.На самом деле слишком много точек (кенг), чтобы обратить внимание.Я не могу закончить его все сразу.《Re从零开始的组件单元测试》
Подробно развернуть.
конец
SluckyUI
Исходный код и структура проекта построены по этой модели, есть и другие соображения в деталях, которые могут отличаться, но идея та же.SluckyUI
Идея состоит в том, чтобы создать семя библиотеки компонентов, чтобы позволить другим разработчикам выполнять быструю вторичную разработку и сократить ненужное создание колес, но в написании все еще много несовершенств.start
Служба поддержки.
Демонстрация онлайн-компонента и исходный код библиотеки компонентов
Недавно я наконец-то разобрался с кодом, а предыдущее написание действительно не очень красивое.Онлайн-демонстрация компонента&Исходный код библиотеки компонентов
Как написать компоненты в библиотеке компонентов?
- «Стандартная формулировка новой библиотеки пользовательского интерфейса, написанная с нуля»
- «Библиотека Re’s UI с нуля, чтобы написать кнопку жизни»
- «Библиотека пользовательского интерфейса Re’s с нуля для написания формы жизни»
- «Библиотека Re’s UI с нуля для написания табличных компонентов жизни»
- «Библиотека Re's UI пишет жизнь с нуля — компонент пошагового управления Steps»
- «Библиотека Re's UI пишет жизнь с нуля — компонент дерева»
- «Внутреннее обучение с нуля настраивает среду Ubuntu + Ngnix + Nodejs + Mysql»
- «Настройка среды LAMP для перезапуска внутреннего обучения с нуля»