ASP.NET 5 Новый тип проекта и работа с Grunt
Несмотря на то, что статья использует название “ASP.NET 5”, она не имеет никакого отношения к тому, что в 2020 году могут понимать под ASP.NET 5. ASP.NET 5 назывался ASP.NET Core до релиза первой версии.
В этой статье я опишу новый проект веб-приложения ASP.NET 5, а также расскажу о настройке и использовании Grunt в нем.
Проект ASP.NET 5
Мы будем использовать Visual Studio 2015 Community Edition - она бесплатна для личного использования.
После ее установки и запуска, выберите “File”, “New”, “Project”, а затем в разделе “Templates”, “Visual C#”, “Web” выберите “ASP.NET Web Application”.
Далее выберите “Empty” шаблон в разделе “ASP.NET 5 Preview Templates”.
После того, как студия закончит генерацию шаблона, вы получите пустой, готовый к работе, ASP.NET 5 проект.
Шаблон приложения ASP.NET 5 значительно отличается от предыдущих версий. Теперь solution разделен на две папки, первая “Solution Items”, вторая “src”. Папка src содержит сам проект, в моем случае GetHabitsAspNet5.
ASP.NET 5 проект содержит новую папку “wwwroot”. Назначение этой папки хранить весь статический контент сайта: html, javascript, css файлы, картинки и другие ресурсы, которые должны быть доступны конечным пользователям вашего сайта. Думайте о этой папке как о корне вашего веб-сайта. Доступ к контенту за пределами этой папки теперь запрещен и вам не нужно беспокоиться, что какие-то файлы из папки проекта, могут быть доступны пользователям (как это было раньше). Ну и, соответственно, не следует хранить в ней файлы с исходным кодом, Less файлы, файлы javascript, которые еще планируется объединять и минифицировать - любые не подготовленные к использованию ресурсы.
Вероятно, раньше для объединения и минификации javascript и css файлов вы использовали механизм бандлов из ASP.NET MVC или функции расширения WebEssentials, но теперь, с нативной поддержкой Grunt, мы можем всю подготовку frontend делать с помощью него.
Используем NPM для получения необходимых пакетов
Visual Studio 2015 “из коробки” поддерживает три пакетных менеджера: NuGet, NPM и Bower.
Пакетные менеджеры позволяют легко устанавливать в ваш проект нужные вам ресурсы.
Предыдущие версии Visual Studio поддерживали только NuGet и он использовался как для установки backend (различные .NET библиотеки), так и для frontend (JQuery, Boostrap и т.д.) пакетов. Теперь NuGet будет использоваться только для .NET библиотек. Вы указываете какие NuGet пакеты вам нужны в проекте в файле project.json, этот файл также содержит настройки проекта и в некотором роде заменяет файл web.config.
Проект ASP.NET 5 также поддерживает NPM пакеты. NPM - пакетный менеджер созданный для управления пакетами написанными для Node JS. Для управления пакетами NPM используется файл package.json.
И наконец, ASP.NET 5 поддерживает пакетный менеджер Bower. Bower - это пакетный менеджер созданный Twitter для поддержки frontend разработки. Вы можете использовать его для управления клиентскими ресурсами, такими как: AngularJS, JQuery, Bootstrap и т.д.
Для подготовки ресурсов к публикации на веб-сервер мы будем использовать Grunt. Grunt - это менеджер задач написанный на NodeJS, он имеет множество плагинов, которые упрощают pre-production подготовку frontend ресурсов. Для его установки и установки плагинов для него, мы будем использовать NPM.
Добавим в проект Grunt:
- Клик правой кнопкой мыши по заголовку проекта и выберите в контекстном меню “Add”, “New Item”.
- Выберите “NPM Configuration” файл в “DNX”, “Client-side”.
- Кликните кнопку “Add”.
Проделав эти шаги, вы добавите файл package.json в корень проекта.
Скорее всего, он будет выглядеть примерно вот так:
{
"version": "1.0.0",
"name": "ASP.NET",
"private": true,
"devDependencies": {
}
}
Для того, чтобы сказать NPM какие пакеты нам требуется установить, нужно добавить их в раздел “devDependencies”. Давайте добавим в него grunt и несколько плагинов к нему.
Исправьте ваш файл package.json, чтобы он выглядел вот так:
{
"version": "1.0.0",
"name": "ASP.NET",
"private": true,
"devDependencies": {
"grunt": "~0.4.5",
"grunt-contrib-uglify": "~0.9.1",
"grunt-contrib-watch": "~0.6.1"
}
}
Мы указали, что нам требуется три пакета: “grunt”, “grunt-contrib-uglify”, “grunt-contrib-watch”, после имени каждого пакета мы указали, версию пакета, которую хотели бы использовать. Обратите внимание, что после того как вы наберете название пакета и поставите двоеточие, студия будет подсказывать вам возможные варианты для выбора версии пакета.
После того как вы сохраните изменения в package.json, в папке “Dependencies” появится новая под директория “NPM” и студия начнет загрузку выбранных пакетов (физически они будут находится в папке “node-modules” в корне проекта - эта папка не отображается в Solution Explorer). Их можно будет увидеть, раскрыв папку “NPM”. Если загрузка не начнется автоматически, вы можете щелкнуть правой кнопкой мыши по ней и выбрать пункт “Restore Packages”.
Зачем нужен Bower
Вы можете использовать Bower для управления пакетами используемыми во frontend разработке. Например, вы можете использовать Bower для установки в ваш проект AngularJS, JQuery, Bootstrap и т.д.
Но я рекомендую использовать загруженные через Bower ресурсы только во время разработки (вы можете использовать не минифицированные, удобные для отладки исходники), а при публикации в production среду переключаться на какой-либо общедоступный CDN, например на Google CDN.
Преимущество использование общедоступных CDN заключается в том, что позволяет браузеру пользователя не загружать одни и те же библиотеки при каждом посещении нового сайта, а загрузить их один раз, а затем просто доставать из кэша, так как они находятся по одному и тому же адресу (естественно, это относится к популярным библиотекам и популярным CDN, так как так будет больше вероятность, что кто-то еще использует их на каком-то другом сайте).
Настроим Grunt для обработки Javascript файлов
Grunt отлично подходит для подготовки любых frontend ресурсов: компиляции Less и Saas файлов в CSS, сжатия изображений, склеивания и минификации Javascript файлов и т.д.
В этот посте мы настроим Grunt для автоматического склеивания и минификации Javascript файлов из Script директории (не забудьте создать ее в корне проекта) в один итоговый файл app.js в папке wwwroot.
Настроим Grunt:
- Клик правой кнопкой мыши по проекту и выберите “Add”, “New Item”.
- В “DNX”, “Client-side” выберите “Grunt Configuration file”.
- Нажмите кнопку Add.
После завершения этих шагов в проекте появится новый файл с именем Gruntfile.js - это файл конфигурации Grunt в проекте. Это обычный javascript файл.
Модифицируйте контент этого файла, чтобы он выглядел вот так:
module.exports = function (grunt) {
//1 секция: загружаем плагины Grunt
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
//2 секция: настраиваем плагины
grunt.initConfig({
uglify: {
scripts: {
files: { 'wwwroot/app.js': ['Scripts/app.js', 'Scripts/**/*.js'] }
}
},
watch: {
scripts: {
files: ['Scripts/**/*.js'],
tasks: ['uglify']
}
}
});
//3 секция: настроим запуск задач
grunt.registerTask('default', ['uglify', 'watch']);
};
Давайте разберемся, что мы добавили в него.
Наш Gruntfile.js содержит три секции:
Первая секция указывает какие NPM плагины Grunt мы будем использовать. Мы указываем два плагина: “grunt-contrib-uglify” и “grunt-contrib-watch” (мы можем использовать их, так как предварительно загрузили, указав в блоке devDependencies файла package.json). Плагины, в контексте Grunt, называются Задачами, так как они производят некоторые действия, после того как Grunt из запускает.
Вторая секция производит настройку загруженных задач.
Uglify задача настроена так, что она будет склеивать и минифицировать все javascript файлы из директории Scripts и результирующий файл с названием app.js размещать в директории “wwwroot”.
Изучим более подробно его настройку:
uglify: {
scripts: {
files: { 'wwwroot/app.js': ['Scripts/app.js', 'Scripts/**/*.js'] }
}
}
uglify:
- название настраиваемой задачи, как правило, оно совпадает с названием npm пакета (grunt
- в названии пакета grunt-contrib-uglify
- это указание, что это плагин для Grunt, а contrib
- то что пакет создан Grunt Team), но вы всегда можете уточнить эту информацию на странице пакета. Вот, например, страница Uglify: https://www.npmjs.com/package/grunt-contrib-uglify.
scripts:
- именованный блок настроек для задачи, в контексте Grunt он называется Target (можно понимать как совокупность настроек выполнения задачи и файлов на которые она будет нацелена) - это может быть любое имя, какое вы захотите использовать. При конфигурировании мы можем указать несколько разных target, я выбрал имя “scripts”, потому что с помощью этого target мы будем склеивать и минифицировать javascript файлы, мы могли бы определить еще один target, который бы склеивал css файлы и назвать его, например, “css”.
uglify: {
scripts: {
files: { 'wwwroot/app.js': ['Scripts/app.js', 'Scripts/**/*.js'] }
},
css: {
files: { 'wwwroot/style.css': ['Content/**/*.css'] }
}
}
При запуске задачи мы можем запускать ее как для всех target, так и для какого-то определенного. В случае запуска для всех target задачи Uglify - сначала будет выполнен target “scripts” и склеены и минифицированы все javascript файлы, а затем target “css” и склеены и минифицированы все css файлы. В случае запуска для какого-то конкретного target - будет произведена обработка либо только javascript, либо только css файлов.
files:
- блок, в котором мы указываем, к каким файлам будет применен target. Синтаксис который я использовал для задания списка файлов, называется “Files Object Format”, подробнее про него можно почитать здесь: http://gruntjs.com/configuring-tasks#files-object-format. В данном синтаксисе слева мы указываем путь до файла с результатами, а справа массив исходных файлов.
Существует несколько альтернативных способов задания списка используемых задачей файлов, прочитать о них всех можно здесь: http://gruntjs.com/configuring-tasks#files.
Также мы можем использоваться блок options
, в котором указываются настройки для запуска задачи. Мы пока его не использовали, так как нас устраивают настройки по-умолчанию.
Вот так могла бы выглядеть настройка Uglify с использованием блока options
:
grunt.initConfig({
uglify: {
options: {
mangle: false
},
my_target: {
files: {
'dest/output.min.js': ['src/input.js']
}
}
}
});
В данном случае options
определяет настройки для всех target задачи, но он может и задаваться индивидуально, для каждого target:
grunt.initConfig({
uglify: {
my_target: {
options: {
mangle: false
},
files: {
'dest/output.min.js': ['src/input.js']
}
}
}
});
Блоки “target”, “file”, “options” - стандартные и, как правило, используются всеми задачами Grunt. Так что умение пользоваться ими здорово поможет при работе с Grunt.
Watch задача настроена так, что она отслеживает любые изменения в Javascript файлах в директории Scripts и при их изменении запускает Uglify:
watch: {
scripts: {
files: ['Scripts/**/*.js'],
tasks: ['uglify']
}
}
Третья секция: grunt.registerTask('default', ['uglify', 'watch']);
, объявляет наши собственные задачи, в ней мы объявляем задачу ‘default’, которая будет последовательно запускать сначала ‘uglify’ - для минификации и склейки файлов, а затем ‘watch’ - для начала отслеживания изменений в файлах.
Для задания маски, по которой мы фильтруем javascript файлы (Scripts/**/*.js
), мы использовали, так называемый, Globbing pattern.
**
в нем задают любую вложенность директорий с любыми файлами, а *
- любые символы в любом количестве, в названии файла.
Теперь давайте запустим настроенные задачи:
- Выберите Меню “View”, “Other Windows”, “Task Runner Explorer”, чтобы открыть окно менеджера задач Grunt.
- Для того, чтобы студия нашла какие задачи есть в проекте, кликните кнопку “Refresh”.
- Для запуска задачи кликните правой кнопкой мыши по задаче “default” и нажмите “Run” - вы только что запустили задачу “default”.
В списке задач вы видите все доступные для запуска задачи, запуск задачи “uglify” запустит ее для всех ее target, вы также можете запустить и отдельный target: Кликните правой кнопкой мыши по “uglify:scripts” и выберите “Run” - вы запустили задачу для target “scripts”.
Теперь давайте назначим запуск задачи “default” на событие открытия проекта:
- Щелкните правой кнопкой мыши по задаче “default”, пункт меню “Bindings”.
- Выберите Open Project.
Теперь при каждом открытии проекта Task Runner будет запускать задачу “default”.
Как учиться работать с Grunt
Если вы никогда раньше не сталкивались с миром Node JS и не использовали Grunt, то может потребоваться некоторое время чтобы освоиться с ним.
Во-первых, прочтите Grunt Getting Started.
Во-вторых, изучите синтаксис конфигурирования Gruntfile.js.
Выбрать нужные вам плагины вы можете здесь: http://gruntjs.com/plugins - каталог содержит несколько тысяч плагинов, но в большинстве случаев вы будете использовать только несколько плагинов и они наверняка будут самыми первыми в списке.
Каждый плагин может иметь свои специфичные настройки и вам нет необходимости знать их наизусть, вы просто переходите на страницу плагина и читаете как он настраивается и смотрите примеры настройки, а затем настраиваете по аналогии.
Вот, например, страницы плагинов watch и uglify.
Также пример настройки Grunt можно прочитать в документации ASP.NET 5.
Ну и наконец статья на frontender.info описывающая настройку нескольких плагинов Grunt.
Заключение
В этой статье мы научились работать с NPM и устанавливать с помощью него Node JS пакеты, настраивать Grunt для автоматической склейки и минификации javascript файлов в ASP.NET 5 проекте, а также запускать Grunt задачи из Visual Studio.
Написано на основе поста Stephen Walther