• Делать pixelperfect ломая поведение flexbox или же делать правильно flexbox ломая pixelperfect?

    @ned4ded
    Верстка, Фронтенд
    Добрый день. Вкусовщина, конечно, но я за нормальную работу стилей, а не подгон под пп, исключением является случай, когда такой подгод обусловлен некоторой идеей дизайнера (но в 90% случаев это просто недочет дизайна).

    Используя flexbox и делая все по PP приходится отказываться от justify-content, и использовать костыли в виде margin чтобы подогнать под макет, в свою очередь это здорово мешает при адаптации под меньшие разрешения, приходится постоянно перебивать размеры margin, с justify-content и flex-wrap адаптировать по сути и не надо оно само адаптируется но не подходит под PP c расхождением до 50-70 пикселей.


    Если расхождение на 50 пикселей, то используйте другой подход при верстке, чтобы быть ближе к макету. Тут же важно распределение пространства между блоками и их позиционирование в документе.

    Иными словами, если вы видите, что у вас в ряду 3 блока и пространство между ними должно распределяться +/- равномерно (но в дизайне один из блоков расположен не на месте), тогда justify-content будет оправдан, но если у вас 3 блока разной ширины с разными отступами и такое решение обусловлено некоторым "видением", то придется выкручиваться (:
    Ответ написан
    Комментировать
  • Как верстать radio-input?

    @ned4ded
    Верстка, Фронтенд
    Добрый день, самый простой способ - скрыть оригинальные радиокнопки, сверстать кнопки с двумя состоянием: вкл и выкл (через отдельный спан или :before + :after для лейбла). Сам чекбокс выбирается с помощью тега label и аттрибута for.

    Собственно, вот пример из бутстрапа: https://getbootstrap.com/docs/4.3/components/forms...

    Обратите внимание на стили
    .custom-control-input:checked ~ .custom-control-label::before { ... }


    Селектор .a ~ .b выбирает все элементы с классом .b, следующие за элементами с классом .a (на одном уровне дома). С помощью данной фишки можно исхитриться и делать много интересных вещей без js: слайдеры, выпадающее меню, реализовать любую логику, зависящую от двух состояний.

    ps как-то ради интереса реализовывал с помощью селекторов логику из 4х состояний, так что все ограничивается вашей фантазией ;)
    Ответ написан
  • Почему объект доступен из замыкания?

    @ned4ded
    Верстка, Фронтенд
    Добрый день.

    Вы удаляете ссылку на объект в переменной user, но не сам объект и не саму абстрактную ссылку (их может быть много). В js нельзя удалить объект, его удалением занимается garbage collector, вы можете удалить все ссылки и тогда объект будет удален из памяти.

    При передачи объекта в замыкание, там сохраняется ссылка на него, а не на переменную user.

    Собственно, даже чуть более простой код будет работать точно так же:
    let object = { test: 'hey' }
    
    let another = object
    
    object = null
    
    console.log(another)
    // { test: 'hey' }
    Ответ написан
    1 комментарий
  • Правильно ли обворачивать весь скрипт в async?

    @ned4ded
    Верстка, Фронтенд
    Сделать можете, но вне анонимной функции код будет синхронный. Если речь идет об оборачивании всего скрипта и у вас 1 файл с 200-300 строками, то вполне нормально, как по мне. Если вы хотите обернуть angular приложение, то чутье мне подсказывает, что вы запутаетесь и / или возникнут какие-нибудь проблемы с импортами (не проверял). Более того, вам нужно ловить reject внутри такой анонимной функции через try-catch на верхнем уровне.

    Но, как по мне, async нужно использовать только там, где он действительно упрощает работу, для многих вещей вполне подойдут promise, а где-то и колбеки.
    Ответ написан
    8 комментариев
  • Как правильно сделать фон с двумя картинками?

    @ned4ded
    Верстка, Фронтенд
    div {
      background-image: url("first-image-url"), url("second-image-url");
    }


    Так же через запятую можно спозиционировать, задать размеры изображениям, сделать их "приклееными" к краям экрана для нормально отображения на различной ширине.
    Ответ написан
    Комментировать
  • EJS (Node.js ) Как передать параметры строки запроса в файл.ejs?

    @ned4ded
    Верстка, Фронтенд
    Доброго дня.

    Я не эксперт ни в ноде, ни в экспрессе, но постараюсь пованговать чуточку насчет отсутствия вывода параметров в консоль. Учитывая, что вы используете middleware без вызова next(), и без отправки отклика назад, то у вас, должно быть, обработка запросов завершается на одном из первых mw - это, скорее всего, причина того, что при /create не выводится что-либо в консоль. Без нормальной ссылки на сорс сложно что-то утверждать.

    НО! т.к. ваш вопрос никоим образом не связан с описанной вами ситуацией, то передать параметры запроса в файл темплейта можно следующим образом:
    app.get('/create', (req, res) => {
    	res.render('name_of_ejs_file', req.query)
    })

    Однако, у вас должен быть правильно настроен движок и цепочка mw должна доходить до обработчика, висящего на пути /create, в противном случае результата не будет.

    Что, собственно, является базовой информацией по express, в связи с чем я предлагаю вам для начало ознакомиться с гайдами на официальном сайте, или сразу прочесть какую-нибудь книгу / пройти какие-нибудь курсы по nodejs + express. Мне кажется, у вас есть определенные проблемы с пониманием базовых концепций express, без знания которых будут возникать баги в самых простых вещах.
    Ответ написан
    Комментировать
  • Почему в gulp перестал работать autoprefixer?

    @ned4ded
    Верстка, Фронтенд
    Попробуйте поправить ковычки, json всегда с двойными. У вас редактор их даже выделил ;)
    Ответ написан
    4 комментария
  • Поможете оценить проект?

    @ned4ded
    Верстка, Фронтенд
    Добрый день.

    Не плохо для учебного проекта, я считаю. Сколько у вас опыт программирования в целом и веб-разработки в частности?

    Есть несколько элементов, которые я бы сделал по-другому во vue:
    1) Использовал бы vuex. event-bus полезен в некоторых местах (чтобы не засорять стор, например), но для работы со сколько-нибудь сложным апи (эмуляцией которого является ваша папка data) он просто необходим. Ну и вместе с ним переработал бы структуру проекта (с использованием модулей, более удобного структурирования компонентов и т.п.). Ну что вот это такое "search-overlay-active-notify-dark-backgr-in-header"?
    3) Поправил бы некоторые орфографические ошибки: stor, imgAndHerInstancesSizes, сont
    4) Не стал бы пересылать в props объект data. Во первых, можно запутаться. Во вторых, данные должны быть как можно более плоскими.
    5) Не стал бы засовывать в computed свойство сеттер, который обладает достаточно сложной логикой. Для исполнения такой логики есть методы. Вообще computed свойства должны быть максимально простыми. Не нужно в них пихать асинхронные импорты, это уже перебор.
    6) Не стал бы использовать localstorage для хранения промежуточных вычислений. В конце концов, для управления состоянием существует vuex.
    7) Не стал бы усложнять логику рендера TheCartNotEmpty, почему просто не сделать ее через if?
    8) Не стал бы изменять DOM напрямую. Когда вы ищите элементы в вашем spa через document.querySelector, то у вас явно проблемы с проектированием )
    9) Переименовал бы компоненты согласно одной из принятых конвенций. Что за TheNews, RptNewsItem? NewsComponent, NewsItemComponent. Не говорю уже о TheContainer, TheActions, название которых не несет никакого смысла.
    10) Избавился бы от string templates. Сделайте их отдельным компонентом.

    В целом по js:
    1) Избавился бы от вложенных if.
    2) Не использовал бы оператор delete для удаления свойств у объекта.

    Ну, можете считать часть этих замечаний делом вкуса, "opinionated" как написали бы наши забугорные коллеги, но может быть вы сможете вынести что-то полезное для себя )

    ps, не стал смотреть доскональна все, проверил 5-6 файлов.
    Ответ написан
    2 комментария
  • Какие диаграммы нужны для полноценного документирования программного проекта?

    @ned4ded
    Верстка, Фронтенд
    Добрый день!

    Так сложилось, что я отучился на бизнес-аналитика и имею некоторый опыт работы в этой сфере (но в данный момент я занимаюсь разработкой).

    Теперь немного тезисно по вашей информации:
    1) Диаграмма - способ представить информацию, любую диаграмму можно описать словами.
    2) Диаграмма - инструмент для выявления новой информации о системе.
    3) Впервые слышу про диаграмму бизнес-объектов: может это что-то крайне редкое (крайне специализированное), но с высокой долей вероятности, это вам не потребуется.
    4) UML - язык, а не гайдлан по документированию ПО, сл-но в книгах с аббревиатурой UML вы не найдете нормального руководства по документированию.

    Вывод из этого следующий: диаграмма используется как подкрепление к документации, как инструмент проектирования ПО (для выявления зависимостей и новых сущностей). В обоих случаях набор нотаций будет зависеть от требований, предъявляемых к таким документам.

    Если вам интересно документирование ПО, то гуглите: техническая документация, техническое задание, ГОСТ 34, ГОСТ 19, SRS, хорошая статья на хабре про это.

    Если вам интересно именно полноценное описание проекта, то гуглите: методологии разработки программного обеспечения, управление проектами, pmi, pmbok, agile.

    Теперь пройдемся по диаграммам в зависимости от назначения. Я сейчас могу выделить несколько направлений (не претендуя на полноту):
    1) уровень бизнеса (любые части системы, находящиеся вне ПО per se)
    2) уровень программного обеспечения (системные модули, компоненты системы уже реализованные на уровне ПО)
    3) уровень данных (структура данных, описание типов данных и т.д.)
    4) уровень hardware (например, топология сети)

    На уровне бизнеса обычно описываются бизнес-процессы (idf0, idf3, aris, bpmn, dfd), воркфлоу, юзкейсы, маиндмапы и проч. - это все идет сюда. На этом уровне выделяются основные процессы, выполняемые внешними относительно системы акторами, выявляются точки их взаимодействия с системой. На основе этого проектируются основные модули системы, исполняемые ими функции и их взаимодействие. Взаимодействие системы с внешней средой.

    На уровне ПО обычно используются алгоритмы, псевдокод, сущность-связь, диаграммы классов, флоучарты, маиндмапы, диаграммы состояний и все вот это вот абстрактное. Как вы понимаете, все сущности, описываемые на этом уровне уже выделены на уровне бизнеса и здесь происходит их уточнение и описываются особенности реализации. Под сущностями я тут понимаю как и глобальные системные модули и подсистемы, так и абстрактные сущности внутри системы, как то "товар", "пост", "юзер" и т.п.

    На уровне данных обычно делается схема бд. Собственно, схема бд строится на основе описанных сущностный из предыдущего уровня.

    Уровень hardware я лично всегда рассматривал редко, но он строится на основе требований бизнеса, требований к программному обеспечению, требований к обработке, хранению данных.

    К сожалению, я не могу в один пост уместить весь объем знаний, полученный мной за годы обучения и практики, но надеюсь, что это направит вас в нужное направление.

    ps на небольших и средних проекта я стараюсь прибегать к одной из нотаций бизнес-процессов, если требуется что-то автоматизировать (idf или bpmn), юзкейсам для выявления интеракций пользователя с приложением; для подготовки к написанию ПО - сущность-связь, иногда алгоритмы.
    Ответ написан
    Комментировать
  • Как убрать пустоту между блоками без Masonry?

    @ned4ded
    Верстка, Фронтенд
    .b2 {
        width: calc(50% - 2px); // 2px можете убрать, когда уберете бордер у b3
        float: right;
    }
    Ответ написан
    Комментировать
  • Как по уму указать статичный ресурс внутри шаблонизатора?

    @ned4ded
    Верстка, Фронтенд
    Добрый день! В своих проектах как раз использую такой "кустарный" подход, разделяя его на два этапа:
    1) подгрузка глобальных констант в движок nunjucks до компиляции страниц (хранятся в json);
    2) добавление фильтра на выдачу локалей (тоже хранятся в json, но в отдельной папке).

    Грубо говоря, это два способа реализации,
    первый - выгрузка глобальной константы в nunjucks в контекст (gulp-nunjucks-render, render api );
    второй - это использование отдельной от nunjucks сущности (в моем случае экземпляр i18next без бекенда), в которой происходит синхронный процесс выдачи данных по запросу через кастомный фильтр nunjucks.

    Сейчас, проведя с такой сборкой уже около 8-9 месяцев, могу сказать, что там много условностей, багов и проблем с производительностью при сборке. И в целом она не умещается в рамки хоть какой-нибудь глобальной концепции по организации кода (что просто усложнит поддержку в будущем). Наверное, более правильное решение - это настроить какой-то готовый генератор статических сайтов, чем писать свою собственную сборку. Но если вам интересно, с чего начать, то структура и код:

    ├── datasets
    │   └── meta.json
    ├── locales
    │   ├── en
    │   │   └── translation.json
    │   └── ru
    ├── tasks
    ...
    └── gulpfile.js
    
    # Это упрощенная структура, 
    # но если вам будет что-то непонятно, я напишу подробнее.


    код html таска на сборку страниц
    import gulp from 'gulp';
    import fs from 'fs';
    import path from 'path';
    import i18next from 'i18next';
    import config from '../gulpfile.config';
    import engine from 'gulp-nunjucks-render';
    import minify from 'gulp-htmlmin';
    import Backend from 'i18next-sync-fs-backend';
    import rename from 'gulp-rename';
    
    i18next.use(Backend).init({
      debug: true,
      fallbackLng: ['en'],
      initImmediate: false,
      backend: {
        loadPath: config.paths.locales + '/{{lng}}/{{ns}}.json' // локали собираются по названиям из папки locales
      },
      ns: ['translation'],
      defaultNS: 'translation'
    });
    
    export function html(done) {
      const envHooks = [
        env => env.addFilter('__', function(key, ns) { // фильтр на поиск и выдачу информации по ключу в i18next
          if(!i18next.exists(key)) return 0;
    
          return i18next.t(key);
        }),
      ]
    
      const data = fs.readdirSync( config.paths.datasets ).reduce( (acc, filename) => {
        return { ...acc, [ path.basename( filename, '.json') ] : require('../' + config.paths.datasets + '/' + filename) };
      }, {});
    
      data.get = function(name) { 
        return this[name];
      }
    
      const [ def ] = i18next.options.fallbackLng;
    
      const rec = (arr) => {
    
        const [lng, ...rest] = arr;
    
        return i18next.changeLanguage(lng, (err) => {
          if(err) throw new Error(err);
    
          return gulp.src(config.paths.pages)
            .pipe(engine({
              data: {
                datasets: data,
              },
              path: ['src/pages/templates'],
              manageEnv: function(env) {
                return envHooks.forEach(fn => fn(env));
              },
            }))
            .pipe(minify({ collapseWhitespace: true }))
            .pipe(rename(function(path) {
    
              path.basename = lng === def ? path.basename : lng + '.' + path.basename;
            }))
            .pipe(gulp.dest(config.server.dest))
            .on('end', () => {
              return rest.length ? rec(rest) : done();
            });
        });
      }
    
      rec(['ru', 'en']); // если язык дефолтный, то страницы компилируются обычным образом, если нет - у них будет префикс с названием языка
    
      return;
    };


    В коде демонстрируется сразу 2 подхода. В темплейтах вызывается по-разному:
    1)
    <!--
    datasets/features.json
    [
      {
        "name" : "independent",
        "_descr" : "features.indep.descr"
      },
      {
        "name" : "secure",
        "_descr" : "features.secure.descr",
      },
    ]
    -->
    
    {% set features = datasets.get('features') %}
    
    <ul class="page-home__features">
      {% for f in features %}
       <li>
        {{ feature.make(f) }}
       </li>
      {% endfor %}
    </ul>


    2)
    <!--
     locales/en/translation.json
    
      "pages" : {
        "home" : {
          "headings" : {
            "qualities": "a perfect solution for projects"
            }
          }
        }
    -->
    
    <code lang="html">
    <h2 class="text-center font-weight-bold mb-4 mb-lg-6">
      {{ 'pages.home.headings.qualities' | __ }}
      <!-- фильтр зарегистрирован под названием __ -->
    </h2>
    </code>
    Ответ написан
    2 комментария
  • Стоит ли переходить с var на let и const?

    @ned4ded
    Верстка, Фронтенд
    Это значительно ровно настолько, насколько вы обеспокоены удобочитаемостью и организованностью вашего кода.

    Рекомендую ознакомиться, если найдется время airbnb codestyle

    Есть, конечно, и практическое значение в использовании const, let и иных фишек es6+, включая иммутабельность значений примитивов первого и скоупов обоих, но раз вы не сталкиваетесь в повседневности с такими проблемами, которые помогают решать константы и блочные переменные, то и знать вам о них, наверное, ни к чему?)
    Ответ написан
    Комментировать
  • VueJS: Import global?

    @ned4ded
    Верстка, Фронтенд
    Добрый день!

    Содержание vue.config.js:
    module.exports = {
      configureWebpack: {
        module: {
          rules: [{
              test: /\.js/,
              loader: 'import-glob'
            },
            {
              test: /\.scss/,
              loader: 'import-glob'
            }
          ]
        }
      }
    }


    Папка src:
    src/
    ├── App.vue
     ...
    │   
    ├── lib
    │   ├── example
    │   │   └── example.js # example2
    │   └── example.js # example1
    └── main.js


    В файлах example.js по дефолту экспортируется функция, вызов которой пишет в консоль браузера название функции.

    Содержание App.vue
    // inside script tag
    import modules from './lib/**/*.js'
    
    const [module0, module1] = modules
    
    module0.default()
    module1.default()
    
    // example1
    // example2


    Для импорта vue файлов вам потребуется дописать test, я вставил конфиг из репозитория библиотеки, но его можно написать компакте (опять же через переписывания поля test).

    Вам бы поставить тег webpack, ваш вопрос не имеет прямого отношения к vue, и никакого отношения к ноде.
    Ответ написан
    Комментировать
  • REF в VUEJS как вызвать метод из другого компонента?

    @ned4ded
    Верстка, Фронтенд
    Добрый день!

    Согласно официальному стайлгайду, стоит избегать использования любого управления состоянием, кроме как через vuex.

    Если по порядку, то я знаю два паттерна, которые позволят решить проблему коммуникаций компонентов вью: flux design pattern (реализованное с помощью библиотеки vuex), и event bus.

    То, что пытаетесь сделать вы, - это event bus, только вместо использования отдельного экземпляра вью вы в качестве шины используете рутовый экземпляр (по крайней мере в первой части кода).

    Если нет желания разбираться во vuex, то попробуйте организовать работу через шину, оно подойдет для обоих перечисленных вами случаев.

    Event bus для вью основан на встроенных во вью кастомных событиях (реализованных через vm.$on и vm.$emit, подробнее). Обычно создается еще один экземпляр вью:
    // Дальше идет псевдокод, возможны синтаксические ошибки.
    
    // event-bus.js
    import Vue from 'vue'
    
    export default new Vue()
    
    // app.js
    import Vue from 'vue'
    import bus from './event-bus'
    
    export default new Vue({
      created() {
         bus.$on('some-event', () => { console.log('hi!') })
      },
    
      components: {
        child: {
          methods: {
            triggerSomeEvent() {
              bus.$emit('some-event')
            }
          }
        }
      }
    })


    Эту шину импортируете в те компоненты, которые подвязаны на события, инициализируемые в этой шине (т.е. и отправитель и получатель события), здесь будет не важно, родитель это, ребенок, потомок или независимый компонент.
    Ответ написан
    Комментировать
  • Бред в валидаторе WC3 с чем связанно?

    @ned4ded
    Верстка, Фронтенд
    Проблема может быть в вашем сорс коде. Бразуер в инструментах разработчика отображает распарсенную структуру, которая хотя и строится по исходному html-коду, отличается от него исправлением некоторых ошибок разработчика.
    Ответ написан
    2 комментария
  • Почему бутстрап неадекватно располагает элементы?

    @ned4ded
    Верстка, Фронтенд
    добрый день, я сначала хотел написать подробный ответ, но...

    проблема не в bs, прочитайте, пожалуйста, эти инструкции:
    https://getbootstrap.com/docs/4.3/layout/grid/ - про сетку,
    https://getbootstrap.com/docs/4.3/components/forms/ - про разметку форм,
    https://getbootstrap.com/docs/4.3/layout/utilities... - утилиты для лейаута

    все остальные проблемы должны отпасть сами собой.
    Ответ написан
    3 комментария
  • Как правильно использовать em в кнопках?

    @ned4ded
    Верстка, Фронтенд
    Добрый вечер!

    Насколько я понимаю работу браузера, то на уровне рендеринга нет никаких em, rem и иных относительных величин, пересчет идет в px, в связи с чем остаток от деления после рекалькуляции em, rem и т.д. иногда может быть бесконечным. Из-за этого у вас выскакивают такие неровные пиксели.

    Более общий момент: какой смысл присваивать значения шрифта для элемента равным rem, а остальным величинам в том же классе делать в em, а не в rem? Вся суть em в том, что такой элемент может быть засунут в тег small, например, и все значения будут пересчитаны относительно этого тега. REM создавался, чтобы избежать сложения значений вложенных em'ов (compounding), а вы в итоге создаете элемент, значения которого привязываются к локальному шрифту, а шрифт этого элемента привязываете к размеру рутового шрифта, WHAAT?

    Есть смысл сделать, например, так:
    .button {
      fz: 1em; // default
      p: 0.5em 0.75em;
      lh: 1.25;
    
      &--small {
        font-size: 0.75em;
      }
    }


    В данном случае кнопка у вас будет соответствовать размеру шрифта элемента-родителя, а если добавить к ней класс .button--small, то 75% шрифта родителя и все значения пересчитаются соответствующим образом.

    Но я бы так делать не рекомендовал из-за возможных проблем с вложенностью и расчетом em. Обычно кнопки редко встречаются в дизайне в строке (собственно, это единственная причина делать их em), и они, обычно, имеют строго заданные размеры, независимо от каких-то других элементов.

    Единственное, где можно считать em хорошей практикой по моему мнению, - это иконки и некоторые текстовые утилиты (типа бутстраповского .small).
    Ответ написан
    2 комментария
  • Как организовать фильтр по огромному массиву данных?

    @ned4ded
    Верстка, Фронтенд
    Добрый день!

    В общих чертах: фильтруемые данные должны быть иммутабельны (что немного против философии vue). Следовательно, вы в модуле, через который делаете апи колл на получение данных, пишите геттеры на разные "срезы" этого массива.

    Ps
    Возможно, вам стоит сразу после получения ответа нормализовать данные: разбить на flatten массивы, преобразовать массивы в объект с ключами - айдишниками; иначе если у вас тяжеловесный массив на 10к+ ("огромность" такого массива может не сильно влиять на производительность, все зависит от многих факторов, но у меня такие просадки появились в тот момент, когда я начал обрабатывать порядка 50к плоских объектов) объектов с огромным количеством полей, то все это может начать тормозить, особенно если у вас частые обновления дома, связанные с этим массивом.

    + помните, что после добавления в стор все объекты оборачиваются в специальные vue-конструкции, которые позволяют сделать данные реактивными, в связи с чем может быть сильная просадка производительности при загрузки в стор без асинхронных чанков.

    Возможно, вам пригодится https://github.com/vuex-orm/vuex-orm, особенно если массив имеет несколько повторяющихся сущностней.

    ps2 300 объектов - это не огромный массив ;) вам вполне подойдет все, что описано "в общих чертах", оптимизация вряд ли понадобится.
    Ответ написан
  • Как сделан скролл без скроллбара?

    @ned4ded
    Верстка, Фронтенд
    Он не скрыт, а отключен для вебкита. Если вы зайдете в фаерфокс, то увидите скролл.

    Собсвтенно, там отключает скролл псевдоэлемент ::-webkit-scrollbar;

    Вот код:
    * ::-webkit-scrollbar {
        display: none;
    }


    Проблема в том, что скролл не ререндерится после дизейбла данного свойства в хроме, а остается невидимым. Видимо, какой-то баг. Если изменить стили таким образом:
    * ::-webkit-scrollbar {
        display: block;
        background-color: hsl(240, 100%, 50%);
    }


    то увидите синюю полоску справа.
    Ответ написан
    1 комментарий
  • В Gulp таск watch останавливается если есть таск сжатия картинок?

    @ned4ded
    Верстка, Фронтенд
    Вааай, ну и каша.

    Для работы с gulp.series и gulp.parallel таск должен возвращать промис или поток. Также, в сигнатуру функции таска приходит колбек для вызова по завершению работы функции (если она асинхронная, не является потоком, etc) , ты можешь использовать его, хотя это и не нужно в данном случае. Сл-но тебе нужно либо добавить return gulp.src('dist/img/*');, либо вызвать колбек после пайпа:
    gulp.task('compress-img', function (done) {
      gulp.src('dist/img/*')
      // ...
      done();
    }


    Первый вариант в данном случае будет более верным решением, но а второй чтоб ты просто знал на будущее. Он тебе может пригодиться для watch таска, например (если ты его захочешь запускать в серии).
    Ответ написан
    Комментировать