[Из песочницы] Приложение Vue.js + Asp.NETCore + TypeScript без Webpack

логотипы


Создаем на Visual Studio 2017 модульное приложение Vue.js + Asp.NETCore + TypeScript без использования Webpack или Broserify. Причем сначала делаем проект с использованием Webpack, а потом без него. Чтобы прочувствовать, от какого счастья мы отказываемся.

Материал рассчитан на способных управиться с VS2017 и знакомых с прогрессивным JavaScript фрэймворком Vue.js.

Цель замены системы сборки — снижение стартового барьера для освоения Vue.js за счет уменьшения количества применяемых инструментов при создании современных веб-приложений.

Кроме того, существенно упрощается процесс отладки приложений, сильно сокращается время на пересборку приложения, а для части сценариев работы — пересборка не требуется совсем.

Содержание

Введение

Проект TryVueWebpack
 — Создание стартовой болванки
 — Добавление программного кода
 — Добавление файлов конфигурации
 — Сборка и запуск приложения

Проект TryVue
 — Создание стартовой болванки
 — Копирование программного кода
 — Добавление файлов конфигурации и компиляция
 — Сборка шаблонов и CSS
 — Создание index.html и запуск приложения

Заключение

Введение
Webpack — очень мощный и полезный инструмент, который позволяет делать практически всё. Вам, рано или поздно, придется его освоить, если собираетесь заниматься веб-разработкой серьезно.

Но когда изучаешь Vue.js одновременно с TypeScript, очень хочется убрать лишних посредников. Хотя бы при освоении новых технологий и на простых задачах. Сложно разбираться c TypeScript, когда получаемый на выходе код является результатом переваривания кучей фильтров и конверторов Webpack.

«Прежде, чем объединяться, и для того, чтобы объединиться, мы должны сначала решительно и определенно размежеваться». В.И. Ленин

В нашем проекте TryVue без Webpack: большую часть работы по сборке и установлению взаимосвязей между модулями будет делать штатный компилятор TypeScript, загрузку модулей во время исполнения — System.js, конкатенацию шаблонов и файлов CSS — Bundler&Minifier (почти штатное расширение к VS2017).

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

Сначала собираем модульное приложение с использованием Webpack. Затем переводим полученное приложение с Webpack на сборку штатным компилятором TypeScript + Bundler&Minifier.

Для иллюстрации способа избавления от Webpack подготовлено решение Asp.Net Core с двумя проектами: TryVueWebpack, TryVue (исходники на gihub). Структура проекта TryVueWebpack приведена на скриншоте, что-то подобное вы получите после выполнения описанных здесь действий.

скрытый скриншот
image


Проект TryVueWebpack
При написании этого руководства использовался пример TypeScript Vue Starter от разработчиков TypeScript из компании Microsoft. Исходный код примера реструктурирован и превращен в проект Asp.Net Core на Visual Studio 2017.

Создание стартовой болванки


Для начала создаем стартовую заготовку для приложения. В качестве отправной точки используем проект «Веб-приложение ASP.NET Core» по шаблону «Пустой»

скрытый скриншот
z6hjq6jlqoty01xsxmwmgnoxzba.png


В новом проекте создаем стартовую страницу wwwroot\index.html, в которой определяем место внедрения приложения Vue.js, а также загружаемый js-файл.

скрытый текст фрагмента wwwroot/index.html

...

    
loading..


Затем обеспечиваем открытие index.html страницы при запуске приложения Asp.Net Core, изменив текст класса в файле Startup.cs.

скрытый текст фрагмента Startup.cs
// Startup.cs
...
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseDefaultFiles();
        app.UseStaticFiles();
    }
}


Сейчас можно проверить, что приложение почти запускается (VS2017 запустит IIS Express, в браузере отобразится «loading…»).

Добавление программного кода


Теперь добавляем в приложение vue-компоненты и другой необходимый код для компиляции и работы приложения.

В каталоге ClientApp\components создаем 6 файлов для двух vue-компонент. Для каждой компоненты стили CSS и код TypeScript выносим в отдельные файлы, а в vue-файле оставляем только шаблон (плюс ссылки на css, ts). Однофайловые Vue-компоненты в чистом виде применять не будем (чтобы не ставить плагин для подсветки синтаксиса и т.д.).

скрытый текст ClientApp/components/Hello






// ClientApp/components/Hello.ts
import Vue from "vue";

