Dioma: Elegant dependency injection container for vanilla JavaScript and TypeScript

Dioma - новая библиотека, реализующая DI контейнеры на JS и TS. Библиотека одновременно имеет очень простое и элегантное API и при этом поддерживает разные способы инстанцирования зависимостей, разные скоупы видимости зависимостей, возможность иметь несколько контейнеров (в том числе child-контейнеры), отслеживает циклические зависимости и умеет в асинхронное инстанцирование. И все это счастье еще хорошо интегрируется с системой типов в TypeScript.

Рекомендую взглянуть на либку. Лично я, вполне вероятно, когда-нибудь её заиспользую в каком-нибудь пет проекте.

Ниже представляю пару примеров кода, чтобы было представление об API.

Использование DI в классах с применением Singletone скоупа
import { inject, Scopes } from "dioma";

class Garage {
open() {
console.log("garage opened");
}

// Single instance of the class for the entire application
static scope = Scopes.Singleton();
}

class Car {
// injects instance of Garage
constructor(private garage = inject(Garage)) {}

park() {
this.garage.open();
console.log("car parked");
}

// New instance of the class on every injection
static scope = Scopes.Transient();
}

// Creates a new Car and injects Garage
const car = inject(Car);

car.park();


Использование DI не с классами
import { Token } from "dioma";

const token = new Token<string>("Value token");

container.register({ token, value: "Value" });

const value = container.inject(token);

console.log(value); // Value


Использование фабрик
import { Token } from "dioma";

const token = new Token<string>("Factory token");

container.register({ token, factory: (container) => "Value" });

const value = container.inject(token);

console.log(value); // Value


https://github.com/zheksoon/dioma

#development #javascript #dependencyInjection #library #github #recommended
Frontend Development Beyond React: Svelte

React - самый популярный инструмент для разработки во фронтенде, но иногда полезно взглянуть и на другие инструменты, чтобы изучить что-то новое и посмотреть на React с новой стороны. Именно этим и занялся автор текущей статьи - он решил изучить Svelte и во время изучения делал заметки про Svelte, которые превратились в большую статью

В статье рассматриваются разные аспекты Svelte, начиная от компилятора и заканчивая паттернами и крутыми фичами Svelte.

https://itnext.io/frontend-development-beyond-react-svelte-1-3-f47eda22cba5

#development #javascript #svelte
zx 8.0.0

Вышел zx 8.0.0. Напоминаю, что zx - это крутой инструмент от гугла, который позволяет удобно писать cli-cкрипты на js.

Глобальных изменений не так много: пакет теперь в 20 раз меньше за счет сборки на esbuild, возможность выполнять командны синхронно, поддержка AbortController, дропнули ssh

https://github.com/google/zx/releases/tag/8.0.0

#development #javascript #zx #library #google
ESLint v9.0.0 released

Вышел Eslint 9.0.0. Eslint начал активно избавляться от всякого legacy, концентрируясь на том, чтобы быть платформой для линтинга, а не супер-комбайном.

Основные изменения касаются отказа от старого конфига, отказа от nodejs < 18 и еще кучи отказов от всякого легаси, а также немного улучшили API для тестирования

Самая важная часть релиза - это переход на плоский конфиг по-умолчанию. Старый формат конфига предполагал указание плагинов и наследуемых конфигов с помощью строк, который затем eslint резолвит в нод-модули.
module.exports = {
extends: ['someSharedConfig']
plugins: ['somePlugin']
}


Это достаточно простое API, но оно имеет ряд недостатков:
- Нужно подстраиваться под правила резвола eslint. Например, если вы хотите в проекте написать кастомное правило, то надо создать полноценный плагин, который должен резолвится по правилам eslint
- При наследовании конфигов eslint будет резолвить плагины этих конфигов от корня, а не от папки с конфигом. Из-за этого появляются разные неприятные эффекты. Например, некоторые конфиги тянут плагины как свои зависимости и рассчитывают, что эти плагины упадет в корень нод-модулей при установке, но такое случается не всегда. Другая проблема, что 2 конфига могут оба тянуть 1 и тот же плагин разных версий. Тогда в корень не попадет ни первая и ни вторая версия плагина. Это большая проблема, которую обходили разными способами, а сообщество поделилось на несколько лагерей (лично я в том лагере, который предлагает указывать все зависимости переиспользуемого конфига в peer-dependencies, чтобы разработчики сами на стороне приложения разобрались как и что лучше установить)

