Прежде чем мы начнем серьезно, я просто хотел указать, что это репост из моего блога на .NET Core (см. внизу этой статьи прямую ссылку на него). Информация, содержащаяся в этой статье, была верна на момент ее написания, но для получения более актуальной информации посетите мой блог.

Что такое бандлинг и зачем он нужен?

Допустим, у вас есть большое приложение MVC. Это многостраничное приложение с JavaScript на каждой странице. Возможно, у вас есть jQuery, Bootstrap JavaScript и Knockoutjs, которые нужно загружать на каждую страницу, и разные наборы моделей представления для каждой из этих нескольких страниц.

Вы можете включить jQuery, Bootstrap и Knockout.js в общий файл макета, но включение каждой из моделей представления на соответствующие страницы может стать утомительным (особенно если вы в конечном итоге используете набор из нескольких моделей представления на этих страницах).

Что, безусловно, может произойти. Лучше повторно использовать, чем повторно внедрять, и все такое.

Немного о том, как работают веб-браузеры

Это не будет подробным описанием того, как работает веб-браузер. Однако я собираюсь дать краткий обзор того, как браузер получает большую часть ресурсов для страницы (css, js, изображения, все, что не является HTML и т.

Допустим, у вас есть следующий файл _layout.cshtml:

<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My Awesome Site</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
          crossorigin="anonymous">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css"
          integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp"
          crossorigin="anonymous">
    <link rel="stylesheet" href="/css/site.css" />
  </head>
  <body>
    
    <div class="container body-content">
      <div class="row">
        <div class="col-xs-12">
          <h3>The best content ever!</h3>
        </div>
      </div>
      
      < /hr>
      <footer>
          <p>Why're you looking down here? The content is up there!</p>
      </footer>
        
    </div>
    
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
            integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
            crossorigin="anonymous"></script>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"
            integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
            crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js"></script>
    <script src="/js/site.js"></script>
  </body>
  
</html>

Как только ваш браузер получит этот файл, он поставит в очередь запросы на внешние ресурсы.

Мое использование здесь внешнего относится к любому ресурсу, который является внешним по отношению к файлу HTML

Ресурсы, которые он начинает запрашивать:

Что с этим не так? Ну вообще ничего страшного в этом нет. Проблема в том, что будет медленно загружать все ресурсы и полностью отображать страницу.

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

Верхний предел зависит от того, какой браузер вы используете.

В приведенном выше примере мы можем видеть некоторые запросы файлов, которые необходимы для отображения главной страницы веб-сайта Amazon в Великобритании. Вы можете видеть, что для загрузки каждого файла требуется некоторое время, каждый из этих файлов необходимо загрузить до полной загрузки страницы.

Вы можете видеть, что для загрузки содержимого DOM потребовалось чуть менее 2 секунд, для загрузки внешних ресурсов — чуть более 3 секунд, но почти 40 секунд для анализа и рисования всего.

Хотя большая часть контента, на загрузку и рендеринг которого ушло 40 секунд, находилась внизу страницы, поэтому вы не увидите его, пока не прокрутите страницу достаточно далеко.

Объединение помогает уменьшить количество одновременных запросов, которые браузер должен выполнить (и подождать), прежде чем он сможет отобразить веб-страницу.

Серьезно, в 2008 году Amazon подсчитала, что замедление загрузки страницы на 1 секунду может стоить им 1 миллиарда долларов

Минификация — это еще один прием, который мы можем использовать для уменьшения времени загрузки страницы, но об этом мы поговорим в другой раз.

Объединение в приложения .NET Core MVC

В среде .NET Framework включить объединение довольно просто. Требуется немного настроить, но как только вы это сделаете, его легко добавить.

Однако в .NET Core нет встроенных вариантов комплектации. Это связано с тем, что связывание рассматривается как действие во время разработки для .NET Core.

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

Итак, как нам связать наш JavaScript и CSS в .NET Core? Ответ — внешние инструменты.

Опции

Существует множество вариантов, которые помогут с комплектацией. Есть:

  • Глоток
  • хрюканье,
  • Бауэр,
  • веб-пакет
  • BundlerMinifier.Core

чтобы назвать только несколько.

Все они имеют свои преимущества и недостатки (в основном в объеме настройки, необходимой для их запуска и работы), и большинство из них являются средствами выполнения задач JavaScript (или просто приложениями JavaScript) и требуют установки npm на вашем компьютере для разработки. (и ваш сервер сборки, если вы его используете), прежде чем вы сможете использовать любой из них.

Зак рассказал о том, как установить npm в своем гостевом посте.

Сегодня я расскажу о вебпаке.

Об остальных я напишу в отдельных постах.

веб-пакет

Создатели вебпака описывают это так:

webpack— этосборщик модулейдля современных приложений JavaScript.

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

Допустим, у вас есть ряд страниц, и каждая из них связана с одним из следующих:

  • поиск продуктов
  • управление аккаунтом (регистрация, просмотр заказов, изменение платежных реквизитов и т. д.)
  • предоставление обратной связи

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

Конечно, никогда не забывайте также о проверке на стороне сервера.

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

webpack Работал пример

Что мы собираемся сделать здесь, так это создать тривиальный пример, используя генератор yoman и немного магии npm. Попутно мы представим TypeScript (но мы не будем его сильно касаться), затем добавим webpack и объединим наш транспилированный JavaScript.

На самом деле мы воссоздадим код в этом репозитории GitHub. Так что смело отправляйтесь туда, чтобы окунуться в подробности.

Пустое веб-приложение

Итак, первое, что мы собираемся сделать, это заставить yoman сгенерировать пустое веб-приложение.

Мы собираемся превратить это в приложение MVC вручную, потому что до сих пор мы шли по легкому пути.

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

yo aspnet

Выберите «Пустое веб-приложение» и дайте ему имя «webpack-ts», затем восстановите его пакеты.

cd webpack-ts
dotnet restore

Добавление MVC

Далее мы хотим добавить в проект MVC и статические файлы. Добавьте следующие две строки в файл project.json:

"Microsoft.AspNetCore.Mvc" : "1.1.0",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",

Затем снова восстановите пакеты

dotnet restore

Затем нам нужно изменить наш startup.cs. Просто возьмите эту версию и вставьте ее поверх текущего класса:

public class Startup
{
  public Startup(IHostingEnvironment env)
  {
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

    builder.AddEnvironmentVariables();
    Configuration = builder.Build();
  }

  public IConfigurationRoot Configuration { get; }

  public void ConfigureServices(IServiceCollection services)
  {
    // here is where we add the MVC service
    services.AddMvc();
  }

  public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
  {
    loggerFactory.AddConsole();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    // here is where we'll add the Static Files service
    app.UseStaticFiles();
    // and here is where we add our routing
    app.UseMvc(routes => {
        routes.MapRoute(    
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");          
        });
  }
}

Что мы сделали здесь, так это добавили, что сказали классу запуска, что мы хотим добавить MVC в список сервисов, доступных для нашего приложения (строка 22). Затем мы сказали ApplicationBuilder, что хотим использовать StaticFiles и маршрутизацию MVC по умолчанию (между строками 37 и 43).

Добавление контроллеров и представлений

Теперь нам нужно добавить контроллер и представление. Вы можете сделать это из терминала, но я покажу вам, как это сделать из VS Code.

Потому что сегодня мы проведем достаточно времени в терминале

Щелкните правой кнопкой мыши узел webpack-ts, выберите «Новая папка» и дайте этой папке имя «Контроллеры». Затем сделайте это снова, чтобы добавить папку Views.

Щелкните правой кнопкой мыши папку «Контроллеры», выберите «Новый файл» и дайте этому файлу имя «HomeContoller.cs». Затем вставьте в него следующий код

using Microsoft.AspNetCore.Mvc;

namespace webpack_ts
{
  public class HomeController : Controller
  {
    // GET: /<controller>/
    public IActionResult Index()
    {
      return View();
    }

    public IActionResult SayName()
    {
      return View();
    }
  }
}

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

Щелкните правой кнопкой мыши узел «Представления», выберите «Новая папка» и дайте этой папке имя «Общие». Затем сделайте это снова (в узле Views) и назовите эту новую папку «Home».

Щелкните правой кнопкой мыши общий узел, выберите «Новый файл» и дайте ему имя «_layout.cshtml» (важно подчеркивание). Затем вставьте в него следующую разметку:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>webpack.ts</title>
  <link rel="stylesheet" href="~/css/bootstrap3-custom/bootstrap.min.css" />
  <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
  <div class="container body-content">
      @RenderBody()
      <hr />
      <footer>
          <p>&copy; @System.DateTime.Now.Year - GaProgMan</p>
      </footer>
  </div>

  <script src="~/js/site.js" asp-append-version="true"></script>
</body>
</html>

Здесь нет ничего особенного, мы просто объявляем, как будет выглядеть наша мастер-страница.

Щелкните правой кнопкой мыши узел «Главная» (под узлом «Представления»), выберите «Новый файл» и дайте этому файлу имя «Index.cshtml». Затем сделайте это снова (в узле Views) и назовите этот новый файл «SayName.cshtml».

Вставьте следующую разметку в файл Index.cshtml:

<h1 id="greeting"></h1>

<script src="~/app/bundle.js"></script>

И следующую разметку в файле SayName.cshtml:

<h1 id="greeting"></h1>

<script src="~/app/someOtherBundle.js"></script>

Наконец, щелкните правой кнопкой мыши узел «Представления», выберите «Новый файл» и дайте этому файлу имя «_ViewImports.cshtml». Затем сделайте это снова (на узле Views) и назовите этот новый файл «_ViewStart.cshtml».

Вот содержимое этих двух файлов — сначала «_ViewImports.cshtml»:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

А теперь «_ViewStart.cshtml»:

@{
  Layout = "_Layout";
}

Добавление поддержки TypeScript

Эта часть не является обязательной на 100%, но TypeScript действительно полезен (хотя поначалу немного лаконичен). Википедия описывает TypeScript как:

[TypeScript] — это строгий надмножество JavaScript, добавляющий к языку необязательную статическую типизацию и объектно-ориентированное программирование на основе классов

TypeScript работает в том же духе, что и CoffeeScript, в том смысле, что он пытается упростить использование JavaScript, скрывая некоторые особенности и крайние случаи синтаксиса JavaScript и обеспечивая полную объектно-ориентированную поддержку (включая наследование).

Я объясню содержимое файлов TypeScript по мере их добавления, но сначала нам нужно немного поколдовать с npm.

Перейдите в свой терминал и выполните эту команду (вам может потребоваться сделать это с помощью sudo или root, если вы используете дистрибутив Linux или Unix-подобный):

npm i -g typescript@next

Это говорит npm установить последнюю версию официального пакета TypeScript. Затем введите эту команду:

npm i -g typings

Это говорит npm установить последнюю версию пакета TypeScript Typings.

Каждая внешняя библиотека, которую вы используете с TypeScript, требует добавления в проект файла «.d.ts» (или typings). Этот файл сообщает TypeScript все о типах, содержащихся в библиотеке (например, что возвращает селектор jQuery и т. д.). Без них вы не сможете транспилировать файл TypeScript, который использует внешнюю библиотеку.

Ну, не без использования ключевого слова any, что не очень хорошая практика, потому что это подрывает всю суть TypeScript.

Добавление файлов TypeScript

Щелкните правой кнопкой мыши узел webpack-ts, выберите «Новая папка» и дайте этой папке имя «Содержимое». Затем щелкните правой кнопкой мыши узел «Содержимое», выберите «Новая папка» и дайте этой папке имя «js».

Щелкните правой кнопкой мыши узел «js», выберите «Новый файл» и дайте этому файлу имя «greeter.ts». Затем вставьте в него следующий TypeScript:

// create the class Greeter and export it
export class Greeter {

  constructor(private message: string){
  }

  sayHello(){
      console.log(this.greetingMessage);
  }

  get greetingMessage() : string{
      return `Hello ${this.message} from TypeScript within a webpack bundle`;
  }
}

Мы создаем класс Greeter как модуль CommonJs и экспортируем его, чтобы его можно было использовать в любом другом модуле или файле.

Давайте быстро взглянем на часть содержимого файла.

constructor(private message: string){
}

Здесь мы создаем конструктор класса Greeter. Мы также передаем аргумент (называемый сообщением) строкового типа.

Самое интересное здесь — использование ключевого слова private. Это говорит TypeScript, что мы хотим, чтобы класс Greeter имел приватную переменную с именем message, типа string, и что он должен инициализировать это значение тем, что мы передаем в конструктор в качестве первого параметра.

get greetingMessage() : string{
   return `Hello ${this.message} from TypeScript within a webpack bundle`;
}

Здесь мы говорим TypeScript создать метод get (называемый GreetingMessage), который будет возвращать строковое значение. Он использует интерполяцию строк ​​для создания возвращаемого значения.

Интерполяция строк — это функция ECMA Script 6

Щелкните правой кнопкой мыши узел «js», выберите «Новый файл» и дайте этому файлу имя «main.ts». Затем вставьте в него следующий TypeScript:

import { Greeter } from './greeter'

export class Main {
    private greeter: Greeter;
    constructor(private defaultElementId: string) {
        this.greeter = new Greeter("there");
    }

    sayHello () {
        this.greeter.sayHello();
        document.getElementById(this.defaultElementId).innerHTML =
                this.greeter.greetingMessage;
    }

    get greetingMessage() : string {
        return this.greeter.greetingMessage;
    }
}

// testing Main class
var instanceOfMain = new Main('greeter');
instanceOfMain.sayHello();

Первое, что мы здесь делаем, это импортируем класс Greeter. Мы делаем это, ища в том же каталоге, что и файл main.ts («./»), файл с именем Greeter (обратите внимание, что нам не нужно указывать расширение файла).

Как и в случае с классом Greeter, мы создаем класс под названием Main и экспортируем его как модуль CommonJs. Этот класс использует экземпляр класса приветствия и использует его методы для взаимодействия со страницей, на которой он находится.

После объявления класса мы используем его экземпляр, чтобы установить значение элемента с идентификатором «приветствие» на «Привет!» и вывести на консоль.

Осталось добавить в узел «js» только один файл: someOther.ts. Вот его содержимое:

export class someOther {
  private myName: string;
  private elementId: string;

  constructor(defaultName: string, idOfElement: string){
    this.myName = defaultName;
    this.elementId = idOfElement;
  }

  sayMyName() {
    console.log(`${this.myName}`);
    document.getElementById(this.elementId).innerHTML = `Hello ${this.myName}`;
  }
}

var instanceOfSomeOther = new someOther('Geoff', 'greeting');
instanceOfSomeOther.sayMyName();

Этот файл представляет собой комбинацию файлов Main и Greeter (без каких-либо внутренних экземпляров или того и другого).

Добавление тсконфигурации

Теперь, когда мы добавили наши файлы TypeScript, мы хотим указать TypeScript, как их транспилировать. Для этого нам нужно добавить файл с именем «tsconfig.json» в корень нашего проекта. Вот содержимое этого файла:

{
  "compilerOptions":{
    "target": "es5",
    "module": "commonjs",
    "sourceMap": true,
    "sourceRoot": "content/js",
    "outDir": "wwwroot/app"
  }, "exclude":[
    "node_modules"
  ]
}

Этот файл сообщает TypeScript, что мы хотим:

  • Транспилировать в ECMA Script 5
  • Используйте шаблон модуля CommonJs
  • Включите исходную карту (например, это позволяет нам размещать точки останова в JS в инструментах разработчика Chrome)
  • Где находится корень исходных файлов (/content/js)
  • Куда поместить транспилированные файлы

Добавление веб-пакета

Наконец-то о самом интересном. До этого момента ни один из наших TypeScript не транспилировался, не говоря уже о пакетах. Давайте сделаем оба сейчас.

Вернемся к терминалу:

npm i -g webpack@next

Это говорит npm установить последнюю версию webpack.

Мы все еще не можем связать наши файлы TypeScript, потому что их нужно сначала транспилировать в JavaScript. Мы могли бы сделать это вручную, запустив tsc в терминале, например:

tsc

Это прочитает наш файл tsconfig.json и создаст файл js и map для каждого из наших файлов TypeScript.

Но нам пришлось бы связывать файлы после их транспиляции. Может ли webpack сделать оба шага за нас?

Конечно.

Добавление загрузчика awesome-typescript

awesome-typescript-loader — это плагин для веб-пакета, который позаботится об этапе транспиляции за вас. Это означает, что когда вы говорите webpack, чтобы связать все ваши javascript

Мы вернемся к этому через минуту

он выполнит для вас транспиляцию из TypeScript в память, прежде чем объединять их. Это означает, что транспилированные файлы JavaScript (например, файлы main.js и main.js.map, созданные из файла main.ts) не появятся на диске, и вам не нужно будет их потом очищать — появятся пакеты на диске, очевидно.

Вернемся к терминалу:

npm i -g awesome-typescript-loader

Теперь, когда у нас установлен awesome-typescript-loader, мы должны создать файл конфигурации webpack.

Добавление webpack.config.json

Если вы запустите команду webpack без каких-либо аргументов (или без файла конфигурации), вы получите большое справочное сообщение cli.

webpack 1.14.0
Usage: https://webpack.github.io/docs/cli.html

Options:
  --help, -h, -?                                                                                  
  --config                                                                                        
  --context                                                                                       
  --entry                                                                                         
  --module-bind                                                                                   
  --module-bind-post                                                                              
  --module-bind-pre                                                                               
  --output-path                                                                                   
  --output-file                                                                                   
  --output-chunk-file                                                                             
  --output-named-chunk-file                                                                       
  --output-source-map-file                                                                        
  --output-public-path                                                                            
  --output-jsonp-function                                                                         
  --output-pathinfo                                                                               
  --output-library                                                                                
  --output-library-target                                                                         
  --records-input-path                                                                            
  --records-output-path                                                                           
  --records-path                                                                                  
  --define                                                                                        
  --target                                                                                        
  --cache [default: true]
  --watch, -w                                                                                     
  --watch which closes when stdin ends                                                            
  --watch-aggregate-timeout                                                                       
  --watch-poll                                                                                    
  --hot                                                                                           
  --debug                                                                                         
  --devtool                                                                                       
  --progress                                                                                      
  --resolve-alias                                                                                 
  --resolve-loader-alias                                                                          
  --optimize-max-chunks                                                                           
  --optimize-min-chunk-size                                                                       
  --optimize-minimize                                                                             
  --optimize-occurence-order                                                                      
  --optimize-dedupe                                                                               
  --prefetch                                                                                      
  --provide                                                                                       
  --labeled-modules                                                                               
  --plugin                                                                                        
  --bail                                                                                          
  --profile                                                                                       
  -d  shortcut for --debug --devtool sourcemap --output-pathinfo
  -p  shortcut for --optimize-minimize                          
  --json, -j                                                                                      
  --colors, -c                                                                                    
  --sort-modules-by                                                                               
  --sort-chunks-by                                                                                
  --sort-assets-by                                                                                
  --hide-modules                                                                                  
  --display-exclude                                                                               
  --display-modules                                                                               
  --display-chunks                                                                                
  --display-error-details                                                                         
  --display-origins                                                                               
  --display-cached                                                                                
  --display-cached-assets                                                                         
  --display-reasons, --verbose, -v                                                                

Output filename not configured.

Я же говорил вам.

Кроме того, это относится к установленной мной версии, и ваша версия может отличаться.

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

Добавьте файл с именем «webpack.config.js» в корень проекта и вставьте это содержимое в:

module.exports = {
  "entry":{
    "bundle": "./content/js/main.ts",
    "someOtherBundle": './content/js/someOther.ts'
  },
  "output": {        
      "path": __dirname + "/wwwroot/app",
      "filename": "[name].js"
  },
  "resolve": {
    "extensions": ['', '.ts', '.webpack.js', '.web.js', '.js']
  },
  "devtool": 'source-map',
  "module": {
    "loaders": [
      {
        "test": /\.ts$/,
        "loader": 'awesome-typescript-loader'
      }
    ]
  }
};

Здесь много чего происходит, поэтому давайте разберем это по частям:

"entry":{
  "bundle": "./content/js/main.ts",
  "someOtherBundle": './content/js/someOther.ts'
},

Это наши точки входа в граф зависимостей webpack. Если мы выберем путь записи «bundle», мы:

  • Найдите файл ./content/js/main.ts
  • Прочтите его содержимое и найдите все модули, указанные в нем как зависимости (через ключевое слово import).

Только один: Greeter.ts

  • Рекурсивно читать содержимое модулей, на которые они полагаются

Нет

  • Поместите эти файлы в память, готовые к выводу
"output": {        
  "path": __dirname + "/wwwroot/app",
  "filename": "[name].js"
},

Здесь мы определяем правила для выходных пакетов.

Переменная __dirName — это переменная узла, которая означает «путь, в котором мы запускаем эту команду», поэтому __dirname + «/wwwroot/app» оценивается как каталог приложения, найденный в каталоге wwwroot в корне нашего проекта (где находится конфигурационный файл webpack, откуда он запускается).

[name] — зарезервированный токен в webpack и означает «имя точки входа». Это означает, что наши две точки входа создадут два пакета, один с именем «bundle.js» и один с именем «someOtherBundle.js».

"resolve": {
  "extensions": ['', '.ts', '.webpack.js', '.web.js', '.js']
},

Здесь мы сообщаем распознавателю веб-пакета, что нас интересуют только файлы с одним из следующих расширений:

  • ‹пустое расширение›
  • .ts
  • .webpack.js
  • .веб.js
  • .js

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

"devtool": 'source-map',

Это говорит webpack создать исходную карту для каждого создаваемого пакета.

"module": {
  "loaders": [
    {
       "test": /\.ts$/,
       "loader": 'awesome-typescript-loader'
    }
  ]
}

Здесь мы называем awesome-typescript-loader плагином.

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

Значение test — это регулярное выражение, которое проверяется на имена файлов в пакете. Любые совпадающие файлы обрабатываются загрузчиком, несоответствующие игнорируются.

Затем список совпадающих файлов передается в awesome-typescript-loader для обработки. А awesome-typescript-loader сделает за нас транспиляцию.

Запуск всего

Теперь, когда мы все настроили, нам нужно запустить две команды в терминале. Сначала нам нужно сказать webpack сделать это:

webpack

Теперь, когда у нас есть файл конфигурации, веб-пакет будет использовать его для обработки и выдаст что-то похожее на это в качестве вывода:

[at-loader] Using [email protected] from typescript and "tsconfig.json" from /path/to/source/webpack-ts/tsconfig.json.
[at-loader] Checking started in a separate process...
[at-loader] Ok, 0.001 sec.
Hash: 438ca430aa379e6d358d
Version: webpack 1.14.0
Time: 1320ms
                 Asset     Size  Chunks             Chunk Names
             bundle.js  2.92 kB       0  [emitted]  bundle
    someOtherBundle.js  2.06 kB       1  [emitted]  someOtherBundle
         bundle.js.map  3.18 kB       0  [emitted]  bundle
someOtherBundle.js.map  2.44 kB       1  [emitted]  someOtherBundle
    + 3 hidden modules

Первые три строки сообщают нам, что awesome-typescript-loader нашел наш файл tsconfig.json и транспилировал все наши файлы TypeScript в JavaScript:

[at-loader] Using [email protected] from typescript and "tsconfig.json" from /path/to/source/webpack-ts/tsconfig.json.
[at-loader] Checking started in a separate process...
[at-loader] Ok, 0.001 sec.

Затем webpack вступает во владение и создает наши связанные файлы JavaScript и их исходные карты:

Hash: 438ca430aa379e6d358d
Version: webpack 1.14.0
Time: 1320ms
                 Asset     Size  Chunks             Chunk Names
             bundle.js  2.92 kB       0  [emitted]  bundle
    someOtherBundle.js  2.06 kB       1  [emitted]  someOtherBundle
         bundle.js.map  3.18 kB       0  [emitted]  bundle
someOtherBundle.js.map  2.44 kB       1  [emitted]  someOtherBundle
    + 3 hidden modules

Возвращаясь к VS Code, мы можем увидеть сгенерированные файлы и их исходные карты:

Поскольку мы собрали наш JavaScript, все, что осталось сделать, — это собрать и запустить приложение:

dotnet run

Одно предостережение, которое следует помнить при просмотре вашего сервера, заключается в том, что вы должны явно указать HomeController в своем запросе (например, «localhost: 5000/Home» для индексной страницы).

Доступ к вашим страницам

Если мы отправим запрос на /Home/Index (или просто /Home), мы получим следующий ответ:

Я включил представление включенного JavaScript в инструмент разработчика Chrome на обоих снимках экрана, чтобы вы могли видеть, что соответствующие пакеты загружены.

Если мы отправим запрос на /Home/SayName, мы получим следующий ответ:

Имя Джеффа было первым, что пришло на ум.

… Возможно, в последнее время я много смотрю Эдди Иззарда.

И это об этом

Как я уже говорил в начале этой статьи, доступно множество различных вариантов, и webpack — лишь один из них. Похоже, что в наши дни это предпочтительный сборщик, Gulp и Grunt потеряли популярность просто потому, что они не такие новые, как webpack.

Разработчики могут быть очень непостоянными. Особенно передние разработчики.

Первоначально опубликовано на сайте dotnetcore.gaprogman.com 5 января 2017 г.