начало
Много раз, чтобы повторно использовать или суммировать, мы будем извлекать компоненты и отправлять их в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сходство.
посмотри сноваoutputDist можно вывести в следующей конфигурации, так как мы сохраняем информацию о пути к файлу во входном файле, поэтому здесь напрямую меняем суффикс.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 для перезапуска внутреннего обучения с нуля»