Теперь же в eslint, как и во всех других основных инструментах, будет возможность явно импортировать конфиги и плагины, что полностью решает все проблемы старой системы.
const react = require("eslint-plugin-react");
module.exports = {
files: ["*.js"],
plugins: {
react
},
rules: {
"react/jsx-uses-react": "error"
}
};


Также оставлена возможность запускать eslint со старой стратегией обработки конфига, указан особую енву.

Также Eslint делает достаточно смелый шаг и дропает поддержку nodejs < v18.18.

Eslint убирает из стандартной поставке разные форматтеры. Если они кому-то нужны, их можно поставить отдельными npm пакетами

Также убрана возможность писать правила для плагинов в формате функций, теперь все правила должна быть описаны в полном формате

В Eslint есть API для автоматической проверки кастомных правил. Его доработали и теперь оно также умеет:
- Проверяет, что в сообщении об ошибке все плейсхолдеры заполнены
- Проверяет, что саджест а) изменяет код б) меняет код на валидный в) сообщения уникальны
- Проверяет, что output теста отличается от изначального code
- Проверяет, что в тесте проверяется message и саджест (если он предоставляется в ошибке)
- Проверяет, что нет дублирующих тест-кейсов

Также ускорили опцию --quiet, которая выводит только ошибки, за счет того, что правила, помеченные как warn перестали запускаться.

В общем, инструмент развивается и скоро все будем переходить на новый формат конфигов

https://eslint.org/blog/2024/04/eslint-v9.0.0-released/

#development #javascript #eslint #release
Figma Plugins

Статья про особенности написания плагинов для Figma. Статья не очень сильно раскрывает как же писать эти самые плагины и с какими проблемами можно столкнуться при написании плагина. Но зато статья разбирает проблемы sandbox'инга плагинов.

Когда вы разрабатываете инструмент, похожий на Figma, и в которой можно встраивать плагины, у вас определенно возникнет проблема с тем, чтобы как-то ограничить возможности плагинов, чтобы они не могли конфликтовать друг с другом, ломать все приложение или влиять на безопасность.

Для этого можно применить sandboxing. Это когда плагины помещаются в какую-то изолированную песочницу, из которой у них очень ограниченный доступ к внешнему миру. Самый простая реализация sandboxing - это iframe, который общается с родительским приложением через postMessage.

Автор рассматривает системы sandboxing'а в Observable (iframe + postmessage) и Val Town (node-deno-vm) и Figma. В Figma для sandboxing'а используется JS движок QuickJS, который запускается прямо в браузере (и, вероятно, скомпилирован в WASM). На мой взгляд, достаточно прикольное решение.

https://macwright.com/2024/03/29/figma-plugins.html

#development #javascript #figma
DevTools Tips & Tricks

10 полезных фичей в DevTools. Некоторые вы уже могли видеть в тысяче других статей про devtools, но другие фичи выглядят достаточно интересно

Полный список фичей:
- При попытке инспектировать popup существует проблема, когда вы переходите в devtools чтобы кликнуть на HTML, фокус с элемента на странице спадает и popup закрывается. В DevTools есть опция, которая предотвращает сброс фокуса при переходе в DevTools
- Использоване LogPoints вместо console.log
- Эмулирование раскладушек (foldable devices) для тестирования верстки для устройств типа samsung fold, где телефон можно разложить в планшет
- Автокомплит в стилях
- Форматы цветов
- Снимок скриншота в эмуляции устройства с высокой плотностью пикселей. В DevTools в рамках эмуляции устройства можно эмулировать не только размер экрана, но и плотность пикселей
- Просмотр событий для Server Sent Events
- Копирование всех изменений стилей, сделанных для данной страницы в devtools
- Live Expressions - это как watch в дебагере, но выводится сразу в devtools.
- Дебаг горизонтальных скролов.

https://frontendmasters.com/blog/devtools-tips-tricks/

#development #javascript #devtools
Migrating 500+ tests from Mocha to Node.js

Хорошая статья про миграцию Astro c Mocha+chai на тест-раннер от ноды. У Astro 600+ тест-сьютов и 1600+ тестов. Большинство из этих тестов интеграционные. Команда Astro захотела переехать на нативное решение в node.js потому что верят в его развитие

Миграция была сделана в 3 этапа: перевели простой пакет, перевели сложный пакет, перевели все остальное

