<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Alexey Pyltsyn on Medium]]></title>
        <description><![CDATA[Stories by Alexey Pyltsyn on Medium]]></description>
        <link>https://medium.com/@lex111?source=rss-19321d28194------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*8yVwVZEB9Ub86UY56z7y2g.png</url>
            <title>Stories by Alexey Pyltsyn on Medium</title>
            <link>https://medium.com/@lex111?source=rss-19321d28194------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 13 Nov 2026 22:41:56 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@lex111/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Состояние JavaScript в 2018 году: обзор Vue.js]]></title>
            <link>https://medium.com/devschacht/the-state-of-javascript-2018-the-view-on-vue-b1606c452344?source=rss-19321d28194------2</link>
            <guid isPermaLink="false">https://medium.com/p/b1606c452344</guid>
            <category><![CDATA[devschacht-for-dummies]]></category>
            <category><![CDATA[devschacht-vue]]></category>
            <category><![CDATA[devschacht]]></category>
            <dc:creator><![CDATA[Alexey Pyltsyn]]></dc:creator>
            <pubDate>Mon, 31 Dec 2018 11:38:24 GMT</pubDate>
            <atom:updated>2018-12-31T11:38:24.320Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Перевод статьи </em><a href="https://twitter.com/cntrmktg"><em>John Willoughby</em></a><em>: </em><a href="https://www.telerik.com/blogs/the-state-of-javascript-2018-the-view-on-vue"><em>The State of Javascript 2018: The View on Vue</em></a><em>.</em></p><p>Результаты исследования <a href="https://2018.stateofjs.com/">State of JavaScript</a> за 2018 год только что были опубликованы, и поскольку мы приблизились к концу года, то сейчас самое время взглянуть на <a href="https://ru.vuejs.org/">Vue.js</a> и посмотреть, как идут дела у этого фреймворка.</p><p>Ежегодный опрос State of JavaScript, проводимый <a href="https://twitter.com/sachagreif">Сашей Грейф (Sacha Greif)</a>, <a href="https://twitter.com/benitteraphael">Рафаэлем Бенит (Raphael Benitte)</a> и <a href="https://twitter.com/michaelrambeau">Майклом Рэмбю (Michael Rambeau)</a>, изучает мнение более 20 тысяч веб-разработчиков относительно тенденциях за прошедший год. Хотя опрос не охватывает целиком всю отрасль, он, тем не менее, даёт довольно хорошую выборку и отличную исходную точку для ознакомления с состоянием Vue. Итак, о чём там говорится?</p><p>Давайте сразу перейдём к интересному — как дела у Vue? Конечно, это не соревнование, но всё же… давайте добавим результаты по React и Angular. А затем, чтобы на самом деле ответить на этот вопрос, давайте также покажем данные за прошлый год, чтобы увидеть, как результаты менялись год от года. Да, в опросе перечислены несколько других фреймворков, однако их использование существенно ниже по сравнению с большой тройкой, поэтому я исключил их.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/585/0*wVGDof4QLJbcVuIT" /></figure><p>График выглядит очень колоритно! Так что на самом деле он нам говорит? Самое важное, что использование всех троих фреймворков увеличилось за последний год. Я не буду вдаваться в подробности данных касательно React или Angular, помимо сравнения их с Vue. Есть статьи по разбору данных опроса касательно <a href="https://www.telerik.com/blogs/a-react-state-of-mind-state-of-javascript-survey-2018">React</a> и <a href="https://www.telerik.com/blogs/the-state-of-js-survey-2018-the-angular-scoop">Angular</a>, в этих статьях вы найдёте всю подробную информацию.</p><p>Единственное, что выделяется — это почти уже все слышали о Vue в этом году. В 2017 году около 5% респондентов сообщили, что они никогда не слышали про Vue, тогда как в этом году этот показатель стал ниже 1%.</p><p>Положительное использование увеличилось с 20% до 29% за 2018 год. Таким образом, использование Vue.js немного выше, чем Angular, и примерно половина от React (не то, что мы сравниваем). Однако… как и со всеми данными, нам нужно поместить их в контекст и соотнести с другой информацией. Vue, пожалуй, проще всего взять и начать использовать, так что эти цифры могут включать больше людей, использующих его в небольших проектах или в целях обучения. Это подтверждается мнениями разработчиков, с которыми я общался в течение прошлого года. Это вовсе не означает, что Vue не используется в реальных проектах, просто 29% людей могут включать в себя большее количество «сомневающихся», нежели чем в других фреймворках. Тем не менее, есть много людей, использующих Vue, и их число растёт.</p><p>Обратите внимание, что голоса за «heard of it, not interested (слышал об этом, но не заинтересован)» и «heard of it, would like to learn (слышал об этом и хотел бы изучить)» держались примерно на одном уровне с небольшим уменьшением. Это соответствует продолжающемуся внедрению, и со временем мы ожидаем, что большее количество людей, выбравших вариант «heard of it, would like to learn», перейдёт группе «used it (использовали его)».</p><p>Последнее, на что следует обратить внимание: людей, отметивших вариант «used it, would not use it again (использовал его и не стал бы использовать снова)» довольно мало и теперь только немного увеличился. Этот показатель ниже, чем в React, и намного ниже, чем у Angular (опять же, мы не это сравниваем). Это очень хороший знак. Люди пытаются, они используют Vue, и им он нравится.</p><h4>Кто эти люди?</h4><blockquote>Обратите внимание, что следующие данные и диаграммы предназначены только для Vue-разработчиков, они не включают информацию обо всех участниках опроса.</blockquote><p>Для опроса также приведена демографическая информация. Первый график — информация о зарплате. Он разделён по фреймворкам, нам интересен Vue, где видно, что 17% респондентов зарабатывают 100–200 тысяч долларов, а 29% зарабатывают в 50–100 тысяч. Диапазон от 50 до 200 тысяч долларов охватывает обычную зарплату разработчиков в США. Что интересно, однако, так это то, что 19% указали свою зарплату как 30–50 тысяч долларов, а 17% — 10–30 тысяч. Они могут быть из других стран с более низкой шкалой заработной платы, или они могут указывать на количество студентов, подрядчиков, занятых неполный рабочий день, или людей на других должностях, которые только переходят в разработку. Эти категории могут указывать на группу людей, которые используют Vue, но не в продакшене.</p><p>Кроме того, если вы один из немногих, кто зарабатывает более 200 тысяч долларов в год на должности разработчика на Vue, немедленно свяжитесь со мной и расскажите, как вы это делаете 😃.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/587/0*eaCRYx6O4hkCYWl7" /></figure><p>Мы также предоставляем данные о размере компании по фреймворку. Здесь мы видим, что по Vue 34% людей указали, что они работают в компании с более чем 100 сотрудниками, а 20% — в компаниях с 5 или менее сотрудниками, поэтому наблюдается довольно хороший разброс в размере компании. Обратите внимание, что сочетание категорий (например, между «1–5» и «1») не было опечаткой с моей стороны, именно так перечислены результаты.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/587/0*NzZnkKgrkIn4KuVY" /></figure><p>Наконец, результаты опроса содержат многолетний опыт работы с каждым фреймворком, и здесь мы видим довольно хороший рост. 30% принявших участие в опросе имеют 2–5 лет опыта, и столько же, 30%, по 5–10 лет опыта, а у 23% — 10–20 лет опыта. Менее двух лет назад было 13%, поэтому мы видим некоторый интерес начального уровня, но не такой, как у более опытных разработчиков.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/589/0*ODEHwIw3ccy2-7Z8" /></figure><h4>Более тщательное изучение</h4><p>Анализ данных относительно Vue, позволяет нам лучше понять, кто и почему используют Vue.</p><p>Начнём с того, что больше всего понравившийся аспект Vue, причиной номер один стала «плавная кривая обучения (easy learning curve)», за которой следуют «элегантный стиль программирования (elegant programming style)» и «хорошая документация (good documentation)». Другими словами, с Vue легко работать. С другой стороны, пункт «высокая производительность (fast performance)» оказался в списке на пятом месте, поэтому тем, кто используют Vue в реальных приложениях, стоит уделить внимание производительности. Следует отметить, что так ответили те участники опроса, которые указали, что использовали Vue и будут использовать его снова.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/590/0*vHF8UKcSTyUWkQZX" /></figure><p>Из числа тех, кто ответил, что «использовали его и НЕ будут использовать его снова», и имейте в виду, что это <strong>очень маленький процент людей</strong>, первой причиной с огромным отрывом стал «неуклюжий стиль программирования (clumsy programming style)». Это, похоже, противоречит тем же причинам, которые нравились другой группе, и предполагает, что Vue похож на пиво со вкусом тыквы. Некоторые люди просто любят его, а другие думают, что это противно. Это вопрос стиля и предпочтений. (Для справки, люди, которые считают, что тыквенное пиво противно, правы 🙂).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/586/0*Sbmd58DOGFg_F8JM" /></figure><p>Следующий интересный набор данных — это место, где находятся счастливые пользователи Vue. Самый высокий процент отмечен в Китае, Франции, Индонезии, Таиланде, Вьетнаме, Нигерии, Мексике, Перу, Бразилии и некоторых других странах. К местам с меньшим степени удовлетворённости относятся США, Индия и Австралия.</p><p>В докладе вкратце (для раздела фреймворков) указывается, что React в настоящее время является самым популярным фреймворком, а Vue неуклонно растёт. В отчёте указывается, что Vue фактически обогнал React по общему количеству звёзд на GitHub. Angular поддерживает значительную пользовательскую базу, и, хотя не все довольны им, он, кажется, хорошо вписывается в определённые ситуации и не проявляет каких-либо признаков исчезновения с лица земли.</p><h4>Но подождите, это ещё не всё!</h4><p>Опрос State of JavaScript даёт нам полезную информацию от большого количества разработчиков, но это не весь рынок. Он также задаёт определённые вопросы, но не всем. Существуют и другие опросы, которые стоит посмотреть, один из которых является <a href="https://insights.stackoverflow.com/survey/2018/#overview">Developer Survey Results</a> от Stack Overflow . Или, по крайней мере, он был бы интересен для рассмотрения, если бы включал Vue, которого пока нет. Vue может расти как на дрожжах, но это не везде (пока ещё!). Обратите внимание, что на Stack Overflow есть тонна вопросов про Vue.</p><p>Опрос от Stack Overflow 2018 года включал Angular и React, а также .NET и ряд других инструментов, но не Vue. Интересно отметить, что в этом опросе Angular превосходит React как наиболее часто используемый фреймворк с 37% против 28% у React. Казалось бы, это противоречит результатам опроса State of JavaScript, где React превосходит Angular. Хотя это не имеет никакого отношения к Vue, это подчёркивает важность детального изучения данных опроса — как именно задавались вопросы? У кого был доступ к опросу? Кто завершил опросы? Это также показывает, что нужно быть осторожнее, полагаясь на результаты только одного опроса.</p><p>Я добавлю две заметки про опрос Stack Overflow. Во-первых, он было проведён в начале 2018 года, так что ему почти год. Во-вторых, я не видел фактического опроса, поэтому я (разумно) предположил, что Vue просто исключён из списка вариантов, поскольку его вообще не было в списке результатов.</p><h4>Кто нанимает</h4><p>Существует ряд других способов посмотреть на рост Vue. Мы можем, например, отобрать вакансии, чтобы увидеть, сколько компаний указывают «Vue» в качестве необходимого навыка в описании вакансии. Поиск по популярному сайту вакансий <a href="https://www.indeed.com/">Indeed.com</a> по запросу «Vue» выдаёт 2 661 вакансию, включающее слово «Vue» в описание. Большинство из них для вакансии на должность разработчика. Если мы действительно хотим получить точное число, мы должны потратить дополнительное время на фильтрацию результатов вакансий по «Vue». Я вижу одну вакансию, относящуюся к «Pearson Vue», другую к «Campus Vue», и третью — «Playstation Vue», но большинство вакансий на поиск Vue-разработчиков, и я больше хочу понять общее ощущение рынка, а не идеальное число.</p><p>Что интересно, React даёт нам 58 433 рабочих места, а Angular — 17 219. Оба результата выглядят так, как будто найденные вакансии, как правило, на поиск соответствующих разработчиков, хотя число React кажется довольно высоким, и любой детальный анализ займёт некоторое время на поиск ключевых слов для фильтрации. Также обратите внимание, что в некоторых вакансиях можно встретить фразу типа «Требуется опыт таких технологий, как React, Angular и т.д.», поэтому работодатели не обязательно ищут разработчика на React.</p><p>Несмотря на все нестыковки, которые я перечисляю, это рисует довольно чёткую картину рынка, который глубоко погружён в React, все ещё силён для Angular, и только начинает работать с Vue в продакшене. При всем этом интересе, который мы видели в других источниках, мы должны ожидать, что вакансии по Vue увеличатся в течение следующих нескольких лет, поскольку интерес переходит в использование.</p><h4>Кто ищет</h4><p>Google всегда хорош для определённой аналитики, поэтому мы можем воспользоваться Google Trends для отслеживания популярности Vue с течением времени на основе поисковых запросов. Здесь также нужно обратить внимание на то, как мы структурируем запрос. Просмотр графика времени говорит нам о многом, например, мы знаем, когда Vue появился на сцене (в 2014 году), поэтому, если результаты не начинаются с нуля в 2014 году, а затем стабильно растут, мы, вероятно, используем неправильные условия поиска. Мы также можем просто погуглить «”Vue”» или другие варианты и посмотреть на ранжирование, и, возможно, нам может потребоваться ещё отфильтровать поисковую выдачу.</p><p>Поиск «Vue» по трендам даёт нам хорошие результаты, начиная с 2004 года, и это, конечно, не то, что нам нужно. Поиск по <a href="https://trends.google.com/trends/explore?date=all&amp;q=vue.js">трендам «Vue.js»</a> даёт нам кривую, которая начинается в 2014 году, а затем поднимается выше, и безусловно нет какого-либо другого «Vue.js», который мог бы привести к неожиданным результатам. С другой стороны, некоторые люди могут просто искать термин «Vue», потому что его чаще сокращают. Поиск только по «Vue.js» будет скучать по таким людям 😊.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/429/0*Ipb7f6uaHzEfwf5C" /></figure><p>В Google Trends также интересен отчёт «interest by region (интерес по регионам)», в котором Южная Корея заняла первое место. Остров Святой Елены на втором месте, и я приветствую любые объяснения, почему это так. Япония на третьем месте и т.д. Я был бы больше взволнован результатами «Остров Святой Елены» (неточные данные?), за исключением того, что анализ трендов только для США возвращает очень похожий график. Исходя из результатов, которые мы видим здесь, Vue явно продолжает расти (и нам не хватает декабрьских данных по итогам 2018 года, что сделает его ещё выше). Люди ищут информацию по нему. Рост в 2018 году вряд ли будет соответствовать росту в 2017 году, но помните, что опрос State of JavaScript показал Vue почти с нулевым числом людей, которые не были знакомы с ним в 2018 году. Я не буду показывать сравнения с React или Angular, поскольку трудно получить точные условия поиска яблок против яблок.</p><h4>Вывод</h4><p>Все эти источники данных полезны в создании картины принятия Vue и его использования в реальном мире. Однако я не могу предостеречь вас достаточно сильно, чтобы каждый источник был взят за одну точку данных. Как я упоминал выше, какие именно вопросы были заданы или использовались поисковые условия, как были собраны данные, кто имел доступ, чтобы внести свой вклад и т.д. — всё это может так или иначе искажать данные. Всю картинку в целом можно получить только путём анализа несколько источников данных. И такая общая картина состоит в том, что Vue может быть номером три, но он растёт, у него уже есть сильные последователи, и это не может не радовать.</p><p>И последнее, что я хочу добавить, — это мой личный опыт участия в ряде конференций по Vue за последний год. Для начала, в прошлом году было добавлено несколько новых конференций Vue, которые собрали большое число участников. Экосистема все ещё растёт, и по мере роста будут проводиться такие виды деятельности, как различные события, и инструменты поддержки, такие как Kendo UI для Vue. Я разговаривал с несколькими разработчиками на этих хорошо посещаемых конференциях Vue, и они полны энтузиазма, и многие из них используют Vue в реальных приложениях в продакшене. Vue здесь и никуда не денется. По крайней мере, на данный момент, потому что в мире веб-приложений единственная реальная константа — это изменения.</p><p><em>Слушайте наш подкаст в </em><a href="https://itunes.apple.com/ru/podcast/%D0%B4%D0%B5%D0%B2%D1%88%D0%B0%D1%85%D1%82%D0%B0/id1226773343"><em>iTunes</em></a><em> и </em><a href="https://soundcloud.com/devschacht"><em>SoundCloud</em></a><em>, читайте нас на </em><a href="https://medium.com/devschacht"><em>Medium</em></a><em>, контрибьютьте на </em><a href="https://github.com/devSchacht"><em>GitHub</em></a><em>, общайтесь в </em><a href="https://t.me/devSchacht"><em>группе Telegram</em></a><em>, следите в </em><a href="https://twitter.com/DevSchacht"><em>Twitter</em></a><em> и </em><a href="https://t.me/devSchachtChannel"><em>канале Telegram</em></a><em>, рекомендуйте в </em><a href="https://vk.com/devschacht"><em>VK</em></a><em> и </em><a href="https://www.facebook.com/devSchacht"><em>Facebook</em></a><em>.</em></p><p><em>Если вам понравилась статья, внизу можно поддержать автора хлопками 👏🏻 Спасибо за прочтение!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b1606c452344" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devschacht/the-state-of-javascript-2018-the-view-on-vue-b1606c452344">Состояние JavaScript в 2018 году: обзор Vue.js</a> was originally published in <a href="https://medium.com/devschacht">devSchacht</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hacktoberfest вернулся и празднует свой пятый год!]]></title>
            <link>https://medium.com/devschacht/hacktoberfest-%D0%B2%D0%B5%D1%80%D0%BD%D1%83%D0%BB%D1%81%D1%8F-%D0%B8-%D0%BF%D1%80%D0%B0%D0%B7%D0%B4%D0%BD%D1%83%D0%B5%D1%82-%D1%81%D0%B2%D0%BE%D0%B9-%D0%BF%D1%8F%D1%82%D1%8B%D0%B9-%D0%B3%D0%BE%D0%B4-186cde3bc0cc?source=rss-19321d28194------2</link>
            <guid isPermaLink="false">https://medium.com/p/186cde3bc0cc</guid>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[devschacht]]></category>
            <dc:creator><![CDATA[Alexey Pyltsyn]]></dc:creator>
            <pubDate>Fri, 12 Oct 2018 15:17:47 GMT</pubDate>
            <atom:updated>2018-11-02T14:34:17.043Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Перевод поста в официальном блоге GitHub </em><a href="http://twitter.com/leereilly"><em>Lee Reilly</em></a><em>: </em><a href="https://blog.github.com/2018-09-24-hacktoberfest-is-back-and-celebrating-its-fifth-year/"><em>Hacktoberfest is back and celebrating its fifth year!</em></a><em>.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*T75lG2E0whnlByIF.png" /></figure><p>Присоединяйтесь к нам в октябре этого года поучаствовать в уже пятом ежегодном <a href="https://hacktoberfest.digitalocean.com/">Hacktoberfest</a>, событии, посвящённом месячному празднованию проектов с открытым исходным кодом (опенсорс). Как и прошлом году в организации нам помогают наши друзья из DigitalOcean, но в этому к нашему партнёрству присоединяется Twilio.</p><p>Легко приобщиться к данному веселью (и получить фирменную футболку!), Все, что вам нужно сделать, это зайти на <a href="https://hacktoberfest.digitalocean.com/">сайт Hacktoberfest</a> для регистрации в качестве участника. Затем отправить 5 пулреквестов в публичные репозитории опенсорс-проектов в период с 1 по 31 октября. Вот и всё! Первые 50 000 участников, которые сделают это, получат футболку лимитированную Hacktoberfest. Полные условия этой акции размещены на сайте Hacktoberfest.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*nOtbAPHG-mRhU3ZC.png" /></figure><p>Если вы никогда раньше не участвовали в опенсорс-проекте, рекомендуем вам поучаствовать в этом празднике опенсорса, а <a href="https://opensource.guide/how-to-contribute/">наше руководство по внесению своего вклада в опенсорс</a>, помогут в этом.</p><p>Хотите поделиться своей любовью к Hacktoberfest? Расскажите миру о хештеге #hacktoberfest в <a href="https://twitter.com/hashtag/hacktoberfest">Twitter</a>, <a href="https://www.facebook.com/hashtag/hacktoberfest">Facebook</a> или <a href="https://www.instagram.com/explore/tags/hacktoberfest/">Instagram</a>.</p><p>В прошлом году более 30 000 человек из более чем 100 стран (119, если быть точным!) создали почти 240 000 пулреквестов в самые разные проекты — все, начиная от правок в документацию и исправлений ошибок вплоть до реализации новых фич и улучшений производительности. Почитайте их рассказы и (а посмотри их селфи!) в Twitter с хештегом <a href="https://twitter.com/hashtag/hacktoberfest">#hacktoberfest</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*VUAZZiQy4uRpVCAY.png" /></figure><h4>Не знаете с чего начать — сделайте перевод для devSchacht!</h4><p>Поскольку перевод в devSchacht делается через PR в <a href="https://github.com/devSchacht/translations">репозитории на GitHub</a> (не забудьте поставить звёздочку, если вам нравится наши переводы!), то мы предлагаем нашим читателям и просто желающим принять участие в Hacktoberfest, перевести какую-нибудь статью. Ниже приведён список статей, перевод которых мы хотели бы наиболее сильнее получить, однако вы можете любую, связанную с веб-разработкой статью:</p><ol><li><a href="https://medium.com/@jdxcode/12-factor-cli-apps-dd3c227a0e46">12 Factor CLI Apps</a> (<strong>забронировано за </strong><a href="https://medium.com/u/7a7d59054bae"><strong>Ufocoder</strong></a>)</li><li><a href="http://blog.rangle.io/refactoring-node-with-higher-order-functions/">Refactoring Node with Higher-Order Functions</a> (<strong>переведено </strong><a href="https://medium.com/u/7a7d59054bae"><strong>Ufocoder</strong></a>)</li><li><a href="https://about.gitlab.com/2017/11/09/gitlab-vue-one-year-later/">How we do Vue: one year later</a></li><li><a href="https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-2/1">Idiomatic Redux: The Tao of Redux, Part 2 — Practice and Philosophy</a></li><li><a href="https://blog.logrocket.com/javascript-typeof-2511d53a1a62">JavaScript typeof</a> (<strong>переведено </strong><a href="https://medium.com/u/7a7d59054bae"><strong>Ufocoder</strong></a>)</li><li><a href="https://blog.logrocket.com/5-reasons-you-shouldnt-be-using-graphql-61c7846e7ed3">5 reasons you shouldn’t be using GraphQL</a> (<strong>переведено</strong>)</li><li><a href="https://daveceddia.com/react-redux-immutability-guide/">Immutability in React and Redux: The Complete Guide</a></li><li><a href="https://spaceninja.com/2018/09/17/what-is-modular-css/">What is Modular CSS?</a></li><li><a href="https://vuejsdevelopers.com/2018/09/17/highly-requested-new-vue-js-features/">5 Most-Requested Features For Vue.js in 2018</a></li><li><a href="https://djangostars.com/blog/what-and-how-to-test-with-enzyme-and-jest-full-instruction-on-react-component-testing/">What and How to Test with Jest and Enzyme. Full Instruction on React Components Testing</a> (<strong>переведено</strong>)</li></ol><p>Руководство — «<a href="https://medium.com/devschacht/contributing-4e86e4481699">Участие в переводах devSchacht</a>»</p><p>Не стесняйтесь переводить и вообще участвовать в Hacktoberfest! 🎃</p><p><em>Слушайте наш подкаст в </em><a href="https://itunes.apple.com/ru/podcast/%D0%B4%D0%B5%D0%B2%D1%88%D0%B0%D1%85%D1%82%D0%B0/id1226773343"><em>iTunes</em></a><em> и </em><a href="https://soundcloud.com/devschacht"><em>SoundCloud</em></a><em>, читайте нас на </em><a href="https://medium.com/devschacht"><em>Medium</em></a><em>, контрибьютьте на </em><a href="https://github.com/devSchacht"><em>GitHub</em></a><em>, общайтесь в </em><a href="https://t.me/devSchacht"><em>группе Telegram</em></a><em>, следите в </em><a href="https://twitter.com/DevSchacht"><em>Twitter</em></a><em> и </em><a href="https://t.me/devSchachtChannel"><em>канале Telegram</em></a><em>, рекомендуйте в </em><a href="https://vk.com/devschacht"><em>VK</em></a><em> и </em><a href="https://www.facebook.com/devSchacht"><em>Facebook</em></a><em>.</em></p><p><a href="https://github.com/devSchacht/translations/tree/master/articles/hacktoberfest-is-back-and-celebrating-its-fifth-year/README.md">Статья на GitHub</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=186cde3bc0cc" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devschacht/hacktoberfest-%D0%B2%D0%B5%D1%80%D0%BD%D1%83%D0%BB%D1%81%D1%8F-%D0%B8-%D0%BF%D1%80%D0%B0%D0%B7%D0%B4%D0%BD%D1%83%D0%B5%D1%82-%D1%81%D0%B2%D0%BE%D0%B9-%D0%BF%D1%8F%D1%82%D1%8B%D0%B9-%D0%B3%D0%BE%D0%B4-186cde3bc0cc">Hacktoberfest вернулся и празднует свой пятый год!</a> was originally published in <a href="https://medium.com/devschacht">devSchacht</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Что такое тестирование и почему мы должны его делать?]]></title>
            <link>https://medium.com/devschacht/what-is-testing-and-why-should-we-do-it-acf06723816b?source=rss-19321d28194------2</link>
            <guid isPermaLink="false">https://medium.com/p/acf06723816b</guid>
            <category><![CDATA[devschacht-for-dummies]]></category>
            <category><![CDATA[devschacht]]></category>
            <dc:creator><![CDATA[Alexey Pyltsyn]]></dc:creator>
            <pubDate>Sat, 01 Sep 2018 16:31:02 GMT</pubDate>
            <atom:updated>2018-09-01T17:35:17.649Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Перевод статьи </em><a href="https://github.com/alexjoverm"><em>Alex Jover Morales</em></a><em>: </em><a href="https://vueschool.io/articles/vuejs-tutorials/what-is-testing-and-why-should-we-do-it/"><em>What’s testing and why should we do it?</em></a><em>.</em></p><p>В первой статье в этой серии из пяти частей о тестировании в JavaScript мы рассмотрим, что такое тестирование и почему мы должны это делать. Если вас интересует тестирование в контексте Vue.js, то обратите внимание на книгу «<a href="https://leanpub.com/testingvueru/c/happycoding">Тестирование компонентов Vue.js с помощью Jest</a>».</p><p>Тестирование в области разработки программного обеспечения — это процесс оценки того, что все части приложения ведут себя так, как ожидалось.</p><p>Тесты выполняют проверки программного обеспечения, проверяя, что полученный результат соответствует спецификациям, учитывая разные входные данные. Каждая из этих проверок называется <em>тестовым сценарием</em> (test case). В рабочем процессе agile каждая пользовательская история должна иметь набор тестовых сценариев. Простой пример:</p><pre>US-01: создание компонента ввода валюты</pre><pre>Сценарии тестирования:<br>– TC-01: он должен принимать только числа<br>1. Введите число «2». Ожидается: все должно быть в порядке<br>2. Введите символ «a». Ожидается: должно отображаться сообщение «Разрешены только числа»<br>– TC02: оно не может быть пустым<br>...</pre><p>В тестовых сценариях проверяются требования и характеристики конкретной функциональной возможности (функционала). Они могут предоставлять определённые детали или шаги, чтобы их можно было воспроизвести.</p><p>Скорее всего, если вы читаете эту статью, вы знаете, что такое тестирование и TDD, но если вы новичок в тестировании, у вас может возникнуть вопрос, который был в своё время у всех нас:</p><p>Не занимает ли тестирование слишком много времени? Нужно ли мне тестировать всё?</p><p>В этой статье мы поговорим о плюсах и минусах тестирования, о типах тестирования, и что ещё есть кроме тестирования для обеспечения качества приложения.</p><h3>Зачем писать тесты?</h3><p>Говоря о том, зачем нужно тестирование, можно упомянуть следующие его преимущества:</p><ul><li>Экономит деньги: без надлежащего тестирования количество времени и ресурсов, необходимых для поддержания продукта в долгосрочной перспективе, намного больше, чем инвестиции в тестирование, не говоря уже о том, что со временем что-то сломается.</li><li>Обеспечивает безопасность кода при командной работе: приложение часто создаётся командами. Разные люди изменяют один и тот же фрагмент кода с течением времени. Наличие тестов делают этот процесс более безопасным, поскольку никто не сломает что-то, не узнав об этом. Это также относится и к будущему, тесты обеспечивает безопасность кода, когда вы вернётесь через год или два для внесения изменений.</li><li>Помогает в создании лучшей архитектуры: когда часть приложения трудно тестировать, это обычно происходит из-за того, что оно тесно связано с другими частями или функциональность вашего приложения слишком сложна. При их тестировании вам нужно будет сделать их слабосвязанными, применить делегирование и паттерны проектирования, чтобы сделать приложение максимально простым и тестируемым.</li><li>Улучшает качество кода: ваш продукт менее подвержен сбоям в работе поскольку тесты помогает написать более надёжный и хороший код, который менее подвержен ошибкам.</li><li>Делает рефакторинг простым и безопасным: создание программного обеспечения — это итеративный процесс. Требования меняются с течением времени, следовательно, меняется и функциональность. Наличие хорошего тестового покрытия позволяет вам модифицировать определённый код, проверяя, что тесты все ещё успешно проходят. Если это не так, вы делаете правки в код таким образом, чтобы тесты прошли.</li></ul><p>Надеюсь, что на данном этапе вы убедились, почему тестирование полезно для вас, вашего приложения и компании, в которой вы работаете.</p><h3>Типы тестов</h3><p>Тесты делятся на разные типы. Каждый тип теста имеет свою цель (назначение) и область действия, и вам следует знать об этом. Каждый разработчик в какой-то момент пишет тест, который тестирует то, чего он не должен.</p><p>У нас есть три основных типа тестов:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/890/0*HXN7bdcfe14G_YnJ" /></figure><ul><li>End-to-end-тесты (сокращённо — E2E) или сквозные тесты, как их называют при переводе: тестируют систему в целом, эмулируя реальную пользовательскую среду. В интернете это тесты, запущенные в браузере, имитирующие щелчки мышью и нажатия клавиш. В общем, набор таких тестов не должен быть большим, так как они дороги для обслуживания и могут легко устареть из-за тестирования системы в целом.</li><li>Интеграционные тесты: цель данных тестов состоит в том, чтобы убедиться, что несколько зависимых друг от друга модулей кода работают вместе, и их взаимодействие работает должным образом.</li><li>Модульные тесты: они тестируют определённую функциональность изолированно. Их легче всего создавать и обслуживать, поэтому большинство тестовых наборов — это модульные тесты.</li></ul><p>Пирамида описывает баланс различных типов тестов. Нижняя часть — это самые быстрые, простые и самые изолированные тесты, а верхние — самые дорогие, самые медленные и охватывают всё приложение в целом.</p><p>Интеграционный слой можно даже разделить на ещё большее количество слоёв:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/890/0*4BTM7BkJBbhm2fmx" /></figure><p>Хотя есть несколько разногласий по поводу количества типов тестов и их имён, наиболее распространёнными являются тесты компонентов и API. Это всего лишь особые типы интеграционных тестов. В частности, тесты компонентов — это тесты, которые мы пишем на стороне фронтенда при тестировании приложения на Vue.js.</p><h3>Статический анализ</h3><p>Тесты — не единственный инструмент для обеспечения качества кода. В наше время для JavaScript также есть инструменты статической типизации и утилиты для проверки кода (<em>linters</em>, далее — линтеры). Они выполняют статический анализ вашего кода для поиска несоответствий выбранному стилю кода, неправильного использования языка, ненадлежащей и плохой практики, ошибок в контракте данных и многое другое.</p><blockquote><em>Контракт данных — формат данных, который будет использоваться некоторой частью приложения, например функцией. Обычно под этим понимается в каком виде будут представлены данные, например, тип входных и возвращаемых данных.</em></blockquote><p>Статическая типизация делает ваш код более безопасным на основе каждого контракта. Такие инструменты, как TypeScript или Flow, позволяют определять переменные, параметры и типы возвращаемых значений. Они гарантируют, что ваши классы, функции и методы имеют определённую структуру, а остальная часть вашего кода хорошо работает в соответствии с этим. Многие компании, принявшие статическую типизацию, сразу же поймали несколько ошибок.</p><p>Давайте сравним типизированную версию и не типизированную версию функции sum:</p><pre>// Нетипизированная функция<br>function sum(a, b) {<br>    return a + b;<br>}</pre><pre>// Типизированная функция<br>function sum(a: number, b: number) : number {<br>    return a + b;<br>}</pre><p>Версия функции без указания типов не мешает нам вызывает её со строчными входными данными, в результате возвращая нам конкатенацию строк. Например, вызов sum(&#39;1&#39;, &#39;2&#39;) возвращает &#39;12&#39;. Однако, если мы используем статическую типизацию, мы получаем ошибку, такую как Argument of type &#39;&quot;1&quot;&#39; is not assignable to parameter of type &#39;number&#39; (<em>Аргумент этого типа &#39;&quot;1&quot;&#39; не может быть присвоен параметру типа &#39;number&#39;</em>), и эта ошибка типизации предотвращает нас во время компиляции совершить вызов функции, который вернёт неверный результат, поскольку мы ожидаем сложение чисел, а не конкатенацию строк.</p><p>Линтеры — это специальные программы, цель которых анализ и проверка различных аспектов кода во время компиляции. JavaScript не имеет преимуществ компилятора, поэтому подвержен ошибкам во время выполнения по сравнению с другими языками, где об ошибках будет сообщено на стадии компиляции. ESLint стал линтером де-факто в JavaScript, а TSLint — в сообществе TypeScript.</p><p>Линтер пытается заполнить пробел, предоставляя правила проверки ошибок синтаксиса, стиля кода и неправильного использования (проблемных паттернов). В результате он уменьшает количество ошибок и повышает качество и корректность вашего кода.</p><p>В качестве примера, если вы используете правило <a href="https://eslint.org/docs/rules/no-var">no-var</a> в ESLint и напишите следующий код:</p><pre>var greet = &#39;Эй, Китти&#39;;</pre><p>Вы получите ошибку Unexpected var, используйте let или const вместо (no-var) (<em>Неожиданный var, используйте let или const вместо него (no-var)</em>).</p><p>В пирамиде статический анализ ещё точнее определён и проверяется быстрее (почти в режиме реального времени), чем модульные тесты, что делает его основой пирамиды:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/890/0*N4aqnFlqgeX1bso7" /></figure><p>Эта <a href="https://vueschool.io/articles/vuejs-tutorials/what-is-testing-and-why-should-we-do-it/">статья</a> является первой частью серии <a href="https://vueschool.io/articles/series/testing-like-a-pro-in-javascript/">Тестируй как профи в JavaScript</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=acf06723816b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devschacht/what-is-testing-and-why-should-we-do-it-acf06723816b">Что такое тестирование и почему мы должны его делать?</a> was originally published in <a href="https://medium.com/devschacht">devSchacht</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[React - это не новый jQuery]]></title>
            <link>https://medium.com/devschacht/react-is-not-the-new-jquery-5825b3269d2c?source=rss-19321d28194------2</link>
            <guid isPermaLink="false">https://medium.com/p/5825b3269d2c</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[devschacht]]></category>
            <category><![CDATA[devschacht-for-dummies]]></category>
            <dc:creator><![CDATA[Alexey Pyltsyn]]></dc:creator>
            <pubDate>Mon, 23 Jul 2018 09:14:57 GMT</pubDate>
            <atom:updated>2018-07-23T15:27:33.044Z</atom:updated>
            <content:encoded><![CDATA[<h3>React — это не новый jQuery</h3><p><em>Перевод статьи </em><a href="https://twitter.com/dmitrigrabov"><em>Dmitri Grabov</em></a><em>: </em><a href="https://medium.com/@dmitrigrabov/react-is-not-the-new-jQuery-e42a19f165f4"><em>React is not the new JQuery</em></a><em>.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*8dLOOJAWO2m2nJTZGd6SSQ.jpeg" /><figcaption>Фотография от <a href="https://unsplash.com/photos/gOROUFiJ8qU?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Mike Marquez</a> с сайта <a href="https://unsplash.com/search/photos/shiny?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>Это был тихий субботний день, когда я столкнулся с таким постом — <a href="http://bradfrost.com/blog/link/replacing-jQuery-with-vue-js-no-build-step-necessary/">React is the New JQuery (React — это новый jQuery)</a>. Я чувствовал, что было довольно много недоразумений, и подумал попытаться разрешить некоторые из поднятых в статье вопросов.</p><p>Я считаю, что обсуждение инструментов с точки зрения их крутости — это пустая трата времени и сил. Каждый инструмент разработан как ответ на улучшение решения распространённых проблем. Когда мы решаем одну проблему, возникают новые, которые, в свою очередь, требуют иных инструментов. Сами инструменты не вызывают сложности, они являются реакцией на более сложную работу, которой мы пытаемся заниматься.</p><p>Цель jQuery в основном заключалась в предоставлении единообразного способа решения проблем, связанными с кроссбраузерностью, а также обеспечить мощными инструментами управления DOM. Этот подход был основан на сервере, генерирующем HTML-страницу, а затем JS загружался на фронтенде для обработки взаимодействий пользователя. Вы можете создавать переключатели или любые компоненты для расширения возможностей браузера по умолчанию. Проблема с данным подходом заключается в том, что ваш пользовательский интерфейс заканчивается тем, что реализуется через клиент и сервер. Чаще всего это означает, что нам нужно два разработчика для реализации функциональных возможностей в двух местах — и на клиенте, и на сервере. Это занимает больше времени, больше общения и, скорее всего, приведёт к багам.</p><p>Вместо того, чтобы думать о React как способе реализации компонентов, подумайте о React как о самом пользовательском интерфейсе. Мы можем собрать пользовательский интерфейс из повторно используемых компонентов, которые создаём по ходу работы над приложением. Мы можем выполнять код таким же образом на сервере, как мы это делаем на клиенте. Это означает, что у нас наконец есть возможность реализовать весь наш пользовательский интерфейс на одном языке программирования. Это не только экономит значительное количество времени, но мы теперь свободны от багов, возникающих из-за того, что какая-нибудь одна из функций реализована в двух местах. Любые обновления теперь могут быть сделаны одним человеком.</p><p>React и Redux также приносят с собой ряд интересных идей, например как то, что пользовательский интерфейс является функцией состояния приложения. Мы больше не сохраняем состояние приложения в DOM, как это было бы с jQuery, поток состояния теперь изменился в обратную сторону. Состояние может находится в хранилище, а всем компонентам нужно сделать повторную отрисовку при каждом обновлении состояния. Хотя потребуется какое-то время, чтобы разобраться в этой концепции, но после этого ваш код станет легче для понимания.</p><p>Теперь я хотел бы рассмотреть некоторые из поднятых вопросов.</p><blockquote>Перепишите свою разметку на JSX. Обязательно замените атрибут class на className, иначе ничего не заработает.</blockquote><p>Причина в том, что JSX представляет собой JS-представление сегмента DOM, который выводит наш компонент. Мы не можем использовать class, потому что это зарезервированное ключевое слово в JavaScript, используемое для объявления классов, появившихся в ES6. className — неплохая альтернатива, поскольку это имя свойства, которое DOM-элементы используют для обозначения атрибута класса.</p><blockquote>Встроенный атрибут onClick, добавляемый к вашему JSX, сопоставляется с функцией для обработки щелчка мыши.</blockquote><p>В то время как обработчики событий выглядят так, как будто они являются встроенными, это всего лишь синтаксис, используемый для их объявления. По факту они реализованы с использованием делегирования, таким образом React применяет один-единственный обработчик событий в корне приложения для обработки всех событий. В результате наше приложение будет по-прежнему эффективным и высокопроизводительным даже с большим количеством обработчиков событий.</p><p>Одно сходство, которое React имеет с jQuery — это то, что они оба гарантируют одинаковую работоспособность событий во всех браузерах, что пытается сделать нашу жизнь немного легче.</p><blockquote>Добавьте this.handleClick = this.handleClick.bind(this); в конструктор, чтобы вызов метода класса заработал.</blockquote><p>Контекстное разыменование — сложная тема и может подловить даже опытных разработчиков. Один из способов обойти эту проблему в React — использовать стрелочные функции, как описано в <a href="https://github.com/facebook/react/issues/9851">этом ишью</a>.</p><blockquote>Это может быть только для меня, но React кажется сравнительно более сложным и неэлегантным.</blockquote><p>Это другой подход. Во многих случаях он будет лучше, но не всегда. Хотя может показаться, что его использование осложняет наше приложение, но на мой взгляд он на самом деле помогает нам справляться со сложностью, которая существует в больших приложениях. Я работал над приложениями, созданными с помощью React с более чем ста тысяч строк кода и на каждом шагу React был огромной помощью и играл важную роль. Некоторые проекты было бы сложно реализовать любым другим способом.</p><p>React может быть сложным, поскольку предполагает не только смену подхода к разработке, но также требует глубокого понимания основ JavaScript. Если вас это интересует, я запускаю <a href="http://constructorlabs.com/">учебную программу по JavaScript в Лондоне</a>, которая охватывает именно эту тему. У нас ещё осталось несколько мест в нашей сентябрьской группе, и я хотел бы помочь вам справиться с изучением React, а также со всеми сопутствующими технологиями.</p><blockquote>Примечание переводчика: а для всех тех, кто не живёт в Лондоне, но хочет изучить React на базовом уровне, предлагаю прочитать небольшую бесплатную книгу <a href="https://leanpub.com/the-road-to-learn-react-russian">«Путь к изучению React»</a>. Это перевод известной книги «The Road to learn React», которая переведена на четыре языка, а совсем недавно был закончен перевод на русский язык. Так что, если вы или кто-нибудь из вашего круга общения ещё не знают React, но желают его изучить, то эта книга будет отличным стартом для погружения в мир React!</blockquote><p><em>Слушайте наш подкаст в </em><a href="https://itunes.apple.com/ru/podcast/%D0%B4%D0%B5%D0%B2%D1%88%D0%B0%D1%85%D1%82%D0%B0/id1226773343"><em>iTunes</em></a><em> и </em><a href="https://soundcloud.com/devschacht"><em>SoundCloud</em></a><em>, читайте нас на </em><a href="https://medium.com/devschacht"><em>Medium</em></a><em>, контрибьютьте на </em><a href="https://github.com/devSchacht"><em>GitHub</em></a><em>, общайтесь в </em><a href="https://t.me/devSchacht"><em>группе Telegram</em></a><em>, следите в </em><a href="https://twitter.com/DevSchacht"><em>Twitter</em></a><em> и </em><a href="https://t.me/devSchachtChannel"><em>канале Telegram</em></a><em>, рекомендуйте в </em><a href="https://vk.com/devschacht"><em>VK</em></a><em> и </em><a href="https://www.facebook.com/devSchacht"><em>Facebook</em></a><em>.</em></p><p><a href="https://github.com/devSchacht/translations/tree/master/articles/react-is-not-the-new-jquery/README.md">Статья на GitHub</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5825b3269d2c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devschacht/react-is-not-the-new-jquery-5825b3269d2c">React - это не новый jQuery</a> was originally published in <a href="https://medium.com/devschacht">devSchacht</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Vue Test Utils и Jest: как писать простые модульные тесты для фронтенда]]></title>
            <link>https://medium.com/devschacht/simple-unit-tests-with-vue-test-utils-and-jest-a93f4ed3de64?source=rss-19321d28194------2</link>
            <guid isPermaLink="false">https://medium.com/p/a93f4ed3de64</guid>
            <category><![CDATA[devschacht]]></category>
            <category><![CDATA[devschacht-vue]]></category>
            <dc:creator><![CDATA[Alexey Pyltsyn]]></dc:creator>
            <pubDate>Thu, 05 Jul 2018 12:58:39 GMT</pubDate>
            <atom:updated>2018-07-05T12:58:39.610Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Перевод статьи </em><a href="https://twitter.com/EddYerburgh"><em>Edd Yerburgh</em></a><em>: </em><a href="https://medium.freecodecamp.org/simple-unit-tests-with-vue-test-utils-and-jest-c384d7abc321"><em>Vue Test Utils and Jest: how to write simple unit tests for your front end</em></a><em>.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*KlrR7EWfaDgtcW5hJGFjHQ.jpeg" /></figure><p>В этой обучающей статье я покажу вам, как тестировать компоненты Vue.</p><p>Мы собираемся писать модульные тесты и тесты снимками с помощью Jest и Vue Test Utils. Всё это без использования Webpack.</p><p>Это руководство предназначено для пользователей, знакомых с модульным тестированием. Если вы новичок в модульном тестировании, ознакомьтесь с моёй статьей про <a href="https://eddyerburgh.me/unit-test-vue-components-beginners">модульное тестирование Vue-компонентов для новичков</a>.</p><h4>Настройка</h4><p>Я сделал <a href="https://github.com/eddyerburgh/vue-unit-test-starter/">простой проект для старта</a>. Склонируйте его в свой каталог:</p><pre>git clone <a href="https://github.com/eddyerburgh/vue-unit-test-starter.git">https://github.com/eddyerburgh/vue-unit-test-starter.git</a></pre><blockquote>Примечание переводчика: со времени написания оригинальной статьи новая версия Vue Test Utils (всё ещё бета-версия), я сделал <a href="https://github.com/lex111/jest-vue-example">форк репозитория автора</a> для использования актуальной на момент перевода версии Vue Test Utils , и если хотите использовать стартовый проект с последней версией Vue Test Utils, то можете склонировать этот репозиторий:</blockquote><pre>git clone git@github.com:lex111/jest-vue-example.git</pre><blockquote>Примечание: в любом случае в статье будет использоваться синтаксис новой на момент перевода версии Vue Test Utils (<a href="https://github.com/vuejs/vue-test-utils/releases/tag/v1.0.0-beta.20">v1.0.0-beta.20</a>)в целях придания актуальности переводимой статье.</blockquote><p>Теперь перейдите в каталог с репозиторием и установите зависимости:</p><pre>cd vue-unit-test-starter &amp;&amp; npm install</pre><p>Когда зависимости установлены, запустите сервер разработки:</p><pre>npm run dev</pre><p>Теперь мы можем вернуться к коду.</p><p>Единственное, что нужно обсудить — псевдонимы. Это способ использования сокращённой записи для импорта файла. Вместо длинных операторов импорта, как показано ниже:</p><pre>import someModule from &#39;../../../../../src/components/someModule&#39;</pre><p>Можно использовать сокращённую нотацию или псевдоним. Самый распространённый псевдоним — это символ @, который указывает на каталог src.</p><pre>import someModule from &#39;@/components/someModule&#39;</pre><p>Примечание: вы можете установить любой псевдоним, который захотите, но проекты vue-cli используют @ для ссылки на каталог src.</p><p>В проектах vue-cli <a href="https://github.com/eddyerburgh/jest-vue-starter/blob/master/build/webpack.base.conf.js#L25">Webpack используется для добавления этого псевдонима</a>. Это классно, но мы не используем Webpack для выполнения наших тестов. По этой причине нужен другой способ разрешения псевдонимов.</p><p>Вот тут-то и вступает в дело Babel. Есть плагин babel-plugin-module-resolver, разрешающий псевдонимы в Babel. Вы можете увидеть его использование в файле .babelrc. Он применяется только в тестовом окружении, поскольку вы запускаете создание сборки в окружении разработки или продакшена, Webpack разрешает данный псевдоним.</p><p>Взгляните на следующий файл:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/af5891488edf200128e43f4e9cf5db21/href">https://medium.com/media/af5891488edf200128e43f4e9cf5db21/href</a></iframe><p>Итак, мы получили общее представление проекта, пришло время добавить Jest.</p><h4>Jest</h4><p>Jest — фреймворк для тестирования. Это один из <a href="https://github.com/eddyerburgh/vue-unit-test-perf-comparison">самых быстрых фреймворков для тестирования однофайловых Vue-компонентов</a> (SFC).</p><p>Помимо выполнение тестов, Jest поставляется с другими возможностями из коробки, такими как подставные (mock) объекты, покрытие кода и тестирование снимками.</p><p>Первое, что нужно сделать, это установить Jest:</p><pre>npm install --save-dev jest</pre><p>Для тестирования однофайловых компонентов, вам нужно скомпилировать их в JavaScript до выполнения тестов. Если вы попытаетесь запустить нескомпилированный однофайловый компонент, вы получите синтаксическую ошибку.</p><p>Jest не компилирует файлы с расширением .vue из коробки. Вам нужно указать это для их компиляции. Это достигается путём добавления поля jest в файл package.json.</p><p>Добавьте код ниже в свой package.json.</p><pre>&quot;jest&quot;: {<br>    &quot;moduleFileExtensions&quot;: [<br>        &quot;js&quot;,<br>        &quot;json&quot;,<br>        &quot;vue&quot;<br>    ],<br>    &quot;transform&quot;: {<br>        &quot;^.+\\.js$&quot;: &quot;&lt;rootDir&gt;/node_modules/babel-jest&quot;,<br>        &quot;.*\\.(vue)$&quot;: &quot;&lt;rootDir&gt;/node_modules/vue-jest&quot;<br>    }<br>}</pre><p>Вы видите поле moduleFileExtensions. Это указывает Jest, чтобы он выполнял файлы с расширением .vue, а также с расширениями .js и .json.</p><p>Также есть поле transform. Оно указывает Jest, как компилировать файлы перед их выполнением. Он находит все файлы с расширением .js и компилирует их с помощью babel-jest. Все vue-файлы компилируются с использованием vue-jest.</p><p>Это пользовательские преобразования, созданные для Jest: babel-jest компилирует JavaScript, vue-jest берёт файлы с расширением .vue и компилирует их в JavaScript.</p><p>Учитывая написанное выше, необходимо установить два пакета:</p><pre>npm install --save-dev babel-jest vue-jest</pre><p>Хорошо, теперь нам нужно добавить тест «на дым» (smoke test), чтобы убедиться, что всё работает, как следует.</p><p>В src/components создайте каталог __tests__. Добавьте файл MessageToggle.spec.js. Таким образом полный путь к тесту будет src/components/__tests__/MessageToggle.spec.js.</p><p>Скопируйте приведённый ниже код:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/743393b744dc33fc3f3fdbcd10f420aa/href">https://medium.com/media/743393b744dc33fc3f3fdbcd10f420aa/href</a></iframe><p>Jest автоматически запускает все JS-файлы в каталоге __tests__. Он даже добавляет переменную тестового окружения, поэтому весь тестовый скрипт выполняется Jest.</p><p>В поле script вашего package.json добавьте скрипт unit:</p><pre>&quot;unit&quot;: &quot;jest&quot;</pre><p>Теперь запустите этот скрипт:</p><pre>npm run unit</pre><p>Отлично, первый тест пройдён 👌.</p><p>Теперь мы напишем более сложные тесты с помощью Vue Test Utils.</p><h4>Vue Test Utils</h4><p><a href="https://github.com/vuejs/vue-test-utils/">Vue Test Utils</a> в данный момент находится в бета-версии, но прямо сейчас вы можете использовать его без особых проблем, т.к. работа над API в значительной степени завершена.</p><p>Установите его:</p><pre>npm install --save-dev vue-test-utils</pre><p>Теперь вы напишите аналогичный тест MessageToggle.spec.js, используя Vue Test Utils.</p><p>Скопируйте код ниже в файл src/components/__tests__/MessageToggle.spec.js.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8d9ef9f87996135f5f40e730914006a5/href">https://medium.com/media/8d9ef9f87996135f5f40e730914006a5/href</a></iframe><p>Здесь мы можем использовать функцию <a href="https://vue-test-utils.vuejs.org/ru/api/#shallowmount">shallowMount</a> для возврата объекта-обёртки. Обёртка содержит разные вспомогательные методы, например, text, который помогает проверять утверждения компонентов. Вы можете посмотреть полный список методов обёртки <a href="https://vue-test-utils.vuejs.org/ru/api/wrapper/#%D1%81%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2%D0%B0">здесь</a>.</p><p>Итак, добавим более сложный тест, выполняющий действие на компоненте Messagetoggle. Скопируйте код ниже в MessageToggle.spec.js:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ef446739a2bc80faadded54ea907938a/href">https://medium.com/media/ef446739a2bc80faadded54ea907938a/href</a></iframe><p>В этот раз мы нажимаем на кнопку (с #toggle-message) в MessageToggle и проверяем, что текст тега &lt;p&gt; изменился правильно.</p><p>Теперь запустите скрипт для запуска тестов:</p><pre>npm run unit</pre><p>Опа, тесты проходят! 🙌</p><p>Vue Test Utils абстрагирует внутренности Vue. Поэтому что вам нужно сделать — изучить API Vue Test Utils.</p><p>Теперь напишем тест для компонента List. Компонент List принимает свойства, к счастью, предоставляет способ передать свойства при монтировании компонента.</p><p>Создайте файл /src/components/__tests__/List.spec.js и вставьте код ниже:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/433ae33210cc84a86dfa70bef806d9a3/href">https://medium.com/media/433ae33210cc84a86dfa70bef806d9a3/href</a></iframe><p>На этот раз, как вы видите, мы используем функцию shallowMount. Это то же самое, что и mount, за исключением того, компонент отрисовывается только на один уровень. Как правило, лучше использовать shallowMount.</p><p>Теперь, когда вы написали модульные тесты, пришло время взглянуть на тестирование снимками.</p><h4>Тестирование снимками</h4><p>У Jest есть такая замечательная возможность, называемая тестированием снимками.</p><p>Тестирование снимками по сути берёт копию вашего дерева компонентов в виде строки, а затем при каждом выполнении тестов сравнивает с этим снимком. Если отрисованный компонент в виде HTML-кода изменился, тест не пройдёт.</p><p>Давайте добавить тест снимка в Message.spec.js.</p><p>Вам нужно отрисовать компонент в строку с помощью vue-server-renderer. Возвращаемая строка не очень читабельная, поэтому добавим ещё jest-serializer-vue, чтобы придать красивый, читаемый вид вашим снимкам.</p><pre>npm install --save-dev vue-server-renderer jest-serializer-vue</pre><p>Также вам нужно сообщить Jest для использования сериализатора. Добавьте поле snapshotSerializers внутри поля jest в ваш файл package.json:</p><pre>&quot;snapshotSerializers&quot;: [<br>    &quot;&lt;rootDir&gt;/node_modules/jest-serializer-vue&quot;<br>]</pre><p>Теперь обновите List.spec.js для добавления теста снимка:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f3882c3f1f2e0089e356183bbbd34312/href">https://medium.com/media/f3882c3f1f2e0089e356183bbbd34312/href</a></iframe><p>Этот тест неглубоко монтирует компонент и отрисовывает его в строку с HTML через использование vue-server-renderer.</p><p>Теперь запустим выполнение тестов:</p><pre>npm run unit</pre><p>В терминале вы увидите уведомление о сохранении только что созданного снимка. Вы можете увидеть, если перейдите в файл src/components/__tests__/__snapshots__/List.spec.js.snap:</p><pre>// Jest Snapshot v1, https://goo.gl/fbAQLP<br><br>exports[`List.vue has same HTML structure 1`] = `<br>&lt;ul&gt;<br>    &lt;li&gt;<br>        list item one<br>    &lt;/li&gt;<br>    &lt;li&gt;<br>        list item two<br>    &lt;/li&gt;<br>&lt;/ul&gt;<br>`;</pre><p>Круто, это и есть снимок. 📸</p><p>Теперь, если разметка List.vue изменится, Jest предупредит вас об этом при выполнении тестов.</p><h4>Выводы</h4><p>Итак, теперь вы создали модульные тесты и тесты снимками, используя Jest и Vue Test Utils.</p><p>Я пропустил ряд концепций. Вы можете посмотреть на <a href="https://github.com/eddyerburgh/jest-vue-example">готовый репозиторий на GitHub</a> (или посмотреть на тот же самый <a href="https://github.com/lex111/jest-vue-example">форк этого репозитория</a> с использованием последней версией Vue Test Utils.), если ваш проект некорректно работает.</p><p>В Jest имеется <a href="https://facebook.github.io/jest/">больше возможностей</a> для облегчения тестирования.</p><p>А у Vue Test Utils в свою очередь также есть много методов — <a href="https://vue-test-utils.vuejs.org/ru/">изучите документацию</a>.</p><blockquote>Из-за того, что русская документация по Vue Test Utils вышла совсем недавно после больших изменений, приветствуются различные исправления опечаток и неточностей. Пожалуйста, создайте PR с обновлениями в <a href="https://github.com/translation-gang/vue-test-utils">форк оригинального репозитория на Translation Gang</a>, так как это сообщество переводит и поддерживает документации по продуктам Vue</blockquote><p>Модульное тестирование Vue-компонентов ещё никогда не было таким простым, так что вперёд писать тесты!</p><p>Если вы узнали что-то интересное из этой статьи, поделитесь ею и не забывайте про 👏 для того, чтобы о ней узнали другие!</p><p><em>Слушайте наш подкаст в </em><a href="https://itunes.apple.com/ru/podcast/%D0%B4%D0%B5%D0%B2%D1%88%D0%B0%D1%85%D1%82%D0%B0/id1226773343"><em>iTunes</em></a><em> и </em><a href="https://soundcloud.com/devschacht"><em>SoundCloud</em></a><em>, читайте нас на </em><a href="https://medium.com/devschacht"><em>Medium</em></a><em>, контрибьютьте на </em><a href="https://github.com/devSchacht"><em>GitHub</em></a><em>, общайтесь в </em><a href="https://t.me/devSchacht"><em>группе Telegram</em></a><em>, следите в </em><a href="https://twitter.com/DevSchacht"><em>Twitter</em></a><em> и </em><a href="https://t.me/devSchachtChannel"><em>канале Telegram</em></a><em>, рекомендуйте в </em><a href="https://vk.com/devschacht"><em>VK</em></a><em> и </em><a href="https://www.facebook.com/devSchacht"><em>Facebook</em></a><em>.</em></p><p><a href="https://github.com/devSchacht/translations/tree/master/articles/vue-test-utils-and-jest-how-to-write-simple-unit-tests-for-your-front-end/README.md">Статья на GitHub</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a93f4ed3de64" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devschacht/simple-unit-tests-with-vue-test-utils-and-jest-a93f4ed3de64">Vue Test Utils и Jest: как писать простые модульные тесты для фронтенда</a> was originally published in <a href="https://medium.com/devschacht">devSchacht</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Как писать Vue-компоненты, которые хорошо взаимодействуют]]></title>
            <link>https://medium.com/devschacht/vue-components-play-nicely-cea6e41afe92?source=rss-19321d28194------2</link>
            <guid isPermaLink="false">https://medium.com/p/cea6e41afe92</guid>
            <category><![CDATA[devschacht]]></category>
            <category><![CDATA[девшахта]]></category>
            <category><![CDATA[devschacht-vue]]></category>
            <dc:creator><![CDATA[Alexey Pyltsyn]]></dc:creator>
            <pubDate>Fri, 29 Jun 2018 13:08:57 GMT</pubDate>
            <atom:updated>2018-06-29T16:35:46.432Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Перевод статьи </em><a href="https://twitter.com/@kball11"><em>Kevin Ball</em></a><em>: </em><a href="https://vuejsdevelopers.com/2018/06/18/vue-components-play-nicely/"><em>How To Build Vue Components That Play Nice</em></a><em>.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*UcVoQeuzNbUGhe6I.jpg" /></figure><p>Очень мало людей, которые пишут Vue-компоненты, изначально собираются выложить их в открытый доступ. Большинство из нас начинают писать компоненты по принципу — у нас есть проблема, которую мы хотим решить, написав для этого компонент. Иногда мы хотим решить одну и ту же проблему в разных местах нашей кодовой базы, поэтому мы берём компонент и рефакторим его немного для того, чтобы сделать повторно используемым. Затем мы хотим использовать компонент в другом проекте и для этого переносим его в отдельный пакет. Тогда у нас возникает мысль: «А почему бы не поделиться этим компонентом с остальным миром?» и мы делаем наш компонент свободно доступным.</p><p>С одной стороны, это здорово, что означает большую и растущую доступность компонентов с открытым исходным кодом для всех, кто работает с Vue (<a href="https://www.npmjs.com/search?q=vue">поиск по «vue» на npmjs.com</a> показывает более 13 000 пакетов).</p><p>С другой стороны, поскольку большинство из этих компонентов эволюционировали из конкретной ситуации, и не у всех из нас имеется опыт разработки компонентов для повторного использования в различных окружениях, многие из них не “хорошо взаимодействуют” (в оригинале “play nice” — прим. пер.) с экосистемой Vue.</p><p>Что значит “хорошо взаимодействует”? В общих чертах это означает, что он выглядит вполне естественным для разработчиков Vue, а также его легко расширить и интегрировать в любое приложение.</p><p>После изучения широкого набора различных компонентов с открытым исходным кодом, вот что я думаю о Vue-компонентах, которые хорошо взаимодействуют:</p><ol><li>Реализована совместимость с директивой v-model</li><li>Компонент прозрачен для событий</li><li>Есть возможность присваивать атрибуты необходимым элементам</li><li>Придерживаются норм браузеров для навигации по клавиатуре</li><li>Отдаётся предпочтение обработчикам событий, а не колбэкам</li><li>Видимость стилей ограничена компонентом</li></ol><h4>Реализована совместимость с директивой v-model</h4><p>Для компонентов, которые по сути являются полями формы — будь то автозаполнение полей для поиска, поля с календарём для ввода даты или что-то ещё, иначе говоря, реализуют дополнительную функциональность для одного поля, позволяющую пользователю указывать данные — одним из наиболее важных способов быть естественным для Vue является поддержка v-model.</p><p>Согласно <a href="https://ru.vuejs.org/v2/guide/components.html#%D0%98%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-v-model-%D0%BD%D0%B0-%D0%BA%D0%BE%D0%BC%D0%BF%D0%BE%D0%BD%D0%B5%D0%BD%D1%82%D0%B0%D1%85">руководству Vue по компонентам</a> директива v-model на компонентах, в основном, работает через передачу свойства value с применением обработчика событий input.</p><p>Например, если бы мы реализовывали элемент ввода даты, который оборачивает поле ввода, то мы инициализировали бы его с использованием свойства value, а при выборе даты вызывали событие input, и в итоге код выглядел бы следующим образом:</p><pre>import datepicker from &#39;my-magic-datepicker&#39;;<br><br>export default {<br>  props: [&#39;value&#39;],<br>  mounted() {<br>    datepicker(this.$el, {<br>      date: this.value,<br>      onDateSelected: (date) =&gt; {<br>        this.$emit(&#39;input&#39;, date);<br>      },<br>    });<br>  }<br>}</pre><h4>Компонент прозрачен для событий</h4><p>Для реализации поддержки директивы v-model необходимо реализовать событие input. Но как насчёт других событий, таких как события нажатий с мыши и клавиатуры и т.д.? В то время как нативные события всплывают в HTML (DOM), обработчики событий во Vue по умолчанию не делают это.</p><p>Например, если я сделаю что-то подобное, это не сработает:</p><pre>&lt;my-textarea-wrapper @focus=&quot;showFocus&quot;&gt;</pre><p>До тех пор, пока мы не напишем код в компоненте-обёртке, который на самом деле генерирует событие focus, обработчик события showFocus никогда не будет вызван. <em>Однако</em> Vue предоставляет нам способ для доступа к применяемым компоненту обработчикам событий, поэтому мы можем присвоить в нужным месте объект $listeners.</p><pre>&lt;div class=&quot;my-textarea-wrapper&quot;&gt;<br>  &lt;textarea v-on=&quot;$listeners&quot;&gt;&lt;/textarea&gt;<br>&lt;/div&gt;</pre><p>Теперь события, которые происходят на текстовом многострочном поле, будут всплывать как обычно.</p><h4>Есть возможность присваивать атрибуты необходимым элементам</h4><p>Как насчёт таких атрибутов как rows для полей с текстовыми областями или title для добавления простой подсказки к любому атрибуту через соответствующий HTML-атрибут.</p><p>По умолчанию Vue принимает атрибуты, применяемые к атрибуту, и помещает их в корневой элемент этого компонента. Это не всегда то, что вам нужно. Однако, если мы снова посмотрим на обёртку над тегом textarea, то в этом случае имело смысл применять атрибуты к самому элементу, а не оборачивающему тегу div.</p><p>Чтобы сделать это, мы указываем компоненту не применять атрибуты по умолчанию, а вместо этого назначать их непосредственно, используя объект $attrs. В нашем JavaScript-коде:</p><pre>export default {<br>  inheritAttrs: false,<br>}</pre><p>А затем в нашем шаблоне:</p><pre>&lt;div class=&quot;my-textarea-wrapper&quot;&gt;<br>  &lt;textarea v-bind=&quot;$attrs&quot;&gt;&lt;/textarea&gt;<br>&lt;/div&gt;</pre><h4>Придерживаются норм браузеров для навигации по клавиатуре</h4><p>Доступность и навигация с помощью клавиатуры — одно из наиболее часто забываемых частей веб-разработки, и одновременно все они являются важными для правильно сделанного компонента, если вам нужен такой компонент, который хорошо взаимодействует в экосистеме.</p><p>В основе этого лежит соответствие стандартам браузера: клавиша табуляция должна позволять выбирать поля формы. Клавиша ввода обычно используется для нажатия на кнопку или перехода по ссылке.</p><p>Полный список навигаций по клавиатуре для стандартных компонентов можно найти на <a href="https://www.w3.org/TR/wai-aria-practices/#aria_ex">сайте W3C</a>. Следуя этим рекомендациям, ваш компонент можно будет использовать во всех приложениях, а не только в тех, которым нужна доступность.</p><h4>Отдаётся предпочтение обработчикам событий, а не колбэкам</h4><p>Когда дело до взаимодействия данными и пользовательскими действиями от вашего компонента к его родителям, то есть два распространённых варианта: колбэки во входных параметрах (они же свойства) и события. Поскольку пользовательские события не всплывают как нативные браузерные события, они функционально одинаковы, но для возможности повторного использования я почти всегда рекомендую использовать события вместо колбэков. Почему?</p><p>В <a href="http://www.fullstackradio.com/87">одном выпуске подкаста Fullstack Radio</a> Крис Фриц, один из разработчиков <a href="https://ru.vuejs.org/v2/guide/team.html">основной команды Vue</a>, привёл следующие причины:</p><ol><li>Использование событий делают компонент более прозрачным в плане того, что должны о нём знать родительские компоненты. Он создаёт чёткое разделение между тем, что получено от родительских компонентов и тем, что отправлено им.</li><li>Вы можете использовать выражения непосредственно в обработчиках событий, позволяя держать их очень компактными для обычных случаев.</li><li>Это больше соответствует Vue — примеры и документация Vue обычно используют события для связи взаимодействия компонента с родительскими компонентами.</li></ol><p>К счастью, если вы используете подход «колбэки в свойствах» (callbacks-in-props), довольно просто изменить компонент для генерации событий вместо этого. Компонент, использующий колбэки, может быть таким:</p><pre>// файл my-custom-component.vue<br>export default {<br>  props: [&#39;onActionHappened&#39;, ...]<br>  methods() {<br>    handleAction() {<br>      // остальной код...<br>      if (typeof this.onActionHappened === &#39;function&#39;) {<br>        this.onActionHappened(data);<br>      }<br>    }<br>  }<br>}</pre><p>Далее при его использование может выглядит так:</p><pre>&lt;my-custom-component :onActionHappened=&quot;actionHandler&quot; /&gt;</pre><p>Переход на новый подход, основанный на событиях, будет выполнен следующим образом:</p><pre>// файл my-custom-component.vue<br>export default {<br>  methods() {<br>    handleAction() {<br>      // остальной код...<br>      this.$emit(&#39;action-happened&#39;, data);<br>    }<br>  }<br>}</pre><p>И использование компонента изменится на:</p><pre>&lt;my-custom-component @action-happened=&quot;actionHandler&quot; /&gt;</pre><h4>Видимость стилей ограничена компонентом</h4><p>Однофайловые компоненты позволяют встраивать стили непосредственно в компоненты, и особенно в сочетании с ограничением области видимости CSS-стилей через атрибут scoped даёт нам отличный способ использовать полностью упакованные, стилизованные компоненты таким образом, чтобы они не влияли на другие части приложения.</p><p>Благодаря такой возможности у вас может возникнуть соблазн поместить все стили в компонент и отправлять в открытый доступ такой полностью стилизованный компонент. Здесь следующая проблема: не все стили приложения одинаковые, и те стили, благодаря которым ваше приложение выглядит хорошо, в чьём-то другом приложении будут выглядеть совсем наоборот.</p><p>Для предотвращения этого я рекомендую сделать так, чтобы все структурные CSS-стили (цвета, рамки, тени и т.д.) были либо исключены из компонента, либо должны быть доступны для отключения в нём. Как вариант, рассмотрите возможность использования настраиваемого SCSS-файла (partial), который позволит пользователям вашего компонента стилизовать его так, как это будет необходимо.</p><p>Недостаток использования внешнего SCSS-файла заключается в том, что вашим пользователям потребуется подключать этот файл в свою систему сборки для компиляции стилей в CSS, иначе им будет показан компонент без стилей. Для получения лучшего из обоих миров, вы можете ограничить область действия стилей в компонента служебным классом, который будет передаваться через входной параметр (свойство компонента), для отключения стилей по умолчанию и удовлетворения потребностей тех пользователей, которые хотят иметь собственное оформление компонента. Если вы создаёте SCSS-стили в виде миксина, то вы могли бы использовать одинаковые SCSS-стили для пользователей, которым требуется большая гибкость для стилизации компонента.</p><pre>&lt;template&gt;<br>  &lt;div :class=&quot;isStyledClass&quot;&gt;<br>    &lt;!-- мой компонент --&gt;<br>  &lt;/div&gt;<br>&lt;/template&gt;</pre><p>Далее в вашем JavaScript-коде компонента:</p><pre>export default {<br>  props: {<br>    disableStyles: {<br>      type: Boolean,<br>      default: false<br>    }<br>  },<br>  computed: {<br>    isStyledClass() {<br>      if (!this.disableStyles) {<br>        return &#39;is-styled&#39;;<br>      }<br>  },<br>}</pre><p>Тогда вы сможете использовать так:</p><pre>@import &#39;my-component-styles&#39;;<br><br>.is-styled {<br>  @include my-component-styles();<br>}</pre><p>Данное решение позволит стилизовать компонент из коробки, но даёт возможность пользователям определять собственную стилизацию компонента с помощью установки свойства disableStyles в значение true без всякого переопределения стилей с более высокой специфичностью, либо использовать ваш миксин с их стилями, или вообще полностью с нуля стилизовать компонент.</p><p><em>Слушайте наш подкаст в </em><a href="https://itunes.apple.com/ru/podcast/%D0%B4%D0%B5%D0%B2%D1%88%D0%B0%D1%85%D1%82%D0%B0/id1226773343"><em>iTunes</em></a><em> и </em><a href="https://soundcloud.com/devschacht"><em>SoundCloud</em></a><em>, читайте нас на </em><a href="https://medium.com/devschacht"><em>Medium</em></a><em>, контрибьютьте на </em><a href="https://github.com/devSchacht"><em>GitHub</em></a><em>, общайтесь в </em><a href="https://t.me/devSchacht"><em>группе Telegram</em></a><em>, следите в </em><a href="https://twitter.com/DevSchacht"><em>Twitter</em></a><em> и </em><a href="https://t.me/devSchachtChannel"><em>канале Telegram</em></a><em>, рекомендуйте в </em><a href="https://vk.com/devschacht"><em>VK</em></a><em> и </em><a href="https://www.facebook.com/devSchacht"><em>Facebook</em></a><em>.</em></p><p><a href="https://github.com/devSchacht/translations/tree/master/articles/how-to-build-vue-components-that-play-nice/README.md">Статья на GitHub</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cea6e41afe92" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devschacht/vue-components-play-nicely-cea6e41afe92">Как писать Vue-компоненты, которые хорошо взаимодействуют</a> was originally published in <a href="https://medium.com/devschacht">devSchacht</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Минимальное руководство по декораторам ECMAScript]]></title>
            <link>https://medium.com/devschacht/a-minimal-guide-to-ecmascript-decorators-c7348f61ba24?source=rss-19321d28194------2</link>
            <guid isPermaLink="false">https://medium.com/p/c7348f61ba24</guid>
            <category><![CDATA[devschacht]]></category>
            <category><![CDATA[devschacht-for-dummies]]></category>
            <dc:creator><![CDATA[Alexey Pyltsyn]]></dc:creator>
            <pubDate>Tue, 26 Jun 2018 09:04:39 GMT</pubDate>
            <atom:updated>2018-07-02T11:46:39.953Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Перевод статьи </em><a href="https://twitter.com/thatisuday"><em>Uday Hiwarale</em></a><em>: </em><a href="https://itnext.io/a-minimal-guide-to-ecmascript-decorators-55b70338215e"><em>A minimal guide to ECMAScript Decorators</em></a><em>.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rRng0oYfLl5_6v1O8hAY-A.png" /></figure><p>Рассмотрим ECMAScript как <strong>язык</strong>, на котором вы разговариваете, например, <strong>английский</strong>. Тогда JavaScript будет <strong>диалектом</strong>, скажем, <strong>британского английского</strong>. Диалект — это сам язык, но основанный на принципах языка, из которого он произошёл. Итак, ECMAScript — это книга рецептов для приготовления/написания JavaScript, и только от шеф-повара/разработчика зависит, следовать его ингредиентам/правилам или нет.</p><p>Как правило, последователи (adopters) JavaScript соблюдают все спецификации, написанные в языке (иначе разработчики сойдут с ума), и отправляют новую версию движка JavaScript очень поздно, пока до конца не убедятся, что всё работает как надо. <strong>TC39</strong> или технический комитет 39 (Technical Committee 39) в ассоциации ECMA International отвечает за поддержку спецификаций языка ECMAScript. Члены этой команды являются частью ECMA International, разработчиками браузеров и представителями компаний, заинтересованных вебом в целом.</p><p>Поскольку ECMAScript — это открытый стандарт, любой может предложить новые идеи или возможности и работать над ними. Следовательно, предложение новой функциональной возможности проходит через 4 основные этапа, и TC-39 участвует в этом процессе, пока предложение не будет готово к внедрению.</p><ul><li><strong>Нулевой этап (</strong><em>stage 0</em><strong>) — </strong>кандидат на предложение (<em>strawman</em>)<br>Представить новую возможность (предложение) в комитет TC-39. Как правило представляется членом TC39 или помощником (contributor) TC39.</li><li><strong>Первый этап</strong> <strong>(</strong><em>stage 1</em><strong>)</strong>— предложение (<em>proposal</em>)<br>Определить варианты использования предложения, зависимости, задачи, демонстрации, полифилы и т.д. Куратор (член TC39) будет отвечать за это предложение.</li><li><strong>Второй этап</strong> <strong>(</strong><em>stage 2</em><strong>)</strong>— черновик (<em>draft</em>)<br>Это первоначальная версия возможности, которая в конечном счёте будет добавлена. Следовательно, должны быть представлены описание и синтаксис. Транспилер, такой как Babel, должен поддерживать и продемонстрировать реализацию.</li><li><strong>Третий этап (</strong><em>stage 3</em><strong>) </strong>— кандидат (<em>candidate</em>)<br>Предложение почти готово и некоторые изменения могут быть сделаны в ответ на критические проблемы, поднятые последователями и комитетом TC39.</li><li><strong>Четвертый этап (</strong><em>stage 4</em><strong>)</strong> — готов (<em>finished</em>)<br>Предложение готово для включения в стандарт.</li></ul><p>В настоящее время (<em>июнь 2018</em>) <strong>декораторы</strong> находятся на <strong>втором этапе</strong>, и у нас есть Babel-плагин для транспиляции декораторов babel-plugin-transform-decorators-legacy. Предложения, находящиеся на втором этапе не рекомендуются для использования в продакшене, поскольку синтаксис новой возможности подвержен изменениям. В любом случае, декораторы прекрасны и очень полезны для ускорения процесса разработки.</p><p>С этого момента мы работаем с экспериментальным JavaScript, поэтому ваша версия Node.js может не поддерживать данную возможность. Поэтому нам нужен транспилятор Babel или TypeScript. Используйте плагин <a href="https://github.com/thatisuday/js-plugin-starter"><strong>js-plugin-starter</strong></a> для настройки очень простого проекта, в котором я добавил поддержку декораторов, которые мы рассмотрим в статье.</p><p>Для понимания декораторов нужно сначала разобраться, что такое <strong>дескриптор свойства</strong> (property descriptor) объекта в JavaScript. Дескриптор свойства представляет собой набор правил для свойства объекта, как например, является ли свойство доступным для записи (<strong>writable</strong>) или перечислимым (<strong>enumerable</strong>). Когда мы создаём простой объект и добавляем некоторые свойства, у каждого из свойств есть дескриптор свойства по умолчанию.</p><pre>var myObj = {<br>    myPropOne: 1,<br>    myPropTwo: 2<br>};</pre><p>myObj — простой JavaScript-объект, который выглядит следующим образом в консоли</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*Y8y_yHAuU4e5qQ98328h9A.png" /></figure><p>Теперь, если присвоим новое значение для свойства, как показано ниже, операция завершится успешно и мы получим изменённое значение.</p><pre>myObj.myPropOne = 10;<br>console.log(myObj.myPropOne); //==&gt; 10</pre><p>Для получения дескриптора свойства, нам нужно использовать метод Object.getOwnPropertyDescriptor(obj, propName). <strong>Own</strong> означает вернуть дескриптор свойства propName, только если оно принадлежит объекту obj, а не его цепочке прототипов.</p><pre>const descriptor = Object.getOwnPropertyDescriptor(<br>    myObj,<br>    &#39;myPropOne&#39;<br>);<br><br>console.log(descriptor);</pre><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*_hI_shyJTWzbDzxAZRG2cw.png" /></figure><p>Метод Object.getOwnPropertyDescriptor возвращает объект с ключами, описывающими разрешения и текущее состояние свойства. value — текущее значение свойства, writable — может ли пользователь назначить новое значение для свойства, enumerable — будет ли это свойство отображаться при перечислениях, например, при итерациях цикла for in или for of, либо в Object.keys и т.д., configurable — есть ли у пользователя разрешение изменять <strong>дескриптор свойства</strong> и может ли он изменять значение на writable или enumerable. В дескрипторе свойств есть ключи get и set — промежуточные функции для возврата или обновления значений, но эти ключи необязательные.</p><p>Для создания нового свойства объекта или обновления существующего свойства с пользовательским дескриптором, мы можем воспользоваться Object.defineProperty. Давайте изменим существующее свойство myPropOne с writable на false, что <strong>запретит изменения</strong> в myObj.myPropOne.</p><pre>&#39;use strict&#39;;<br><br>let myObj = {<br>    myPropOne: 1,<br>    myPropTwo: 2<br>};<br><br>// изменяем дескриптор свойства<br>Object.defineProperty(myObj, &#39;myPropOne&#39;, {<br>    writable: false<br>});<br><br>// распечатываем дескриптор свойства<br>let descriptor = Object.getOwnPropertyDescriptor(<br>    myObj, &#39;myPropOne&#39;<br>);<br>console.log(descriptor);<br><br>// устанавливаем новое значение<br>myObj.myPropOne = 2;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*OA4CAoOYemieJ9lB5wmqCg.png" /></figure><p>Как видно из вышеприведённой ошибки, наше свойство myPropOne недоступно для записи, поэтому, если пользователь попытается присвоить ему новое значение, будет выброшена ошибка.</p><blockquote>Если Object.defineProperty обновляет существующий дескриптор свойства, тогда <strong>исходный дескриптор</strong> будет <strong>переопределен</strong> новыми изменениями. Object.defineProperty возвращает исходный объект myObj после изменений.</blockquote><p>Давайте посмотрим, что произойдёт, если мы установим ключ дескриптора enumerable в значение false.</p><pre>let myObj = {<br>    myPropOne: 1,<br>    myPropTwo: 2<br>};<br><br>// изменяем дескриптор свойства<br>Object.defineProperty(myObj, &#39;myPropOne&#39;, {<br>    enumerable: false<br>});<br><br>// распечатываем дескриптор свойства<br>let descriptor = Object.getOwnPropertyDescriptor(<br>    myObj, &#39;myPropOne&#39;<br>);<br>console.log(descriptor);<br><br>// распечатываем ключи<br>console.log(Object.keys(myObj));</pre><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*Aa-unAIvyxiw3kGjIz4Ewg.png" /></figure><p>Как видно из приведённого выше результата в консоли, мы не видим свойство myPropOne при вызове Object.keys.</p><p>При определении нового свойства с использованием Object.defineProperty и передадим ему пустой дескриптор {}, будет задан дескриптор по умолчанию, который выглядит так:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*e3FZCJKiLjbMVJnFbHcKIg.png" /></figure><p>Теперь давайте определим новое свойство с пользовательским дескриптором, где для ключа дескриптора configurable установлено значение false. Мы сохраним writable в значение false, а enumerable в значение true с value, установленным в 3.</p><pre>let myObj = {<br>    myPropOne: 1,<br>    myPropTwo: 2<br>};<br><br>// изменяем дескриптор свойства<br>Object.defineProperty(myObj, &#39;myPropThree&#39;, {<br>    value: 3,<br>    writable: false,<br>    configurable: false,<br>    enumerable: true<br>});<br><br>// распечатываем дескриптор свойства<br>let descriptor = Object.getOwnPropertyDescriptor(<br>    myObj, &#39;myPropThree&#39;<br>);<br>console.log(descriptor);<br><br>// изменяем дескриптор свойства<br>Object.defineProperty(myObj, &#39;myPropThree&#39;, {<br>    writable: true<br>});</pre><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*QulK_GxuflHPaJ6X4UwqAA.png" /></figure><p>Установив дескриптор ключа configurable в значение false, мы потеряли возможность изменять дескриптор нашего свойства myPropThree. Это очень полезно, если вы не хотите, чтобы ваши пользователи манипулировали рекомендуемым поведением объекта.</p><p><strong>get</strong> (геттер) и <strong>set</strong> (сеттер) в свойстве также можно установить в дескрипторе свойства. Но когда вы определяете геттер, придётся кое-чем пожертвовать. У вас нет <strong>начального значения</strong> или ключа value в дескрипторе вообще, потому что геттер вернёт значение этого свойства. Вы также не можете использовать ключ writable в дескрипторе, потому что ваши записи выполняются через сеттер, и вы можете предотвратить запись там. Взгляните на документацию MDN по <a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/get">геттеру</a> и <a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/set">сеттеру</a>, или прочитайте <a href="https://codeburst.io/javascript-object-property-attributes-ac012be317e2">эту статью</a>, если вам не нужны подробные объяснения.</p><blockquote>Вы можете и/или обновлять сразу несколько свойств, используя Object.defineProperties, принимающий два аргумента. Первый аргумент — <strong>целевой объект</strong>, свойства которого должны быть добавлены/изменены, а второй аргумент — это объект с key в качестве <strong>имени свойства</strong> и value как дескриптор свойства. Эта функция возвращает <strong>целевой объект</strong>.</blockquote><p>У функции Object.create следующий синтаксис:</p><pre>let obj = Object.create(prototype, {property: descriptor, ... })</pre><p>Здесь prototype — это объект, который будет прототипом obj. Если prototype равен null, тогда у obj не будет прототипа. Когда вы определяете пустой или непустой объект с синтаксисом var obj= {} по умолчанию obj.__proto__ будет указывать на Object.prototype, следовательно, obj имеет прототип класса Object.</p><p>Это похоже на использование Object.create вместе с Object.prototype в качестве первого аргумента (<em>прототип создаваемого объекта</em>).</p><pre>&#39;use strict&#39;;<br><br>let obj = Object.create(Object.prototype, {<br>    a: { value: 1, writable: false },<br>    b: { value: 2, writable: true }<br>});<br><br>console.log(obj.__proto__);<br>console.log(`obj.hasOwnProperty(&#39;a&#39;) =&gt; ${obj.hasOwnProperty(&#39;a&#39;)}`);</pre><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*Fc2_huyI1qxhEif4E9wHRw.png" /></figure><p>Но когда мы устанавливаем <strong>prototype</strong> в значение null, мы получаем ошибку, показанную ниже.</p><pre>&#39;use strict&#39;;<br><br>let obj = Object.create(null, {<br>    a: { value: 1, writable: false },<br>    b: { value: 2, writable: true }<br>});<br><br>console.log(obj.__proto__);<br>console.log(`obj.hasOwnProperty(&#39;a&#39;) =&gt; ${obj.hasOwnProperty(&#39;a&#39;)}`);</pre><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*JOvcTkY5uzgrjlOBhz0QtQ.png" /></figure><h4>✱ Декоратор метода класса</h4><p>Теперь, когда мы выяснили, как мы можем определять и настраивать новые или существующие свойства объекта, давайте обратим внимание на декораторы и почему мы вообще мы обсуждали дескрипторы свойств вообще.</p><p>Декоратор — это функция JavaScript (<em>рекомендуется чистая функция</em>), которая используется для изменения свойств/методов класса или самого класса. Когда вы добавляете синтаксис @decoratorFunction в начало <strong>свойства класса</strong> или <strong>метода</strong>, либо самого <strong>класса</strong>, decoratorFunction <strong>вызывается</strong> с несколькими аргументами, <strong>которые мы можем использовать для изменения класса или свойств класса</strong>.</p><p>Давайте создадим простую функцию декоратора readonly. Но до этого давайте создадим класс User с методом getFullName, который возвращает полное имя пользователя, путём объединения firstName и lastName.</p><pre>class User {<br>    constructor(firstname, lastName) {<br>        this.firstname = firstname;<br>        this.lastName = lastName;<br>    }<br><br>    getFullName() {<br>        return `${this.firstname} ${this.lastName}`;<br>    }<br>}<br><br>// создаём экземпляр<br>const user = new User(&#39;John&#39;, &#39;Doe&#39;);<br>console.log(user.getFullName());</pre><p>Код выше выведет John Doe на консоль. Но есть огромная проблема, поскольку кто-то может изменить метод getFullName.</p><pre>User.prototype.getFullName = function() {<br>    return &#39;ВЗЛОМАНО!&#39;;<br>}</pre><p>При это мы получим следующий результат.</p><pre>ВЗЛОМАНО!</pre><p>Чтобы избежать общедоступного доступа для переопределения любого из наших методов, нам нужно изменить дескриптор свойства метода getFullName, который находится в объекте User.prototype.</p><pre>Object.defineProperty(User.prototype, &#39;getFullName&#39;, {<br>    writable: false<br>});</pre><p>Теперь, если пользователь попытается переопределить метод getFullName, он получит ошибку.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*UVOaz8O1FoSa7KVpIBFMxA.png" /></figure><p>Но если у нас несколько методов в классе User, делать вручную это не так здорово. Поэтому в таком случае на помощь приходит декораторы. Мы можем добиться того же, добавив синтаксис @readonly перед методом getFullName, как показано ниже.</p><pre>function readonly(target, property, descriptor) {<br>    descriptor.writable = false;<br>    return descriptor;<br>}<br><br>class User {<br>    constructor(firstname, lastName) {<br>        this.firstname = firstname;<br>        this.lastName = lastName;<br>    }<br><br>    @readonly<br>    getFullName() {<br>        return `${this.firstname} ${this.lastName}`;<br>    }<br>}<br><br>User.prototype.getFullName = function() {<br>    return &#39;ВЗЛОМАНО!&#39;;<br>}</pre><p>Посмотрите на метод readonly. Он принимает три аргумента. property — это имя свойства/метода в объекте target (<em>который идентичен </em><em>User.prototype</em>), а descriptor — дескриптор переданного свойства. Внутри функции декоратора мы должны возвратить descriptor. Этот descriptor заменит существующий дескриптор свойства для этого свойства.</p><p>Существует ещё одна версия синтаксиса декоратора, похожая на @decoratorWrapperFunction(...customArgs). Но с этим синтаксисом decoratorWrapperFunction должен вернуть decoratorFunction, который аналогичен в используемом ранее примере.</p><pre>function log(logMessage) {<br>    // возвращаем функцию декоратора<br>    return function (target, property, descriptor) {<br>        // сохраняем исходное значение, которое является методом (функцией)<br>        const originalMethod = descriptor.value;<br><br>        // заменяем реализацию метода<br>        descriptor.value = function(...args) {<br>            console.log(&#39;[LOG]&#39;, logMessage);<br><br>            // вызов исходного метода<br>            // `this` указываем на экземпляр<br>            return originalMethod.call(this, ...args);<br>        };<br><br>        return descriptor;<br>    }<br>}<br><br>class User {<br>    constructor(firstname, lastName) {<br>        this.firstname = firstname;<br>        this.lastName = lastName;<br>    }<br><br>    @log(&#39;calling getFullName method on User class&#39;)<br>    getFullName() {<br>        return `${this.firstname} ${this.lastName}`;<br>    }<br>}<br><br>var user = new User(&#39;John&#39;, &#39;Doe&#39;);<br>console.log(user.getFullName());</pre><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*sUHsV_OSQUSehgfblsYvRg.png" /></figure><p>Декораторы не различают статические и нестатические методы. Код ниже будет работать прекрасно, изменится только то, как вы будете получать доступ к методу. То же самое относится к <strong>декораторам полей экземпляра</strong>, которые мы увидим ниже.</p><pre>@log(&#39;calling getFullName method on User class&#39;)<br>static getVersion() {<br>    return &#39;v1.0.0&#39;;<br>}<br><br>console.log(User.getVersion());</pre><h4>✱ Декоратор полей экземпляра класса</h4><p>До сих пор мы видели изменение дескриптора свойства с помощью синтаксиса @decorator или @decorator(..args), но как насчёт <strong>общедоступных/закрытых свойств</strong> (<em>полей экземпляра класса</em>)?</p><p>В отличие от typescript или java у JavaScript-классов нет полей экземпляра класса или свойств класса. Это связано с тем, что всё, что определено в class и вне constructor, должно принадлежать <strong>прототипу</strong>. Но есть новое <a href="https://github.com/tc39/proposal-class-fields">предложение</a> для включения полей экземпляра класса с модификаторами доступа public и private, который сейчас находится на <a href="https://github.com/tc39/proposals">третьем этапе</a>, и для него есть <a href="https://babeljs.io/docs/plugins/transform-class-properties/">соответствующий Babel-плагин</a>.</p><p>Давайте определим простой класс User, но на этот раз нам не нужно устанавливать значения по умолчанию для firstName и lastName.</p><pre>class User {<br>    firstName = &#39;default_first_name&#39;;<br>    lastName = &#39;default_last_name&#39;;<br><br>    constructor(firstName, lastName) {<br>        if (firstName) {<br>            this.firstName = firstName;<br>        }<br>        if (lastName) {<br>            this.lastName = lastName;<br>        }<br>    }<br><br>    getFullName() {<br>        return `${this.firstname} ${this.lastName}`;<br>    }<br>}<br><br>const defaultUser = new User();<br>console.log(&#39;[defaultUser] ==&gt; &#39;, defaultUser);<br>console.log(&#39;[defaultUser.getFullName] ==&gt; &#39;, defaultUser.getFullName());<br><br>const user = new User( &#39;John&#39;, &#39;Doe&#39; );<br>console.log(&#39;[user] ==&gt; &#39;, user);<br>console.log(&#39;[user.getFullName] ==&gt; &#39;, user.getFullName());</pre><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*44yA-f6PZURlQ-FOf4Vrww.png" /></figure><p>Теперь, если проверите prototype класса User, вы не увидите свойства firstName и lastName.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*pUvV2kP_Evs0JWbhYK-KFg.png" /></figure><p><strong>Поля экземпляров класса</strong> очень полезная и важная часть объектно-ориентированного программирования (ООП). Хорошо, что есть предложение для этого, но эта история ещё далека от завершения.</p><p>В отличие от <strong>методов класса, которые находятся в прототипе класса</strong>, <strong>поля экземпляра класса существуют в объекте/экземпляра</strong>. Поскольку поле экземпляра класса не является ни частью класса, ни его прототипом, очень сложно изменить его дескриптор. Babel даёт нам функцию initializer в дескрипторе свойства поля экземпляра класса вместо value. Почему используется функция initializer вместо ключа value — эта тема обсуждается, и поскольку декораторы находятся на <strong>второй стадии</strong>, окончательный черновик ещё не опубликован, чтобы объяснить причины этого, но вы можете последовать ответу на <a href="https://stackoverflow.com/questions/31433630/does-the-es7-decorator-spec-require-descriptors-to-have-an-initializer-method">Stack Overflow</a>, чтобы понять предысторию.</p><p>С учётом вышесказанного давайте изменим предыдущей пример и создадим простой декоратор @upperCase, который изменит регистр значение поля по умолчанию экземпляра класса.</p><pre>function upperCase( target, name, descriptor ) {<br>    const initValue = descriptor.initializer();<br><br>    descriptor.initializer = function() {<br>        return initValue.toUpperCase();<br>    }<br><br>    return descriptor;<br>}<br>class User {<br>    @upperCase<br>    firstName = &#39;default_first_name&#39;;<br><br>    lastName = &#39;default_last_name&#39;;<br><br>    constructor(firstName, lastName) {<br>        if (firstName) {<br>            this.firstName = firstName;<br>        }<br>        if (lastName) {<br>            this.lastName = lastName;<br>        }<br>    }<br><br>    getFullName() {<br>        return `${this.firstname} ${this.lastName}`;<br>    }<br>}<br>console.log(new User());</pre><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*5_SX5itRYtBIojyjY7-wHQ.png" /></figure><p>Мы также можем использовать <strong>функцию декоратора с параметрами</strong>, чтобы сделать его более настраиваемым.</p><pre>function toCase(CASE = &#39;lower&#39;) {<br>    return function (target, name, descriptor) {<br>        const initValue = descriptor.initializer();<br><br>        descriptor.initializer = function() {<br>            return<br>                (CASE === &#39;lower&#39;) ?<br>                initValue.toLowerCase() :<br>                initValue.toUpperCase();<br>        }<br><br>        return descriptor;<br>    }<br>}<br>class User {<br>    @toCase(&#39;upper&#39;)<br>    firstName = &#39;default_first_name&#39;;<br><br>    lastName = &#39;default_last_name&#39;;<br><br>    constructor(firstName, lastName) {<br>        if (firstName) {<br>            this.firstName = firstName;<br>        }<br>        if (lastName) {<br>            this.lastName = lastName;<br>        }<br>    }<br><br>    getFullName() {<br>        return `${this.firstname} ${this.lastName}`;<br>    }<br>}<br><br>console.log(new User());</pre><p>Функция descriptor.initializer используется внутри <strong>Babel</strong> для создания ключа value дескриптора свойства в свойстве объекта. Эта функция возвращает начальное значение, присвоенное полю экземпляра класса. Внутри декоратора нам нужно вернуть ещё одну функцию initializer, которая вернет окончательное значение.</p><blockquote>Предложение поля экземпляра класса — очень экспериментальная возможность, и существует большая вероятность, что её синтаксис может измениться, до того, как она перейдет на <strong>четвёртый этап</strong>. Поэтому, пока не рекомендуется использовать поля экземпляра класса вместе с декораторами.</blockquote><h4>Декоратор класса</h4><p>Теперь мы уже знаем на что способны декораторы. Они могут изменять свойства и поведение методов класса и полей экземпляра класса, предоставляя гибкость для динамического достижения всего этого с помощью более простого синтаксиса.</p><p><strong>Декораторы класса</strong> немного отличаются от декораторов, которые мы видели ранее. Раньше мы использовали <strong>дескриптор свойства</strong> для изменения поведения свойства или метода, но в случае с декоратором класса нам нужно вернуть функцию конструктора.</p><p>Давайте разберёмся сначала, что такое функция конструктора. JavaScript-класс на самом деле это не что иное, как функция, используемая для добавления <strong>методов прототипа</strong> и определения некоторых значений для полей.</p><pre>function User(firstName, lastName) {<br>    this.firstName = firstName;<br>    this.lastName = lastName;<br>}<br><br>User.prototype.getFullName = function() {<br>    return `${this.firstname} ${this.lastName}`<br>}<br><br>const user = new User(&#39;John&#39;, &#39;Doe&#39;);<br><br>console.log(user);<br>console.log(user.__proto__);<br>console.log(user.getFullName());</pre><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*8upRjd8kwXbOntVmrjvOqg.png" /></figure><blockquote><a href="https://blog.bitsrc.io/what-is-this-in-javascript-3b03480514a7">Вот большая статья</a> для понимания this в JavaScript.</blockquote><p>Итак, когда мы вызываем new User, вызывается функция User с аргументами, которые мы передали, и взамен мы получаем объект. Получается, User — функция-конструктор. Кстати говоря, каждая функция в JavaScript является функцией-конструктором, поскольку, если вы посмотрите на function.prototype, вы получите свойство constructor. Пока мы используем ключевое слово new с функцией, мы должны ожидать возврата объекта.</p><blockquote>Если вы вернете корректный объект JavaScript из функции конструктора, то это значение будет использоваться вместо создания нового объекта, используя присваивания через this. Это сломает цепочку прототипов, потому что у возвращённого объекта не будет методов прототипа функции конструктора.</blockquote><p>Имея это в виду, давайте сосредоточимся на том, что может сделать декоратор класса. Декоратор класса должен быть наверху класса, по аналогии, как раньше это было сделано с названием метода или поля. Этот декоратор по-прежнему функция, но которая возвращает функцию-конструктор или класс.</p><p>Предположим, у меня есть простой класс User, как показано ниже.</p><pre>class User {<br>    constructor(firstName, lastName) {<br>        this.firstName = firstName;<br>        this.lastName = lastName;<br>    }<br>}</pre><p>Сейчас у нашего класса User нет никаких методов. Как говорилось ранее, декоратор класса должен вернуть функцию-конструктор.</p><pre>function withLoginStatus(UserRef) {<br>    return function(firstName, lastName) {<br>        this.firstName = firstName;<br>        this.lastName = lastName;<br>        this.loggedIn = false;<br>    }<br>}<br><br>@withLoginStatus<br>class User {<br>    constructor(firstName, lastName) {<br>        this.firstName = firstName;<br>        this.lastName = lastName;<br>    }<br>}<br><br>let user = new User(&#39;John&#39;, &#39;Doe&#39;);<br>console.log(user);</pre><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*rM3KBl5wFGoMNkq3DDFrgg.png" /></figure><p>Функция декоратора класса получает целевой класс UserRef, который в приведённом выше примере является User (<em>на котором применяется декоратора</em>) и должен возвращать функцию-конструктор. Это открывает двери для бесконечных возможностей, которые можно сделать с декоратором. Следовательно, декораторы класса более популярны, чем декораторы методов/свойств.</p><p>Но приведённый выше пример слишком простой, и мы не хотим создавать новый конструктор, когда как наш класс User может иметь массу свойств и прототипов. Хорошая новость заключается в том, что у нас есть ссылка на класс внутри функции декоратора, то есть UserRef. Мы можем вернуть новый класс из функции конструктора, который расширяет User класс (<em>точнее класс </em><em>UserRef</em>). Поскольку класс тоже функция-конструктор, то это сработает.</p><pre>function withLoginStatus( UserRef ) {<br>    return class extends UserRef {<br>        constructor(...args ) {<br>            super(...args);<br>            this.isLoggedIn = false;<br>        }<br><br>        setLoggedIn() {<br>            this.isLoggedIn = true;<br>        }<br>    }<br>}<br><br>@withLoginStatus<br>class User {<br>    constructor(firstName, lastName) {<br>        this.firstName = firstName;<br>        this.lastName = lastName;<br>    }<br>}<br><br>let user = new User(&#39;John&#39;, &#39;Doe&#39;);<br>console.log(&#39;Before ===&gt; &#39;, user);<br><br>// установить, что пользователь вошёл<br>user.setLoggedIn();<br>console.log(&#39;After ===&gt; &#39;, user);</pre><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*uWCbna4Q89ZWCz5Xmv5Hdg.png" /></figure><p>Вы можете объединить несколько декораторов вместе, разместив их друг под другом. Порядок выполнения их будет таким же, как порядок добавления.</p><p>Декораторы — это красивый способ быстрее достичь цели. Подождите некоторое время, пока они не будут добавлены в спецификации ECMAScript.</p><p><em>Слушайте наш подкаст в </em><a href="https://itunes.apple.com/ru/podcast/%D0%B4%D0%B5%D0%B2%D1%88%D0%B0%D1%85%D1%82%D0%B0/id1226773343"><em>iTunes</em></a><em> и </em><a href="https://soundcloud.com/devschacht"><em>SoundCloud</em></a><em>, читайте нас на </em><a href="https://medium.com/devschacht"><em>Medium</em></a><em>, контрибьютьте на </em><a href="https://github.com/devSchacht"><em>GitHub</em></a><em>, общайтесь в </em><a href="https://t.me/devSchacht"><em>группе Telegram</em></a><em>, следите в </em><a href="https://twitter.com/DevSchacht"><em>Twitter</em></a><em> и </em><a href="https://t.me/devSchachtChannel"><em>канале Telegram</em></a><em>, рекомендуйте в </em><a href="https://vk.com/devschacht"><em>VK</em></a><em> и </em><a href="https://www.facebook.com/devSchacht"><em>Facebook</em></a><em>.</em> <a href="https://github.com/devSchacht/translations/tree/master/articles/a-minimal-guide-to-ecmascript-decorators/README.md">Статья на GitHub</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c7348f61ba24" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devschacht/a-minimal-guide-to-ecmascript-decorators-c7348f61ba24">Минимальное руководство по декораторам ECMAScript</a> was originally published in <a href="https://medium.com/devschacht">devSchacht</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Vue.js  —  соображения и трюки]]></title>
            <link>https://medium.com/devschacht/vue-js-considerations-and-tricks-58ec768ac237?source=rss-19321d28194------2</link>
            <guid isPermaLink="false">https://medium.com/p/58ec768ac237</guid>
            <category><![CDATA[devschacht-vue]]></category>
            <category><![CDATA[devschacht]]></category>
            <dc:creator><![CDATA[Alexey Pyltsyn]]></dc:creator>
            <pubDate>Thu, 21 Jun 2018 09:25:02 GMT</pubDate>
            <atom:updated>2018-06-21T09:25:02.195Z</atom:updated>
            <content:encoded><![CDATA[<h3>Vue.js — соображения и трюки</h3><p><em>Перевод статьи </em><a href="https://twitter.com/mistyHarsh"><em>Harshal Patil</em></a><em>: </em><a href="https://blog.webf.zone/vue-js-considerations-and-tricks-fa7e0e4bb7bb"><em>Vue.js — Considerations and Tricks</em></a><em>.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*Agh6VagdEwoIziUUnbxgOg.png" /></figure><p>Vue.js — отличный инструмент. Однако, когда вы начинаете создавать крупномасштабные приложения на JavaScript, вы сталкиваетесь с границами Vue.js. Эти границы на самом деле не ограничивают фреймворк, скорее это важные решения проектирования, принимаемые периодически командой Vue.js.</p><p>В отличие от React или Angular, Vue.js удовлетворяет потребности разного уровня разработчиков. Это дружелюбный, простой в использовании для начинающих и не менее гибкий для экспертов. Он не пытается уйти от DOM. Вместо этого он хорошо работает с ним.</p><p>С учётом вышесказанного, эта статья будет больше похожа на каталог из отличных <strong>дискуссий, вопросов и трюков</strong>, которые мне попались на пути к просветлению Vue.js.</p><p>Опять же, приведённые обсуждения актуальны на день написания статьи (18 мая 2018 года). При обновлении фреймворка, браузера или JS API, они могут потерять достоверность и стать непонятными.</p><h4>1. Почему Vue.js не использует ES-классы из коробки для компонентов?</h4><p>Если вы пришли из фреймворка, похожего на Angular, или из какого-нибудь языка высокого уровня для бэкенда приложения, ваш первый вопрос мог быть таким: почему не использовать классы для создания компонентов?</p><p>Создатель Vue.js, Эван Ю, отлично ответил на этот вопрос в комментарии на GitHub:</p><p><a href="https://github.com/vuejs/vue/issues/2371#issuecomment-284052430">Use standard JS classes instead of custom syntax? · Issue #2371 · vuejs/vue</a></p><p>Вот три главные причины, по которым не используются классы для объявления компонентов:</p><ol><li>ES-классы недостаточно хороши для удовлетворения требований текущего API Vue.js. Классы в ES не полностью реализованы и их часто критикуют как шаг в неверном направлении. Классы с приватными полями и декораторами, после их стабилизации (достижения stage 3, как минимум), возможно, помогут.</li><li>ES-классы отлично подходят только тем, кто знаком с языками программирования с поддержкой ООП. Это просто исключает значительную часть веб-сообщества, которая не использует сложные инструменты для сборки проектов или транспилеры.</li><li><strong>Создание отличной иерархии компонентов пользовательского интерфейса (UI) — это отличная композиция компонентов. Речь идёт не о большой иерархии наследования. К сожалению, классы в ES лучше подходят для последнего.</strong></li></ol><h4>2. Как я могу создать собственный абстрактный компонент?</h4><p>Если создания крупномасштабных приложений недостаточно, у вас может появится сумасшедшая идея реализации абстрактного компонента, например &lt;transition&gt; или &lt;router-view&gt;. Определённо была дискуссия по этому поводу, но в реальности она ничем не кончилась.</p><p><a href="https://github.com/vuejs/vuejs.org/issues/720">Any plan for docs of abstract components? · Issue #720 · vuejs/vuejs.org</a></p><p>Однако не стоит пугаться, с хорошим понимаем слотов, вы можете создавать собственные абстрактные компоненты. Есть очень хороший пост в блоге, объясняющий, как это сделать.</p><p><a href="https://medium.com/devschacht/vue-abstract-components-bc4bc2b89baf">Написание абстрактных компонентов во Vue.js</a></p><p>Но всё-таки подумайте дважды, прежде чем воспользоваться этим. Мы всегда полагались на примеси и простые функции для решения задач, оказавшись в тупиковой ситуации.</p><p><a href="https://stackoverflow.com/a/35964246/5723098">How do I extend another VueJS component in a single-file component? (ES6 vue-loader)</a></p><h4>3. Мне не очень нравится подход с однофайловым компонентом. Я больше привык к разделению HTML, CSS и JavaScript</h4><p>Никто не мешает вам сделать подобное. Если вы философ старой школы «важности разделения», который любит буквально всё разделять на отдельные файлы или ненавидеть странное поведение с файлами .vue, то, безусловно, это возможно. Всё, что вам нужно сделать:</p><pre>&lt;!-- https://ru.vuejs.org/v2/guide/single-file-components.html --&gt;<br><br>&lt;!-- my-component.vue --&gt;<br>&lt;template src=&quot;./my-component.html&quot;&gt;&lt;/template&gt;<br>&lt;script src=&quot;./my-component.js&quot;&gt;&lt;/script&gt;<br>&lt;style src=&quot;./my-component.css&quot;&gt;&lt;/style&gt;</pre><p>Однако сразу возникает следующий вопрос: <em>мне всегда нужно 4 файла (vue + html + js + css) для моего компонента. Могу ли я избавиться каким-то образом от файлов </em><em>.vue</em>? Ответ - определённо, да, у вас есть такая возможность, используя vue-template-loader.</p><p><a href="https://github.com/ktsn/vue-template-loader">ktsn/vue-template-loader</a></p><p>Мои коллеги написали по поводу этого отличный пост:</p><p><a href="https://medium.com/devschacht/vue-template-loader-5fb1ab6c3436">Использование vue-template-loader с Vue.js для компиляции шаблонов HTML</a></p><h4>4. Функциональные компоненты</h4><p>Благодаря React.js функциональные компоненты стали сумасшествием, пусть и с благими намерениями: они быстрые, без состояния и легко тестируются. Тем не менее, у них есть подводные камни.</p><h4>4.1 Почему я не могу использовать класс, основанный на декораторе @Component для функциональных компонентов?</h4><p>Снова возвращаясь к классам, следует отметить, что классы представляют собой структуры данных для хранения локального состояния. Если функциональные компоненты не имеют состояния, то нет никакого смысла в использовании декоратора @Component.</p><p>Соответствующее обсуждение имеется по адресу:</p><p><a href="https://github.com/vuejs/vue-class-component/issues/120">How to create functional component in @Component? · Issue #120 · vuejs/vue-class-component</a></p><h4>4.2 Внешние классы не применяются к функциональным компонентам</h4><p>Функциональные компоненты не имеют привязки к классу и стилю, как обычные компоненты. Нужно вручную применять эти привязки внутри функции отрисовки.</p><ul><li><a href="https://github.com/vuejs/vue-loader/issues/1014">DOM class attribute not rendered properly with functional components · Issue #1014 · vuejs/vue-loader</a></li><li><a href="https://github.com/vuejs/vue/issues/7554">class attribute ignored on functional components · Issue #7554 · vuejs/vue</a></li></ul><h4>4.3 Функциональные компоненты всегда повторно отрисовываются?</h4><blockquote><em>TLDR: будьте осторожны при использовании </em><strong><em>компонентов с состоянием</em></strong><em> внутри функциональных компонентов</em></blockquote><p><a href="https://github.com/vuejs/vue/issues/4037#issuecomment-258164999">Functional components are re-rendered when props are unchanged. · Issue #4037 · vuejs/vue</a></p><p>Функциональные компоненты — нетерпеливы, что означает, что функция отрисовки вызывается напрямую. Это также означает, что вы должны:</p><p>Избегать использования компонента с состоянием непосредственно внутри в функции отрисовки, потому что это создаст различное определение компонента при каждом вызове функции отрисовки.</p><p><strong>Функциональный компонент лучше использовать, если они являются листовыми компонентами (leaf components).</strong></p><h4>4.4 Как сгенерировать событие из функционального компонента?</h4><p>Генерация события из функционального компонента не очевидна. К сожалению, об этом не написано в документации. Метод $emit недоступен в функциональном компоненте. Следующий вопрос на Stack Overflow может помочь.</p><p><a href="https://stackoverflow.com/questions/50288996/how-to-emit-an-event-from-vue-js-functional-component">How to emit an event from Vue.js Functional component?</a></p><h4>5. Прозрачные компоненты-обёртки</h4><p>Прозрачный компонент-обёртка оборачивает некоторую структуру DOM и всё ещё использует события внутри этой структуры вместо корневого элемента DOM. Например,</p><pre>&lt;!-- Обёртка компонента для поля ввода --&gt;<br>&lt;template&gt;<br>    &lt;div class=&quot;wrapper-comp&quot;&gt;<br>        &lt;label&gt;Моя метка&lt;/label&gt;<br>        &lt;input @focus=&quot;$emit(&#39;focus&#39;)&quot; type=&quot;text&quot;/&gt;<br>    &lt;/div&gt;<br>&lt;/template&gt;</pre><p>В коде выше нас в действительности интересует тег input, а не корневой элемент div, поскольку он добавлен в основном для стилизации и косметической цели. Пользователя компонента могут интересовать несколько событий поля ввода, такие как blur, focus, click, hover и т.д. <em>Это означает, что мы должны повторно генерировать каждое событие</em>. Наш компонент будет выглядеть так.</p><pre>&lt;!-- Обёртка компонента для поля ввода --&gt;<br>&lt;template&gt;<br>    &lt;div class=&quot;wrapper-comp&quot;&gt;<br>        &lt;label&gt;Моя метка&lt;/label&gt;<br>        &lt;input type=&quot;text&quot;<br>            @focus=&quot;$emit(&#39;focus&#39;)&quot;<br>            @click=&quot;$emit(&#39;click&#39;)&quot;<br>            @blur=&quot;$emit(&#39;blur&#39;)&quot;<br>            @hover=&quot;$emit(&#39;hover&#39;)&quot;<br>        /&gt;<br>    &lt;/div&gt;<br>&lt;/template&gt;</pre><p><strong>Этот код противоречит принципу DRY (не повторяй себя) и выглядит грязным.</strong> Простое решение состоит в том, чтобы просто повторно связать ваши слушатели событий с требуемыми DOM-элементам, используя свойство vm.$listeners.</p><pre>&lt;!-- Обратите внимание на использование $listeners --&gt;<br>&lt;template&gt;<br>    &lt;div class=&quot;wrapper-comp&quot;&gt;<br>        &lt;label&gt;Моя метка&lt;/label&gt;<br>        &lt;input v-on=&quot;$listeners&quot; type=&quot;text&quot;/&gt;<br>    &lt;/div&gt;<br>&lt;/template&gt;<br>&lt;!-- Использование: событие @focus связывается ко внутреннему элементу ввода --&gt;<br>&lt;custom-input @focus=&quot;onFocus&quot;&gt;&lt;/custom-input&gt;</pre><h4>6. Почему невозможно использовать v-on или генерировать события из слота</h4><p>Я часто видел, как разработчики пытались генерировать событие из слота или прослушивать событие в слоте. Это просто невозможно.</p><p>Компонент slot предоставляется посредством вызова/родительским компонентом. Это означает, что все события должны связываться с вызывающим компонентом. Попытка прослушать эти изменения означает, что ваш родительский и дочерний компоненты тесно связаны, и есть ещё один способ сделать это, который красиво объяснил Эван Ю:</p><ul><li><a href="https://github.com/vuejs/vue/issues/4332#issuecomment-263444492">Is it possible to emit event from component inside slot · Issue #4332 · vuejs/vue</a></li><li><a href="https://github.com/vuejs/vue/issues/4781">Suggestion: v-on on slots · Issue #4781 · vuejs/vue</a></li></ul><h4>7. Слот в слоте (читай: внук слота)</h4><p>В какой-то момент вы столкнетесь с таким сценарием. Представьте, что у вас есть компонент, например, <strong>A</strong>, который принимает несколько слотов. Следуя принципам композиции, вы создаёте другой компонент <strong>B</strong>, использующий компонент <strong>A</strong>. Теперь вы компонент <strong>B</strong> и используете его в компоненте <strong>C</strong>.</p><blockquote>Вопрос: как передать слот из компонента <strong>C</strong> в компонент <strong>A</strong>?</blockquote><p>Ответ на этот вопрос зависит от того, что вы используете? Если вы используете функцию отрисовки, то это довольно тривиально. Функция отрисовки <strong>B</strong> будет такой:</p><pre>// Функция render для компонента B<br>function render(h) {<br>    return h(&#39;component-a&#39;, {<br>        // Передача слотов, так как они относятся к компоненту A<br>        scopedSlot: this.$scopedSlots<br>    }<br>}</pre><p>Однако, если используете шаблон как функцию отрисовки, то вам не повезло. К счастью, в этом вопросе есть прогресс, и, возможно, есть решение для такого случая.</p><p><a href="https://github.com/vuejs/vue/pull/7765">feat(core): support passing down scopedSlots with v-bind by yyx990803 · Pull Request #7765 · vuejs/vue</a></p><p>Надеюсь, эта запись поможет поглубже взглянуть на некоторые из соображений проектирования во Vue.js, а также даст некоторые подсказки/трюки для более продвинутого использования Vue.js.</p><p><em>Слушайте наш подкаст в </em><a href="https://itunes.apple.com/ru/podcast/%D0%B4%D0%B5%D0%B2%D1%88%D0%B0%D1%85%D1%82%D0%B0/id1226773343"><em>iTunes</em></a><em> и </em><a href="https://soundcloud.com/devschacht"><em>SoundCloud</em></a><em>, читайте нас на </em><a href="https://medium.com/devschacht"><em>Medium</em></a><em>, контрибьютьте на </em><a href="https://github.com/devSchacht"><em>GitHub</em></a><em>, общайтесь в </em><a href="https://t.me/devSchacht"><em>группе Telegram</em></a><em>, следите в </em><a href="https://twitter.com/DevSchacht"><em>Twitter</em></a><em> и </em><a href="https://t.me/devSchachtChannel"><em>канале Telegram</em></a><em>, рекомендуйте в </em><a href="https://vk.com/devschacht"><em>VK</em></a><em> и </em><a href="https://www.facebook.com/devSchacht"><em>Facebook</em></a><em>.</em></p><p><a href="https://github.com/devSchacht/translations/tree/master/articles/vuejs%E2%80%8A%E2%80%94%E2%80%8Aconsiderations-and-tricks/README.md">Статья на GitHub</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=58ec768ac237" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devschacht/vue-js-considerations-and-tricks-58ec768ac237">Vue.js  —  соображения и трюки</a> was originally published in <a href="https://medium.com/devschacht">devSchacht</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Использование vue-template-loader с Vue.js для компиляции шаблонов HTML]]></title>
            <link>https://medium.com/devschacht/vue-template-loader-5fb1ab6c3436?source=rss-19321d28194------2</link>
            <guid isPermaLink="false">https://medium.com/p/5fb1ab6c3436</guid>
            <category><![CDATA[vue]]></category>
            <category><![CDATA[devschacht]]></category>
            <category><![CDATA[devschacht-vue]]></category>
            <dc:creator><![CDATA[Alexey Pyltsyn]]></dc:creator>
            <pubDate>Tue, 19 Jun 2018 19:54:16 GMT</pubDate>
            <atom:updated>2018-06-19T19:54:16.671Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Перевод статьи </em><a href="https://github.com/Akanksha-26"><em>Akanksha Sharma</em></a><em>: </em><a href="https://alligator.io/vuejs/vue-template-loader/"><em>Using vue-template-loader with Vue.js to Compile HTML Templates</em></a><em>.</em></p><figure><img alt="ÐÐ°ÑÑÐ¸Ð½ÐºÐ¸ Ð¿Ð¾ Ð·Ð°Ð¿ÑÐ¾ÑÑ Vue typescript" src="https://cdn-images-1.medium.com/proxy/1*JdIjLO1YlxkjAeQ8zAEcrg.png" /></figure><p>Большинство людей, знакомых с Angular 2+, знают, что для компиляции HTML-шаблонов просто нужно добавить URL-адрес шаблона в TypeScript-файл компонента и дело с концом. В случае Vue рекомендуется использовать теги &lt;template&gt; для сборки разметки шаблона в подавляющем большинстве случаев.</p><p>Мы можем использовать <a href="https://github.com/ktsn/vue-template-loader">vue-template-loader</a>, если хотим использовать Vue со способом сборки шаблонов, как в Angular. Поскольку <strong>vue-template-loader</strong> поддерживает vue-class-component, мы можем использовать декораторы для стилевых классов компонентов (class-styled components).</p><blockquote>vue-template-loader компилирует HTML в отдельные функции отрисовки в соответствующих TypeScript- или JavaScript-файлах.</blockquote><h4>Установка</h4><p>Нам понадобится обычный проект Vue.js вместе с зависимостями webpack.</p><p>Установите vue-template-loader, используя yarn или npm, например так:</p><pre># yarn<br>$ yarn add vue-template-loader<br><br># npm<br>$ npm install vue-template-loader</pre><h4>Конфигурация webpack для JavaScript</h4><p>Теперь мы можем интегрировать <strong>vue-template-loader</strong> с использованием webpack.</p><p>Добавьте vue-template-loader в качестве правила в вашем конфигурационном файле webpack.config.js:</p><pre>module.exports = {<br>  module: {<br>    rules: [<br>        {<br>          test: /\.html$/,<br>          loader: &#39;vue-template-loader&#39;,<br>          // Мы не хотим передавать файл `src/index.html` этому загрузчику.<br>          exclude: /index.html/,<br>        }<br>    ]<br>  }<br>}</pre><p>Отрисовку ресурсов, используемых в HTML-шаблоне, связанных с обработкой атрибута src в тегах, можно указать с помощью опций:</p><pre>module.exports = {<br>  module: {<br>    rules: [<br>      {<br>        test: /\.html$/,<br>        loader: &#39;vue-template-loader&#39;,<br><br>        // Мы не хотим передавать файл `src/index.html` этому загрузчику.<br>        exclude: /index.html/,<br>        options: {<br>          transformToRequire: {<br>            img: &#39;src&#39;<br>          }<br>        }<br>      }<br>    ]<br>  }<br>}</pre><p>Обратите внимание, что для работы вышеуказанных опций также необходимо добавление загрузчика для обработки файлов изображений (см. <a href="https://github.com/webpack-contrib/file-loader">file-loader</a>).</p><h4>Конфигурация для TypeScript</h4><p>Если мы хотим использовать <strong>vue-template-loader</strong> с TypeScript, нам нужны зависимости tsloader и typescript, установленные в проекте вместе с webpack.</p><blockquote>vue-template-loader используется аналогичным образом для конфигурации webpack как для JavaScript, так и для TypeScript.</blockquote><p>Единственное дополнение будет в каталоге typings нашего проекта. Нам нужно добавить шим в typings, чтобы TypeScript понимал файлы .vue:</p><pre>// Для работы/импорта файлов *.vue в TypeScript, требуется шим<br>declare module &#39;*.vue&#39; {<br>  import Vue from &#39;vue&#39;;<br>  export default Vue;<br>}<br><br>// Определение типа модуля TypeScript, требуемого vue-template-loader<br>declare module &#39;*.html&#39; {<br>  import Vue, { ComponentOptions } from &#39;vue&#39;;<br><br>  interface WithRender {<br>    &lt;V extends Vue&gt;(options: ComponentOptions&lt;V&gt;): ComponentOptions&lt;V&gt;<br>    &lt;V extends typeof Vue&gt;(component: V): V<br>  }<br><br>  const withRender: WithRender<br>  export = withRender<br>}</pre><h4>Использование в файлах JavaScript/TypeScript</h4><p>Теперь давайте создадим файл с шаблоном с названием nest.html:</p><pre>&lt;div class=&quot;nest&quot;&gt;<br>  &lt;p&gt;{{ text }}&lt;/p&gt;<br>  &lt;button type=&quot;button&quot; @click=&quot;baz()&quot;&gt;Нажми на меня!&lt;/button&gt;<br>&lt;/div&gt;</pre><p>Теперь давайте добавим файл nest.js, использующий nest.html. Мы может использовать <strong>vue-template-loader</strong> с или без декораторов класса, используя es6 с Vue:</p><pre>// Без декораторов класса в JavaScript<br>import withRender from &#39;./nest.html&#39;;<br><br>export default withRender({<br>  data () {<br>    return {<br>      text: &#39;Я крокодил&#39;<br>    };<br>  },<br>  methods: {<br>    baz () {<br>      console.log(&#39;Кнопка нажата!&#39;);<br>    };<br>  };<br>});</pre><pre>// С декораторами<br>import Vue from &#39;vue&#39;;<br>import Component from &#39;vue-class-component&#39;;<br>import WithRender from &#39;./nest.html&#39;;<br><br>@WithRender<br>@Component<br>export default class Nest extends Vue {<br>  text = &#39;Я крокодил!&#39;;<br><br>  baz() {<br>    console.log(&#39;Кнопка нажата!&#39;);<br>  }<br>}</pre><p>Его также можно использовать в TypeScript следующим образом в файле nest.ts:</p><pre>import Vue from &#39;vue&#39;;<br>import { Component } from &#39;vue-property-decorator&#39;;<br>import WithRender from &#39;./nest.html&#39;;<br><br>@WithRender<br>@Component({})<br>export default class NestComponent extends Vue {<br>  data() {<br>    return {<br>      text: &#39;Я крокодил!&#39;<br>    }<br>  };<br><br>  baz() {<br>    console.log(&#39;Кнопка нажата!&#39;);<br>  }<br>};</pre><h4>Вывод</h4><p>Использование <strong>vue-template-loader</strong> обеспечивает отличную поддержку TypeScript, а также может уменьшить количество компилируемых файлов, так как исключаются файлы .vue. Наконец, это очень легко понять людьми, работающими с Angular.</p><p><em>Слушайте наш подкаст в </em><a href="https://itunes.apple.com/ru/podcast/%D0%B4%D0%B5%D0%B2%D1%88%D0%B0%D1%85%D1%82%D0%B0/id1226773343"><em>iTunes</em></a><em> и </em><a href="https://soundcloud.com/devschacht"><em>SoundCloud</em></a><em>, читайте нас на </em><a href="https://medium.com/devschacht"><em>Medium</em></a><em>, контрибьютьте на </em><a href="https://github.com/devSchacht"><em>GitHub</em></a><em>, общайтесь в </em><a href="https://t.me/devSchacht"><em>группе Telegram</em></a><em>, следите в </em><a href="https://twitter.com/DevSchacht"><em>Twitter</em></a><em> и </em><a href="https://t.me/devSchachtChannel"><em>канале Telegram</em></a><em>, рекомендуйте в </em><a href="https://vk.com/devschacht"><em>VK</em></a><em> и </em><a href="https://www.facebook.com/devSchacht"><em>Facebook</em></a><em>.</em></p><p><a href="https://github.com/devSchacht/translations/tree/master/articles/using-vue-template-loader-with-vuejs-to-compile-html-templates/README.md">Статья на GitHub</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5fb1ab6c3436" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devschacht/vue-template-loader-5fb1ab6c3436">Использование vue-template-loader с Vue.js для компиляции шаблонов HTML</a> was originally published in <a href="https://medium.com/devschacht">devSchacht</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Написание абстрактных компонентов во Vue.js]]></title>
            <link>https://medium.com/devschacht/vue-abstract-components-bc4bc2b89baf?source=rss-19321d28194------2</link>
            <guid isPermaLink="false">https://medium.com/p/bc4bc2b89baf</guid>
            <category><![CDATA[devschacht-vue]]></category>
            <category><![CDATA[vue]]></category>
            <category><![CDATA[devschacht]]></category>
            <dc:creator><![CDATA[Alexey Pyltsyn]]></dc:creator>
            <pubDate>Mon, 18 Jun 2018 16:37:42 GMT</pubDate>
            <atom:updated>2018-06-18T16:37:42.641Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Перевод статьи </em><a href="https://twitter.com/@tribex_"><em>Joshua Bemenderfer</em></a><em>: </em><a href="https://alligator.io/vuejs/vue-abstract-components/"><em>Writing Abstract Components with Vue.js</em></a><em>.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*SFWLoijYgfJSLOBb" /></figure><blockquote>Компоненты Vue великолепны, не так ли? Они инкапсулируют представление и поведение приложения в красивые небольшие компонуемые части. Если вам нужна небольшая дополнительная функциональность, просто присоедините директивы! Дело в том, что директивы довольно негибкие и не подходят для всего. Например, директивы не могут (казалось бы самое простое?) генерировать события. Что ж, это Vue, конечно, есть решение — абстрактные компоненты!</blockquote><p>Абстрактные компоненты похожи на обычные компоненты, за исключением того, что они ничего отрисовывают в DOM. Они просто добавляют дополнительное поведение к существующим. Вам наверняка знакомы встроенные абстрактные компоненты Vue, такие как &lt;transition&gt;, &lt;component&gt; и &lt;slot&gt;.</p><p>Отличный вариант использования абстрактных компонентов наблюдается, когда элемент входит в область просмотра с помощью IntersectionObserver. Давайте посмотрим на реализацию простого абстрактного компонента для обработки этого.</p><blockquote>Если вам нужна соответствующая готовая для продакшена реализация, взгляните на <a href="https://github.com/heavyy/vue-intersect">vue-intersect</a>, на котором основана эта статья.</blockquote><h4>Приступаем к работе</h4><p>Сначала создадим быстрый компонент, который просто отрисовывает его содержимое. Для этого мы ненадолго посмотрим на функции отрисовки.</p><p>Файл IntersectionObserver.vue:</p><pre>export default {<br>   // Включает абстрактный компонент во Vue.<br>   // Это свойство не задокументировано и может изменить в любой момент,<br>   // но ваш компонент должен работать без него.<br>  abstract: true,<br>  // Ура, функции отрисовки!<br>  render() {<br>    // Без компонента-обёртки, мы можем отрисовать только один дочерний компонент.<br>    try {<br>      return this.$slots.default[0];<br>    } catch (e) {<br>      throw new Error(&#39;IntersectionObserver.vue может отрисовывать один и только один дочерний компонент.&#39;);<br>    }<br><br>    return null;<br>  }<br>}</pre><p>Поздравляем! У вас теперь есть абстрактный компонент, который, ну, ничего не делает! Отрисовкой занимается дочерний компонент.</p><h4>Добавление IntersectionObserver</h4><p>Хорошо, теперь давайте придерживаться логики для IntersectionObserver.</p><blockquote>Внимание: IntersectionObserver изначально не поддерживается IE или Safari, поэтому вам может для него полифил.</blockquote><p>Файл IntersectionObserver.vue:</p><pre>export default {<br>  // Остальной код из предыдущего листинга...<br><br>  mounted () {<br>    // Нет реальной потребности объявлять наблюдателя в качестве свойства данных,<br>    // потому что он не должен быть реактивным.<br><br>    this.observer = new IntersectionObserver((entries) =&gt; {<br>      this.$emit(entries[0].isIntersecting ? &#39;intersect-enter&#39; : &#39;intersect-leave&#39;, [entries[0]]);<br>    });<br><br>    // Нужно подождать следующего тика для того, чтобы дочерний элемент мог отрисоваться.<br>    this.$nextTick(() =&gt; {<br>      this.observer.observe(this.$slots.default[0].elm);<br>    });<br>  }<br>}</pre><p>Хорошо, теперь у нас есть абстрактный компонент, который можно использовать следующий образом:</p><pre>&lt;intersection-observer @intersect-enter=&quot;handleEnter&quot; @intersect-leave=&quot;handleLeave&quot;&gt;<br>  &lt;my-honest-to-goodness-component&gt;&lt;/my-honest-to-goodness-component&gt;<br>&lt;/intersection-observer&gt;</pre><p>Однако, это ещё не конец.</p><h4>Заканчиваем</h4><p>Нам нужно убедиться, что нет оставшихся IntersectionObservers при удалении компонента из DOM, поэтому давайте по-быстрому исправим это.</p><pre>export default {<br>  // Остальной код из предыдущих листингов...<br>  <br>  destroyed() {<br>    // Кстати, почему W3C выбрало &quot;disconnect&quot; для названия метода?<br>    this.observer.disconnect();<br>  }<br>}</pre><p>И в качестве бонусных очков, давайте добавим настраиваемый порог видимости элемента (threshold) для наблюдателя с помощью входных данных.</p><p>Файл IntersectionObserver.vue:</p><pre>export default {<br>// Остальной код из предыдущих листингов...<br><br>  // Входные данные работают отлично в абстрактных компонентов!<br>  props: {<br>    threshold: {<br>      type: Array<br>    }<br>  },<br>  <br>  // Остальной код из предыдущих листингов...<br>  <br>  this.observer = new IntersectionObserver((entries) =&gt; {<br>    this.$emit(entries[0].isIntersecting ? &#39;intersect-enter&#39; : &#39;intersect-leave&#39;, [entries[0]]);<br>  }, {<br>    threshold: this.threshold || 0<br>  });<br>  <br>  // Остальной код из предыдущих листингов...<br>}</pre><blockquote>Полный код IntersectionObserver.vue можно найти <a href="https://gist.github.com/lex111/b94f0fa80f510cc1e335321413376322">здесь</a></blockquote><p>Окончательное использование будет выглядит так:</p><pre>&lt;intersection-observer @intersect-enter=&quot;handleEnter&quot; @intersect-leave=&quot;handleLeave&quot; :threshold=&quot;[0, 0.5, 1]&quot;&gt;<br>  &lt;my-honest-to-goodness-component&gt;&lt;/my-honest-to-goodness-component&gt;<br>&lt;/intersection-observer&gt;</pre><p>Вот так, ваш первый абстрактный компонент!</p><p>Большое спасибо Thomas Kjærgaard / Heavyy за <a href="https://github.com/heavyy/vue-intersect">первоначальную реализацию и идею</a>!</p><p><em>Слушайте наш подкаст в </em><a href="https://itunes.apple.com/ru/podcast/%D0%B4%D0%B5%D0%B2%D1%88%D0%B0%D1%85%D1%82%D0%B0/id1226773343"><em>iTunes</em></a><em> и </em><a href="https://soundcloud.com/devschacht"><em>SoundCloud</em></a><em>, читайте нас на </em><a href="https://medium.com/devschacht"><em>Medium</em></a><em>, контрибьютьте на </em><a href="https://github.com/devSchacht"><em>GitHub</em></a><em>, общайтесь в </em><a href="https://t.me/devSchacht"><em>группе Telegram</em></a><em>, следите в </em><a href="https://twitter.com/DevSchacht"><em>Twitter</em></a><em> и </em><a href="https://t.me/devSchachtChannel"><em>канале Telegram</em></a><em>, рекомендуйте в </em><a href="https://vk.com/devschacht"><em>VK</em></a><em> и </em><a href="https://www.facebook.com/devSchacht"><em>Facebook</em></a><em>.</em> <a href="https://github.com/devSchacht/translations/tree/master/articles/writing-abstract-components-with-vuejs/README.md">Статья на GitHub</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bc4bc2b89baf" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devschacht/vue-abstract-components-bc4bc2b89baf">Написание абстрактных компонентов во Vue.js</a> was originally published in <a href="https://medium.com/devschacht">devSchacht</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>