npm install, npm build
. И только после этого папочку 'public' Мы деплоим «куда надо».Но есть и другой (я бы назвал его
А что, если не нужно проводить сборку, а просто вставить 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)
JustDont
08.12.2019 12:29+4Вот уже и выросло поколение, которое считает работу бандлера (по сути не являющуюся чем-то более интересным, чем поиск/замена/склейка строк или узлов AST) магией, и восторгающееся тем, что бандлер, оказывается, не обязателен.
Мы потеряем юнит тесты
Не потеряете.
скорость
Не потеряете. Или для вас будет открытием то, что минифицировать и оптимизировать тоже можно без бандлера?
да и как быть с импортом компонентов
Не надо с ними «быть», во всех уважающих себя браузерах импорты уже работают нативно. Ну и еще немного можно эту работу расширить через вот это.
да и вообще спагетти код какой-то получится…
Подождите, вы серьезно считаете модульный код с импортами и экспортами «спагетти»? А монолитную функцию на 50 000 строк — я так полагаю, нет?norguhtar
09.12.2019 05:47Я вот все знаю, но выбираю webpack :) Почему? Просто в этом случае разработка приложения на том же vue можно распихать нормально по файлам компонентам и нормально туда сюда это все импортировать. И это становится не такой болью как обычно.
mayorovp
09.12.2019 08:45Не потеряете. Или для вас будет открытием то, что минифицировать и оптимизировать тоже можно без бандлера?
Без бандлера — можно, а вот без этапа сборки вообще — не получится.
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> `; }
vds64_max Автор
08.12.2019 13:44Спасибо, что написали! Тоже хотел про него написать когда писал про Preact, но вылетело из головы )
staticlab
08.12.2019 13:26У preact нет JSX
Как это нет, если даже на главной странице пример с JSX?
vintage
08.12.2019 13:59Размер скачиваемых браузером файлов: 542 Kb, время: 589 ms
Вы считаете это нормальным для вывода 3 слов в теге h1?
riky
09.12.2019 05:20тоже активно использую такой способ.
шаблоны удобно писать в теге скрипт:
<sc*ript type="text/x-template" id="product-options">....</scr*ipt>
Vue.component('product-options', { template: '#product-options' }
lasc
09.12.2019 05:38Все неплохо, до тех пор когда нужно будет поставить либу, и тут окажется что для половины либ прямого способа нет.
mayorovp
09.12.2019 08:57Через unpkg.com можно подключить любой npm-пакет (если он опубликован в основном репозитории, конечно же).
dfuse
09.12.2019 13:02Не получится. Т.к. импорты надо переписывать. https://habr.com/ru/post/474672/ я поступил так.
mayorovp
09.12.2019 13:19Там же есть экспериментальная фича
?module
, которая переписывает все статические импорты чтобы те работали. Обратите внимание, что она тут и используется...dfuse
09.12.2019 14:14Да, но допустим он размотает
import Foo from 'foo'
вconst Foo = window.Foo
или как он там это делает, но файл то кто будет грузить? Я руками? В index.html все все все прописывать? А что если это зависимость зависимости и тд?mayorovp
09.12.2019 14:26Насколько я понял, он размотает
import Foo from 'foo'
во что-то вродеimport Foo from 'foo@1.2.3?module'
. А грузить это будет браузер.dfuse
09.12.2019 14:50Так а скрипт то сам как будет грузиться? Он какой то добавочный код подсунет чтоб тег script приземлить на страницу? По-моему он дальше чем текстовая замена не идет и в рантайме ничего не делает особого.
mayorovp
09.12.2019 14:51Зачем добавочный код и тэг script? Какую проблему вы сейчас пытаетесь решить?
dfuse
09.12.2019 16:08Физически код зависимости как попадет на страницу? Вот вы например запросили пакет с A, прописали его:
<script type="application/javascript" src="https://unpkg.com/a@1.0.0/a.production.min.js"></script>
А он в свою очередь потянет еще что-то. Не все ж пакеты как реакт несут в себе полную сборку, некоторые еще что-то требуют. И далее по цепочке. Как это разруливать?
mayorovp
09.12.2019 16:12Браузер увидит конструкцию "
import ...
" и загрузит зависимости. Зачем тут ещё какой-то дополнительный код и динамически формируемый тэг script?dfuse
09.12.2019 16:58wipe я был не прав, 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 и привет… следовательно любой другой пакет потенциально может так отпасть, следовательно нет никакой уверенности (((
Вы читали статью мою, которую я выше кинул? Там все это описано.
Статью спасает что топ левел реакт как скрипт прописан...
mayorovp
09.12.2019 17:02Вы вообще читаете что вам пишут?
Во-первых, да, в режиме
?module
unpkg именно что перепишет все зависимости так, чтобы они смогли нормально загрузиться.
Во-вторых, UMD — это формат самодостаточного бандла, готового к подключению на страницу тэгом script
dfuse
09.12.2019 17:18Да, читаю, я отредактировал коммент, вы правы, а я нет (по части переписывания путей)
Во-вторых, UMD — это формат самодостаточного бандла, готового к подключению на страницу тэгом script
Это не так. UMD — обертка, она может иметь прописанные package identifiers и обращения к global scope в качестве фоллбэка.
UMD не равно bundle со всеми зависимостями. Реакт же не отрезолвился вообще https://unpkg.com/react@16.12.0?module (ссылка сгенеренная Unpkg). А Вы читаете, что вам пишут? )))
mayorovp
09.12.2019 17:34Реакт не отрезолвился потому что он поставляется в формате UMD, а не es6 module
Но у него и импортов-то нет
dfuse
09.12.2019 17:37Я и говорю, повезло. А может и не повезти. Я регулярно встречаю странные поставки без ES6 и в UMD без бандла...
Еще интересно, а что будет, если я импортну библиотеку, которая импортнет реакт, думаю все сломается, т.к. не видно кода, который бы догадался, что реакт уже есть на топ левеле, и модуль можно не грузить. Иначе сломается точно, т.к. реакт не резолвится.
mayorovp
09.12.2019 19:13Исторически именно прямое подключение библиотек на страницу было основным сценарием использования, так что все легаси-библиотеки подключить через unpkg проще чем собрать в бандл.
А потому я сомневаюсь, что невезение будет частым.
Brother-Ur
09.12.2019 10:25Стоп, подождите. А как насчет react-rails?
vds64_max Автор
09.12.2019 10:25Для него нужен свежий Rails и Ruby, а у нас нельзя было трогать ОС и всё что внутри.
Brother-Ur
09.12.2019 10:40Если я не ошибаюсь, то мы использовали react-rails на третьей версии RoR. Или у вас все было еще хуже?
Focushift
09.12.2019 11:59Меня умиляет неадекватность этого сравнения.
Добавили для реакта преобразователь — сразу реакт почемуто стал удобнее.
Давайте для Vue тоже подгрузим такой же конвертер? Тоже станет удобнее, тогда можно будет более легкую версию фреймворка грузить, без компилятора шаблонов.
Учитывая, что кроме отрисовки компонентов и значений переменных в реакте больше ничего нет и надо грузить кучу библиотек(как ранее в коментах предложили, «для удобства»), это тоже не имеет значения?
dfuse
09.12.2019 13:02А как насчет использования библиотек? ;)
Я дальше пошел и преобразования в воркер засунул: https://habr.com/ru/post/474672/
KhodeN
09.12.2019 19:51Кажется, вы боретесь с проблемой, которой нет. Собрать бандл на любом фреймворке (React, Preact, Vue, Svelte) и интегрировать его в любой сайт нет никакой сложности.
На реакте вполне можно писать без JSX, и не нужно будет тащить babel в рантайм.
Рекомендую приглядется к Svelte, он для написание разных виджетов и частей страниц очень неплохо подходит (за счет почти отсутствия рантайма)
vds64_max Автор
10.12.2019 10:28К Svelte Мы не только присмотрелись, но и пробовали его в продакте Про Svelte
stardust_kid
А почему бы не компилировать jsx в IDE?
vds64_max Автор
Можно сделать полностью сборку в bundle.js через тот-же npm build и импортировать его в html страницу. Но как подключать root компонент? Через window.onload и тп. Проблема в том, что в таком виде нужно продумывать подключение root компонентов в зависимости от загрузки dom.
staticlab
Выставляете наружу из бандла метод initialize, в который пробрасываете корневой элемент для рендеринга.