На первом этапе перевели простой пакет, который позволяет создавать новые astro-проекты через astro create. Этот пакет простой с точки зрения миграциии, потому что там были только юнит-тесты. В целом, миграция прошла гладко и серьезных проблем не обнаружилось:
- Неудобно, что флаги командной строки у nodejs многословные (--test-name-pattern вместо --match или -m)
- указание файлов через glob работает немного по другому
- Многопоточность выключается только программно, а не через флаг. В прочем, начиная с 21 nodejs можно включать и через флаг

Далее команда переводила проект по-сложнее и там появилась более серьезные проблема. Nodejs гарантирует изоляцию тестов через запуск каждого теста в отдельном процессе. Тесты в astro уже хорошо изолированы и процессная изоляция просто замедляла исполнение тестов. Поэтому команда Astro сделала неприятный воркераунд: перед запуском тестов, все тест-файлы объединялись в один, чтобы nodejs стартовал все тесты в одном процессе.

Также есть разница в написании проверок в chai и nodejs.

Например, в chai есть способа сравнения на равенство

import { expect } from "chai";

expect("foo").to.eq("foo")
expect("foo").to.be.eq("foo")
expect("foo").to.equal("foo")
expect("foo").to.be.equal("foo")


В node.js способ всего один, что делает код более консистентным
import { assert } from "node:assert/strict";

assert.equal("foo", "foo")


С другой стороны, в chai можно удобно проверить наличие подстроки в строке
import { expect } from "chai";

expect("It's a fine day").includes("fine")


в Node.js же это придется проверять через string.includes
import assert from "node:assert/strict";

assert.equal("It's a fine day".includes("fine"), true)



Третий этап миграции - это мигрировать все остальные тесты в проекте. Звучит как достаточно объемная работа, но Astro воспользовалась помощью сообщества, которое откликнулось и переписало 300 тест-сьютов за неделю

Итоговый результат:
- Переехали на nodejs test runner и отказались от mocha + chai
- В целом Astro довольны переездом
- Текущее API nodejs не всегда удобное и быстрое, но команда nodejs прислушивается к сообществу и решает эти проблемы


https://astro.build/blog/node-test-migration/

#development #javascript #mocha #nodejs #testing #migration #astro
Node.js 22 is now available!

Вышла Nodejs 22, которая станет LTS-кой осенью.

Основные изменения:
- Новый V8 - WASM GC, Array.fromAsync, методы в Set и хелперы для итераторов
- Компилятор Maglev включен по-дефолту. Это увеличит производительность небольших cli
- С включенным экспериментальным флагом можно require-ить синхронные ES-модули
- node --run запускает скрипты из package.json.
- При работе со стримами используется High Water Mark - это отметка, обозначающая, сколько данных приложение готово принять с потока для обработки. В Nodejs22 дефолтное значение High Water Mark повышено до 64кб.
- node --watch запускает скрипты в watch режиме (переведено из экспериментальной фичи в стабильный функционал)
- Имплементация WebSocket вышла из эксперимента в стабильный пакет
- Добавлен glob и globSync в node:fs

https://nodejs.org/en/blog/announcements/v22-release-announce

#development #javascript #nodejs #release
Announcing TypeScript 5.5 Beta

Выпущен Typescript 5.5 Beta. Ниже опишу основные изменения

Улучшение уточнения типов в предикатах. В канале уже был пост про это, но коротко повторюсь. Часто TypeScript-у нужно было явно указывать, что функция уточняет тип аргумента. Теперь же Typescript это будет понимать сам.

Пример кода, который ведет себя по-разному в 5.4 и 5.5

// 5.4 - nums: (number | null)[]
// 5.5 - nums: number[]
const nums = [1, 2, 3, null, 5].filter(x => x !== null);

nums.push(null); // ok in TS 5.4, error in TS 5.5


Улучшена проверка доступа к полю по индексу. Если TS уверен, что по текущим переменным там будет корректный тип, он не будет кидать ошибку

function f1(obj: Record<string, unknown>, key: string) {
if (typeof obj[key] === "string") {
// Now okay, previously was error
obj[key].toUpperCase();
}
}


Теперь можно импортировать типы в JSDoc через @import. Импортирование типов в JS файл для использования в JSDoc-е - не самая популярная фича (хотя я использую эту фичу несколько раз в год). Раньше необходимо было делать import внутри декларации типа, теперь же можно явно прописать импорт модуля. Легче показать на примера

