Хотите расти как разработчик и найти крутую работу? Не протирайте штаны — займитесь Open Source проектами. Так легче всего попасть в лучшие команды разработчиков и положить себе в резюме настоящий проект, вместо нелепых «примеров кода». Но найти подходящий проект для участия сложно. Начинаются лень и отговорки, а за ними — отсутствие профессионального роста, критики по-настоящему крутых программистов, уныние и застой.
На Cult of Martians мы собираем интересные задачи для современных веб-программистов. Можно выбрать подходящую по сложности, продолжительности и специализации. Задачи не выдуманы «из воздуха» — каждая решает насущную проблему, и решить ее можно через создание нового Open Source проекта или улучшение существующего. Решайте задачи, прокачивайтесь, присылайте решение на оценку. Лучших могут пригласить к себе на работу компании, программистам которых понравится ваше решен ие.
Для новичков, задача на пару дней
uvu — минималистичная система юнит-тестов для Node.js.
Для нее есть плагин для ESLint — eslint-plugin-uvu/. В этом плагине есть правило uvu/prefer-is-for-primitives
; ему нужно добавить возможность авто-исправления кода при запуске eslint --fix
.
Польза: строка в резюме, которая показывает знание ESLint.
Для новичков, задача на пару дней
uvu — минималистичная система юнит-тестов для Node.js. Самый простой тест в ней выглядит так:
import { test } from 'uvu'
test('something', () => {
…
})
test('another', () => {
…
})
test.run()
Можно заставить uvu
выполнять только один тест (например, для целей отладки), заменив test()
на test.only()
. Но легко потом забыть заменить test.only()
на test()
обратно.
Надо написать правило в eslint-plugin-uvu, которое будет предупреждать пользователя о забытом test.only()
. Правило не надо делать auto-fixable, иначе во время отладки тестов test.only()
будет убираться по сохранению файла.
Польза: строка в резюме, которая показывает знание ESLint.
Для новичков, задача на пару дней
uvu — минималистичная система юнит-тестов для Node.js. Самый простой тест в ней выглядит так:
import { test } from 'uvu'
test('something', () => {
…
})
test('another', () => {
…
})
test.run()
В конце каждого файла с тестами нужно писать test.run()
, чтобы каждый файл теста был само-исполняемым файлом (node index.test.js
). Но test.run()
легко забыть.
Надо написать правило в eslint-plugin-uvu, которое будет предупреждать пользователя о забытом test.run()
.
Польза: строка в резюме, которая показывает знание ESLint.
Для новичков, задача на пару дней
В Node.js можно добавлять node:
-префикс, чтобы показать, что мы имеем в виду встроенный в Node.js модуль, а не npm-пакет.
import { writeFileSync } from 'node:fs'
Но при разработке легко забыть добавить этот префикс. Хочется иметь правило в ESLint, которое будет гарантировать, что префикс есть во всех нужных местах.
Такое правило есть в eslint-plugin-unicorn, но этот плагин идет с множеством лишних подзависимостей. Хочется иметь какое-то минималистичное решение.
Польза: строка в резюме, которая показывает знание ESLint.
Для новичков, задача на пару дней
PostCSS-плагин postcss-dark-theme-class
позволяет сделать темную и светлую тему для сайта полностью на CSS.
Для этого он копирует содержимое @media (preferred-color-scheme: dark)
в html.is-dark
.
Нужно добавить поддержку @media (preferred-color-scheme: light)
.
Польза: строка в резюме с PR в популярный проект.
Для новичков, задача на неделю
OkColor — это Figma-плагин для работы с OKLCH.
Но этот color picker не использует оптимизации color picker’а Марсиан, поэтому работает медленно. В итоге автору пришлось снизить разрешение <canvas>
, что заметно.
Нужно перенести оптимизации из color picker’а Марсиан и поднять разрешение.
Польза: строка в резюме, которая покажет знание API Figma и сложных JS-задач.
Для уверенных в себе, задача на день
Nano Stores Persistent — умный стор, который синхронизирует данные с localStorage
.
В современных браузерах есть Back-Forward Cache, который позволяет восстанавливать страницу из кэша при нажатии кнопок Назад/Вперед. Он сохраняет на диск снимок памяти страницы и при нажатии Назад мгновенно показывает страницу из кэша.
Но если на следующей странице пользователь изменил что-то в localStorage, то при нажатии Назад страница восстановится из кэша, но данные в умном сторе останутся старыми. Нужно добавить среду для тестирования и событие pageshow
, которое будет доставать обновление из localStorage
.
Польза: строка в резюме, которая доказывает знание продвинутых инструментов TypeScript.
Для уверенных в себе, задача на неделю
Nano Stores I18n имеет функцию param()
для создания строк перевода, в которых есть параметры:
export const messages = i18n('post', {
published: params<{ at: string }>('Was published at {at}')
})
Сейчас нужно явно указывать (через <{ at: string }>
), какие параметры есть в строке перевода.
Но новый TypeScript умеет парсить строки и выводить типы из них.
Польза: строка в резюме, которая доказывает знание продвинутых инструментов TypeScript.
Для уверенных в себе, задача на неделю
pnpm умеет выполнять скрипты параллельно (и даже дает крутой UI для объединения вывода):
❯ pnpm test
> pnpm run --recursive --include-workspace-root /^test:/
Scope: all 2 workspace projects
. test:js$ eslint .
└─ Running...
. test:styles$ stylelint **/*.css **/*.svelte
└─ Done in 640ms
. test:types$ tsc --noEmit
└─ Done in 72ms
. test:audit$ pnpm audit --prod
│ No known vulnerabilities found
└─ Done in 3s1s
web test:run$ c8 pnpm unit
└─ Done in 3.6s
│ • • • • (4 / 4)
└─ Done in 3.1s
web test:check$ svelte-check
│ svelte-check found 0 errors and 0 warnings
└─ Done in 1.7s
Этот инструмент создавался в основном с прицелом на запуск одной и той же задачи в нескольких проектах монорепозитория (аргумент --recursive
). Однако, его можно использовать и в одном проекте (--parallel
), запуская задачи через регулярные выражения (/^test:/
).
Не работают две вещи:
--parallel
запрещено использовать.--parallel
не включает красивый UI, как на примере выше с --recursive
.Польза: строка в резюме с PR в популярный проект.
Для уверенных в себе, задача на неделю
Сайт PostCSS имеет страницу с API всех классов.
Мы генерируем эту страницу с помощью скрипта из AST TypeDoc. Но, недавно, генерация сломалась после того, как:
Польза: строка в резюме с PR в популярный проект.
Для уверенных в себе, задача на неделю
Цветовой миксер OKLCH показывает отдельно 3D-модель цветового пространства и 3 среза. Хотелось бы соединить срезы с 3D-моделью.
Например, можно нарисовать тонкую линию на 3D-модели — там, где находятся текущие срезы.
Польза: строка в резюме с PR в популярный проект.
Для уверенных в себе, задача на неделю
В цветовом миксере OKLCH самая долгая операция — рисование на <canvas>
. Сейчас это происходит в том же потоке, в котором работает браузер, поэтому пользователь может видеть «фризы».
Задача состоит в том, чтобы добавить Web Worker и перенести рисование по <canvas>
в OffscreenCanvas
. Сложность в том, что браузер Safari до сих пор не поддерживает OffscreenCanvas
: для него нужно будет сохранить старый подход с главным потоком.
Польза: строка в резюме с PR в популярный проект.
Для уверенных в себе, задача на неделю
В цветовом миксере OKLCH самая долгая операция — рисование на <canvas>
. Есть идея, как ее ускорить: несколько веб-воркеров будут генерировать ImageBitmap
для своей части графика.
Польза: строка в резюме с PR в популярный проект.
Для уверенных в себе, задача на неделю
«Diamond problem», или проблема ромбовых зависимостей — это непредсказуемое поведение реактивных сторов, у которых зависимости строятся так:
┏━▶ C ━┓
┃ ▼
A D
┃ ▲
┗━▶ B ━┛
В «правильных» системах, при изменении стора A, сначала пересчитываются сторы B и C, и только потом D.
В Nano Stores обнаружена проблема с тем, что при некоторых ситуациях пересчет идет непредсказуемо. Нужно разобраться и придумать решение.
Польза: строка в резюме с PR в популярный проект.
Для уверенных в себе, задача на неделю
В нашем цветом миксере OKLCH мы показываем цветовое пространство OKLCH в виде 3-х срезов. Но само пространство трехмерное. Хочется добавить 3D-отображение с возможностью покрутить его мышкой.
Польза: строка в резюме с PR в популярный проект.
Для продвинутых, задача на пару дней
AnyCable использует gRPC для коммуникации между сервером веб-сокетов и Ruby приложением. Официальная библиотека для работы с gRPC в Ruby является сложной оберткой над библиотекой на C и имеет проблемы с поддержкой (отставание от версий Ruby, баги, которые медленно закрываются, регрессии производительности).
Компания Cookpad разрабатывает альтернативный SDK для работы с gRPC в Ruby: grpc_kit.
Задача — попробовать переписать RPC сервер AnyCable на grpc_kit.
Польза: познакомиться с AnyCable и gRPC, принести пользу сообществу.
Для новичков, задача на неделю
Gem anyway_config предоставляет единый API для конфигурирования Ruby приложений из разных источников данных (YAML файлы, переменные окружения, Rails Credentials).
Doppler — это сервис для управления секретами, который позволяет командам держать конфигурационные данные в едином (и безопасном) месте.
Задача — добавить возможность загружать данные из Doppler в Anyway Config.
Польза: познакомиться с Anyway Config и Doppler, принести пользу сообществу.
Для продвинутых, задача на пару дней
Logidze позволяет работать с версиями объектов Active Record моделей и историей их изменений, хранящейся в виде инкрементального лога в отдельной колонке таблицы БД.
Лог изменений генерируется автоматически с помощью триггеров в БД, а конкретно, с помощью BEFORE
триггеров. К сожалению, данный тип триггеров не работает для партиционнированных таблиц.
Необходимо добавить альтернативный режим работы Logidze — через AFTER
триггеры.
Польза: познакомиться с Logidze, погрузиться в PostgreSQL, принести пользу сообществу.
Для новичков, задача на пару дней
Ruby Next — транспайлер для Ruby, который позволяет трансформировать новые синтаксические конструкции языка в совместимые со старыми версиями Ruby и альтерантивными имплементациями.
Один из режимов работы Ruby Next — это создание новых, транспилированных, файлов из исходных кодов с помощью CLI. Например:
$ ruby-next nextify lib/anycable/config.rb --single-version -o tmp/transpiled.rb -V
RubyNext core strategy: refine
RubyNext transpile mode: rewrite
Generated: tmp/transpiled.rb
В некоторых случаях удобнее не создавать новую копию файла, а переписывать оригинал. Необходимо добавить такую возможность.
Польза: познакомиться с Ruby Next, попрактивоваться в написании и тестировании CLI, принести пользу Ruby-сообществу.
Для новичков, задача на неделю
Gem anyway_config предоставляет единый API для конфигурирования Ruby приложений из разных источников данных (YAML файлы, переменные окружения, Rails Credentials).
EJSON — это библиотека для хранения конфигурации в зашифрованном виде прямо в репозитории, разрабатываемая Shopify. Функционал похож на Rails Credentials, но имеет важные отличия:
Задача — добавить возможность загружать данные из ejson-файла в Anyway Config.
Польза: познакомиться с Anyway Config и EJSON, принести пользу сообществу.
Для новичков, задача на неделю
Browserslist Lint — инструмент проверки конфига Browserslist на популярные ошибки.
Было бы хорошо добавить автоматическое исправление ошибок в JS API и использовать его на сайте Browserslist.
Как исправлять каждое правило:
missedNotDead
: добавить not dead
в конец запроса.countryWasIgnored
: добавить >0.3%
в начало (или заменить другой запрос >x%
).limitedBrowsers
: добавить в конец 2 versions, not dead
.alreadyDead
: убрать найденные мёртвые браузеры.Польза: строка в резюме с PR в популярный проект.
Для новичков, задача на неделю
Нужно выпустить npm-пакет, который можно будет запустить через npx
.
После запуска он будет проходить по всем переданным файлам, искать в них цвета в форматах типа #cc0000
, rgb(255, 255, 255)
, hsl(0 10 10 / 0.2)
, и заменять их на цвет в формате oklch()
.
npx convert-to-oklch **/*.css
Польза: получить опыт работы с Node.js.
Для новичков, задача на неделю
postcss-load-config
использует Jest для юнит-тестов. Но из-за слабой поддержки ESM в Jest, проект не может добавить поддержку ESM-конфигов.
Нужно перевести проект на uvu.
Польза: строка в резюме с PR в популярный проект.