Минимальный фронтовый Dockerfile с поддержкой Brotli
Brotli — алгоритм сжатия данных. Наравне с gzip, позволяет уменьшить размер передаваемых по сети данных, но делает это несколько эффективнее. Если gzip можно использовать “из коробки”, то вот brotli приходится настраивать руками.
Для включения, также, необходимо добавить несколько строк в ваш nginx.conf:
#development #frontend #docker #nginx
Brotli — алгоритм сжатия данных. Наравне с gzip, позволяет уменьшить размер передаваемых по сети данных, но делает это несколько эффективнее. Если gzip можно использовать “из коробки”, то вот brotli приходится настраивать руками.
# build container
FROM node:20-alpine AS builder
WORKDIR /app
COPY . .
RUN npm i
RUN npm run build
# runtime container
FROM alpine
RUN apk add brotli nginx nginx-mod-http-brotli
COPY --from=builder /app/dist /usr/share/nginx/html
COPY ./nginx/nginx.conf /etc/nginx/http.d/default.conf
CMD ["nginx", "-g", "daemon off;"]
EXPOSE 80
EXPOSE 443
Для включения, также, необходимо добавить несколько строк в ваш nginx.conf:
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/javascript application/json;
#development #frontend #docker #nginx
🔥5
Код 10 летней давности 😱
Наткнулся на свою реализацию всем известной игры “Змейка”, было такое тестовое задание. Коду почти 10 лет, там даже es6 ещё нет. 😅
Работает как на клавиатуре (на стрелочках), так и на телефонах (тап по сторонам игрового поля).
Код: https://github.com/SanichKotikov/test-snake-game/blob/master/index.html
Игра: https://sanichkotikov.github.io/test-snake-game/
П.С. Кто помнит для чего эта точка с запятой в начале кода? 😅
Наткнулся на свою реализацию всем известной игры “Змейка”, было такое тестовое задание. Коду почти 10 лет, там даже es6 ещё нет. 😅
Работает как на клавиатуре (на стрелочках), так и на телефонах (тап по сторонам игрового поля).
Код: https://github.com/SanichKotikov/test-snake-game/blob/master/index.html
Игра: https://sanichkotikov.github.io/test-snake-game/
П.С. Кто помнит для чего эта точка с запятой в начале кода? 😅
;(function (){
// code
})();
🔥4
Минимальный “джентльменский набор” для стилизации разметки
Есть куча разных подходов, языков и инструментов для стилизации разметки, но мой выбор всегда был, и наверное будет, в пользу чистого CSS. Почему именно так — отдельный вопрос, сейчас не об этом.
CSS modules
Для начала, необходимо решить проблему именования. Нет именования — нет проблемы. 😎 CSS modules полностью закрывает этот вопрос, и избавляет нас от необходимости придумывать уникальные имена CSS классов в рамках проекта. Например, в Vite конфигурация может выглядеть следующим образом:
CSS custom properties + CSS nesting
Кастомные свойства, они же переменные, поддерживаются всеми браузерами с 2017 года. Сегодня их можно использовать как есть, без каких либо дополнительных инструментов. Например, для поддержки нескольких тем оформления, или просто как глобальные константы:
Для вложенных селекторов существует спецификация CSS Nesting, которая поддерживается основными браузерами с 2023 года. На данный момент такой поддержки всё ещё маловато, поэтому тут не обойтись без инструментов, например npm пакета postcss-nesting.
PostCSS + Autoprefixer
Ну и конечно, куда же без этой парочки. Как бы ни старались разработчики браузеров, всё ещё существуют CSS свойства с разными префиксами. Нет ни какой пользы в том, чтобы писать их самостоятельно, лучше доверить это дело автоматизации.
Вот и весь набор! Всё максимально просто и компактно.
#frontend #development #npm #css #postcss
Есть куча разных подходов, языков и инструментов для стилизации разметки, но мой выбор всегда был, и наверное будет, в пользу чистого CSS. Почему именно так — отдельный вопрос, сейчас не об этом.
CSS modules
Для начала, необходимо решить проблему именования. Нет именования — нет проблемы. 😎 CSS modules полностью закрывает этот вопрос, и избавляет нас от необходимости придумывать уникальные имена CSS классов в рамках проекта. Например, в Vite конфигурация может выглядеть следующим образом:
css: {
modules: {
localsConvention: 'dashesOnly',
},
},
CSS custom properties + CSS nesting
Кастомные свойства, они же переменные, поддерживаются всеми браузерами с 2017 года. Сегодня их можно использовать как есть, без каких либо дополнительных инструментов. Например, для поддержки нескольких тем оформления, или просто как глобальные константы:
:root {
--color-primary: #7f56d9;
--color-accent: #89e469;
--color-warning: #e9ae56;
--color-danger: #ff0000;
}
Для вложенных селекторов существует спецификация CSS Nesting, которая поддерживается основными браузерами с 2023 года. На данный момент такой поддержки всё ещё маловато, поэтому тут не обойтись без инструментов, например npm пакета postcss-nesting.
PostCSS + Autoprefixer
Ну и конечно, куда же без этой парочки. Как бы ни старались разработчики браузеров, всё ещё существуют CSS свойства с разными префиксами. Нет ни какой пользы в том, чтобы писать их самостоятельно, лучше доверить это дело автоматизации.
import nesting from 'postcss-nesting';
import autoprefixer from 'autoprefixer';
export default {
plugins: [
nesting({}),
autoprefixer({ flexbox: 'no-2009' }),
],
};
Вот и весь набор! Всё максимально просто и компактно.
#frontend #development #npm #css #postcss
👍4
CSS content-visibility
Оптимизировать скорость отображения большого количества элементов можно не только через Javascript. Хороший пример — CSS свойство content-visibility, которое напрямую влияет на такие этапы как recalculate styles, layout и paint. Для примера, рассмотрим простой SolidJS код отображения списка из 1898 emoji разделённых на 9 групп:
https://github.com/SanichKotikov/solid-emoji-demo
(компонент EmojiList)
Если запустить приведённый выше пример, и посмотреть во вкладку Performance инструментов разработки браузера, вы увидите что бОльшая часть времени уходит не на выполнение Javascript, а на тот самый layout. Происходит это потому, что браузеру нужно “посчитать” весь список полностью, несмотря на то что пользователь видит только малую его часть. Вот тут нам и пригодится content-visibility, с помощью которого мы можем “попросить” браузер не считать то, что пользователь ещё не видит (в нашем случае группы).
Обратите внимание, что “спрятанный” таким образом контент остаётся достижимым для таких операций как поиск на странице, в отличие от виртуализации на Javascript.
Важное примечание: Цифры приведённые ниже — MacBook M1. Для сравнения, iPhone 12 pro в режиме сбережения энергии будет в 4 раза медленнее! Кстати, именно такое замедление CPU является рекомендованным в Chrome.
Добавим оптимизацию и посмотрим что изменится.
Кстати, без свойства contain-intrinsic-size, которое “бронирует” место под содержимое групп, “магии” не получится.
По итогу, можно сказать что “двумя строчками CSS” мы сократили время отображения списка на ~34%. Да, можно сократить ещё, но об этом в другой раз.
П.С. Вычислять высоту через JS не обязательно, можно заранее посчитать и указать среднее значение в CSS. Однако в таком случае бегунок прокрутки может иногда прыгать.
#frontend #development #solidjs #css #performance
Оптимизировать скорость отображения большого количества элементов можно не только через Javascript. Хороший пример — CSS свойство content-visibility, которое напрямую влияет на такие этапы как recalculate styles, layout и paint. Для примера, рассмотрим простой SolidJS код отображения списка из 1898 emoji разделённых на 9 групп:
https://github.com/SanichKotikov/solid-emoji-demo
(компонент EmojiList)
Если запустить приведённый выше пример, и посмотреть во вкладку Performance инструментов разработки браузера, вы увидите что бОльшая часть времени уходит не на выполнение Javascript, а на тот самый layout. Происходит это потому, что браузеру нужно “посчитать” весь список полностью, несмотря на то что пользователь видит только малую его часть. Вот тут нам и пригодится content-visibility, с помощью которого мы можем “попросить” браузер не считать то, что пользователь ещё не видит (в нашем случае группы).
Обратите внимание, что “спрятанный” таким образом контент остаётся достижимым для таких операций как поиск на странице, в отличие от виртуализации на Javascript.
Важное примечание: Цифры приведённые ниже — MacBook M1. Для сравнения, iPhone 12 pro в режиме сбережения энергии будет в 4 раза медленнее! Кстати, именно такое замедление CPU является рекомендованным в Chrome.
Recalculate: ~6 ms
Layout: ~24 ms
Paint: ~4 ms
Общее время: ~56 ms
Добавим оптимизацию и посмотрим что изменится.
{
'content-visibility': 'auto',
'contain-intrinsic-size': `auto ${size}px`,
}
Recalculate: ~2 ms
Layout: ~12 ms
Paint: ~2 ms
Общее время: ~37 ms
Кстати, без свойства contain-intrinsic-size, которое “бронирует” место под содержимое групп, “магии” не получится.
По итогу, можно сказать что “двумя строчками CSS” мы сократили время отображения списка на ~34%. Да, можно сократить ещё, но об этом в другой раз.
П.С. Вычислять высоту через JS не обязательно, можно заранее посчитать и указать среднее значение в CSS. Однако в таком случае бегунок прокрутки может иногда прыгать.
#frontend #development #solidjs #css #performance
GitHub
GitHub - SanichKotikov/solid-emoji-demo
Contribute to SanichKotikov/solid-emoji-demo development by creating an account on GitHub.
👍5
TypeScript обещает ускориться в 10 раз к 7 версии… Что тут ещё сказать, ждём! 😎
https://devblogs.microsoft.com/typescript/typescript-native-port/
https://devblogs.microsoft.com/typescript/typescript-native-port/
Microsoft News
A 10x Faster TypeScript
Embarking on a native port of the existing TypeScript compiler and toolset to achieve a 10x performance speed-up.
🔥4
Интересный момент при замере performance в Chrome
Обратил внимание на интересный момент во вкладке Performance, где при использовании кнопки “Record and reload” фаза Layout существенно медленнее чем при обычной записи. Скорее всего причина в “накладных расходах”, таких как замеры Largest Contentful Paint, Cumulative Layout Shift и т.п. При этом, в скорости выполнения JS разницы не заметил.
Обратил внимание на интересный момент во вкладке Performance, где при использовании кнопки “Record and reload” фаза Layout существенно медленнее чем при обычной записи. Скорее всего причина в “накладных расходах”, таких как замеры Largest Contentful Paint, Cumulative Layout Shift и т.п. При этом, в скорости выполнения JS разницы не заметил.
В продолжении темы оптимизации
В прошлом посте я рассказывал про оптимизацию средствами CSS, на примере конкретного свойства. Пришло время поговорить и про JS.
Возьмём всё тот же код с использованием SolidJS: https://github.com/SanichKotikov/solid-emoji-demo
Примечание: В этот раз все цифры будут указаны с учётом 4х кратного замедления, т.к. они ближе к цифрам в реальных условиях. Плюс, замеры производились на production сборке.
В качестве отправной точки возьмём код, в котором стили объявлены через свойство style из JS:
Выносим всю стилизацию, кроме contain-intrinsic-height, из JS в CSS файл, и сразу получаем следующий результат:
Выполнение JS кода, а также recalculate style, сократились примерно в двое. Кстати, если использовать emotion/css, то это практически ни как не повлияет на изначальные цифры. Делаем очевидный вывод — стилизация через JS (в рантайме) имеет свои накладные расходы.
Интересно, что если унести и contain-intrinsic-height в CSS, само собой с каким-то усреднённым значением, то это может замедлить Layout до ~24 ms.
Как ещё можно сократить время выполнения JS в таком, казалось бы, простом коде? Избавимся от “конструкций” библиотеки (в нашем случае SolidJS), там где это возможно.
Во-первых, избавимся от отдельного компонента EmojiButton, т.к. в нём нет ни какого практического смысла. Запомните, чем больше в проекте компонентов, тем он медленнее, в том числе и на этапе сборки.
Во-вторых, заменим For на обычный .map, т.к. список emoji статический, и в этом компоненте тут нет какого-то особого смысла. Попутно можно удалить и createMemo, по той же причине. Кстати, компонент Index медленнее чем For.
В итоге, получаем ещё немного прироста в выполнении JS:
П.С. Изменения можно посмотреть в том же репозитории, ветки css и js.
#development #performance #solidjs #javascript
В прошлом посте я рассказывал про оптимизацию средствами CSS, на примере конкретного свойства. Пришло время поговорить и про JS.
Возьмём всё тот же код с использованием SolidJS: https://github.com/SanichKotikov/solid-emoji-demo
Примечание: В этот раз все цифры будут указаны с учётом 4х кратного замедления, т.к. они ближе к цифрам в реальных условиях. Плюс, замеры производились на production сборке.
В качестве отправной точки возьмём код, в котором стили объявлены через свойство style из JS:
Script ~54 ms
Recalculate: ~7 ms
Layout: ~19 ms
PrePaint: ~2 ms
Paint: ~7 ms
Выносим всю стилизацию, кроме contain-intrinsic-height, из JS в CSS файл, и сразу получаем следующий результат:
Script ~24 ms
Recalculate: ~3 ms
Layout: ~19 ms
PrePaint: ~1.3 ms
Paint: ~6.3 ms
Выполнение JS кода, а также recalculate style, сократились примерно в двое. Кстати, если использовать emotion/css, то это практически ни как не повлияет на изначальные цифры. Делаем очевидный вывод — стилизация через JS (в рантайме) имеет свои накладные расходы.
Интересно, что если унести и contain-intrinsic-height в CSS, само собой с каким-то усреднённым значением, то это может замедлить Layout до ~24 ms.
Как ещё можно сократить время выполнения JS в таком, казалось бы, простом коде? Избавимся от “конструкций” библиотеки (в нашем случае SolidJS), там где это возможно.
Во-первых, избавимся от отдельного компонента EmojiButton, т.к. в нём нет ни какого практического смысла. Запомните, чем больше в проекте компонентов, тем он медленнее, в том числе и на этапе сборки.
Во-вторых, заменим For на обычный .map, т.к. список emoji статический, и в этом компоненте тут нет какого-то особого смысла. Попутно можно удалить и createMemo, по той же причине. Кстати, компонент Index медленнее чем For.
В итоге, получаем ещё немного прироста в выполнении JS:
Script ~19 ms
П.С. Изменения можно посмотреть в том же репозитории, ветки css и js.
#development #performance #solidjs #javascript
GitHub
GitHub - SanichKotikov/solid-emoji-demo
Contribute to SanichKotikov/solid-emoji-demo development by creating an account on GitHub.
Data Flow и модификация данных
Data Flow (поток данных) — концепция, описывающая движение данных между различными компонентами системы.
Желательно избегать модификации данных на всём пути этого потока, однако бывают различные ситуации, в том числе и бизнес требования, когда модифицировать данные всё же приходится. Самый простой пример — сортировка. И вот тут возникает главный вопрос — а где именно эти данные модифицировать? Универсальный (простой) ответ — максимально близко к тому месту, где это требуется.
Например, если речь идёт о какой-то локальной сортировке в одном или нескольких UI компонентах, тогда желательно это делать именно там. Грубой ошибкой, в данном случае, будет сортировка в модуле API.
И наоборот, если модификация продиктована разницей именования полей между фронтом и беком, идеальным местом будет модуль API.
Data Flow (поток данных) — концепция, описывающая движение данных между различными компонентами системы.
Желательно избегать модификации данных на всём пути этого потока, однако бывают различные ситуации, в том числе и бизнес требования, когда модифицировать данные всё же приходится. Самый простой пример — сортировка. И вот тут возникает главный вопрос — а где именно эти данные модифицировать? Универсальный (простой) ответ — максимально близко к тому месту, где это требуется.
Например, если речь идёт о какой-то локальной сортировке в одном или нескольких UI компонентах, тогда желательно это делать именно там. Грубой ошибкой, в данном случае, будет сортировка в модуле API.
И наоборот, если модификация продиктована разницей именования полей между фронтом и беком, идеальным местом будет модуль API.
🔥1
Внутренние отступы кнопок в мобильном Safari
Столкнулся с занятной особенностью мобильного Safari. Если явно не указать внутренние боковые отступы (paddings) у элемента button, браузер проставит их автоматически отталкиваясь от размера шрифта.
Кстати, если вы хотите полностью сбросить стили кнопок по умолчанию:
#development #css #safari
Столкнулся с занятной особенностью мобильного Safari. Если явно не указать внутренние боковые отступы (paddings) у элемента button, браузер проставит их автоматически отталкиваясь от размера шрифта.
Кстати, если вы хотите полностью сбросить стили кнопок по умолчанию:
button {
padding: 0;
margin: 0;
font-size: inherit;
border: none;
background: none;
appearance: none;
}
#development #css #safari
👍3🔥1
Vite vs Webpack: нюанс с React.memo()
Недавно обратил внимание на то, что Vite включает в бандл слишком много неиспользуемого кода. Чтобы выяснить, почему так происходит, я создал простой JS проект, в котором использовал последние (на момент написания) версии Vite и Webpack, с минимальной конфигурацией.
Важно: В этом примере не использовался параметр sideEffects, про него напишу отдельно.
Итак, есть некий модуль, из которого торчит два компонента:
Однако, используется только один — Test. И тут главный вопрос: что произойдёт с TestMemo при сборке проекта? Логично предположить, что раз он не используется, то и в бандл он не попадёт. Но это не совсем так!
Фрагмент сборки от Webpack:
Фрагмент сборки от Vite:
Vite, в отличие от Webpack, оставляет в бандле все компоненты которые обёрнуты в memo, forwardRef и подобные функции. И как следствие, он оставляет и всё что используется из этих компонентов. В общем, в большом проекте это может быть довольно много кода, который может тянуть внешние библиотеки и т.д. и т.п.
#development #frontend #webpack #vite
Недавно обратил внимание на то, что Vite включает в бандл слишком много неиспользуемого кода. Чтобы выяснить, почему так происходит, я создал простой JS проект, в котором использовал последние (на момент написания) версии Vite и Webpack, с минимальной конфигурацией.
Важно: В этом примере не использовался параметр sideEffects, про него напишу отдельно.
Итак, есть некий модуль, из которого торчит два компонента:
// Простой компонент
export { Test } from './test';
// Компонент обёрнутый в React.memo
export { TestMemo } from './test-memo';
Однако, используется только один — Test. И тут главный вопрос: что произойдёт с TestMemo при сборке проекта? Логично предположить, что раз он не используется, то и в бандл он не попадёт. Но это не совсем так!
Фрагмент сборки от Webpack:
function f() {
return (0, d.jsx)("p", {children: "TEST"})
}
Фрагмент сборки от Vite:
function a() {
return e.jsx("p", {children: "TEST"})
}
// Пу пу пу…
t.memo(() => e.jsx("p", {children: "MEMO"}));
Vite, в отличие от Webpack, оставляет в бандле все компоненты которые обёрнуты в memo, forwardRef и подобные функции. И как следствие, он оставляет и всё что используется из этих компонентов. В общем, в большом проекте это может быть довольно много кода, который может тянуть внешние библиотеки и т.д. и т.п.
#development #frontend #webpack #vite
🔥4
Children в SolidJS и порядок выполнения
Недавно столкнулся с не совсем очевидным моментом, связанным с props.children в SolidJS. Для понимания проблемы возьмём вот такой код:
Примечание: Опустим момент, что компонент Wrapper не реактивный, сейчас нас это не интересует.
Вопреки ожиданиям, компоненты выполнятся в следующем порядке: App > Wrapper > Content > Provider. В результате чего, контекст из Provider будет недоступен в компоненте Content. Чтобы понять, что пошло не так, давайте посмотрим во что превращается JSX при сборке проекта:
Параметр children превратился в getter функцию, которая будет выполнена при любой попытке чтения! Например, при передаче в качестве аргумента в функцию:
Очевидным решением проблемы, в данном случае, будет замена интерфейса параметра children компонента Wrapper, с JSX на функцию, вызов которой вернёт этот самый JSX:
#development #frontend #solidjs #javascript #jsx
Недавно столкнулся с не совсем очевидным моментом, связанным с props.children в SolidJS. Для понимания проблемы возьмём вот такой код:
function Wrapper(props) {
return props.when
? props.wrap(props.children, props.when)
: props.children;
}
function App() {
return (
<Wrapper
when={true}
wrap={(content) => (
<Provider>{content}</Provider>
)}
>
<Content />
</Wrapper>
);
}
Примечание: Опустим момент, что компонент Wrapper не реактивный, сейчас нас это не интересует.
Вопреки ожиданиям, компоненты выполнятся в следующем порядке: App > Wrapper > Content > Provider. В результате чего, контекст из Provider будет недоступен в компоненте Content. Чтобы понять, что пошло не так, давайте посмотрим во что превращается JSX при сборке проекта:
function App() {
return _$jsx(Wrapper, {
when: true,
wrap: content => _$jsx(Provider, {
children: content
}),
get children() {
return _$jsx(Content, {});
}
});
}
Параметр children превратился в getter функцию, которая будет выполнена при любой попытке чтения! Например, при передаче в качестве аргумента в функцию:
props.wrap(props.children, props.when)
Очевидным решением проблемы, в данном случае, будет замена интерфейса параметра children компонента Wrapper, с JSX на функцию, вызов которой вернёт этот самый JSX:
function App() {
return (
<Wrapper
when={true}
wrap={(content) => (
<Provider>{content()}</Provider>
)}
>
{() => <Content />}
</Wrapper>
);
}
#development #frontend #solidjs #javascript #jsx
🔥2
React != SolidJS на примере эффектов
Несмотря на высокую “внешнюю” схожесть, под капотом эти библиотеки отличаются как чёрное от белого. В отличие от React с его предсказуемым жизненным циклом, компоненты Solid выполняются только один раз, а дальше в дело вступает реактивная система, которая выполняет только то, что действительно должно быть выполнено, и делает это оптимально.
П.С. Менять состояние из эффектов — довольно плохая идея и лучше такого кода избегать, в React так точно.
#development #frontend #solidjs #react #javascript
Несмотря на высокую “внешнюю” схожесть, под капотом эти библиотеки отличаются как чёрное от белого. В отличие от React с его предсказуемым жизненным циклом, компоненты Solid выполняются только один раз, а дальше в дело вступает реактивная система, которая выполняет только то, что действительно должно быть выполнено, и делает это оптимально.
П.С. Менять состояние из эффектов — довольно плохая идея и лучше такого кода избегать, в React так точно.
#development #frontend #solidjs #react #javascript
🔥1
На счёт предыдущего поста. Если очень сильно хочется как в SolidJS но не хочется/можется уйти от React, то есть вот такой пакет: https://www.npmjs.com/package/@preact/signals-react
🔥1
Причина закрытия WebSocket соединения
Если вы работали с WebSocket без каких либо обёрток, возможно вы обратили внимание, что метод close может принимать два параметра: код и причину закрытия. А CloseEvent, в свою очередь, оба эти значения может содержать.
Однако, этот код не гарантирует что в логе будет 'Reason'! А всё потому, что при вызове метода close, сначала отправляется соответствующая команда на сервер, который кстати может и не ответить. Но даже если он ответил, нет гарантий что он вернёт нам эту же причину.
В общем, CloseEvent.reason — причина закрытия с сервера, поэтому там может быть всё что угодно.
П.С. Есть ещё CloseEvent.wasClean, по которому можно понять было ли соединение закрыто “чисто” или что-то пошло не так.
#development #frontend #javascript
Если вы работали с WebSocket без каких либо обёрток, возможно вы обратили внимание, что метод close может принимать два параметра: код и причину закрытия. А CloseEvent, в свою очередь, оба эти значения может содержать.
const socket = new WebSocket(url);
socket.onclose = (event) => {
console.log(event.reason);
};
socket.close(1000, 'Reason');
Однако, этот код не гарантирует что в логе будет 'Reason'! А всё потому, что при вызове метода close, сначала отправляется соответствующая команда на сервер, который кстати может и не ответить. Но даже если он ответил, нет гарантий что он вернёт нам эту же причину.
В общем, CloseEvent.reason — причина закрытия с сервера, поэтому там может быть всё что угодно.
П.С. Есть ещё CloseEvent.wasClean, по которому можно понять было ли соединение закрыто “чисто” или что-то пошло не так.
#development #frontend #javascript
👍2👎1
До кучи, вот небольшое приложение https://github.com/SanichKotikov/ws-test-app/ Писал чтобы потестировать как WebSocket будет себя вести на мобильных устройствах, в том числе в PWA. Там же есть ссылка на уже развёрнутое приложение.
GitHub
GitHub - SanichKotikov/ws-test-app
Contribute to SanichKotikov/ws-test-app development by creating an account on GitHub.
👍2
Принудительное выполнение компонента в SolidJS
Помним, что компоненты в SolidJS, в отличие от React, выполняются только “один” раз. Однако, бывают случаи когда необходимо выполнить компонент “заново” при изменении каких-то данных. Например, нужно полностью обновить форму редактирования при выборе другого блюда:
Параметр keyed компонента Show как раз для этого и предназначен. При этом, в параметре when необходимо указать значение, при изменении которого произойдёт повторное выполнение.
#development #frontend #javascript #solidjs
Помним, что компоненты в SolidJS, в отличие от React, выполняются только “один” раз. Однако, бывают случаи когда необходимо выполнить компонент “заново” при изменении каких-то данных. Например, нужно полностью обновить форму редактирования при выборе другого блюда:
<Resource data={dishData} onReload={dishActions.refetch}>
{(dish) => (
<Show keyed when={dish().id}>
<DishForm
dish={dish()}
categories={categories()}
onSubmit={onDishSave}
/>
</Show>
)}
</Resource>
Параметр keyed компонента Show как раз для этого и предназначен. При этом, в параметре when необходимо указать значение, при изменении которого произойдёт повторное выполнение.
#development #frontend #javascript #solidjs
🔥1
TypeScript + .filter(Boolean)
Тип переменной foo будет соответствовать
Обычно предлагается следующее решение:
Но есть вариант получше:
Теперь
П.С. Есть аналогичный “хак” и для Object.keys (хотя он и не совсем корректен):
#development #frontend #typescript
const numbers = [1, 2, null, void 0, 3];
const foo = numbers.filter(Boolean);
Тип переменной foo будет соответствовать
(number | null | undefined)[], хотя в действительности ни null ни undefined в массиве не будет.Обычно предлагается следующее решение:
numbers.filter((n): n is number => !!n);
Но есть вариант получше:
// global.d.ts
type Falsy = false | '' | 0 | 0n | null | undefined;
type Truthy<T> = T extends Falsy ? never : T;
interface Array<T> {
filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];
filter<S extends T>(predicate: BooleanConstructor, thisArg?: any): Truthy<S>[];
}
interface ReadonlyArray<T> {
filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];
filter<S extends T>(predicate: BooleanConstructor, thisArg?: any): Truthy<S>[];
}
Теперь
numbers.filter(Boolean) будет возвращать number[].П.С. Есть аналогичный “хак” и для Object.keys (хотя он и не совсем корректен):
// global.d.ts
interface ObjectConstructor {
keys<T extends {}>(obj: T): ReadonlyArray<keyof T>;
}
#development #frontend #typescript
👍2🔥2
Бизнес логика vs функциональное мышление
Бизнес логика — весьма абстрактное понятие. Разработчики до сих пор продолжаются “сраться” на тему того, что считать бизнес логикой, а самое главное где она должна быть. Как один из примеров, предлагается держать бизнес логику исключительно в “умных” компонентах.
Напомню базовое определение:
> Бизнес логика — совокупность правил, принципов, зависимостей поведения объектов предметной области.
Под него подходят, как сложные вычисления на беке, так и правила по которым устанавливается размер и цвет кнопок на фронте. В данном контексте довольно сложно говорить о том, чтобы держать бизнес логику только в “умных” компонентов. При таком подходе, их количество будет стремиться к бесконечности, а для “глупых” может не остаться места.
Не знаю как вас, но меня всегда смущала эта широта трактовки бизнес логики. И сложность эта говорит о том, что возможно этот термин вообще стоит обходить стороной, и уж тем более не завязывать на него какие-то правила построения приложения.
К тому же, есть отличная альтернатива — функциональное мышление (проектирование), о котором я писал (https://t.me/around_dev/48) не так давно. Этот подход подразумевает разделение всего кода на три составляющие: данные, вычисления и действия. При этом, деление на “умные” и “глупые” компоненты прекрасно ложится на этот подход, где глупые компоненты это вычисления, а умные — действия.
#development
Бизнес логика — весьма абстрактное понятие. Разработчики до сих пор продолжаются “сраться” на тему того, что считать бизнес логикой, а самое главное где она должна быть. Как один из примеров, предлагается держать бизнес логику исключительно в “умных” компонентах.
Напомню базовое определение:
> Бизнес логика — совокупность правил, принципов, зависимостей поведения объектов предметной области.
Под него подходят, как сложные вычисления на беке, так и правила по которым устанавливается размер и цвет кнопок на фронте. В данном контексте довольно сложно говорить о том, чтобы держать бизнес логику только в “умных” компонентов. При таком подходе, их количество будет стремиться к бесконечности, а для “глупых” может не остаться места.
Не знаю как вас, но меня всегда смущала эта широта трактовки бизнес логики. И сложность эта говорит о том, что возможно этот термин вообще стоит обходить стороной, и уж тем более не завязывать на него какие-то правила построения приложения.
К тому же, есть отличная альтернатива — функциональное мышление (проектирование), о котором я писал (https://t.me/around_dev/48) не так давно. Этот подход подразумевает разделение всего кода на три составляющие: данные, вычисления и действия. При этом, деление на “умные” и “глупые” компоненты прекрасно ложится на этот подход, где глупые компоненты это вычисления, а умные — действия.
#development
🔥1