Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Всем доброго времени суток, меня зовут Михаил. Я .net разработчик в компании Orion Innovation. Сегодня речь пойдет про наш опыт создания веб приложения при помощи Blazor. Обсудим с какими проблемами мы столкнулись при разработке и почему вообще решили использовать Blazor.
Статья подойдет для разработчиков, которые только собираются попробовать эту новую технологию и поможет взвесить все за и против. Ну что же давайте приступим!
Пожалуй, осталось совсем немного людей, кто хоть раз не слышал про новый, модный, молодежный фреймворк от Майкрософт. Однако, для тех кто в танке. Blazor это фреймворк для построения web приложений с использованием всеми любимой платформы .net. Если опустить детали, то можно выделить 3 главных компонента, которыми вы будете пользоваться при создании своих сайтов: Razor pages, .Net core и web технологии (html, css, js).
Для тех из вас, кто следит за продуктами Microsoft, эти названия не будут каким-то открытием. Вся тройка хорошо известна и давно используется компаниями в коммерческой разработке. Мы и раньше могли создавать html странички, пользуясь синтаксисом razor, а так же описывать логику на C#. При этом все самые интересные вещи, такие как генерация странички и исполнение кода, проходили на стороне сервера. Вот где Blazor выступает инноватором. Впервые C# начал исполняться в браузере, и что самое главное, без необходимости использования дополнительных расширений, как это было с Silverligtht. И хотя вы можете также пользоваться Blazor Server, с исполнением кода и рендерингом html страницы на стороне сервера, команда наших разработчиков после догих дебатов пришла к выводу, что мы выберем версию Blazor с клиентской обработкой (то есть при изменении какого либо компонента интерфейса, не будет выполняться запрос к серверу. Перерисовка происходит лишь на стороне браузера), которую мы будем называть Blazor WebAssembly.
Если говорить совсем честно, то когда перед нами поставили задачу сделать проект для заказчика, никто даже и не задумывался о том, чтобы использовать Blazor, мы надеялись всё реализвать на всем знакомой и НАДЕЖНОЙ связке Asp. Net Core + React. Но заказчик настоял на том чтобы все было написано на С#, аргументируя это тем, что их команда разработчиков не хочет учить JS . При этом, они обязательно хотели поддержку Internet Explorer, что подразумевало использование Blazor Server (т.к Internet Explorer не поддерживает WebAssembly). Но забегая вперед, мы предпочли рендеринг в браузере, и вот почему.
Как уже упоминалось, Blazor Server выполняет все вычисления на стороне сервера, также стоит добавить, что транспортом, который используется для доставки страничек в браузер, является SignalR, который в свою очередь работает на WebSocket. Именно поэтому для каждого пользователя, находящегося на сайте, пришлось бы держать открытое соедение и порт на сервере, что, мягко говоря, не желательно. Особенно когда планируешь приложение с несколькими десятками, а то и сотнями одновременных онлайн пользователей. И к тому же не надо забывать, что при каждом действии пользователя, которое влечет хоть малейшее изменение интерфейса, будет вызываться перерисовка , которая также выполняется на сервере, а это значит нам нужно данные отправить и дождаться новых. Этот процесс адекватно выглядит в странах с хорошим интернет соеденением, таких как Россия. Тем не менее, есть много стран, где скорость сети оставляет желать лучшего, и где пользователь успеет заварить чашку кофе, между кликом по кнопке и обновлением страницы.
Сложно поверить, но нам удалось изменить требования (отчасти). Заказчики согласились отказаться от Blazor Server и поддержки Internet Explorer, хотя не от Blazor. Так мы пришли к Blazor WebAssembly, который использует C# в качестве языка для разработки клиентской логики с одной стороны и имеет структуру проекта, схожую с уже существующими JavaScript фреймворками, такими как Angular(TypeScript) и React.
У нас не было возможности выбрать лучшую, по нашему мнению технологию. Быть может такая возможность будет у вас. Именно поэтому давайте разберемся, так ли на самом деле плох Blazor или наоборот так ли он хорош? Стоит ли сделать выбор в пользу Blazor или продолжать пользоваться Angular и React?
Experience
После работы с Blazor мы пришли к мнению, что этот фреймворк что-то среднее между Angular и React. Первое и основное, это конечно цвет.) Случайно так вышло или нет, но эмблема имеет фиолетовый цвет, который мы можем получить смешением красного Angular и синего React . Остается только гадать как происходит процесс дизайн в “Оконной” компании.
Во-вторых, Blazor, как и Angular, является полноценным, мощным фрейворком, а это значит, что практически вся необходимая функциональность доступна нам из коробки. В случае с Blazor это .net со всевозможными алгоритмами, которые реализовал Microsoft. А если вам этого недостаточно, то в вашем распоряжении есть NuGet. Всеми пакетами, конечно, воспользоваться не получится, т.к надо помнить, что наш код исполняется в JS песочнице.
В-третьих, типизация. С#, как и TypeScript, является строго типизированным языком, а это значит, что множество ошибок будут выявлены еще на этапе компиляции. Плюс большим преимуществом является то, что современные IDE будут давать вам больше подсказок, т.к в отличии от JS, в C# все свойства и поля классов известны до сборки программы, и дополнительные не появятся в runtime.
С другой стороны, от React Blazor взял одностороннюю привязку данных и способ работы с html компонентами. Так, например, в Blazor, когда вы используете на странице какой-то ваш компонент, вы не можете обращаться с ним как с обычным html тегом: добавлять класс, указывать любые атрибуты, как это было возможно в Angular. Точно также Blazor не создает новые html теги, он просто вставляет содержание компонента в то место, где этот компонент был использован, из-за чего при отладке в браузере становится сложнее искать ошибки в приложение, т.к сложнее найти место, где начинается один компонент и заканчивается другой.
К слову об отладке. Вы не сможете поставить breakpoint [ST1] в клиентский код, открыв панель разработчика в браузере, поскольку в браузере исполняется Web Assembly. Поэтому пройтись дебагером можно только в Visual Studio, но этот самый дебагер также не всегда корректно работает.
Blazor constraints
Query parameters2
Начнем с проблем, с которыми мы столкнулись в процессе разработки. Где-то в середине проекта перед нашей командой была поставлена задача реализации фильтров на одной из страниц. При этом состояние фильтров должно было храниться в URL, для того чтобы ваш товарищ, которому вы отправляете ссылку на страницу сразу мог увидеть именно те данные, которые сейчас перед глазами у вас, а не выставлял фильтры заново. Ко всему прочему фильтры могли выставляться не только на одной странице, но также переносится при переходе с других. Это в свою очередь означает, что на странице “A” могут находится фильтры 1, 2, 3, а на странице “B” только 4, 5, 6. Поэтому нам бы понадобился такой механизм передачи данных через URL, при котором мы могли бы передавать на страницу динамическое число параметров. Данная проблема легко решается в JavaScript фреймворках, использованием query параметров (/user?id=12&option=option). В React, к примеру, есть библиотеки для реализации такого функционала.
В Blazor, к сожалению, наша команда не смогла найти похожего функционала. Microsoft использует следующую модель для маршрутиризации:
Для тех, кто видит такую картинку в первый раз, директива “page” используется для указания на каком адресе находится страница.
Каждой секции адреса соответствует переменная в C# файле. И все бы хорошо, но при такой схеме построения URL, мы обязаны передавать все переменные при открытии страницы. И даже наличие необязательных переменных не сильно помогает проблеме (это переменные со знаком вопроса), т.к мы можем не указывать только последние переменные. Поэтому нам пришлось писать собственную реализацию.
Но в защиту Blazor нужно добавить что Microsoft анонсировал добавление поддержки query параметров в .net 6, но пока мы имеем то, что имеем.
JS Insertions
Как уже ранее упоминалось, одним из критериев выбора Blazor перед другими фреймворками, является возможность писать полноценные SPA без использования JS. Вот только вы почти наверняка не сможете полностью избавиться от использования JavaScript.
Почему? Потому что как только вы захотите реализовать интерфейс, который хоть отдаленно можно назвать современным,вам обязательно потребуются различные слайдеры, выпадающие меню и списки, хорошенько заправленные красивыми анимашками. Но реализация подобного функционала обязательно потребует работы с DOM, а C# не имеет методов работы с DOM. Так умеет только JS. Вы, конечно, можете поискать библиотеку, которая что-то подобное может. К примеру, уже есть обертка jQuery на .net, но это в 100% будет библиотека которая вызывает JS методы из C#. И в теории такие обертки должны иметь схожую функционаьность, а на практике это не так. Поскольку оборачивают, как правило, самые популярные методы, а не те что нужны вам.
Поэтому будьте готовы использовать вот такие конструкции:
IJSRuntime js;
_module ??= await js.InvokeAsync<int>("./path-to-js-file", "<method name>");
А значит, вам все равно придется хотя бы на базовом уровне знать JS. При этом алгоритм, начало которого находится на стороне с#, середина в JS, а конец опять в с#, сложнее не только отлаживать, но и поддерживать. Особенно когда со временем кода на стороне JS, у вас будет становиться все больше и больше.
Application’s changes tracking
И последнее, о чем хотелось упомянуть, это отслеживание изменений. Когда в консоли с помощью “npm start”, вы запускаете приложение, то запускается сервер, который это приложение обслуживает, в частности. следит за изменениями, сделанными вами в проекте, и применяет их.
В случае с Blazor, это команда выглядит так – dotnet watch run. Здесь также запускается сервер для обслуживания приложения, но время, которое Blazor тратит с момента внесения изменений в проект до отображения этих изменений в браузере, отличается очень значительно.
5 секунд у Blazor, против 800 милисекунд у Angular и React. В самом начале нашего проекта, даже был момент, когда один из наших разработчиков решил делать верстку на React, а потом переносить в .net. Конечно, позднее все привыкли к медленной перезагрузке, но от этого она не стала быстрее, как и процесс разработки.
Blazor advantages
Вот что сам Microsoft относит к преимуществам Blazor:
Использование .NET для разработки веб-приложений на стороне клиента предоставляет следующие преимущества:
Cоздавайте код на C#, а не на JavaScript. (Преимущество исключительно для почитателей C#).
Возможность использовать существующую экосистему .NET с библиотеками .NET (Да, это преимущество, но использовать получится не всё).
Сохранение единой логики приложений для сервера и клиента (А разве мы не можем сделать тоже самое, если у нас сервер на NodeJS ?).
Высокая производительность, надежность и безопасность платформы .NET:
Производительность будет упираться в возможности Web Assembly, а также в скорость исполнения тех же JS функций, которые вызываются из Web Assembly).
Надежность ? Спорный момент, учитывая сколько уже багов было исправлено в Angular и React. A Blazor только начинает это делать.
Безопасность – в конечном счете все зависит от библиотек, которые вы используете. А алгоритмы шифрования реализованны схожим образом в разных языках программирования.
Cохранение высокого уровня продуктивности с помощью Visual Studio в Windows, Linux и macOS.
Cоздавайте приложения на основе распространенных языков, платформ и инструментов, которые отличаются стабильностью, широким набором функций и простотой в использовании.
Итог
После использования Blazor у меня сложилось четкое ощущение того, что на 2021 год Blazor это такой ускоспециализированный фреймворк, на любителя. Но пока что он не может полноценно соперничать с Angular и React. При этом уже есть функционал, который реализован проще и очевиднее, чем в JS [ST1] фреймворках.
Вот где Blazor потенциально мог бы быть использован:
Проект с маленьким числом или полным отсутствием сложных визуальных эффектов (что сводит к минимуму использование js).
Планируете использовать библиотеку которая доступна только на C#.
Существует кодовая база, которую вы планируете, а самое главное, можете использовать в браузерной песочнице.
А вот где точно его не следует использовать:
Все, что не поддерживает WebAssembly, в частности если вы хотите иметь поддержку старых браузеров, как например IE.
Планируете использовать в своем проекте нативный функционал, как например WebRTC или WebGL.
Если вы ориентируетесь на устройства с низкой скоростью передачи и (или), страны с медленным интернетом. По скольку размер Blazor приложения существенно больше. 0,8 мб у Angular против 4мб у Blazor, для приложения с одинаковым функционалом. Вот статья где подробно разобрана попытка портирования Angular приложения на Blazor.
Если у вас есть вопросы - готов пообщаться в комментариях.