Пересмотренное руководство по Grunt для начинающих

Original author: Matt Bailey
  • Translation
  • Tutorial
Еще в марте 2013 года я написал статью руководство по Grunt для начинающих и она стала самой посещаемой статьей на моем сайте. Я написал ее в то время, когда сам только начинал своё знакомство с Grunt, и это было скорее руководство для себя, чем для кого-то ещё. Теперь, спустя 18 месяцев, я почувствовал, что пришло время пересмотреть как я использую Grunt потому что сейчас я знаю гораздо больше, чем в то время.

Если вам не терпится просто увидеть код, то весь он есть на Github.

Установка Node и Grunt для всех пользователей


В первую очередь вы должны убедиться, что у вас установлены Node и Grunt CLI (command line interface).

  • На сайте Node.js есть установщики для различных операционных систем. Всю информацию можно найти здесь.
  • После установки Node.js просто выполните следующую команду в вашем терминале (я использую iTerm2) для установки grunt-cli

    npm install -g grunt-cli
    


Создание каталога проекта


Наш проект потребует несколько каталогов. Их структура представлена ниже:

grunt/
src/
src/images/
src/scripts/
src/styles/

Создание gruntfile


Прежде всего, я больше не использую scaffolding инструменты (такие как <ш>grunt init или Yeoman). Я настроил все с нуля. Это означает, что у меня гораздо больше понимания что происходит в данный момент. Это совсем не сложно как только вы сделали это несколько раз.

В корне проекта создаем файл с названием Gruntfile.js
В этот файл добавьте следующий код:

module.exports = function(grunt) {

    require('time-grunt')(grunt);

    require('load-grunt-config')(grunt, {
        jitGrunt: true
    });
};


Хотите верьте, хотите нет, это всё что касается нашего Gruntfile.

time-grunt говорит вам, сколько времени заняли каждая задача и общая сборка, а jitGrunt: true говорит load-grunt-config использовать более быстрый загрузчик задач jit-grunt (это необязательно, но скорость это хорошо, правда?).

Создание файла пакета


Давайте двигаться дальше и создадим наш наш базовый файл package.json. Этот файл будет содержать в ближайшее время зависимости нашего проекта. Добавьте следующее (очевидно, измените упоминания «my-project» на настоящее имя вашего проекта).

{
  "name": "my-project",
  "version": "0.0.1",
  "description": "My project"
}

Добавление зависимостей


Теперь у нас есть все необходимое, чтобы начать добавление модулей. Последовательно выполните каждую строку кода представленного ниже:

npm install grunt --save-dev
npm install time-grunt --save
npm install load-grunt-config --save-dev
npm install grunt-concurrent --save-dev
npm install grunt-contrib-clean --save-dev
npm install grunt-contrib-imagemin --save-dev
npm install grunt-sass --save-dev
npm install grunt-contrib-uglify --save-dev

Если вы посмотрите в package.json, то должны увидеть что-то вроде этого:

{
  "name": "my-project",
  "version": "0.0.1",
  "description": "My project",
  "devDependencies": {
    "grunt": "^0.4.5",
    "grunt-concurrent": "^1.0.0",
    "grunt-contrib-clean": "^0.6.0",
    "grunt-contrib-imagemin": "^0.8.1",
    "grunt-contrib-uglify": "^0.6.0",
    "grunt-sass": "^0.16.1",
    "load-grunt-config": "^0.13.1"
  },
  "dependencies": {
    "time-grunt": "^1.0.0"
  }
}

Вот список того, о чем мы только что установили:
grunt: сам планировщик задач.
time-grunt: необязательное, но приятное дополнение — он говорит вам сколько времени заняли каждая задача и общая сборка.
load-grunt-config: позволяет сохранить наш главный gruntfile коротким и лаконичным. Более подробно об этом чуть ниже.
grunt-concurrent: выполнять задачи одновременно. Из коробки Grunt выполняет задачи одну за другой, что может занять некоторое время в зависимости от объема и типа задач, которые необходимо выполнить. Однако часто возникают задачи, которые не зависят от других задач, и могут выполняться одновременно.
grunt-contrib-clean: все очень просто, эта задача удаляет мусор — используйте с осторожностью!
grunt-contrib-imagemin: незаменим, т.к. для всех ваших изображений необходима оптимизация.
grunt-sass: компилирует ваши в SASS/SCSS файлы в CSS. Обратите внимание: этот модуль использует более быстрый, но экспериментальный libsass компилятор. Если вы испытываете проблемы, то, вероятно, должны использовать стабильный, но более медленный grunt-contrib-sass.
grunt-contrib-uglify: делает ваш javascript прекрасным и безобразным.

