Недавно столкнулся с проблемой, что требуется 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