Недавно столкнулся с проблемой, что требуется https для локальной разработки. Решение нашел довольно быстро:
Так что если вам нужно показать что-то локально поднятое, а ещё желательно, чтобы SSL или TLS сверху накинули эта тулза отлично подойдет.
https://ngrok.com/
#w_corner_tools
Ngrok. Это платформа с удобной CLI утилитой (написана, кстати, на node.js), которая позволяет организовать удалённый доступ на веб-сервер, ну или любой другой сервер, запущенный на ПК. ПК при этом может не иметь статического IP адреса или быть за NAT'ом. Так что если вам нужно показать что-то локально поднятое, а ещё желательно, чтобы SSL или TLS сверху накинули эта тулза отлично подойдет.
https://ngrok.com/
#w_corner_tools
Ngrok
ngrok | API Gateway, Kubernetes Ingress, Webhook Gateway
ngrok simplifies app delivery by unifying API gateway, Kubernetes ingress, multi-cluster load balancing and more with ngrok's Universal Gateway.
Чисто лол-кек, В Хроме, 6
Очередная крутая фича браузера и зачем нам эти браузерные войны в статье Саши Майорова.
https://medium.com/@frontman/funes-8-math-pow-не-равно-972955382594
З.Ы. в комментах-таки говорят, что в Chrome Nightly уже поправили
**9 === Math.pow(6, 9) //false.Очередная крутая фича браузера и зачем нам эти браузерные войны в статье Саши Майорова.
https://medium.com/@frontman/funes-8-math-pow-не-равно-972955382594
З.Ы. в комментах-таки говорят, что в Chrome Nightly уже поправили
Medium
FunES#8: Math.pow не равно**
JavaScript зарисовки в стиле WTF
Деструктуризация динамических полей
Совсем недавно задумался над тем, как получать значение поля, которое было назначенно динамически.
Кажется, что теперь мы не можем прямо из объекта получить свойство по ключу(одноименная переменная уже есть в скоупе). Но тут на помощь нам приходит переименование деструктуризированных свойств:
Совсем недавно задумался над тем, как получать значение поля, которое было назначенно динамически.
const myActionName = 'ACTION'const actionByActionName = { [myActionName]: action }Кажется, что теперь мы не можем прямо из объекта получить свойство по ключу(одноименная переменная уже есть в скоупе). Но тут на помощь нам приходит переименование деструктуризированных свойств:
const { [myActionName]: actionName } = actionByActionNamechild_process
В ноде есть 4 способа запуска дочернего процесса:
#w_corner_nodejs
В ноде есть 4 способа запуска дочернего процесса:
child_process.spawn - начинает асинхронно отдтавать данные сразу, как запустится процесс. Его выгодно использовать при работе с большими объемами данных, например, с огромными файлами или выводом результатов утилит вроде curl. Данные получаем при помощи event-listener'а(.on('data', () => {...}))..exec - ждёт от процесса сигнала завершения и получаем набор данных от него целиком, хорошо подходит, чтобы получить какой-то не большой текст, например код статуса, данные возвращает в callback. При попытке работать с большим потоком вывода по-умолчанию нода вернёт ошибку..execFile - как exec, но напрямую запускает исполняемый файл, без оболочки..fork - как spawn, но позволяет обмениваться сообщениями с дочерними процессами через функции send/on.#w_corner_nodejs
keyof в поисках типаЖили были функции без типов. Среди них были такие,
как
prop, возвращающие поля из объекта.
const prop = (obj, key) => obj[key]
Когда наступило время раздора и хаоса и пришли типы, неопытные программисты часто ошибались в том, как организовать верный вывод типов таких функций, но для любого поля результат был
any. (и жили они без noImplicitAny)
const prop = (obj: {}, key: any) => obj[key]
const example = { meow: 'meow' }
prop(example, 'meow') // type: any
"Как так!", — восклицали они, — "Ведь мы видели, что по ключам всегда получаем тип!"
И были правы. В TypeScript существует поиск типов (
Lookup Types) , который и позволяет получить связанный с ключем тип.Тогда к ним пришел важный тип и дал новое магическое слово -
keyof.Оно давало особую способность проникать в публичные имена ключей типов и создавать литеральный объединенный тип (
Union).*
const example = { meow: 'meow', murr: 'murr' }
type CatSays = keyof typeof example // "meow" | "murr"
Благодоря знанию о
keyof и Lookup Types они быстро сообразили, как затипизировать их функцию prop:
const prop<T, K extends keyof T>(obj: T, key: K) => obj[key]
Теперь они смогут спокойно жить и припевать в типобезопасном мире, типизируя любые функции, которые как-то получают только нужные поля объекта!
—
* с помощью
keyof можно получить все публичные не статические ключи пренадлежащие именно типу, потому в примере мы вынужденны получать запросом типа typeof.#w_corner_ts
TSLint to ESLint
TSLint обещает скоро уже стать deprecated. И уже пора бы переносить все проекты с ним на новые рельсы. Очевидно, что единсвенный выбор сейчас - ESLint. Ну и куда же в современном проекте без Prettier'а. Пройдемся немного по шагам, которые сделал я для подобного переноса.
1. Во первых, не хотелось переформатировать проект, потому я сразу пошел искать тулзу, которая мне переконвертирует все мои правила из TSLint, и супер, что такая уже есть - tslint-to-eslint-config.
Запускаем
3. Перименуем
4. Обновим поле
6. PROFIT! Можно удалять tslint и избавляться от правил из
Некоторые мои проекты хранятся в монорепо, тч для нормальной работы
Также
P.S. Все же с
#w_corner_ts
TSLint обещает скоро уже стать deprecated. И уже пора бы переносить все проекты с ним на новые рельсы. Очевидно, что единсвенный выбор сейчас - ESLint. Ну и куда же в современном проекте без Prettier'а. Пройдемся немного по шагам, которые сделал я для подобного переноса.
1. Во первых, не хотелось переформатировать проект, потому я сразу пошел искать тулзу, которая мне переконвертирует все мои правила из TSLint, и супер, что такая уже есть - tslint-to-eslint-config.
Запускаем
npx tslint-to-eslint-config
2. Тулза оказалась достаточно не плохой. Но все нужные пакеты для использования ESLint она сама не поставила :(. Поставим сами, за одно добавим Prettier. (хотя и создатель сказал не использовать, но я продлжаю выбирать yarn в качестве своего менеджера зависимостей, как минимум тк я подсел на workspaces)yarn add eslint eslint-config-prettier eslint-plugin-prettier prettier @typenoscript-eslint/parser @typenoscript-eslint/eslint-plugin @typenoscript-eslint/eslint-plugin-tslint -D
3. Перименуем
eslintrc.js в .eslintrc.js, либо придётся добавить флаг в скрипте -c eslintrc.js.4. Обновим поле
noscripts в package.json."lint": "eslint --ignore-path .gitignore --ext .js,.jsx,.ts,.tsx"
5. Добавим Prettier. Сперва в массив plugins - plugins: [..., 'prettier'], затем в rules - rules: { 'prettier/prettier': 'error', ... }
6. Почему-то tslint-to-eslint-config генерирует несколько не сущесвующих правил в плагине @typenoscript-eslint/eslint-plugin, тч после первого запуска lint'a вам придется их подтереть или поискать альтернативы.6. PROFIT! Можно удалять tslint и избавляться от правил из
@typenoscript-eslint/tslint плагина.Некоторые мои проекты хранятся в монорепо, тч для нормальной работы
ESLint потребовалась небольшая докрутка: parserOptions.project в .eslintrc.js поддерживает также массив, тч потребовалось внести каждое приложение, содержащее tsconfig.json отдельно.Также
vscode сразу не хотел обрабатывать нужные конфиги, не беда, в issue к плагину vscode-eslint предложили рабочее решение.P.S. Все же с
tslint-to-eslint-config некоторые правила останутся не перенесеными, тч смотрим также созланный тулзой файл tslint-to-eslint-config.log.#w_corner_ts
GitHub
GitHub - palantir/tslint: :vertical_traffic_light: An extensible linter for the TypeScript language
:vertical_traffic_light: An extensible linter for the TypeScript language - palantir/tslint
Второй подход к снаряду поиска типов
Сколько же решений по типизации экшенов выдает Stackoverflow, вплоть до пакетов с тремя звездочками на Github и каждый способ не лишен изъянов.
Возьмем например довольно очевидный способ создания экшена "в лоб":
И по общей договоренности с командой мы решили, что тип поля
И так, приступим исправлять типизацию.
Что же для нас такое этот
Это функция, принимающая
Чтобы это сделать мы воспользуемся таким вот хитрым хелпером, который позволит доказать, что тип действительно строка (если у вас есть идеи как это сделать проще - велком в личку).
Итоговый
P.S. В примерах не исключены ошибки ☺️
Всех с наступающим!🎄
#w_corner_ts
Сколько же решений по типизации экшенов выдает Stackoverflow, вплоть до пакетов с тремя звездочками на Github и каждый способ не лишен изъянов.
Возьмем например довольно очевидный способ создания экшена "в лоб":
interface Action<T, P> {
readonly type: T;
readonly payload?: P;
}
const createAction = <T extends string, P>(type: T) => (payload: P): Action<T, P> => {
return { type, payload };
}
В таком случае от нас TS будет требовать пробрасывать вторым аргументом в дженерик payload, что нам не всегда нужно (тк нельзя в дженерик с двумя аргументами передавать только один, ну и если попробуем от этого избавиться, то все равно в конце концов мы теряем тип от type).И по общей договоренности с командой мы решили, что тип поля
type обязательно должен быть строкой.И так, приступим исправлять типизацию.
Что же для нас такое этот
createAction в итоге. Это функция, принимающая
type и payload и возвращающая объект с этими двумя полями, а главное сохраняющая типы.const createAction = (type) => (payload) => ({
type,
payload,
})
И первый тип, с которым надо нам надо разобраться - это тип Action, содержащий payload, type и более базовый тип - ReduxAction (для него достаточно поля type)interface ReduxAction<T extends string> {
type: T
}
export interface Action<Type extends string, Payload = void> extends ReduxAction<Type> {
payload?: Payload
}
Тут все довольно просто. Обернем в это createAction.const createAction = <T extends string, P>(type: T) => (payload?: P): Action<T, P> => ({
type,
payload,
})
Чтож, мы пришли примерно к тому же, что и было в примере с SO. Только payload вне зависимости от экшена не обязательный, а типы этого поля так и не выводятся. Добавим магии lookup types и посмотрим, что у нас получится.export const createAction = <A extends Action<A['type'], A['payload']>>(type: A['type']) => (payload: A['payload']) => ({
type,
payload,
})
Теперь у нас выводится типы тайпсрипта по типу экшена. Так мы не можем доказать тайпчекеру, что тип у A['type'] - строка, и это не сработает (пример). Впрочем, мы и не пытались.Чтобы это сделать мы воспользуемся таким вот хитрым хелпером, который позволит доказать, что тип действительно строка (если у вас есть идеи как это сделать проще - велком в личку).
type StingTypeField = {
type: string
}
type LookupStringTypeField<T, K> = K extends keyof T ? (T extends StingTypeField ? T[K] : never) : never
В LookupStringTypeField мы говорим, что поле в объекте точно есть поле K и оно точно строка, а иначе и не может быть (never).Итоговый
createAction:const createAction = <A extends Action<LookupStringTypeField<A, 'type'>, A['payload']>>(type: A['type']) => (payload: A['payload']) => ({
type,
payload,
})
И конечно ссылка с примером.P.S. В примерах не исключены ошибки ☺️
Всех с наступающим!🎄
#w_corner_ts
www.typenoscriptlang.org
TS Playground - An online editor for exploring TypeScript and JavaScript
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
Небольшой пост по безопасности на фронтенде, куда вообще смотреть? Заметил, что мало кто в этой теме разбирается даже на базовом уровне, а тема важная.
Основные вопросы:
Виды атак, какой вектор, какая цель?
XSS, CSRF, clickjacking.
Как защититься?
CORS + SOP, CSP, Cookie: secure, httpOnly, SameSite
https://application.security/free-application-security-training - в интерактивном режиме показывается как можно произвести атаку и как от нее защититься
https://developer.mozilla.org/ru/docs/Web/HTTP/CORS
https://developer.mozilla.org/ru/docs/Web/HTTP/CSP
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
https://developer.mozilla.org/ru/docs/Web/HTTP/Cookies#secure_(%D0%B1%D0%B5%D0%B7%D0%BE%D0%BF%D0%B0%D1%81%D0%BD%D1%8B%D0%B5)_%D0%B8_httponly_cookies
https://habr.com/ru/post/340146/ - про то, как работает JWT
#w_corner_secure
Основные вопросы:
Виды атак, какой вектор, какая цель?
XSS, CSRF, clickjacking.
Как защититься?
CORS + SOP, CSP, Cookie: secure, httpOnly, SameSite
https://application.security/free-application-security-training - в интерактивном режиме показывается как можно произвести атаку и как от нее защититься
https://developer.mozilla.org/ru/docs/Web/HTTP/CORS
https://developer.mozilla.org/ru/docs/Web/HTTP/CSP
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
https://developer.mozilla.org/ru/docs/Web/HTTP/Cookies#secure_(%D0%B1%D0%B5%D0%B7%D0%BE%D0%BF%D0%B0%D1%81%D0%BD%D1%8B%D0%B5)_%D0%B8_httponly_cookies
https://habr.com/ru/post/340146/ - про то, как работает JWT
#w_corner_secure
Kontra
Application Security Training For Developers | Kontra
Kontra is an Application Security Training platform built for modern development teams.
MSW
Часто вам приходилось разрабатывать интерфейс без готовой ручки на бэкенде? Все эти временные данные на уровне стора или Promise.resolve с данными на уровне сервисов/sdk и прочие подходы, обеспечивающие нам одни и теже данные. А писать e2e тесты, когда чтобы замокать результат запросов всегда приходилось придумывать свои велосипеды (да-да, е2е с фейковыми данными запросами ужас и моветон - мы всегда поднимаем весь стек и ждём, что нигде ничего не отвалится и нашей машинке хватит сил).
Хватит. Почти всегда для того, чтобы подсунуть фэйковые данные на уровне сети я выбирал nock, но время идёт, индустрия движется, а подход к моку сервера в тестах остаётся прежним. Только не с Mock Service Worker и вот вам несколько причин перейти на него:
1. Простая установка
2. Возможность запускать одни и те же обработчики и для серверных (например,в случае с SSR) и для клиентских тестов из коробки
3. Возможность делать более умные обработчики на этапе жизни «без нужной бэкендовой ручки», а затем переиспользовать их в тестах
4. Поддержка rest и grqphql
5. Максимально прозрачное поведение и простота отладки
6. Ваши обработчики похожи на реальные express мидлвары
Ставим пакет, запускаем
#w_corner_testing
Часто вам приходилось разрабатывать интерфейс без готовой ручки на бэкенде? Все эти временные данные на уровне стора или Promise.resolve с данными на уровне сервисов/sdk и прочие подходы, обеспечивающие нам одни и теже данные. А писать e2e тесты, когда чтобы замокать результат запросов всегда приходилось придумывать свои велосипеды (да-да, е2е с фейковыми данными запросами ужас и моветон - мы всегда поднимаем весь стек и ждём, что нигде ничего не отвалится и нашей машинке хватит сил).
Хватит. Почти всегда для того, чтобы подсунуть фэйковые данные на уровне сети я выбирал nock, но время идёт, индустрия движется, а подход к моку сервера в тестах остаётся прежним. Только не с Mock Service Worker и вот вам несколько причин перейти на него:
1. Простая установка
2. Возможность запускать одни и те же обработчики и для серверных (например,в случае с SSR) и для клиентских тестов из коробки
3. Возможность делать более умные обработчики на этапе жизни «без нужной бэкендовой ручки», а затем переиспользовать их в тестах
4. Поддержка rest и grqphql
5. Максимально прозрачное поведение и простота отладки
6. Ваши обработчики похожи на реальные express мидлвары
Ставим пакет, запускаем
npx msw init public/ --save и вперед. Не забываем читать доку, и экспериментировать, думаю, обязательно найдете больше юзкейсов для себя.#w_corner_testing
mswjs.io
Quick start
Get MSW up and running in under five minutes.
Да будет Typenoscript
С этого поста хочу начать последовательный цикл дипдайва в тайпскрипт, в самом широком смысле: от причин использования, простейших типов и их юзкейсов, до устройства системы типов, транспилятора, точек его расширения и всего вокруг этого чудесного инструмента.
Начнем с самого начала: с базовых типов, из которых выводится все остальное.
То, что TypeScript является типизированной надстройкой над JavaScript, от которой после компиляции не остаётся и следа, означает, что первый перенял от второго всю его идеологию. Одним из таких моментов является разделение типов данных на типы значения (примитивные) и ссылочные типы.
Корнем всей иерархии типов можно считать unknown, который является типобезопасным аналогом any. Все типы совместимы с типом unknown, в, то время как сам тип unknown совместим только с самим собой и типом any.
Произвольный тип any — с него для многих и начнется знакомство с системой типов TypeScript.
Далее идут простые примитивные типы, имеющие свои аналоги в JavaScript: number, string, boolean, bigint, symbol. Важно понимать, что типы, идентификаторы которых начинаются с прописной буквы представляют объектные типы (ссылочные типы) описывающие одноимённые типы из JavaScript (Number, String, Boolean и т.д.). В Typenoscript их можно расширить (через extends) и реализовать (через implements).
В отдельную категорию можно вынести примитивные типы null, undefined, void, never, считая их в некотором роде «типами отсутствия».
Enum - перечисление также считается примитивным типом.
Для каждого из этих типов есть литеральный подтип, которые, как можно понять из названия, представляют литералы обычных примитивных типов.
#w_corner_ts
С этого поста хочу начать последовательный цикл дипдайва в тайпскрипт, в самом широком смысле: от причин использования, простейших типов и их юзкейсов, до устройства системы типов, транспилятора, точек его расширения и всего вокруг этого чудесного инструмента.
Начнем с самого начала: с базовых типов, из которых выводится все остальное.
То, что TypeScript является типизированной надстройкой над JavaScript, от которой после компиляции не остаётся и следа, означает, что первый перенял от второго всю его идеологию. Одним из таких моментов является разделение типов данных на типы значения (примитивные) и ссылочные типы.
Корнем всей иерархии типов можно считать unknown, который является типобезопасным аналогом any. Все типы совместимы с типом unknown, в, то время как сам тип unknown совместим только с самим собой и типом any.
Произвольный тип any — с него для многих и начнется знакомство с системой типов TypeScript.
Далее идут простые примитивные типы, имеющие свои аналоги в JavaScript: number, string, boolean, bigint, symbol. Важно понимать, что типы, идентификаторы которых начинаются с прописной буквы представляют объектные типы (ссылочные типы) описывающие одноимённые типы из JavaScript (Number, String, Boolean и т.д.). В Typenoscript их можно расширить (через extends) и реализовать (через implements).
В отдельную категорию можно вынести примитивные типы null, undefined, void, never, считая их в некотором роде «типами отсутствия».
Enum - перечисление также считается примитивным типом.
Для каждого из этих типов есть литеральный подтип, которые, как можно понять из названия, представляют литералы обычных примитивных типов.
#w_corner_ts
React Testing Library и Enzyme
Все больше и больше проектов уходят с Enzyme и переходят на RTL. Про это сейчас пишут статьи, делают доклады и даже оффициальная дока Recat рекомендует React Testing Library. Чем же так не угодил Enzyme и почему от него стоит отказаться.
1. Он завязан на кишки React, а значит очередное обновление ломает обратную совместимость и требует обновление Enzyme (а также вероятно написанных тестов)
2. Enzyme родился в Airbnb, но сейчас фактически поддерживается одним человеком.
3. Enzyme периодически вынуждает тестировать реализацию как «белый ящик», что также делает тесты более хрупкими.
Как начать писать тесты с RTL? Лично я рекомендую для старта почитать документацию, посмотреть мой доклад и этот плейлист. Для более заинтересованных в тестах также не могу оставить без внимания интенсив Hexlet по тестированию фронтенда.
#w_corner_testing
Все больше и больше проектов уходят с Enzyme и переходят на RTL. Про это сейчас пишут статьи, делают доклады и даже оффициальная дока Recat рекомендует React Testing Library. Чем же так не угодил Enzyme и почему от него стоит отказаться.
1. Он завязан на кишки React, а значит очередное обновление ломает обратную совместимость и требует обновление Enzyme (а также вероятно написанных тестов)
2. Enzyme родился в Airbnb, но сейчас фактически поддерживается одним человеком.
3. Enzyme периодически вынуждает тестировать реализацию как «белый ящик», что также делает тесты более хрупкими.
Как начать писать тесты с RTL? Лично я рекомендую для старта почитать документацию, посмотреть мой доклад и этот плейлист. Для более заинтересованных в тестах также не могу оставить без внимания интенсив Hexlet по тестированию фронтенда.
#w_corner_testing
piotrstaniow.pl
Time to say goodbye - Enzyme.js
The world has already moved - to React Testing Library
Заметки
идеальная система не та, в которую уже нечего добавить, а та, из которой уже нечего убрать
За последние лет 8 я попробовал минимум 30 приложений для ведения заметок, дел, чеклистов, WTR, финансов и прочих потоков информации, которые хочу структурировать.
А хотелось структурировать все. GTD для всех дел. Цеттелькастен для всех заметок. Выжать максимум из приложений для финансов. Еженедельная очистка want to read инбокса.
Косу нужно было идеально заточить, чтобы косить.
В результате вместо того, чтобы выполнять задуманную работу, куча времени уходило на поиск и освоение очередного разухабистого инструмента для GTD, обвес и настройка плагинами Obsidian’а, докрутка базы знаний в Notion. В конце концов полное отчаяние от того, что в итоге снова получилось слишком сложно.
Тогда я решил зайти с противоположного конца. Завел просто файлик в облаке.
В него писал короткий список с перечислением проектов, над которыми я фокусируюсь в текущую неделю. Сразу под этим списком вписывал все дни недели, а каждый вечер писал список из нескольких пунктов под следующим днем. Тоже самое сделал с финансами.
Через несколько недель такого упрощения я понял, какие именно элементы в моей системе продуктивности были лишние, избавился от них и смог вернуться в Things3.
Так же поступил с моим Obsidian. Создал новый сейф, избавился от всех лишних плагинов и сложных структур в заметках, оставил только самое необходимое.
В итоге пришло осознание, что для Zettelkasten'а достаточно папки с текстовыми файлами, куда я записываю сформировавшиеся мысли и иногда перечитываю их.
Для написания больших текстов вернулся к org-моду emacs.
Итогом пусть будет мысль, что практика - хорошо, а паралич выбора и FOMO - плохо. Надеюсь этот виток ведения дел окажется более удачным.
идеальная система не та, в которую уже нечего добавить, а та, из которой уже нечего убрать
За последние лет 8 я попробовал минимум 30 приложений для ведения заметок, дел, чеклистов, WTR, финансов и прочих потоков информации, которые хочу структурировать.
А хотелось структурировать все. GTD для всех дел. Цеттелькастен для всех заметок. Выжать максимум из приложений для финансов. Еженедельная очистка want to read инбокса.
Косу нужно было идеально заточить, чтобы косить.
В результате вместо того, чтобы выполнять задуманную работу, куча времени уходило на поиск и освоение очередного разухабистого инструмента для GTD, обвес и настройка плагинами Obsidian’а, докрутка базы знаний в Notion. В конце концов полное отчаяние от того, что в итоге снова получилось слишком сложно.
Тогда я решил зайти с противоположного конца. Завел просто файлик в облаке.
В него писал короткий список с перечислением проектов, над которыми я фокусируюсь в текущую неделю. Сразу под этим списком вписывал все дни недели, а каждый вечер писал список из нескольких пунктов под следующим днем. Тоже самое сделал с финансами.
Через несколько недель такого упрощения я понял, какие именно элементы в моей системе продуктивности были лишние, избавился от них и смог вернуться в Things3.
Так же поступил с моим Obsidian. Создал новый сейф, избавился от всех лишних плагинов и сложных структур в заметках, оставил только самое необходимое.
В итоге пришло осознание, что для Zettelkasten'а достаточно папки с текстовыми файлами, куда я записываю сформировавшиеся мысли и иногда перечитываю их.
Для написания больших текстов вернулся к org-моду emacs.
Итогом пусть будет мысль, что практика - хорошо, а паралич выбора и FOMO - плохо. Надеюсь этот виток ведения дел окажется более удачным.
🔥3❤🔥1