Настройка задач


Один из лучших модулей которые я представил это load-grunt-config. Он позволяет нам поместить конфиг для каждой из наших задач в отдельный файл. Это гораздо удобнее, чем хранить все настройки в одном большом Gruntfile.
Создайте следующие файлы в директории grunt:
grunt/aliases.yaml
grunt/concurrent.js
grunt/clean.js
grunt/imagemin.js
grunt/jshint.js
grunt/sass.js
grunt/uglify.js
grunt/watch.js

Обратите внимание: имена этих файлов должны соответствовать именам задач.

Скопируйте и вставьте конфиг для каждой задачи ниже в соответствующий файл.

ALIASES.YAML

default:
  description: 'Default (production) build'
  tasks:
    - prod
dev:
  description: 'Development build'
  tasks:
    - 'concurrent:devFirst'
    - 'concurrent:devSecond'
img:
  description: 'Image tasks'
  tasks:
    - 'concurrent:imgFirst'
devimg:
  description: 'Development build and image tasks'
  tasks:
    - dev
    - img
prod:
  description: 'Production build'
  tasks:
    - 'concurrent:prodFirst'
    - 'concurrent:prodSecond'
    - img

Здесь мы определяем различные псевдонимы для наших задач:
default — выполняет задачи prod при запуске grunt в командной строке.
dev — выполняет задачи разработки (но не задачи изображений).
img — выполняет задачи изображений.
devimg — выполняет задачи разработки и изображений.
prod — выполняет задачи производства и изображений.
Кликните сюда для получения дополнительных сведений о настройке псевдонимов для задач при помощи load-grunt-config.

CONCURRENT.JS

module.exports = {

    // Опции
    options: {
        limit: 3
    },

    // Задачи разработки
    devFirst: [
        'clean',
        'jshint'
    ],
    devSecond: [
        'sass:dev',
        'uglify'
    ],

    // Производственные задачи
    prodFirst: [
        'clean',
        'jshint'
    ],
    prodSecond: [
        'sass:prod',
        'uglify'
    ],

    // Задачи изображений
    imgFirst: [
        'imagemin'
    ]
};

Для примера возьмем задачи разработки. Вы можете видеть, что они настроены для запуска сначала clean, а затем одновременно sass:dev и uglify для восстановления css и javascript.
Кликните сюда для получения дополнительных сведений о настройке grunt-concurrent.

CLEAN.JS

module.exports = {
    all: [
        "dist/"
    ]
};

Настроить grunt-contrib-clean довольно просто. Здесь я просто удалил все содержимое каталога /dist. используйте эту задачу с осторожностью — она удалит без разбора все, что вы скажите без каких-либо предупреждений. Поэтому убедитесь, что вы настроили ее правильно.
Кликните сюда для получения дополнительных сведений о настройке grunt-contrib-clean.

IMAGEMIN.JS

module.exports = {
    all: {
        files: [{
            expand: true,
            cwd: 'src/',
            src: ['images/*.{png,jpg,gif}'],
            dest: 'dist/'
        }]
    }
};

Конфиг выше просто оптимизирует все изображения в src/images/ и сохраняет их в dist/images/.
Кликните сюда для получения дополнительных сведений о настройке grunt-contrib-imagemin.

SASS.JS

module.exports = {
    // Development settings
    dev: {
        options: {
            outputStyle: 'nested',
            sourceMap: true
        },
        files: [{
            expand: true,
            cwd: 'src/styles',
            src: ['*.scss'],
            dest: 'dist/styles',
            ext: '.css'
        }]
    },
    // Production settings
    prod: {
        options: {
            outputStyle: 'compressed',
            sourceMap: false
        },
        files: [{
            expand: true,
            cwd: 'src/styles',
            src: ['*.scss'],
            dest: 'dist/styles',
            ext: '.css'
        }]
    }
};

Я разделил задачи sass на процессы разработки и продакшена. Конфиг очень похож, но для целей разработки я установил стиль вывода "nested" и включил карту кода.
Кликните сюда для получения дополнительных сведений о настройке grunt-sass.

JSHINT.JS

module.exports = {

    options: {
        reporter: require('jshint-stylish')
    },

    main: [
        'src/scripts/*.js'
    ]
};

JShint проверяет ваш jsvascript и гарантирует что с ним все тип-топ.
Кликните сюда для получения дополнительных сведений о настройке grunt-contrib-jshint.

UGLIFY.JS

module.exports = {
    all: {
        files: [{
            expand: true,
            cwd: 'src/scripts',
            src: '**/*.js',
            dest: 'dist/scripts',
            ext: '.min.js'
        }]
    }
};

Uglify просто берет ваши Javascript файлы и минифицирует их.
Кликните сюда для получения дополнительных сведений о настройке grunt-contrib-uglify.

WATCH.JS

module.exports = {

    options: {
        spawn: false,
        livereload: true
    },

    scripts: {
        files: [
            'src/scripts/*.js'
        ],
        tasks: [
            'jshint',
            'uglify'
        ]
    },

    styles: {
        files: [
            'src/styles/*.scss'
        ],
        tasks: [
            'sass:dev'
        ]
    },
};

Watch запускает указанные задачи всякий раз, когда файлы за которыми он следит каким-либо образом изменяются — добавляются, удаляются, редактируются.

Note: The easiest way to get Livereload working is to install the browser extension.

Click here for more information on configuring grunt-contrib-watch and Livereload.

Запуск задач


Если вы закончили настройку вашего проекта, как описано выше, то теперь вы можете запустить задачи. Как обсуждалось ранее существуют различные псевдонимы задач, которые вы можете запускать. Теперь просто введите grunt в командной строке в корне вашего проекта.

Если все пройдет хорошо вы увидите текст загрузки, прокручивающий экран вниз, а потом сообщение, на подобие этого:

Я люблю маленькие сводки, которые предоставляет grunt-time. Я вижу, как много времени заняло выполнение, каждого из наборов задач. Плюс сколько времени занял весь процесс сборки.
В зависимости от ваших потребностей вы также могли бы выполнить grunt dev, grunt devimg, или grunt img.

Вы можете также запустить grunt watch, если хотите чтобы grunt следил за изменениями ваших .sass и .js и автоматически запускал sass или jshint и uglify.

Резюме


На самом деле это все. Если вы поэкспериментируете с тем что представлено выше вы скоро обретете уверенность, начнете добавлять задачи и модифицировать рабочий процесс в лучшую сторону в соответствии с вашими требованиями.

