Статьи

Написание удивительного сценария сборки с Grunt

Grunt — это фантастическая система сборки для веб-разработки, но ее сложно настроить. В этом руководстве вы научитесь настраивать Grunt для создания современного веб-проекта. Когда вы закончите, ваш Gruntfile сможет:

  • Копировать файлы из исходного каталога в каталог сборки
  • Удалить файлы сборки
  • Скомпилируйте файлы Stylus и добавьте к ним префиксы поставщиков.
  • Компилировать CoffeeScript
  • Сократить CSS и JavaScript
  • Компиляция Jade
  • Автоматически создавать исходные файлы при их изменении
  • Запустите сервер разработки

Начиная

Если вы еще этого не сделали, установите Node.js и NPM . Вам также необходимо установить интерфейс командной строки Grunt, выполнив команду npm install -g grunt-cli . Это позволяет вам запускать команду grunt из любой точки вашей системы.

Создайте package.json с содержимым ниже.

 json { "name": "grunt_tutorial", "description": "An example of how to set up Grunt for web development.", "author": , "dependencies": { "grunt": "0.xx", "grunt-autoprefixer": "0.2.x", "grunt-contrib-clean": "0.5.x", "grunt-contrib-coffee": "0.7.x", "grunt-contrib-connect": "0.4.x", "grunt-contrib-copy": "0.4.x", "grunt-contrib-cssmin": "0.6.x", "grunt-contrib-jade": "0.8.x", "grunt-contrib-jshint": "0.6.x", "grunt-contrib-stylus": "0.8.x", "grunt-contrib-uglify": "0.2.x", "grunt-contrib-watch": "0.5.x" }, "engine": "node >= 0.10" } 

Этот файл определяет ваш проект как пакет NPM и объявляет зависимости вашего проекта. У каждой зависимости есть номер версии. Например, grunt-contrib-copy: "0.4.x" указывает NPM установить последнюю версию 0.4 пакета grunt-contrib-copy . Запустите в консоли npm install чтобы установить зависимости.

копия

Хороший скрипт сборки всегда хранит исходный код отдельно от файлов сборки. Это разделение позволяет вам уничтожить сборку, не затрагивая ваш источник, и предотвращает случайное редактирование сборки.