// в 5.4
/**
* @param {import("./some-module").SomeType} myValue
*/
function doSomething(myValue) {
// ...
}

// в 5.5
/** @import * as someModule from "some-module" */

/**
* @param {someModule.SomeType} myValue
*/
function doSomething(myValue) {
// ...
}


Также теперь TS умеет проверять регулярки на валидность (но только те, что пишутся сразу в коде, а не те, которые создаются через new RegExp).

Изоляция деклараций типов. Библиотеки предоставляют свои типы в .d.ts файлах. Часто так бывает, что для проверки типов необходимо проходить по всем импортам внутри .d.ts, чтобы вывести все типы и убедиться в их корректности. Это может занимать много времени, особенно в больших проектах. Поэтому в TS ввели режим isolatedDeclarations, которые проверяет, что все типы .d.ts выводимы из файла без прыгания по импортам, что значительно ускоряет тайп-чек.

Опять же, разберем на примере
import { add } from "./add";

const x = add(); // ОК: тип не объявлен, но переменная не экспортируется

// ОШИБКА, экспортируется, но тип непонятен
export function foo() {
return x;
}

// OK, тип указан явно
export function foo(): string {
return x;
}

// OK, тип легко выводится
export let x = 10;
// ОК, тип легко выводится
export function y() { return 20; }

// OK, есть `as number`
export function z() { return Math.max(x, y()) as number; }


В tsconfig добавлена поддержка ${configDir} в описании путей. При использовании композиции конфигов была боль с описанием относительных путей т.к. ts обрабатывает их не так, как иногда хочется. Теперь же можно использовать ${configDir} , чтобы указывать пути относительно конфига. Пример использования

{
"compilerOptions": {
"typeRoots": [
"${configDir}/node_modules/@types"
"${configDir}/custom-types"
],
"outDir": "${configDir}/dist"
}
}


Также проведены оптимизации внутри TypeScript. TS стал быстрее собирать проекта на 5-8%, а language server стал работать на 10-20% быстрее. Кроме того размер пакета (архива) снизился 5.5МБ до 3.7МБ

Теперь нельзя переопределить undefined. До 5.5 нельзя было делать type null = any, type number = any и прочие переопределения. Но можно было переопределить type undefined = any. Теперь так нельзя

А также куча других изменений, но самые большие я коротко пересказал

https://devblogs.microsoft.com/typescript/announcing-typescript-5-5-beta/

#development #javascript #typescript
Дайджест за 2024-04-22 - 2024-05-03

ESLint v9.0.0 released
Вышел Eslint 9.0.0. Eslint начал активно избавляться от всякого legacy, концентрируясь на том, чтобы быть платформой для линтинга, а не супер-комбайном.

Основные изменения касаются отказа от старого конфига, отказа от nodejs < 18 и еще кучи отказов от всякого легаси, а также немного улучшили API для тестирования

Figma Plugins
Статья про особенности написания плагинов для Figma. Статья не очень сильно раскрывает как же писать эти самые плагины и с какими проблемами можно столкнуться при написании плагина. Но зато статья разбирает проблемы sandbox'инга плагинов.

Когда вы разрабатываете инструмент, похожий на Figma, и в которой можно встраивать плагины, у вас определенно возникнет проблема с тем, чтобы как-то ограничить возможности плагинов, чтобы они не могли конфликтовать друг с другом, ломать все приложение или влиять на безопасность.

DevTools Tips & Tricks
10 полезных фичей в DevTools. Некоторые вы уже могли видеть в тысяче других статей про devtools, но другие фичи выглядят достаточно интересно

Migrating 500+ tests from Mocha to Node.js
Хорошая статья про миграцию Astro c Mocha+chai на тест-раннер от ноды. У Astro 600+ тест-сьютов и 1600+ тестов. Большинство из этих тестов интеграционные. Команда Astro захотела переехать на нативное решение в node.js потому что верят в его развитие

Миграция была сделана в 3 этапа: перевели простой пакет, перевели сложный пакет, перевели все остальное

Node.js 22 is now available!
Вышла Nodejs 22, которая станет LTS-кой осенью.

Основные изменения:

Announcing TypeScript 5.5 Beta
Выпущен Typescript 5.5 Beta. Ниже опишу основные изменения