Еще раз, код, прилагаемый к этой статье можно найти на Github.

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 16

    0
    Как там говорил граф «де ля фер»: «Для Графа это слишком мало, а для Атоса слишком много». Хотя, в целом, довольно полезно, можно понять, в какую сторону копать и что в целом все довольно просто и может что-нибудь там улучшить, типа минифицировать, перепропроцессорить и т.д.
      –1
      Уже не первая статья по Grunt за последнее время, и, если честно, после работы с Gulp'ом, невольно задаешься вопросом зачем кому-то сейчас начинать с Grunt'а и возиться с ним, когда можно взять Gulp.
        +9
        В вашем комментарии слова «Grunt» и «Gulp» можно спокойно поменять местами. Лично я в свое время вернулся обратно на Grunt с Gulp. И еще знаю несколько точно таких же случаев.
          +1
          По какой причине вы это сделали?
            +2
            Тогда это было связано с нестабильной работой вотчера и нескольких плагинов, кое-каких критически нужных плагинов не было (часть уже появилась) и еще какие-то мелочи, сейчас уже не вспомню.

            На текущий момент Gulp выигрывает только в скорости у Grunt, но это для меня вообще не критично и переписывать конфиги нет ни желания, ни смысла.
        0
        Теперь ждём пересмотренное дополненное руководство по Grunt для начинающих, 3-е издание.
          0
          Когда конфиг обратно соберут в один файл.
          0
          ну и рабочий пример использования grunt (ссылка fork me внизу):
            0
            Вам как раз советы из статьи помогли бы разбить конфиг на более мелкие, ускорить скорость за счет grunt-jit и уменьшить код за счет load-grunt-config.
              0
              попробовал jit-grunt. на легком пректе нет никакого выигрыша.

              на тяжелом — банально помирает. проще уж уходить на Gulp.
                0
                Ничего не мешает использовать task runner совместно с build tool. Если есть существующий проект на Grunt, то уходить на Gulp может не иметь смысла, т.к. профит будет минимален. Будет иметь смысл переписать только те таски которые действительно многоступенчаты.

                jit-grunt, интересно — по какой причине он отваливается? Я работаю над крупным проектом и до сих пор проблем не было.
            +2
            Спасибо, но перешел на Gulp и не собираюсь возвращаться обратно. Во-первых скорость работы гораздо возросла, особенно для компиляции bootsprap less, во-вторых гибкость настройки тасков — не нужно писать json-стиль, гораздо удобнее nodejs-стиль с использованием потоков.

            Ну а после прокачки навыков уже смотришь в сторону отказа от менеджеров задач как таковых и запуска модулей напрямую.

            blog.keithcirkel.co.uk/why-we-should-stop-using-grunt/
              +1
              Очень похожую статью читал еще в феврале.
              www.html5rocks.com/en/tutorials/tooling/supercharging-your-gruntfile/
              • UFO just landed and posted this here
                  0
                  Вот вроде Grunt предназначен для того, чтобы уменьшить объём работы. Но каждый раз когда я добавляю css файл в свой head_css.php, я должен добавить строчку в другом формате в Gruntfile.js, притом не забыв о порядке в котором следуют файлы. Редактирование\удаление скриптов тоже приводит к двойной работе. А ведь нужные файлы в нужном порядке уже есть в html шаблоне.

                  Немного погуглив удалось найти только плагин делающий обратное, т.е. он добавляет в html файл скрипты из Gruntfile.js.

                  Быть может кто-то знает как называется плагин который мне нужен или как в грунтфайле выполнить что-то вроде

                  function css_files()
                  {
                      var lnks = [];
                      ret = false;
                  
                      $.get('head_css.php', function(data) {
                  
                          var obj = $('<div>').html(data);
                  
                  
                          obj.find('link').each(function()
                          {
                              lnks.push($(this).attr('href'));
                          });
                  
                          ret = lnks;
                  
                      });
                  
                      return ret;
                  }    
                  


                  Пример подключаемого файла head_css.php
                  <!-- Библиотеки вначале -->
                  <!--Import Google Icon Font-->
                  <link rel="stylesheet" href="/css/lib/materialize/css/materialize.min.css"   media="screen,projection"/>
                  <link rel="stylesheet" href="/css/lib/social-likes_flat.css" />
                  <link rel="stylesheet" href="/css/lib/jquery.gridster.css" />
                  
                  <link rel="stylesheet" href="/css/alien.css" />
                  
                  <!-- Самописный CSS потом -->
                  <link rel="stylesheet" href="/css/style.css" />
                  <link rel="stylesheet" href="/theme/template_styles.css" />
                  
                  
                    0
                    Готовое решение
                    	var js_files = [];
                    	var fs = require('fs');
                    	var jsdom = require("jsdom").jsdom;
                    
                    	var data = fs.readFileSync( __dirname + '/application/views/page/footer_js.php', 'utf8');
                    	var document = jsdom(data.toString());
                    				
                    	var srcs = document.querySelectorAll('script');
                    	Array.prototype.forEach.call(srcs, function(el, i) {
                    		js_files.push('.' + el.getAttribute('src'));
                    	});
                    

                  Only users with full accounts can post comments. Log in, please.