PageSourceSearch

https://varya.me/component---src-templates-post-js-content-file-pa…-in-use-index-ru-md-95aa5ed355a7ee29460c.js

js varya.me collected 2026-09-24 10:33:13 UTC 19,879 bytes, 2 lines download raw bytes

1"use strict";(self.webpackChunkvarya_me=self.webpackChunkvarya_me||[]).push([[408],{8453:function(e,t,n){n.d(t,{RP:function(){return r},xA:function(){return c}});var a=n(6540);const l=a.createContext({});function r(e){const t=a.useContext(l);return a.useMemo(()=>"function"==typeof e?e(t):{...t,...e},[t,e])}const s={};function c({components:e,children:t,disableParentContext:n}){let c;return c=n?"function"==typeof e?e({}):e||s:r(e),a.createElement(l.Provider,{value:c},t)}},9966:function(e,t,n){n.r(t),n.d(t,{default:function(){return f}});var a=n(8453),l=n(6540);function r(e){const t=Object.assign({p:"p",a:"a",span:"span",ul:"ul",li:"li",h2:"h2",img:"img"},(0,a.RP)(),e.components);return l.createElement(l.Fragment,null,l.createElement(t.p,null,"Хочу поделиться опытом поддержания единого стиля JavaScript в одном из своих проектов. Недавно мы решили пробовать\nмолодой инструмент JSCS, и результат его использования понравился всем членам команды."),"\n",l.createElement("excerpt"),"\n",l.createElement(t.p,null,"Когда я присоединилась к проекту ",l.createElement(t.a,{href:"http://styleguide.sc5.io/"},"SC5 Styleguide"),", мне сразу бросилось в глаза отсутствие\nединого стиля для JavaScript кода. Это ещё не было ужасающим, но было ясно, что проект в скором времени будет расти и чем раньше мы начнём\nприлагать усилия к соблюдению единого стиля, тем лучше. Тем более, я уже знала о существовании и особенностях JSCS,\nпотому что на одном из моих проектов ",l.createElement(t.a,{href:"http://frontendbabel.info/articles/jscs-javascript-code-style/"},"публиковался перевод\nстатьи о нем"),". Поэтому мы даже не стояли перед вопросом,\nкакой инструмент выбрать."),"\n",l.createElement(t.p,null,"Конечно, есть и другие решения. Чаще всего называют JSLint и JSHint. Но давайте я сначала расскажу вам одну историю."),"\n",l.createElement(t.p,null,"Оказывается, когда авторы JSHint познакомились с JSCS, он им так понравился, что они предпочли стать его\nконтрибьютерами, чем развивать проверку стиля в своём инструменте. А у себя оставили более сложные штуки, не про стиль,\nа про программирование."),"\n",l.createElement("blockquote",{class:"twitter-tweet",lang:"ru"},l.createElement("p",null,"And with that, JSCS now has all the style enforcement rules that are\nbeing dropped in ",l.createElement("a",{href:"https://twitter.com/JSHint"},"@JSHint")," 3.0: ",l.createElement("a",{href:"https://t.co/W98EMSiTN5"},l.createElement(t.a,{href:"https://t.co/W98EMSiTN5"},"https://t.co/W98EMSiTN5"))," cc ",l.createElement("a",{href:"https://twitter.com/valueof"},"@valueof")),"— Mike Sherov (@mikesherov) ",l.createElement("a",{href:"https://twitter.com/mikesherov/status/419596672520318976"},"4 января 2014")),"\n",l.createElement("script",{async:!0,src:"//platform.twitter.com/widgets.js",charset:"utf-8"}),"\n",l.createElement(t.p,null,"Получается, выбор стоит не между JSLint, JSHint и JSCS, а между JSLint и комбинацией JSHint + JSCS."),"\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">"jslint"</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">"jshint"</span><span class="token punctuation">,</span> <span class="token string">"jscs"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div>'}}),"\n",l.createElement(t.p,null,"А учитывая, что инструмент новый, со стройной архитектурой, контрибьютить в него будет одно удовольствие да и меньше\nшансов на слишком долгую жизнь багов из-за какого-нибудь непроходимого легаси."),"\n",l.createElement(t.p,null,"Вдохновляет также и тот факт, что JSCS уже выбрали такие уважаемые команды как разработчики jQuery, Bootsrap и\nAngularJS."),"\n",l.createElement(t.p,null,"Итак, JSCS — это npm-пакет, и установить его можно как глобаÐ
1»ÑŒÐ½Ð¾ на свою машину так и локально на конкретный проект:"),"\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm install jscs</code></pre></div>'}}),"\n",l.createElement(t.p,null,"Кроме того, понадобится создать конфигурационный файл ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">.jscsrc</code>'}})," и там описать, какого стиля должен придерживаться\nJavaScript на вашем проекте. Этот файл помещается в корень проекта."),"\n",l.createElement(t.p,null,"Несмотря на большое количество правил, которые поддерживает JSCS, конфиг вряд ли будет большим, потому что в инструменте\nпредусмотрены пресеты. Популярных стилей для JavaScript кода не так много, и если вы выбрали один из них, то нет нужды\nописывать стиль полностью. Достаточно указать, на кого вы хотели бы быть похожим:"),"\n",l.createElement(t.ul,null,"\n",l.createElement(t.li,null,"airbnb"),"\n",l.createElement(t.li,null,"crockford"),"\n",l.createElement(t.li,null,"google"),"\n",l.createElement(t.li,null,"jquery"),"\n",l.createElement(t.li,null,"mdcs"),"\n",l.createElement(t.li,null,"wikimedia"),"\n",l.createElement(t.li,null,"yandex"),"\n"),"\n",l.createElement(t.p,null,"Даже если у вас есть расхождения с этими стилями, всё равно удобно выбрать максимально похожий пресет, потому что в JSCS\nвозможно переопределить правила пресета."),"\n",l.createElement(t.p,null,"И, конечно, важно, что инструмент уже достаточно зрелый. А значит, есть все необходимые дружественные пакеты и плагины\nдля разных редакторов."),"\n",l.createElement(t.h2,{id:"как-это-было",style:{position:"relative"}},l.createElement(t.a,{href:"#%D0%BA%D0%B0%D0%BA-%D1%8D%D1%82%D0%BE-%D0%B1%D1%8B%D0%BB%D0%BE","aria-label":"как это было permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),"Как это было"),"\n",l.createElement(t.p,null,"В общем, учитывая все эти факты, мы остановились на JSCS. Начали с того, что написали подходящую нам конфигурацию и тут\nже исключили из списка для проверки все наши файлы. У проекта уже была модульная структура, поэтому это оказалось\nнесложным."),"\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">{\n    ...\n\n    "excludeFiles": [\n      "node_modules/**",\n      "src/modules/a/**",\n      "src/modules/b/**",\n      "src/*.js\n    ]\n}</code></pre></div>'}}),"\n",l.createElement(t.p,null,"Мы договорились, что начиная работать с каким-нибудь модулем, кроме реализации фич, мы также будем править стиль и\nвычеркивать исправленные модули из списка непроверяемых файлов. Соблюдая это, мы довольно быстро исправили все файлы и\nобошлись без конфликтов."),"\n",l.createElement(t.p,null,"Гораздо важнее оказалось поддержание исправленных файлов в их исправленном состоянии во время будуших правок. Конечно,\nтут нам помогают автоматические проверки. Но возникает вопрос, настолько строги мы должны быть в этих проверках и когда\nименно проверять. Ведь поддержка стиля не должна становиться самоцелью и должна перетягивать на себя весь фокус\nразработки."),"\n",l.createElement(t.p,null,"В итоге мы пришли к концепции раздения ответственности. Так, для основного репозитория мы выбрали жесткую политику\nв вопросе соблюдения стиля, а для форков — рекомендательную. Мы настроили Travis так, чтобы оÐ
1½ проверял стиль для\nпул-реквестов. Если стиль не соблюден, пул-реквест не может быть влит в основной репозиторий. Таким образом, там вообще\nникогда нет кода с плохим стилем. В то же время для форков всё гораздо мягче. Мы отказались от насильственных pre-push\nхуков с проверкой стиля, но рекомендуем самостоятельную установку pre-commit хука и использование плагинов JSCS для\nредакторов, чтобы узнавать об ошибках в процессе разработки, а не тогда, когда ломается пул-реквест. Все рекомендации\nнаписаны у нас в разработческой документации, и новые члены команды активно ими пользуются."),"\n",l.createElement(t.p,null,"Всем особенно нравится, как реализована поддержка в редакторах. Ведь конфигурация стиля приезжает в репозиторий проекта\nвместе с кодом, и редактор считывает её самостоятельно. А, главное, у разных проектов может быть разный стиль, и для\nперекрестной работы не требуется никакая перенастройка."),"\n",l.createElement(t.img,{src:"http://varya.me/jscs-talk/pictures/sublime.gif",alt:""}),"\n",l.createElement(t.p,null,"Ну и, конечно, всегда есть возможность запустить проверку стиля вручную как gulp-таск."),"\n",l.createElement(t.img,{src:"http://varya.me/jscs-talk/pictures/travis.png",alt:""}),"\n",l.createElement(t.h2,{id:"предостережения",style:{position:"relative"}},l.createElement(t.a,{href:"#%D0%BF%D1%80%D0%B5%D0%B4%D0%BE%D1%81%D1%82%D0%B5%D1%80%D0%B5%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F","aria-label":"предостережения permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),"Предостережения"),"\n",l.createElement(t.p,null,"Во время внедрения инструмента мы столкнулись с парочкой неудобств. Думаю, стоит о них упомянуть, тем более, что к ним\nнашлись решения."),"\n",l.createElement(t.p,null,'Основное расстройство — ошибка "out of memory" при запуске gulp-таска с проверкой. Оказалось, что недостаточно исключить\nфайлы в конфигурации JSCS. Gulp всё равно сначала пытается работать с ними всеми и пока дело доходит до JSCS, память уже\nкончается. В итоге мы пришли к использованию пакета ',l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">gulp-ignore</code>'}}),":"),"\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:"<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">gulp.task('jscs', function() {\n  return gulp.src([\n    '**/*.js'\n  ])\n  .pipe(gulpIgnore.exclude([\n    'node_modules/**',\n    'demo-output/**'\n  ]))\n  .pipe(jscs());\n})</code></pre></div>"}}),"\n",l.createElement(t.p,null,"Это не очень хорошее решение, ведь здесь пришлось перечислить все те исключения, которые уже задекларированы в ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">.jscsrc</code>'}}),".\nНо лучшего варианта у нас пока нет."),"\n",l.createElement(t.p,null,"И, второй момент: если вы используете watch в разработке, то скорее всего захотите видеть ошибки в терминале, но не\nпрерывать исполнение таска. Для этого потребуется ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">gulp-plumber</code>'}}),":"),"\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">
1gulp.task(\'jscs\', function() {\n  return gulp.src([\n    \'**/*.js\'\n  ])\n  ...\n  .pipe(plumber())\n  .pipe(jscs());\n});</code></pre></div>'}}),"\n",l.createElement(t.p,null,"Всё, больше никаких проблем или вопросов относительно иструмента у нас не было. Он прекрасно работает и уже сохранил нам\nтысячи человекочасов."),"\n",l.createElement(t.h2,{id:"а-также",style:{position:"relative"}},l.createElement(t.a,{href:"#%D0%B0-%D1%82%D0%B0%D0%BA%D0%B6%D0%B5","aria-label":"а также permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),"А также"),"\n",l.createElement(t.p,null,"Возможно, вас также заинтересует ",l.createElement(t.a,{href:"http://habrahabr.ru/post/220229/"},"рассказ автора JSCS")," и мои\n",l.createElement(t.a,{href:"http://varya.me/jscs-talk/"},"слайды")," от доклада на эту тему."))}var s=function(e={}){const{wrapper:t}=Object.assign({},(0,a.RP)(),e.components);return t?l.createElement(t,e,l.createElement(r,e)):r(e)},c=n(5556),i=n.n(c),u=n(3433),o=n(9868),m=n(7037),p=n(3928),g=n(4449);const d={Box:u.a,Button:o.$,Text:m.E,Heading:p.DZ,Paragraph:p.fz,PatternJourney:p.Rl,PureHtml:p.Qi,Section:p.wn,Hero:p.lq,Widget:p.x0,PatternJourney:p.Rl,WidgetContainer:p.uM,Workshop:p.cR,ProjectRoles:p.JV,DsAspects:p.nD,Link:p.N_,Image:p._V,ImageBlock:p.Dq,Map:p.T5,YandexImage:p.zX,Instagram:p.pd},h=e=>({children:t})=>l.createElement(p.DZ,{level:e},t),E={h1:h(1),h2:h(2),h3:h(3),h4:h(4),h5:h(5),h6:h(6),p:({children:e})=>l.createElement(p.fz,{standout:!0},e),a:p.N_,ul:p.Ul,ol:p.Ol,div:({"data-excerpt":e,children:t,...n})=>e?l.createElement(p.fz,{as:"div",lead:!0},t):l.createElement("div",n,t)};E.h1.propTypes={children:i().node};const S=({data:{mdx:e,site:{siteMetadata:{siteUrl:t}}},children:n,pageContext:{next:r,prev:s,fileSourceUrl:c}})=>{const{readingTime:i,slug:o,disqusIdentifier:m}=e.fields,{date:h,title:S,subTitle:f,cover:v,tumblr:x}=e.frontmatter,y=e.frontmatter.tags&&e.frontmatter.tags.split(","),b=o.startsWith("blog/");return e?l.createElement(p.PE,null,l.createElement(p.I0,{imageUrl:v&&v.childImageSharp.gatsbyImageData.images.fallback.src,tags:y,date:h,readingTime:b&&parseInt(i.minutes)>0?`${Math.round(i.minutes).toFixed(1)} min read`:null,title:S,subTitle:f}),l.createElement(p.G$,{data:e}),l.createElement(u.a,{flex:"grow",width:"xlarge",margin:{horizontal:"auto"},pad:"medium",direction:"column"},l.createElement(a.xA,{components:{...E,...d}},n),l.createElement(u.a,{direction:"row",fill:"horizontal",justify:"center",margin:{bottom:"auto"},pad:{vertical:"medium"}},y&&y.length>0&&y.map(e=>l.createElement(p.vw,{key:e,name:e.trim(),slug:(0,g.fX)(e),margin:"xsmall"}))),b&&l.createElement(l.Fragment,null,l.createElement(p.WB,{flex:!1,prevSlug:s&&`/${s.fields.slug}`,nextSlug:r&&`/${r.fields.slug}`,prevTitle:s&&s.frontmatter.title,nextTitle:r&&r.frontmatter.title,pad:{vertical:"medium"}}),l.createElement(p.Sn,{link:c}),l.createElement(p.Hw,{slug:o,title:S,disqusIdentifier:m,tumblr:x,siteUrl:t})))):null};function f(e){return l.createElement(S,e,l.createElement(s,e))}}}]);
2//# sourceMappingURL=component---src-templates-post-js-content-file-path-content-posts-jscs-in-use-index-ru-md-95aa5ed355a7ee29460c.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.