Для начала вы заставите Grunt скопировать файлы из source каталога в каталог build . Создайте файл Gruntfile.js и вставьте в него следующее:

 javascript module.exports = function(grunt) { // configure the tasks grunt.initConfig({ copy: { build: { cwd: 'source', src: [ '**' ], dest: 'build', expand: true }, }, }); // load the tasks grunt.loadNpmTasks('grunt-contrib-copy'); // define the tasks }; 

Давайте разберемся с этим. В Node, когда вам require модуль, вызывается функция modules.exports и возвращается результат. Установив modules.exports `в Gruntfile, вы говорите Node возвращать функцию, которая определяет конфигурацию Grunt. grunt.initConfig — это метод, который принимает один аргумент: объект, свойства которого настраивают отдельные задачи Grunt.

Внутри конфигурации Grunt вы добавили конфигурацию для задачи copy . Эта задача имеет одну подзадачу, которая называется build . В Grunt некоторые задачи, называемые многозадачными , могут иметь несколько подзадач, которые можно вызывать отдельно. Для copy вам не нужна эта функция, но все равно необходимо иметь хотя бы одну подзадачу.

Внутри подзадачи build находится формат массива файлов Grunt. Этот формат является одним из способов, которыми Grunt позволяет вам предоставлять исходные файлы для задачи. cwd указывает на каталог с исходными файлами, а src указывает исходные файлы. '**' — это шаблон, который указывает Grunt на совпадение с любым файлом. dest — это то, где Grunt будет выводить результат задачи. Вы установили его на "build" чтобы сказать grunt скопировать содержимое в каталог сборки. Если есть файл source/index.html , эта конфигурация выведет build/index.html . Наконец, вы устанавливаете параметр expand на true чтобы включить все эти параметры.

grunt.loadNpmTasks("grunt-contrib-copy"); говорит Grunt загрузить задачи из пакета grunt-contrib-copy . Это дает нам команду copy , которую вы можете запустить, набрав grunt copy в вашей консоли.

чистый

Теперь, когда у вас есть каталог для build , пришло время написать задачу, которая его очистит. После настройки копирования добавьте следующее:

 javascript clean: { build: { src: [ 'build' ] }, }, 

Как и у copy , у вас есть clean цель с конфигурацией задачи. src clean конфигурации имеет значение "build" для удаления каталога build .

После grunt.loadNpmTasks("grunt-contrib-copy"); , загрузите задачу clean , которая позволит вам запустить grunt clean из консоли.

 javascript grunt.loadNpmTasks('grunt-contrib-clean'); 

Сложение

Разве не было бы замечательно, если бы у вас была задача build , которая удаляла бы старую сборку перед копированием новых исходных файлов? Давайте добавим один!

 javascript // define the tasks grunt.registerTask( 'build', 'Compiles all of the assets and copies the files to the build directory.', [ 'clean', 'copy' ] ); 

Метод registerTask создает новую задачу. Первый аргумент, "build" , определяет имя задачи. Второе — это описание задачи. Последний представляет собой массив задач, которые будут выполняться. Задача build запускает задачу clean за которой следует задача copy .

стилус

Стилус — это отличный язык, который компилируется в CSS. Он улучшает CSS несколькими способами, включая добавление переменных, вложенности и функций.

 javascript stylus: { build: { options: { linenos: true, compress: false }, files: [{ expand: true, cwd: 'source', src: [ '**/*.styl' ], dest: 'build', ext: '.css' }] } }, 

Это немного отличается от других конфигураций задач. Подзадача build все еще существует, но теперь у нее есть два свойства: options и files . options указывает, как мы хотим, чтобы задача велась. Мы добавили две опции: compress определяет, должен ли сжатый вывод CSS, и linenos добавляет номера строк селекторов в исходных файлах linenos .

files используется тот же формат отображения массивов файлов, что и раньше. Это запустит задачу для всех файлов в source каталоге, которые заканчиваются на .styl . ext изменяет расширение выходных файлов на .css .

Теперь, когда задача stylus выводит файлы CSS в каталог build , больше нет причин копировать файлы stylus в каталог build . Давайте изменим конфигурацию copy чтобы предотвратить это.

 javascript copy: { build: { cwd: 'source', src: [ '**', '!**/*.styl' ], dest: 'build', expand: true }, }, 

! в начале пути предотвращает включение файлов, соответствующих шаблону. Не забудьте добавить "stylus" в задачу build .

 javascript grunt.registerTask( 'build', 'Compiles all of the assets and copies the files to the build directory.', [ 'clean', 'copy', 'stylus' ] ); 

Autoprefixer

Autoprefixer — это плагин, который добавляет префиксы вендора в свойства CSS3 после компиляции файлов стилуса в CSS. Это отличная замена для библиотек, таких как Nib и Compass .

Идите вперед и добавьте конфигурацию autoprefixer .

 javascript autoprefixer: { build: { expand: true, cwd: 'build', src: [ '**/*.css' ], dest: 'build' } }, 

Заметив шаблон? Эта конфигурация очень похожа на другие задачи. Одно заметное отличие — это cwd и dest которые установлены на "build" . Это заставляет autoprefixer выводить файлы в ту же папку, из которой он их читает, что заменяет исходные файлы.

Как и раньше, вам также нужно загрузить задачу Autoprefixer.

 javascript grunt.loadNpmTasks('grunt-autoprefixer'); 

Вместо того, чтобы помещать все задачи CSS в build , создайте новую задачу для таблиц стилей и добавьте эту задачу для сборки.

 javascript // define the tasks grunt.registerTask( 'stylesheets', 'Compiles the stylesheets.', [ 'stylus', 'autoprefixer' ] ); grunt.registerTask( 'build', 'Compiles all of the assets and copies the files to the build directory.', [ 'clean', 'copy', 'stylesheets' ] ); 

Минификация CSS

Передача клиенту множества громоздких CSS-файлов может реально замедлить время загрузки сайта. К счастью, пакет grunt-contrib-cssmin минимизирует CSS-файлы и объединяет их в один файл. Еще раз начнем с настройки.

 javascript cssmin: { build: { files: { 'build/application.css': [ 'build/**/*.css' ] } } }, 

Вместо использования формата массива файлов эта конфигурация использует формат объектов файлов Grunt, который отображает несколько файлов в одно место назначения. Все CSS-файлы в каталоге build будут минимизированы и выведены в build/application.css .

Загрузите пакет и добавьте минимизацию CSS в задачу stylesheets .

 javascript grunt.loadNpmTasks('grunt-contrib-cssmin'); 
 javascript grunt.registerTask( 'stylesheets', 'Compiles the stylesheets.', [ 'stylus', 'autoprefixer', 'cssmin' ] ); 

CoffeeScript

CoffeeScript — это фантастический язык, который компилируется в JavaScript. Он имеет чистый, красивый синтаксис, включает в себя классы и скрывает множество уродливых аспектов JavaScript.

Добавить CoffeeScript в проект легко! Сначала добавьте конфигурацию.

 javascript coffee: { build: { expand: true, cwd: 'source', src: [ '**/*.coffee' ], dest: 'build', ext: '.js' } }, 

Это извлекает исходные файлы CoffeeScript, изменяет их расширения на .js и выводит их в каталог build . Затем загрузите пакет grunt-contrib-coffee .

 javascript grunt.loadNpmTasks('grunt-contrib-coffee'); 

Добавьте задачу scripts и добавьте ее в задачу build .

 javascript grunt.registerTask( 'scripts', 'Compiles the JavaScript files.', [ 'coffee' ] ); grunt.registerTask( 'build', 'Compiles all of the assets and copies the files to the build directory.', [ 'clean', 'copy', 'stylesheets', 'scripts' ] ); 

Еще раз, вам нужно добавить исключение для copy чтобы файлы CoffeeScript не копировались в каталог build .

 javascript copy: { build: { cwd: 'source', src: [ '**', '!**/*.styl', '!**/*.coffee' ], dest: 'build', expand: true }, }, 

Уродовать

Как и cssmin , UglifyJS минимизирует файлы JavaScript и объединяет их в один файл. Вот конфигурация:

 javascript uglify: { build: { options: { mangle: false }, files: { 'build/application.js': [ 'build/**/*.js' ] } } }, 

По умолчанию UglifyJS заменит имена переменных и функций в ваших скриптах на более короткие имена. Это удобно, если код вашего проекта автономен, но если он используется совместно с другим проектом, это может вызвать проблемы. Установка mangle в false отключает это поведение.

Как и задача cssmin , в этой задаче также используется формат объекта files.

Загрузите пакет и добавьте "uglify" в задачу scripts .

 javascript grunt.loadNpmTasks('grunt-contrib-uglify'); 
 javascript grunt.registerTask( 'scripts', 'Compiles the JavaScript files.', [ 'coffee', 'uglify' ] ); 

Убираться

Когда вы запускаете grunt build , в дополнение к build/application.css и build/application.js все остальные файлы CSS и JavaScript находятся в каталоге build . Поскольку они вам не нужны, добавьте подзадачи, чтобы удалить их в clean конфигурации.

 javascript clean: { build: { src: [ 'build' ] }, stylesheets: { src: [ 'build/**/*.css', '!build/application.css' ] }, scripts: { src: [ 'build/**/*.js', '!build/application.js' ] }, }, 

При запуске задачи, если вы не указали подзадачу, Grunt запустит их все. Если вы запустите grunt clean из консоли, он запустит clean:build , clean:stylesheets и clean:scripts . Это не проблема, потому что если clean задача не может удалить файл, она просто игнорирует его.

Обратите внимание, как build/application.css и build/application.js исключены из подзадач stylesheets и scripts . Вы не хотите, чтобы удалить эти ложные после всей вашей тяжелой работы!

Обновите задачи, чтобы использовать соответствующие подзадачи.

 javascript // define the tasks grunt.registerTask( 'stylesheets', 'Compiles the stylesheets.', [ 'stylus', 'autoprefixer', 'cssmin', 'clean:stylesheets' ] ); grunt.registerTask( 'scripts', 'Compiles the JavaScript files.', [ 'coffee', 'uglify', 'clean:scripts' ] ); grunt.registerTask( 'build', 'Compiles all of the assets and copies the files to the build directory.', [ 'clean:build', 'copy', 'stylesheets', 'scripts' ] ); 

нефрит

Jade — это язык шаблонов, который делает написание HTML увлекательным. Добавьте Jade в свой проект с помощью пакета grunt-contrib-jade .

 javascript jade: { compile: { options: { data: {} }, files: [{ expand: true, cwd: 'source', src: [ '**/*.jade' ], dest: 'build', ext: '.html' }] } }, 

Как и задачи со stylus и coffee , jade настраивается с использованием формата массива файлов. Заметьте объект data внутри options ? Этот объект передается каждому шаблону при компиляции файлов Jade. Это удобно для таких вещей, как создание отдельных сборок для разработки и производства или создание динамического контента.

Как и прежде, вам нужно добавить исключение в задачу copy чтобы предотвратить копирование файлов Jade.

 javascript copy: { build: { cwd: 'source', src: [ '**', '!**/*.styl', '!**/*.coffee', '!**/*.jade' ], dest: 'build', expand: true }, }, 

Не забудьте загрузить grunt-contrib-jade и добавить его в `build`.

 javascript grunt.loadNpmTasks('grunt-contrib-jade'); 
 javascript grunt.registerTask( 'build', 'Compiles all of the assets and copies the files to the build directory.', [ 'clean:build', 'copy', 'stylesheets', 'scripts', 'jade' ] ); 

Часы

Ваш Gruntfile действительно начинает сиять, но разве не было бы хорошо, если бы вам не приходилось запускать grunt build каждый раз, когда вы вносили изменения? С grunt-contrib-watch вам не нужно! Давайте настроим задачу, которая будет следить за изменениями в вашем исходном коде и автоматически создавать их.

 javascript watch: { stylesheets: { files: 'source/**/*.styl', tasks: [ 'stylesheets' ] }, scripts: { files: 'source/**/*.coffee', tasks: [ 'scripts' ] }, jade: { files: 'source/**/*.jade', tasks: [ 'jade' ] }, copy: { files: [ 'source/**', '!source/**/*.styl', '!source/**/*.coffee', '!source/**/*.jade' ], tasks: [ 'copy' ] } }, 

stylesheets , scripts и подзадачи Jade следят за изменениями в файлах Stylus, CoffeeScript и Jade и выполняют соответствующие задачи. Задача copy просматривает все остальные файлы в приложении и копирует их в каталог сборки.

Опять же, вам нужно загрузить задание.

 javascipt grunt.loadNpmTasks('grunt-contrib-watch'); 

Сервер разработки

Ни одна среда веб-разработки не обходится без сервера разработки. Пакет grunt-contrib-connect — это полнофункциональный статический файловый сервер, который идеально подходит для вашего проекта.

 javascript connect: { server: { options: { port: 4000, base: 'build', hostname: '*' } } } 

Вы настроили сервер для размещения каталога build на порту 4000. По умолчанию Connect будет размещать сайт только на localhost хосте, что ограничивает доступ к серверу за пределами вашего компьютера. Установка hostname в "*" позволяет получить доступ к серверу из любого места.

Как и раньше, вам также нужно загрузить задачу NPM.

 javascript grunt.loadNpmTasks('grunt-contrib-connect'); 

Если вы попытаетесь запустить grunt connect из командной строки, сервер запустится, а затем сразу остановится. Это связано с тем, что по умолчанию задача grunt connect не выполняется бесконечно. Вы узнаете, как это исправить, в следующем разделе.

По умолчанию

Разве не было бы замечательно, если бы у вас была задача, которая объединяла все другие задачи в одну? Задача по default идеально подходит для этого.

 javascript grunt.registerTask( 'default', 'Watches the project for changes, automatically builds them and runs a server.', [ 'build', 'connect', 'watch' ] ); 

Задача по default запускает `build` для создания начальной сборки. Затем он запускает сервер Connect. Наконец, он запускает watch чтобы посмотреть файлы на предмет изменений и собрать их. Поскольку watch продолжается до тех пор, пока оно не будет уничтожено, сервер Connect будет работать неограниченное время. Запустите grunt в консоли и перейдите по адресу http: // localhost: 4000, чтобы увидеть ваш проект!

Вывод

Мы многое рассмотрели в этом уроке, и Грант может сделать гораздо больше. Полный список всех плагинов, доступных для Grunt, можно найти на сайте плагинов Grunt . Счастливое ворчание!