Улучшение уточнения типов в предикатах. В канале уже был пост про это, но коротко повторюсь. Часто TypeScript-у нужно было явно указывать, что функция уточняет тип аргумента. Теперь же Typescript это будет понимать сам.


——————————————

Спасибо что читаете, ставите реакции и отмечаетесь в комментариях. Если вы хотите помочь каналу - расскажите о нем своим коллегамдрузьям. Также оставляйте фидбек по формату, материалу и чему-угодно еще 🙂
React 19 Beta

Выпущен React 19 Beta! Обновляться пока рано, но уже можно готовиться к изменениям.

Первое большое изменение - Actions. Команда React не стала мудрить и взяла термин, который используется кучей тулов для менеджмента состояния и начала его использовать. В React-компонентах часто необходимо делать асинхронные действия, например, загружать данные из API. Сейчас в React это можно сделать композицией нескольких useState. А в React 19 можно использовать несколько новых хуков, которые упрощают работу с такими функциями

Пример использования нового API

const [name, setName] = useState("");  
const [error, setError] = useState(null);
const [isPending, startTransition] = useTransition();

const handleSubmit = () => {
startTransition(async () => {
const error = await updateName(name);
if (error) {
setError(error);
return;
}
redirect("/path");
})
};


Кроме useTransition появился еще useActionState, который упрощает работу с экшнами. Также в Form'ы можно прокидывать action-ы

function ChangeName({ name, setName }) {  
const [error, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const error = await updateName(formData.get("name"));
if (error) {
return error;
}
redirect("/path");
return null;
},
null,
);
return (
<form action={submitAction}>
<input type="text" name="name" />
<button type="submit" disabled={isPending}>Update</button>
{error && <p>{error}</p>}
</form>
);
}


Также для удобства добавили хук useOptimistic, который позволяет упростить применение паттерна Optimistic UI. useOptimistic очень похож на useState, но отличается тем, ему на вход приходит эталонное значение и хук в state возвращает оптимистичное значение, пока action, в рамках котого произошел оптимистичный апдейт, не завершится.

function ChangeName({currentName, onUpdateName}) {  
const [optimisticName, setOptimisticName] = useOptimistic(currentName);
const submitAction = async formData => {
const newName = formData.get("name");
setOptimisticName(newName);
const updatedName = await updateName(newName);
onUpdateName(updatedName);
};
return (
<form action={submitAction}>
<p>Your name is: {optimisticName}</p>
<p>
<label>Change Name:</label>
<input
type="text"
name="name"
disabled={currentName !== optimisticName}
/>
</p>
</form>
);
}


Еще один новый хук use, позволяет дождаться промиса внутри компонента. Из особенностей - хук use может нарушать правила хуков и быть вызван внутри if-ов и других условных конструкций

import {use} from 'react';  

function Comments({commentsPromise}) {
// `use` will suspend until the promise resolves.
const comments = use(commentsPromise);
return comments.map(comment => <p key={comment.id}>{comment}</p>);
}

function Page({commentsPromise}) {
// When `use` suspends in Comments,
// this Suspense boundary will be shown.
return (
<Suspense fallback={<div>Click Me Load More...</div>}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
)
}


Наконец-то можно прокидывать ref как prop компонету, без использования forwardRef.

Также добавлено много фичей для серверного рендера, в частности серверные компоненты, серверные экшны и улучшены удобство рендера meta-тегов, style, script async, preload.

Еще из знаковых изменений - корректная поддержка Custom Elements.

Изменений реально много, в рамках поста все не умещается. Основные я показал, но лучше, конечно же, ознакомиться с изменениями лично.

https://react.dev/blog/2024/04/25/react-19

#development #javascript #react #release
Великолепная детективная история
Vitest: invalid JSON syntax found at position -1.

Алло, это канал о витесте? Ну а если серьёзно, то пожалуй столкнулся с одним из самых интересных багов в своей жизни.

Я уже рассказывал, что витест для нас компромиссный опыт и породил экстравагантные практикие в духе «гоняем 100 пайплайнов и проверяем, что не флакает». В общем, задумал я обновить его немного, открыл пул-реквест, погонял те самые 100 пайплайнов — всё зеленое! Мёрджим!

Проходит 2 недели и 60% пайплайнов начинают падать… Разработчики ругаются, тимлид предлагает откатывать, я в замешательстве — работало же! Снова начинаю гонять пайплайны, находим 3 проблемных теста, которые никто не трогал уже полгода. Выключаем — всё снова стабильно и зелено. Начинаю разбираться…

