Когда все начинают знакомство с React или Vue, как с двумя самыми популярными фреймворками для frontend, конечно-же все используем магические команды npm install, npm build. И только после этого папочку 'public' Мы деплоим «куда надо».

Но есть и другой (я бы назвал его извращенный) не стандартный способ, о котором многие начинающие фронтэнд разработчики даже не знают, так как они «выросли» на npm install/build.

А что, если не нужно проводить сборку, а просто вставить js код в html?




Подождите плевать мне в лицо и бросать камни с надписью 'I love node'… Мы конечно знаем, что без сборки Мы потеряем юнит тесты, скорость, да и как быть с импортом компонентов, и иерархией файлов, да и вообще спагетти код какой-то получится…

Так для чего Вам (и Нам) это и как это работает ?


На днях к нам прилетел заказ от «бизнеса» по добавлению функционала в их BPM/ERP систему, которая по-сути является сильно модифицированным Redmine. Всё это чудо делалось довольно давно и крутится на VPS сервере с кучей helper'ов микросервисов для считывания данных производства, станков и тп. Трогать ОС нельзя…

Redmine — написан на Ruby on Rails, и генерирует весь фронт на сервере. Всё взаимодействие на фронтэнде в дописанных там плагинах было через jquery. Сейчас RoR научился работать с webpack и можно прикрутить «человеческую npm», но это в последних версиях, а у нас древний Ruby и Centos 6 на котором нет последней версии ни Ruby ни рельсов. Собирать из исходников и перелопатить всё ради добавления нескольких реактивных форм как-то не хочется, поэтому Мы начали искать путь добавления React или Vue в шаблон страницы Rails просто как обычный JS без npm и сборок.
И быстро нашли, причём для обоих.

Vue без Vue npm




С Vue оказалось всё очень просто. Инициирование компонентов выглядит конечно «странно», но в целом читабельно и «писабельно».

Пример простой страницы на Vue c компонентом:
<html>
<head>
    <script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>
    <title>Stranger Vue things</title>
</head>
<body>
<div id="vue-app"></div>
<script type="text/javascript">
const titleComponent = `<h1>{{ title }}</h1>`;

var app = new Vue({
    el: '#vue-app',
    template: titleComponent,
    data: function () {
        return {
            title: 'Stranger Vue things'
        };
    }
});
</script>
</body>
</html>

Размер скачиваемых браузером файлов: 371 Kb, время: 590 ms

Можно даже импортировать Vue компоненты в обычном формате .vue с использованием http-vue-loader и не создавать спагетти код. Очень удивило, что из зависимостей нужен всего один vue, что не может не радовать.

React без React npm


С Реактом всё чуть сложнее но не сильно. Для работы JSX нужно импортировать babel. Для работы с DOM, нужен react-dom. Без вышеперечисленного react не будет нормально работать. Вместо одного импорта нужно сделать три.

Пример простой страницы на React c компонентом:

<html lang="en">
<head>
  <title>React Stranger Things</title>
  <script type="application/javascript" src="https://unpkg.com/react@16.0.0/umd/react.production.min.js"></script>
  <script type="application/javascript" src="https://unpkg.com/react-dom@16.0.0/umd/react-dom.production.min.js"></script>
  <script type="application/javascript" src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
</head>

<body>
  <div id="root"></div>

<script type="text/babel">
const rootElement = document.getElementById('root')    
class TitleComponent extends React.Component {    
    render() { 
        return (
            <h1> {this.props.title}</h1>
        );
    } 
}

function App(){
  return(
    <div>
        <TitleComponent title="React Stranger Things"/>
    </div>
  )
}

ReactDOM.render(
    <App />,
    rootElement
)
</script>
</body>
</html>

Размер скачиваемых браузером файлов: 542 Kb, время: 589 ms

Здесь в отличии от Vue не нужно писать шаблон компонента как строку, пишем всё как обычно, что довольно удобно и не вызывает никакого дискомфорта.

И кого Мы выбрали?


Если брать размер скачиваемых браузером импортов js — победитель Vue. Но это только на первый взгляд. Так как у нас было не много компонентов Мы сделали задачу на обоих. И удобнее было писать на React: нет почти никакой разницы при написании со сборкой, а в размере импортов разница не сильно значительная.

А как-же Preact ?


Preact — это «мини» версия react, которая чуть быстрее и весит всего 3 Кб. Как только я услышал о нашей задаче — первое о чём я вспомнил — preact. Открыв документацию меня ждал не приятный сюрприз: React ? Preact.
У preact нет JSX, написание компонентов сильно отличается от React. Учиться писать на «preact way» для нашей мини-задачи сильно избыточно и «дорого».

Это костыль! Ударьте его им же


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

