Поделиться через


Использование Grunt в ASP.NET Core

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

В этом примере в качестве отправной точки используется пустой проект ASP.NET Core, чтобы продемонстрировать, как автоматизировать процесс создания клиента с нуля.

В готовом примере очищается целевой каталог развертывания, объединяются файлы JavaScript, проверяется качество кода, содержимое файлов JavaScript сжимается и развертывается в корне веб-приложения. Мы будем использовать следующие пакеты:

  • grunt: пакет runner задачи Grunt.

  • grunt-contrib-clean: подключаемый модуль, который удаляет файлы или каталоги.

  • grunt-contrib-jshint: подключаемый модуль, который проверяет качество кода JavaScript.

  • grunt-contrib-concat: подключаемый модуль, который объединяет файлы в один файл.

  • grunt-contrib-uglify: подключаемый модуль, который минифицирует JavaScript для уменьшения размера.

  • grunt-contrib-watch: подключаемый модуль, который просматривает действие файла.

Подготовка приложения

Для начала настройте новое пустое веб-приложение и добавьте образцы файлов TypeScript. Файлы TypeScript автоматически компилируются в JavaScript с помощью параметров Visual Studio по умолчанию и будут рассматриваться как необработанные материалы, которые следует обработать с помощью Grunt.

  1. В Visual Studio создайте новый ASP.NET Web Application.

  2. В диалоговом окне Новый проект ASP.NET выберите пустой шаблон ASP.NET Core и нажмите кнопку "ОК".

  3. В обозревателе решений просмотрите структуру проекта. В папке \src содержатся пустые узлы wwwroot и Dependencies.

    Пустое веб-решение

  4. В каталог проекта добавьте новую папку с именем TypeScript.

  5. Перед добавлением файлов убедитесь, что в Visual Studio для файлов TypeScript выбран параметр компилирования при сохранении. Последовательно выберите Сервис>Параметры>Текстовый редактор>Typescript>Проект:

    Параметры, задающие автоматическую компиляцию файлов TypeScript

  6. Щелкните правой кнопкой мыши каталог TypeScript и выберите в контекстном меню Добавить > Новый элемент. Выберите элемент файла JavaScript и присвойте файлу Tastes.ts имя (обратите внимание на расширение *.ts). Скопируйте строку кода TypeScript ниже в файл (при сохранении новый Tastes.js файл будет отображаться с исходным кодом JavaScript).

    enum Tastes { Sweet, Sour, Salty, Bitter }
    
  7. Добавьте второй файл в каталог TypeScript и назовите его Food.ts. Скопируйте приведенный ниже код в файл.

    class Food {
      constructor(name: string, calories: number) {
        this._name = name;
        this._calories = calories;
      }
    
      private _name: string;
      get Name() {
        return this._name;
      }
    
      private _calories: number;
      get Calories() {
        return this._calories;
      }
    
      private _taste: Tastes;
      get Taste(): Tastes { return this._taste }
      set Taste(value: Tastes) {
        this._taste = value;
      }
    }
    

Настройка NPM

Затем настройте NPM для загрузки grunt и grunt-tasks.

  1. В обозревателе решений щелкните проект правой кнопкой мыши и выберите в контекстном меню Добавить > Новый элемент. Выберите элемент файла конфигурации NPM, оставьте имя package.jsonпо умолчанию и нажмите кнопку "Добавить".

  2. В файле package.json внутри объекта devDependencies в фигурных скобках введите "grunt". Выберите grunt из списка IntelliSense и нажмите клавишу ВВОД. Visual Studio заключит имя пакета grunt в двойные кавычки и добавит двоеточие. Справа от двоеточия выберите последнюю стабильную версию пакета в верхней части списка IntelliSense (нажмите Ctrl-Space, если IntelliSense не отображается).

    grunt IntelliSense

    Примечание.

    Для организации зависимостей NPM использует семантическое версионирование. Семантическое версионирование, также известное как SemVer, определяет пакеты со схемой нумерации <основная>.<дополнительная>.<исправление>. IntelliSense упрощает семантическое версионирование, отображая лишь несколько распространенных вариантов. Верхний элемент в списке IntelliSense (0.4.5 в примере выше) считается последней стабильной версией пакета. Символ каретки (^) соответствует самой последней основной версии, а тильда (~) — самой последней дополнительной версии. Дополнительные сведения о выражениях в SemVer см. в справочнике по средству синтаксического анализа версий SemVer NPM.

  3. Добавьте дополнительные зависимости для загрузки пакетов grunt-contrib-* для clean, jshint, concat, uglify и watch, как показано в примере ниже. Версии не обязательно должны соответствовать примеру.

    "devDependencies": {
      "grunt": "0.4.5",
      "grunt-contrib-clean": "0.6.0",
      "grunt-contrib-jshint": "0.11.0",
      "grunt-contrib-concat": "0.5.1",
      "grunt-contrib-uglify": "0.8.0",
      "grunt-contrib-watch": "0.6.1"
    }
    
  4. Сохраните файл package.json.