Ошибка выглядит так — Error: Failed to parse JSON file, invalid JSON syntax found at position -1. Спасибо, очень информативно! Собираю такой же докер образ как на CI, тыкаю проблемные тест — ничего. Т.к. проблема воспроизводится только на CI, то решаю запатчить vite через yarn patch, добавив название файла в лог. Сработало — проблемный файл мы генерируем на CI и путь до него известен.

Проверяю содержимое файла до тестов — всё на месте. Проверяю после тестов — и снова всё на месте. Но в тестах почему-то всё так же ломается. И тут я замечаю, что у падающих шардов есть кое-что общее — падает именно первый тест. Смотрю как это работает внутри vite — обычный fs.readFile и JSON.parse. В голову закрадывается страшная идея — а что если это какя-то проблема с файловой системой и одновременным чтением одного файла из нескольких процессов. Ищу ишью в ноде, но ничего прям конкретного не вижу. Уже начинаю писать скрипт для стресс-теста одновременного чтения, чтобы проверить гипотезу и тут в голову приходит идея — а что если кто-то этот файл всё таки перезаписывает?

Проверяю файл через fs.stat сразу после записи и после тестов — даты создания и редактирования отличаются! Смотрю немного в пайплайн и понимаю, что внутри одной из команд мы запускаем генерацию этого файла. Мда! А ларчик просто открывался, как говорится. Убираю лишнюю генерацию и всё сразу же зеленеет.

Для меня было откровением, что при записи файл может принимать какое-то промежуточное состояние. Т.е. не before → after, а before → empty → after.

Рефлексируя о дебаге и что могло упростить поиск, пришёл к такому алгоритму:
1. Если ошибка указывает на неочевидное место, то её сразу же надо патчить, чтобы сузить радиус дебага (в очередной раз могу поругать бандлинг зависимостей в vite, кажется в новой версии зависимости ошибка уже содержит путь до файла).
2. В ошибках нужно искать общие признаки (в моём случае что падает только первый тест в каждом из шардов).
3. Проверять самые простые гипотезы в userland коде, а не искать какие-то баги в больших популярных библиотеках (vite и node в нашем случае)

Остаётся вопрос: а почему ошибка не сразу всплыла, а через 2 недели?
Ответ прост: у нас 4 шарда и не все тесты импортируют проблемный файл. С добавлением/удалением тестов порядок в шардах немного меняется и тесты, которые читают файл, становятся первыми в очереди и попадают в те самые первые 5 секунд, когда мы перезаписываем файл.

Такой вот детектив. А как вы провели вечер пятницы?
Deep Dive into Rspack & Webpack Tree Shaking

Крутой разбор механизма работу Tree-shaking в Webpack. Tree-shaking - это фича бандлеров, которая позволяет при сборке выкидывать код, который не нужен в конечном приложении. Решение о неиспользуемости кода принимается на разных уровнях анализа - как на основе анализа стейтментов в конкретном файле, так и на основе анализа импортов и экспортов

В Webpack tree-shaking реализуется тремя механизмами: оптимизация usedExports, оптимизация sideEffect и оптимизация dead code elimination. Оптимизации разбираются от простых к сложным.

Первая разбираемая оптимизация: Dead Code Elimination (уничтожение мертвого кода). Эта оптимизация работает на двух уровнях.

Первый уровень работает на уровне парсинга модуля - он определяет, какие ветви кода являются очевидно неиспользуемыми - например, вечно ложные ветви кода и неиспользуемые константы

Например

if(false){
console.log(a) // очевидно неиспользуемая ветвь кода, можно удалять
} else {
console.log(b);
}


Второй уровень работает уже на этапе предобработки итоговых файлов и удаляет тот код, который не может быть удален первой стадией обработки.
Например, второй уровень справится вот с этим кодом


function get_one(){
return 1;
}
let res = get_one() + get_one(); // функции заинлайнятся, а результат сложится

if(res != 2){ // сборщик понимает что тут 2 != 2, что неверно
console.log(c);
}


Оптимизация usedExports убирает из кода неиспользуемые экспорты. Бандлер, при сборке проекта, промечает все экспортируемые сущности как используемые и неиспользуемые. Все экспорты, которые в итоге оказались неиспользуемыми, можно смело удалять

Например