export default Vue.extend({
    props: ['name', 'initialEnthusiasm'],
    data() {
        return {
            enthusiasm: this.initialEnthusiasm
        }
    },
    methods: {
        increment() { this.enthusiasm++; },
        decrement() {
            if (this.enthusiasm > 1) {
                this.enthusiasm--;
            }
        },
    },
    computed: {
        exclamationMarks(): string {
            return Array(this.enthusiasm + 1).join('!');
        }
    }
});

/* ClientApp/components/Hello.css */
.greeting {
    font-size: 20px;
}

скрытый текст ClientApp/components/AppHello






// ClientApp/components/AppHello.ts
import Vue from "vue";
import HelloComponent from "./Hello.vue";

export default Vue.extend({
    data() {
        return {
            name: "World"
        }
    },
    components: {
        HelloComponent
    }
});

/* ClientApp/components/AppHello.css */
body {
    background-color: aliceblue;
}


В каталоге ClientApp создаем файл index.ts, используемый как точка входа в приложение, а также заглушку vue-stub.ts, которая позволит компилятору TypeScript понимать, что делать с vue-модулями.

скрытый текст ClientApp\index.ts, ClientApp\vue-stub.ts
// ClientApp/index.ts
import Vue from "vue";
import AppHelloComponent from "./components/AppHello.vue";

let v = new Vue({
    el: "#app-root",
    template: '',
    //render: h => h(AppHelloComponent),
    components: {
        AppHelloComponent
    }
});

// vue-stub.ts
declare module "*.vue" {
    import Vue from "vue";
    export default Vue;
}


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


Определяем конфигурацию NPM (менеджера пакетов Node.js), компилятора TypeScript, а также Webpack.

Добавляем в проект файл конфигурации NPM под именем package.json. Если у вас включено автоматическое обновление NPM-пакетов, учтите, что обновление может идти долго. Кроме того, возможен сбой при обновлении. В случае сбоя придется повторить восстановление пакетов, а лучше закрыть VS2017 и установить NPM-пакеты из командной строки.

скрытый текст package.json
{
  "version": "1.0.0",
  "name": "asp.net",
  "private": true,
  "scripts": {
    "build": "webpack"
  },
  "dependencies": {
    "vue": "^2.5.13"
  },
  "devDependencies": {
    "css-loader": "^0.28.9",
    "ts-loader": "^3.5.0",
    "typescript": "^2.7.2",
    "vue-loader": "^14.1.1",
    "vue-template-compiler": "^2.5.13",
    "webpack": "^3.11.0"
  }
}


Добавляем в проект файл конфигурации TypeScript под именем tsconfig.json, в котором определяются опции компилятора (compilerOptions) и каталог, в котором компилятор будет искать «свои» файлы (include).

скрытый текст tsconfig.json
{
  "compilerOptions": {
    "outDir": "./built/",
    "sourceMap": true,
    "strict": true,
    "module": "es2015",
    "moduleResolution": "node",
    "target": "es5"
  },
    "include": [
        "./ClientApp/**/*"
    ]
}


Добавляем в проект файл JavaScript под именем webpack.config.js, в котором определяются входные/выходные файлы и способы их обработки.

скрытый текст webpack.config.js
// webpack.config.js
var path = require('path')
var webpack = require('webpack')

module.exports = {
  entry: './ClientApp/index.ts',
  output: {
    path: path.resolve(__dirname, 'wwwroot/dist'),
    publicPath: 'wwwroot/dist/',
    filename: 'build.js'
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            // Since sass-loader (weirdly) has SCSS as its default parse mode, we map
            // the "scss" and "sass" values for the lang attribute to the right configs here.
            // other preprocessors should work out of the box, no loader config like this necessary.
            'scss': 'vue-style-loader!css-loader!sass-loader',
            'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
          }
          // other vue-loader options go here
        }
      },
      {
        test: /\.tsx?$/,
        loader: 'ts-loader',
        exclude: /node_modules/,
        options: {
          appendTsSuffixTo: [/\.vue$/]
        }
      },
      {
        test: /\.(png|jpg|gif|svg)$/,
        loader: 'file-loader',
        options: {
          name: '[name].[ext]?[hash]'
        }
      }
    ]
  },
  resolve: {
    extensions: ['.ts', '.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  },
  devServer: {
    historyApiFallback: true,
    noInfo: true
  },
  performance: {
    hints: false
  },
  devtool: '#eval-source-map'
}

if (process.env.NODE_ENV === 'production') {
  module.exports.devtool = '#source-map'
  // http://vue-loader.vuejs.org/en/workflow/production.html
  module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: true,
      compress: {
        warnings: false
      }
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: true
    })
  ])
}


Сборка и запуск приложения


Остается проверить работоспособность сделанного. Закрываем Visual Studio и через командную строку в каталоге проекта выполняем следующее:

npm install
npm run build
dotnet run


В браузере идем по указанному адресу, например, localhost:52643. В вашем случае порт наверняка будет другим. Должны получить что-то подобное изображенному на скриншоте.

screenshot

Этот способ сборки и запуска приложения далеко не самый удобный, но его было проще описать. Запускать полученное приложение можно прямо из VS2017 (Ctrl+F5) или просто открывать в браузере файл wwwroot\index.html.

Со сборкой чуть посложнее. Если потребуется часто запускать скрипты сборки из package.json, попробуйте NPM Task Runner — достаточно популярное расширение к VS2017.

Желающие могут посмотреть внимательно на файл wwwroot\dist\build.js. Это файл у меня имеет размер 893kB, там код нашего приложения собран вместе с кодом vue.esm.js. Причем сборщик туда закопал не только наш код JavaScript, но также и CSS. Если в этом файле поставить в нужном месте точку остановки и походить отладчиком, то можно увидеть, что Webpack выполняет массу полезной работы. Обеспечивает инициализацию компонент с учетом зависимостей, кэширует вызовы и т.д.

Встроенный отладчик VS2017 на ts-файлах работать не будет, если оставить webpack.config.js без изменений. После некоторых изысканий нашел, что отладчик начинает работать если установить опцию {devtool:'#source-map'} вместо {devtool:'#eval-source-map'}. Так как этот конфиг я взял у большого гуру, а сам не хочу разбираться на что ещё влияет эта опция, то оставил исходную версию.

Проект TryVue
Теперь приступаем к созданию проекта Vue.js + Asp.NETCore + TypeScript без Webpack.

Создание стартовой болванки


Процедура создания стартовой заготовки для проекта TryVue идентична ранее описанной процедуре для проекта TryVueWebpack. Стартовую страницу wwwroot\index.html поправим позже.

Копирование программного кода


Полностью копируем папку ClientApp из сделанного в предыдущем разделе проекта. Удаляем файл ClientApp/vue-stub.ts.

Меняем расширение имени файлов *.vue → *.html. Затем в этих файлах удаляем тэги

loading…


Загружаем System.js, который, в свою очередь, грузит все необходимое и стартует приложение.




Запуск полученного приложения в среде Visaul Studio — обычный (например: F5). Нормально работает встроенный отладчик VS2017, причем точки остановки можно ставить и в коде ts-модулей.

Заключение
Отказ от Webpack при разработке Vue.js-приложений, позволил вести разработку и отладку исключительно в привычной среде VS2017. В получении бандлов участвует только TypeScript и конкатенатор.

Для сравнения — в случае использования Webpack, в процедуре сборки участвуют, как минимум: webpack, typescript, ts-loader, css-loader, sass-loader, vue-loader, vue-style-loader, vue-template-compiler, vue-template-es2015-compiler, vue-hot-reload-api. Всего в каталоге node_modules: более 400 пакетов объемом около 80 Мб.

Правда, для production-версии полезно vue-шаблоны компилировать в рендер-функции, поэтому посредники для нашего случая тоже потребуется. Но, всё равно, без Webpack их будет значительно меньше.

Когда собираешь бандлы (main.js, main.css, app-temlates.html) без Webpack, есть понимание, из чего и как они получены. Поэтому незначительные правки можно вносить в бандлы напрямую (потом не забывать переносить в исходники). Экономия времени и нервов очень большая, особенно, при прототипировании отдельных компонент, для экспериментов и проверки идей.

Надеюсь, и вам, описанное здесь, принесет пользу.

Ссылки:

  • При написании статьи частично использовался: TypeScript Vue Starter.
  • При создании КДПВ (картинки для привлечения внимания) использованы логотипы официальных сайтов продуктов: vuejs.org, docs.microsoft.com, typescriptlang.org, webpack.js.org.
  • Мой пример на github.

.

© Habrahabr.ru