Вот и наступило главное событие.
Обзор
Среда хостинга отличается, и исходный код необходимо обработать и опубликовать в npm.
Уточните следующие цели:
- файл объявления типа экспорта
- экспорт
umd
/Commonjs module
/ES module
и т. д. 3 формы для пользователей, чтобы представить - Поддержка файлов стилей
css
Познакомить не толькоless
- Поддержка загрузки по требованию
Весь код в этом разделе можно найти в репозиторииchapter-3полученный в отделении.
файл объявления типа экспорта
Поскольку он используетсяtypescript
написана библиотека компонентов, пользователи должны пользоваться преимуществами системы типов.
Мы можем сгенерировать файл объявления типа, и вpackage.json
Определите запись в следующим образом:
package.json
{
"typings": "types/index.d.ts", // 定义类型入口文件
"scripts": {
"build:types": "tsc --emitDeclarationOnly" // 执行tsc命令 只生成声明文件
}
}
воплощать в жизньyarn build:types
, вы можете обнаружить, что корневой каталог был сгенерированtypes
папка(tsconfig.json
определено вoutDir
поле), структура каталогов такая же, какcomponents
Папки остаются прежними, а именно:
types
├── alert
│ ├── alert.d.ts
│ ├── index.d.ts
│ ├── interface.d.ts
│ └── style
│ └── index.d.ts
└── index.d.ts
Таким образом, пользователь вводитnpm
package, вы можете получать автоматические подсказки и повторно использовать определения типов связанных компонентов.
Далее будетts(x)
дождитесь обработки файлаjs
документ.
Обратите внимание, что нам нужно вывести
Commonjs module
так же какES module
Два модульных типа файлов (пока не рассматриваем)umd
), следующие виды использованияcjs
Относится кCommonjs module
,esm
Относится кES module
.
Рекомендуемая литература для студентов, которые сомневаются в этом:Импорт, требование, экспорт, module.exports смешанное подробное объяснение
Экспорт модулей Commonjs
На самом деле его можно использоватьbabel
илиtsc
Инструменты командной строки для компиляции кода (на самом деле, многие библиотеки инструментов делают это), но учитывая, чтоРабота со стилями и их загрузка по запросу, мы используемgulp
связать воедино этот процесс.
вавилонская конфигурация
Установить первымbabel
и связанные с ним зависимости
yarn add @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime --dev
yarn add @babel/runtime-corejs3
новый.babelrc.js
Файл, напишите следующее:
.babelrc.js
module.exports = {
presets: ['@babel/env', '@babel/typescript', '@babel/react'],
plugins: [
'@babel/proposal-class-properties',
[
'@babel/plugin-transform-runtime',
{
corejs: 3,
helpers: true,
},
],
],
};
о@babel/plugin-transform-runtime
а также@babel/runtime-corejs3
:
- подобно
helpers
параметры установлены наtrue
, который может быть многократно сгенерирован в процессе компиляции кодаhelper
функция(classCallCheck
,extends
и т.д.) для уменьшения размера генерируемого кода; - подобно
corejs
Установить как3
, который может ввести по требованию, не загрязняя глобальныйpolyfill
, обычно используемый при написании библиотеки классов (рекомендую: не вводитеpolyfill
, который, в свою очередь, информирует пользователя о том, что нужно ввестиpolyfill
, чтобы избежать повторного введения или конфликта, который будет подробно упомянут позже).
узнать большеОфициальная документация — @babel/plugin-transform-runtime
Настройте целевую среду
Чтобы избежать перевода синтаксиса, изначально поддерживаемого браузером, создайте новый.browserslistrc
Файл, согласно требованиям адаптации, записывается в диапазон поддерживаемых браузеров, который действует на@babel/preset-env
.
.browserslistrc
>0.2%
not dead
not op_mini all
Жаль, что,@babel/runtime-corejs3
Не может быть уменьшен снова на основе поддержки целевого браузера по требованию.polyfill
введение см.@babel/runtime for target environment .
это означает@babel/runtime-corejs3
даже впрыснет все возможное при нацеливании на современные двигателиpolyfill
: Излишне увеличивает размер конечного пакета.
Для библиотек компонентов (где объем кода может быть большим) я лично рекомендую поместитьpolyfill
Право выбора возвращается пользователю и выполняется в среде хоста.polyfill
. Если у пользователей есть требования совместимости, они, естественно, будут использовать@babel/preset-env + core-js + .browserslistrc
выйти на мировой уровеньpolyfill
, этот набор фишек вводит минимальный целевой браузер, который не поддерживаетAPI
всеpolyfill
.
Буду
@babel/preset-env
изuseBuiltIns
Значение параметра установлено наusage
, при этом ставяnode_modules
отbabel-loader
серединаexclude
Исключенные учащиеся могут захотеть использовать эту функцию:"useBuiltIns: usage" for node_modules without transpiling #9419, где это не поддерживаетсяissue
Перед упомянутым содержанием, по-прежнему послушноuseBuiltIns
Установить какentry
или не ставитьnode_modules
отbabel-loader
серединаexclude
.
Поэтому библиотеку компонентов не нужно делать лишней и вводить избыточныеpolyfill
, хорошо документированный, больше всего на свете (например,zentа такжеantdтак).
Сейчас@babel/runtime-corejs3
заменить@babel/runtime
, только дляhelper
Извлечение функции.
yarn remove @babel/runtime-corejs3
yarn add @babel/runtime
.babelrc.js
module.exports = {
presets: ['@babel/env', '@babel/typescript', '@babel/react'],
plugins: ['@babel/plugin-transform-runtime', '@babel/proposal-class-properties'],
};
@babel/transform-runtime
изhelper
Варианты по умолчаниюtrue
.
конфигурация глотка
установить сноваgulp
связанные зависимости
yarn add gulp gulp-babel --dev
новыйgulpfile.js
, напишите следующее:
gulpfile.js
const gulp = require('gulp');
const babel = require('gulp-babel');
const paths = {
dest: {
lib: 'lib', // commonjs 文件存放的目录名 - 本块关注
esm: 'esm', // ES module 文件存放的目录名 - 暂时不关心
dist: 'dist', // umd文件存放的目录名 - 暂时不关心
},
styles: 'components/**/*.less', // 样式文件路径 - 暂时不关心
scripts: ['components/**/*.{ts,tsx}', '!components/**/demo/*.{ts,tsx}'], // 脚本文件路径
};
function compileCJS() {
const { dest, scripts } = paths;
return gulp
.src(scripts)
.pipe(babel()) // 使用gulp-babel处理
.pipe(gulp.dest(dest.lib));
}
// 并行任务 后续加入样式处理 可以并行处理
const build = gulp.parallel(compileCJS);
exports.build = build;
exports.default = build;
Исправлятьpackage.json
package.json
{
- "main": "index.js",
+ "main": "lib/index.js",
"scripts": {
...
+ "clean": "rimraf types lib esm dist",
+ "build": "npm run clean && npm run build:types && gulp",
...
},
}
воплощать в жизньyarn build
, получите следующее:
lib
├── alert
│ ├── alert.js
│ ├── index.js
│ ├── interface.js
│ └── style
│ └── index.js
└── index.js
Наблюдая за скомпилированным исходным кодом, можно обнаружить: многиеhelper
метод был извлечен в@babel/runtime
, форма импорта и экспорта модуля такжеcommonjs
Технические характеристики.
lib/alert/alert.js
экспорт модуля ES
генерироватьES module
можно сделать лучшеtree shaking, исходя из предыдущего шагаbabel
Настройте, обновите следующее:
- настроить
@babel/preset-env
изmodules
Вариантыfalse
, закройте преобразование модуля; - настроить
@babel/plugin-transform-runtime
изuseESModules
Вариантыtrue
,использоватьES module
Введение формыhelper
функция.
.babelrc.js
module.exports = {
presets: [
[
'@babel/env',
{
modules: false, // 关闭模块转换
},
],
'@babel/typescript',
'@babel/react',
],
plugins: [
'@babel/proposal-class-properties',
[
'@babel/plugin-transform-runtime',
{
useESModules: true, // 使用esm形式的helper
},
],
],
};
Цель достигнута, будем использовать переменные окружения для различенияesm
а такжеcjs
(Вы можете установить соответствующую переменную среды при выполнении задачи), и, наконец,babel
Конфигурация выглядит следующим образом:
.babelrc.js
module.exports = {
presets: ['@babel/env', '@babel/typescript', '@babel/react'],
plugins: ['@babel/plugin-transform-runtime', '@babel/proposal-class-properties'],
env: {
esm: {
presets: [
[
'@babel/env',
{
modules: false,
},
],
],
plugins: [
[
'@babel/plugin-transform-runtime',
{
useESModules: true,
},
],
],
},
},
};
Изменить следующийgulp
Связанная конфигурация, извлечениеcompileScripts
задача, добавитьcompileESM
Задача.
gulpfile.js
// ...
/**
* 编译脚本文件
* @param {string} babelEnv babel环境变量
* @param {string} destDir 目标目录
*/
function compileScripts(babelEnv, destDir) {
const { scripts } = paths;
// 设置环境变量
process.env.BABEL_ENV = babelEnv;
return gulp
.src(scripts)
.pipe(babel()) // 使用gulp-babel处理
.pipe(gulp.dest(destDir));
}
/**
* 编译cjs
*/
function compileCJS() {
const { dest } = paths;
return compileScripts('cjs', dest.lib);
}
/**
* 编译esm
*/
function compileESM() {
const { dest } = paths;
return compileScripts('esm', dest.esm);
}
// 串行执行编译脚本任务(cjs,esm) 避免环境变量影响
const buildScripts = gulp.series(compileCJS, compileESM);
// 整体并行执行任务
const build = gulp.parallel(buildScripts);
// ...
воплощать в жизньyarn build
, можно обнаружить, что сгенерированныйtypes
/lib
/esm
три папки, наблюдайтеesm
каталог с той же структуройlib
/types
Последовательны, файлы jsES module
Импорт и экспорт в виде модуля.
esm/alert/alert.js
не забудь датьpackage.json
Добавьте связанные записи.
package.json
{
+ "module": "esm/index.js"
}
Работа с файлами стилей.
копировать меньше файлов
мы будемless
файл включен вnpm
пакет, пользователь может пройтиhappy-ui/lib/alert/style/index.js
Представлен в форме по запросуless
файл, где вы можете напрямую скопировать файл меньшего размера в целевую папку.
существуетgulpfile.js
ЧжунсинcopyLess
Задача.
gulpfile.js
// ...
/**
* 拷贝less文件
*/
function copyLess() {
return gulp
.src(paths.styles)
.pipe(gulp.dest(paths.dest.lib))
.pipe(gulp.dest(paths.dest.esm));
}
const build = gulp.parallel(buildScripts, copyLess);
// ...
Наблюдаемыйlib
каталог, можно найтиless
файл был скопирован вalert/style
Под содержанием.
lib
├── alert
│ ├── alert.js
│ ├── index.js
│ ├── interface.js
│ └── style
│ ├── index.js
│ └── index.less # less文件
└── index.js
Некоторые учащиеся могли обнаружить проблему: если пользователь не используетless
препроцессор, использующийsass
программа или даже роднаяcss
план, существующий план не будет работать. После анализа выделяют следующие 3 схемы предварительного отбора:
- Уведомить пользователей об увеличении
less-loader
; - упаковать полный
css
файл, продолжитьПолная суммаПредставлять; - Обеспечить отдельный
style/css.js
файл, который импортирует компонентыcss
файловые зависимости, неless
Зависимость, базовая библиотека компонентов сглаживает различия.
Вариант 1 приведет к увеличению затрат на использование.
Сценарий 2 не может импортировать файлы стилей по запросу (впоследствии вumd
Мы также предоставляем этот файл стиля при упаковке).
Вышеупомянутые два варианта действительно являются последним средством (голос за кадром: если вы используетеcss in js
Не такое уж и дерьмо).
Схема 3 больше соответствует текущей ситуации,antd
Эта схема также используется.
В процессе сборки библиотеки компонентов возникает проблема, которая меня давно мучает: зачем мнеalert/style/index.js
представлятьless
файл илиalert/style/css.js
представлятьcss
документ?
ответУправление зависимостями стилей.
Предположим, существует следующий сценарий: введение<Button />
,<Button />
зависел от<Icon />
, пользователю необходимо вручную импортировать стиль вызываемого компонента (<Button />
) и зависимые от него стили компонентов (<Icon />
), крайне проблематично столкнуться со сложными компонентами, поэтому разработчики библиотек компонентов могут предоставить такую возможность.js
файл, пользователь вручную импортирует этотjs
файл, вы можете импортировать стили соответствующего компонента и его зависимых компонентов.
Продолжить наше путешествие.
сгенерировать css-файл
Установите связанные зависимости.
yarn add gulp-less gulp-autoprefixer gulp-cssnano --dev
Будуless
файл для создания соответствующегоcss
файл, вgulpfile.js
увеличить вless2css
Задача.
// ...
/**
* 生成css文件
*/
function less2css() {
return gulp
.src(paths.styles)
.pipe(less()) // 处理less文件
.pipe(autoprefixer()) // 根据browserslistrc增加前缀
.pipe(cssnano({ zindex: false, reduceIdents: false })) // 压缩
.pipe(gulp.dest(paths.dest.lib))
.pipe(gulp.dest(paths.dest.esm));
}
const build = gulp.parallel(buildScripts, copyLess, less2css);
// ...
воплощать в жизньyarn build
, компонентstyle
каталог уже существуетcss
файл.
Далее нам понадобитсяalert/style/css.js
чтобы помочь пользователям представитьcss
документ.
сгенерировать css.js
ссылка здесьantd-toolsреализация: в обработкеscripts
задача, стопstyle/index.js
, сгенерироватьstyle/css.js
, и представитless
Суффикс файла изменен наcss
.
Установите связанные зависимости.
yarn add through2 --dev
gulpfile.js
// ...
/**
* 编译脚本文件
* @param {*} babelEnv babel环境变量
* @param {*} destDir 目标目录
*/
function compileScripts(babelEnv, destDir) {
const { scripts } = paths;
process.env.BABEL_ENV = babelEnv;
return gulp
.src(scripts)
.pipe(babel()) // 使用gulp-babel处理
.pipe(
through2.obj(function z(file, encoding, next) {
this.push(file.clone());
// 找到目标
if (file.path.match(/(\/|\\)style(\/|\\)index\.js/)) {
const content = file.contents.toString(encoding);
file.contents = Buffer.from(cssInjection(content)); // 文件内容处理
file.path = file.path.replace(/index\.js/, 'css.js'); // 文件重命名
this.push(file); // 新增该文件
next();
} else {
next();
}
}),
)
.pipe(gulp.dest(destDir));
}
// ...
cssInjection
Реализация:
gulpfile.js
/**
* 当前组件样式 import './index.less' => import './index.css'
* 依赖的其他组件样式 import '../test-comp/style' => import '../test-comp/style/css.js'
* 依赖的其他组件样式 import '../test-comp/style/index.js' => import '../test-comp/style/css.js'
* @param {string} content
*/
function cssInjection(content) {
return content
.replace(/\/style\/?'/g, "/style/css'")
.replace(/\/style\/?"/g, '/style/css"')
.replace(/\.less/g, '.css');
}
Затем упакуйте его, вы можете увидеть компонентыstyle
создается в каталогеcss.js
файл, введение также является предыдущим шагомless
преобразованныйcss
документ.
lib/alert
├── alert.js
├── index.js
├── interface.js
└── style
├── css.js # 引入index.css
├── index.css
├── index.js
└── index.less
нагрузка по требованию
добавить в package.jsonsideEffects
атрибуты, подходитES module
достигатьtree shaking
эффект (отметить зависящий от стиля файл какside effects
, чтобы не удалить по ошибке).
// ...
"sideEffects": [
"dist/*",
"esm/**/style/*",
"lib/**/style/*",
"*.less"
],
// ...
Представьте следующим образом, вы можете сделатьjs
Детали загружаются по запросу, но стили нужно импортировать вручную:
import { Alert } from 'happy-ui';
import 'happy-ui/esm/alert/style';
Его также можно импортировать с помощью:
import Alert from 'happy-ui/esm/alert'; // or import Alert from 'happy-ui/lib/alert';
import 'happy-ui/esm/alert/style'; // or import Alert from 'happy-ui/lib/alert';
Приведенный выше способ импорта файлов стилей не очень элегантен, и он импортируется напрямую.Полная суммаФайлы стилей далеки от того, что они предназначены для загрузки по требованию.
Пользователи могут использоватьbabel-plugin-importчтобы помочь и уменьшить объем написания кода.
import { Alert } from 'happy-ui';
⬇️
import Alert from 'happy-ui/lib/alert';
import 'happy-ui/lib/alert/style';
сгенерировать умд
«Упаковка» в прямом смысле, генерирующая полный объемjs
файл иcss
Файл импортируется пользователем вне цепочки. выберите здесьrollup
упаковать.
Отверстие осталось заполнить.
To be Continued...