Пакеты для каждого элемента devDependencies будут загружены вместе с любыми файлами, которые требуются для каждого пакета. Файлы пакета находятся в каталоге node_modules (нажмите кнопку Показать все файлы в обозревателе решений).

Модули узлов grunt

Примечание.

При необходимости можно вручную восстановить зависимости в обозреватель решений, щелкнув Dependencies\NPM правой кнопкой мыши и выбрав в контекстном меню пункт Восстановить пакеты.

Пункт

Настройка Grunt

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

  1. Щелкните проект правой кнопкой мыши и выберите Добавить>Новый элемент. Выберите шаблон элемента файла JavaScript, измените имя Gruntfile.jsна и нажмите кнопку "Добавить".

  2. Добавьте в раздел Gruntfile.js следующий код. Функция initConfig задает параметры для каждого пакета, а оставшаяся часть модуля загружает и регистрирует задачи.

    module.exports = function (grunt) {
      grunt.initConfig({
      });
    };
    
  3. В функции initConfig добавьте параметры для задачи clean, как показано в примере Gruntfile.js ниже. Задача clean принимает массив строк каталога. Эта задача удаляет файлы из каталога wwwroot/lib и удаляет весь каталог /temp.

    module.exports = function (grunt) {
      grunt.initConfig({
        clean: ["wwwroot/lib/*", "temp/"],
      });
    };
    
  4. Под функцией initConfig добавьте вызов grunt.loadNpmTasks. Это позволит подготовить задачу к запуску из Visual Studio.

    grunt.loadNpmTasks("grunt-contrib-clean");
    
  5. Сохраните Gruntfile.js. Файл должен выглядеть примерно так, как показано на снимке экрана ниже.

    Исходный файл Gruntfile

  6. Щелкните правой кнопкой мыши Gruntfile.js и выберите обозреватель runner задач в контекстном меню. Откроется окно Task Runner Explorer.

    Пункт меню

  7. В окне Диспетчер выполнения задач убедитесь, что clean отображается в разделе Задачи.

    Список задач в диспетчере выполнения задач

  8. Щелкните правой кнопкой мыши задачу "clean" и выберите в контекстном меню пункт Выполнить. В командном окне отображается ход выполнения задачи.

    Диспетчер выполнения задач выполняет задачу

    Примечание.

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

  9. Добавьте в функцию initConfig запись для concat, используя приведенный ниже код.

    Массив свойств src перечисляет файлы, которые нужно объединить (в том порядке, в котором они должны быть объединены). Свойство dest присваивает путь к созданному объединенному файлу.

    concat: {
      all: {
        src: ['TypeScript/Tastes.js', 'TypeScript/Food.js'],
        dest: 'temp/combined.js'
      }
    },
    

    Примечание.

    Свойство all в приведенном выше коде является именем целевого объекта. Целевые объекты используются в некоторых задачах Grunt для разрешения нескольких сред сборки. Встроенные целевые объекты можно просмотреть с помощью IntelliSense. Также можно назначить собственные целевые объекты.

  10. Добавьте задачу jshint, используя приведенный ниже код.

    Для каждого файла JavaScript, находящегося в каталоге temp, выполняется служебная программа jshint code-quality.

    jshint: {
      files: ['temp/*.js'],
      options: {
        '-W069': false,
      }
    },
    

    Примечание.

    Параметр "-W069" является ошибкой, созданной jshint, когда JavaScript использует синтаксис скобки для назначения свойства вместо нотации точек, Tastes["Sweet"] а не Tastes.Sweet. Параметр отключает предупреждение, чтобы разрешить rest процесс продолжить.

  11. Добавьте задачу uglify, используя приведенный ниже код.

    Задача минифизовает combined.js файл, найденный в временном каталоге, и создает файл результата в wwwroot/lib после стандартного файла> соглашения <об именовании.min.min.js.

    uglify: {
     all: {
       src: ['temp/combined.js'],
       dest: 'wwwroot/lib/combined.min.js'
     }
    },
    
  12. В вызове grunt.loadNpmTasks, который загружает grunt-contrib-clean, включите тот же вызов для jshint, concat и uglify, используя приведенный ниже код.

    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    
  13. Сохраните Gruntfile.js. Файл должен выглядеть примерно так, как показано в примере ниже.

    Пример готового файла Grunt

  14. Обратите внимание, что список задач в диспетчере выполнения задач содержит задачи clean, concat, jshint и uglify. Выполните каждую задачу по порядку и просмотрите результаты в обозреватель решений. Каждая задача должна выполниться без ошибок.

    Диспетчер выполнения задач выполняет каждую задачу

    Задача сцепления создает новый combined.js файл и помещает его в временный каталог. Задача jshint просто выполняется и не создает выходные данные. Задача uglify создает новый файл combined.min.js и помещает его в каталог wwwroot/lib. По завершении решение должно выглядеть примерно так, как показано на снимке экрана ниже.

    Обозреватель решений после выполнения всех задач

    Примечание.

    Чтобы получить дополнительные сведения о параметрах для каждого пакета, перейдите на страницу https://www.npmjs.com/ и выполните поиск по имени пакета в поле поиска на главной странице. Например, можно выполнить поиск пакета grunt-contrib-clean, чтобы получить ссылку на документацию с описанием всех его параметров.

Итоги

Используйте метод Grunt registerTask() для выполнения набора задач в определенной последовательности. Например, чтобы выполнить приведенные выше шаги в порядке clean -> concat -> jshint -> uglify, добавьте в модуль приведенный ниже код. Код следует добавить на тот же уровень, что и вызовы loadNpmTasks(), за пределами initConfig.

grunt.registerTask("all", ['clean', 'concat', 'jshint', 'uglify']);

Новая задача будет отображаться в диспетчере выполнения задач в разделе "Задачи псевдонимов". Можно щелкнуть правой кнопкой мыши и запустить ее так же, как и другие задачи. Задача all будет выполнять clean, concat, jshint и uglify по порядку.

Задачи псевдонимов Grunt

Просмотр изменений

Задача watch отслеживает файлы и каталоги. watch активирует задачи автоматически при обнаружении изменений. Добавьте приведенный ниже код в initConfig, чтобы отслеживать изменения в *.js файлы в каталоге TypeScript. При изменении файла JavaScript watch запустит задачу all.

watch: {
  files: ["TypeScript/*.js"],
  tasks: ["all"]
}

Добавьте вызов loadNpmTasks(), чтобы отобразить задачу watch в диспетчере выполнения задач.

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

Щелкните правой кнопкой мыши задачу watch в диспетчере выполнения задач и выберите в контекстном меню пункт "Выполнить". В командном окне, в котором отображается выполняемая задача watch, будет отображаться сообщение "Waiting…". Откройте один из файлов TypeScript, добавьте пробел, а затем сохраните файл. Это позволит активировать задачу watch и запустить выполнение других задач в указанном порядке. Пример выполнения показан на снимке экрана ниже.

Выходные данные выполняемых задач

Привязка к событиям Visual Studio

Если вы не хотите запускать задачи вручную каждый раз, когда работаете в Visual Studio, привяжите задачи к событиям До сборки, После сборки, Очистка и Открытие проекта.

Привяжите задачу watch, чтобы она выполнялась при каждом открытии Visual Studio. В диспетчере выполнения задач щелкните правой кнопкой мыши задачу watch и выберите в контекстном меню пункт Привязки>Открытие проекта.

Привязка задачи к событию открытия проекта

Выгрузите и снова загрузите проект. При повторной загрузке проекта задача watch начинает выполняться автоматически.

Итоги

Grunt — это эффективный запускатель задач, который можно использовать для автоматизации большинства задач по сборке клиента. Grunt использует NPM для доставки своих пакетов, а также обеспечивает интеграцию средств с Visual Studio. Диспетчер выполнения задач Visual Studio обнаруживает изменения в файлах конфигурации и предоставляет удобный интерфейс для выполнения задач, просмотра выполняемых задач и привязки задач к событиям Visual Studio.