Комментарии (44)


  1. stardust_kid
    08.12.2019 12:00

    А почему бы не компилировать jsx в IDE?


    1. vds64_max Автор
      08.12.2019 12:04
      -1

      Можно сделать полностью сборку в bundle.js через тот-же npm build и импортировать его в html страницу. Но как подключать root компонент? Через window.onload и тп. Проблема в том, что в таком виде нужно продумывать подключение root компонентов в зависимости от загрузки dom.


      1. staticlab
        08.12.2019 13:31

        Выставляете наружу из бандла метод initialize, в который пробрасываете корневой элемент для рендеринга.


  1. JustDont
    08.12.2019 12:29
    +4

    Вот уже и выросло поколение, которое считает работу бандлера (по сути не являющуюся чем-то более интересным, чем поиск/замена/склейка строк или узлов AST) магией, и восторгающееся тем, что бандлер, оказывается, не обязателен.

    Мы потеряем юнит тесты

    Не потеряете.

    скорость

    Не потеряете. Или для вас будет открытием то, что минифицировать и оптимизировать тоже можно без бандлера?

    да и как быть с импортом компонентов

    Не надо с ними «быть», во всех уважающих себя браузерах импорты уже работают нативно. Ну и еще немного можно эту работу расширить через вот это.

    да и вообще спагетти код какой-то получится…

    Подождите, вы серьезно считаете модульный код с импортами и экспортами «спагетти»? А монолитную функцию на 50 000 строк — я так полагаю, нет?


    1. Focushift
      08.12.2019 13:18
      +2

      Работа бабела на лету никак не повлияет на скорость? НУОК.


      1. justboris
        08.12.2019 13:26

        Вместо babel можно взять buble, он будет поменьше весить, чем babel-standalone.


      1. JustDont
        08.12.2019 13:27

        Работа бабеля никак не зависит от наличия или отсутствия бандлера. Ничего не мешает прогонять проект через бабель без бандлера.


    1. norguhtar
      09.12.2019 05:47

      Я вот все знаю, но выбираю webpack :) Почему? Просто в этом случае разработка приложения на том же vue можно распихать нормально по файлам компонентам и нормально туда сюда это все импортировать. И это становится не такой болью как обычно.


    1. mayorovp
      09.12.2019 08:45

      Не потеряете. Или для вас будет открытием то, что минифицировать и оптимизировать тоже можно без бандлера?

      Без бандлера — можно, а вот без этапа сборки вообще — не получится.


  1. justboris
    08.12.2019 13:22
    +1

    Вместо JSX можно использовать template strings при помощи пакета htm:


    import htm from 'https://unpkg.com/htm?module'
    const html = htm.bind(React.createElement);
    
    function Component({name}) {
      return html`
        <div>${name}</div>
      `;
    }


    1. vds64_max Автор
      08.12.2019 13:44

      Спасибо, что написали! Тоже хотел про него написать когда писал про Preact, но вылетело из головы )


  1. staticlab
    08.12.2019 13:26

    У preact нет JSX

    Как это нет, если даже на главной странице пример с JSX?


    1. indestructable
      08.12.2019 13:38

      Думаю, имеется ввиду, что нет компилятора jsx


      1. vds64_max Автор
        08.12.2019 13:47

        Верно, там пример через комплиятор, без компилятора там рекомендуют использовать htm.


        1. staticlab
          08.12.2019 14:17

          Он же через тот же самый babel компилируется.


  1. vintage
    08.12.2019 13:59

    Размер скачиваемых браузером файлов: 542 Kb, время: 589 ms

    Вы считаете это нормальным для вывода 3 слов в теге h1?


    1. vds64_max Автор
      08.12.2019 14:25

      Конечно нет, для этого оно и показано ) Использовать так react и vue костыль для очень узких задач, как и описано в выводах.


      1. vintage
        09.12.2019 10:21

        Для каких задач?


  1. riky
    09.12.2019 05:20

    тоже активно использую такой способ.
    шаблоны удобно писать в теге скрипт:
    <sc*ript type="text/x-template" id="product-options">....</scr*ipt>

        Vue.component('product-options', {
            template: '#product-options'
        }


  1. lasc
    09.12.2019 05:38

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


    1. mayorovp
      09.12.2019 08:57

      Через unpkg.com можно подключить любой npm-пакет (если он опубликован в основном репозитории, конечно же).


      1. dfuse
        09.12.2019 13:02

        Не получится. Т.к. импорты надо переписывать. https://habr.com/ru/post/474672/ я поступил так.


        1. mayorovp
          09.12.2019 13:19

          Там же есть экспериментальная фича ?module, которая переписывает все статические импорты чтобы те работали. Обратите внимание, что она тут и используется...


          1. dfuse
            09.12.2019 14:14

            Да, но допустим он размотает import Foo from 'foo' в const Foo = window.Foo или как он там это делает, но файл то кто будет грузить? Я руками? В index.html все все все прописывать? А что если это зависимость зависимости и тд?


            1. mayorovp
              09.12.2019 14:26

              Насколько я понял, он размотает import Foo from 'foo' во что-то вроде import Foo from 'foo@1.2.3?module'. А грузить это будет браузер.


              1. dfuse
                09.12.2019 14:50

                Так а скрипт то сам как будет грузиться? Он какой то добавочный код подсунет чтоб тег script приземлить на страницу? По-моему он дальше чем текстовая замена не идет и в рантайме ничего не делает особого.


                1. mayorovp
                  09.12.2019 14:51

                  Зачем добавочный код и тэг script? Какую проблему вы сейчас пытаетесь решить?


                  1. dfuse
                    09.12.2019 16:08

                    Физически код зависимости как попадет на страницу? Вот вы например запросили пакет с A, прописали его:


                    <script type="application/javascript" src="https://unpkg.com/a@1.0.0/a.production.min.js"></script>


                    А он в свою очередь потянет еще что-то. Не все ж пакеты как реакт несут в себе полную сборку, некоторые еще что-то требуют. И далее по цепочке. Как это разруливать?


                    1. mayorovp
                      09.12.2019 16:12

                      Браузер увидит конструкцию "import ..." и загрузит зависимости. Зачем тут ещё какой-то дополнительный код и динамически формируемый тэг script?


                      1. dfuse
                        09.12.2019 16:58

                        wipe я был не прав, Unpkg все перепишет https://unpkg.com/next-redux-wrapper@4.0.1/es6/index.js?module, но реакт распространяется как UMD, он несовместим с import=module: https://unpkg.com/react@16.12.0?module и привет… следовательно любой другой пакет потенциально может так отпасть, следовательно нет никакой уверенности (((


                        Вы читали статью мою, которую я выше кинул? Там все это описано.


                        Статью спасает что топ левел реакт как скрипт прописан...


                        1. mayorovp
                          09.12.2019 17:02

                          Вы вообще читаете что вам пишут?


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


                          Во-вторых, UMD — это формат самодостаточного бандла, готового к подключению на страницу тэгом script


                          1. dfuse
                            09.12.2019 17:18

                            Да, читаю, я отредактировал коммент, вы правы, а я нет (по части переписывания путей)


                            Во-вторых, UMD — это формат самодостаточного бандла, готового к подключению на страницу тэгом script

                            Это не так. UMD — обертка, она может иметь прописанные package identifiers и обращения к global scope в качестве фоллбэка.


                            UMD не равно bundle со всеми зависимостями. Реакт же не отрезолвился вообще https://unpkg.com/react@16.12.0?module (ссылка сгенеренная Unpkg). А Вы читаете, что вам пишут? )))


                            1. mayorovp
                              09.12.2019 17:34

                              Реакт не отрезолвился потому что он поставляется в формате UMD, а не es6 module


                              Но у него и импортов-то нет


                              1. dfuse
                                09.12.2019 17:37

                                Я и говорю, повезло. А может и не повезти. Я регулярно встречаю странные поставки без ES6 и в UMD без бандла...


                                Еще интересно, а что будет, если я импортну библиотеку, которая импортнет реакт, думаю все сломается, т.к. не видно кода, который бы догадался, что реакт уже есть на топ левеле, и модуль можно не грузить. Иначе сломается точно, т.к. реакт не резолвится.


                                1. mayorovp
                                  09.12.2019 19:13

                                  Исторически именно прямое подключение библиотек на страницу было основным сценарием использования, так что все легаси-библиотеки подключить через unpkg проще чем собрать в бандл.


                                  А потому я сомневаюсь, что невезение будет частым.


  1. Brother-Ur
    09.12.2019 10:25

    Стоп, подождите. А как насчет react-rails?


    1. vds64_max Автор
      09.12.2019 10:25

      Для него нужен свежий Rails и Ruby, а у нас нельзя было трогать ОС и всё что внутри.


      1. Brother-Ur
        09.12.2019 10:40

        Если я не ошибаюсь, то мы использовали react-rails на третьей версии RoR. Или у вас все было еще хуже?


  1. Focushift
    09.12.2019 11:59

    Меня умиляет неадекватность этого сравнения.

    Добавили для реакта преобразователь — сразу реакт почемуто стал удобнее.
    Давайте для Vue тоже подгрузим такой же конвертер? Тоже станет удобнее, тогда можно будет более легкую версию фреймворка грузить, без компилятора шаблонов.
    Учитывая, что кроме отрисовки компонентов и значений переменных в реакте больше ничего нет и надо грузить кучу библиотек(как ранее в коментах предложили, «для удобства»), это тоже не имеет значения?


  1. dfuse
    09.12.2019 13:02

    А как насчет использования библиотек? ;)
    Я дальше пошел и преобразования в воркер засунул: https://habr.com/ru/post/474672/


    1. vds64_max Автор
      09.12.2019 15:27

      Интересное решение, спасибо, что поделились.


      1. dfuse
        09.12.2019 16:08

        Спасибо! Удивительно насколько различается кол-во пришедших читать пост, подача — важно )))


  1. KhodeN
    09.12.2019 19:51

    Кажется, вы боретесь с проблемой, которой нет. Собрать бандл на любом фреймворке (React, Preact, Vue, Svelte) и интегрировать его в любой сайт нет никакой сложности.


    На реакте вполне можно писать без JSX, и не нужно будет тащить babel в рантайм.


    Рекомендую приглядется к Svelte, он для написание разных виджетов и частей страниц очень неплохо подходит (за счет почти отсутствия рантайма)


    1. vds64_max Автор
      10.12.2019 10:28

      К Svelte Мы не только присмотрелись, но и пробовали его в продакте Про Svelte