// index.js
import { a } from './util'
console.log(a)

// util.js
export const a = true

export const b = false // экспорт будет удален т.к. не используется


Как это работает: webpack помечаем неиспользуемые импорты особой инструкцией /* unused harmony export b */, которая обрабатывается механизмом, который отвечает за dead code elimination. Такие экспорты считаются неиспользуемым кодом, а значит его можно удалить

Поверх этих двух оптимизаций работает оптимизация sideEffects, она позволяет удалить модуль, если а) ни один его экспорт не используется б) он не имеет сайд-эффектов. Пункт а) мы уже разобрали - за это отвечает механизм usedExports, но как определить, есть ли в модуле сайд-эффекты?

Допустим, есть модуль, в котором обе экспортирующиеся переменные не используются, но есть вызов функции

export const c = 123;
export const d = test();
function test(){
/* some code */
}


Как определить, что функция test не создает сайд-эффектов (например, не добавляет что-то в window) без глубокого анализа (т.к. глубокий анализ - вещь сложная и замедлит сборку). Для этого есть 2 способа:

Первый - пометить вызов функции чистым

export const c = 123;
export const d = /*#__PURE__*/ test();
function test(){
/* some code */
}


В этом случае бандлер доверяет разработчику и считает, что вызов функции не несет сайд-эффектов и его можно удалить. Эти конструкции, как правило, расставляются другими сборщиками или авторами библиотек. Например, babel вставляет такие инструкции при транспиляции кода.

Второй вариант - пометить весь модуль чистым. Делается это через поле в package.json

// package.json
{
"sideEffects": false
}


Бандлер также доверяет этому полю. Однако, здесь могут возникнуть сложные ситуации, когда модуль А имеет sideEffects: false, а он использует модуль Б, который имеет sideEffects: true. Есть еще всякие разные граничные случаи и каждый бандлер обрабатывает их по-своему.

В статье более подробно раскрываются механизмы работы этих оптимизаций, приводится в пример собранный webpack'ом код, а также рассматривается, когда эти механизмы работают плохо или не работают.

Рекомендую к прочтению, если вы периодически занимаетесь инфраструктурой сборки в проекте.


https://github.com/orgs/web-infra-dev/discussions/17

#development #javascript #webpack #treeShaking #performance
Извините, но сегодня день начнется с рекомендаций других каналов 🙃

Прилетело несколько рекомендаций реально крутых штук
Первую рекомендацию вы, вероятно, могли видеть уже в других каналах: подборка каналов про веб-разработку с авторскими постами.

Подборка реально крутая, смотрите что вам по душе и подписывайтесь!

🔗 https://www.tg-me.com/addlist/Z6Efi4jXwe9lODcy
Канал про решение алгоритмических задач и подготовку к собеседованиям - Algorithmics. Я сам не фанат алгоритмических секций на собеседованиях, но контент в канале действительно крутой контент по разбору задач. В канале постятся сами задачки и краткое решение, в блоге - детальное объяснение решения и решение задачи на нескольких языках.

Рекоменндую к подписке, если вам интересны алгоритмические задачки
Hello Bun: How Sveld now deploys 2x faster on GitHub and Render

Небольшая статья про перевод инфраструктуры сборки проекта для Svelte на Bun. В целом, миграция для такого небольшого проекта дело достаточно тривиальное - поменять несколько команд и потратить вечерок на замену небольших конструкций кода (для автора это cli-скрипт и код авто-тестов)

Какие результаты:
- Сборка пакета в github-actions проходит в 2-3 раза быстрее
- Пакеты устанавливаются в 2-20 раз быстрее. При этом bun без кешей не сильно отстает от Yarn с кэшами.
- Юнит-тесты бегут в 2 раза быстрее
- В 2 раза ускорился деплой в Render (это платформа для деплоя статичных сайтов

https://render.com/blog/hello-bun-deploy-2x-faster-on-github-render

#development #javascript #bun #migration #svelte
The Front End Developer (Engineer) Handbook 2024

Невероятно огромный handbook про профессию фронтенд инженера в 2024 году. В хендбуке описано все - начиная от определения профессии, переходя через базовые знания (работы сети например) и заканчивая обзором современных инструментов и практик.

Рекомендую к просмотру

https://frontendmasters.com/guides/front-end-handbook/2024/

#development #frontend
2024/05/10 03:19:52
Back to Top
HTML Embed Code: