Как я перестал любить Angular +106


Вступление


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


На дворе 2017ый год и для каждого нового продукта/проекта встает вопрос выбора фреймворка для разработки. Долгое время я был уверен, что новый Angular 2/4 (далее просто Angular) станет главным трендом enterprise разработки еще на несколько лет вперед и даже не сомневался что буду работать только с ним.


Сегодня я сам отказываюсь использовать его в своем следующем проекте.


Дисклеймер: данная статья строго субъективна, но таков мой личный взгляд на происходящее и касается разработки enterprise-level приложений.


AngularJS



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


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


Angular



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


Конечно путь к этому был долог и полон Breaking Changes, но на сегодняшний день Angular 4 стабилен и позиционируется как полностью production-ready.


Одна из наиболее крутых вещей, которую дал нам новый Angular — популяризация TypeScript.
Лично я был с ним знаком и работал еще до того, как он стал основным для моего любимого фреймворка, но многие узнали о нем именно благодаря Angular.


TypeScript



Не буду подробно останавливаться на TypeScript, т.к. это тема для отдельной статьи,
да и написано о нем уже больше чем нужно. Но для enterprise разработки TypeScript дает огромное количество преимуществ. Начиная с самой статической типизации и областями видимости и заканчивая поддержкой ES7/8 даже для IE9.


Главное преимущество работы с TypeScript — богатый инструментарий и прекрасная поддержка IDE. По нашему опыту, юнит тестов с TS приходится писать существенно меньше.


Vue



Если вы читаете данную статью, то с вероятностью 95% вы уже знаете что это такое.


Но для тех 5% кто еще не знает — Vue.js это крайне легковесный (но очень богатый по функционалу) фреймворк, вобравший в себя многое хорошее, как из AngularJS, так и из React.


Фактически больше он похож все же на React, но шаблоны практически идентичны AngularJS (HTML + Mustache).


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


Предыстория


Было — большой проект на AngularJS


Последний мой проект, который совсем недавно вышел в production, мы писали на AngularJS 1.5-1.6.


Вопреки наличию стабильной версии Angular уже долгое время, мы приняли решение не мигрировать на него по ряду причин (не столько технических, сколько политических).
Но одной из фич современного веба мы пользовались с самого начала — это TypeScript.


Вот пример нашего компонента из данного проекта:


import {Component} from "shared-front/app/decorators";
import FileService, {ContentType, IFile} from "../file.service";
import AlertService from "shared/alert.service";

@Component({
    template: require("./file.component.html"),
    bindings: {
        item: "<",
    },
})
export default class FileComponent {
    public static $inject = ["fileService"];
    public item: IFile;

    constructor(private fileService: FileService, private alertService: AlertService) {
    }

    public isVideo() {
        return this.item.contentKeyType === ContentType.VIDEO;
    }

    public downloadFile() {
        this.fileService.download(this.getFileDownloadUrl()).then(() => {
            this.alertService.success();
        });
    }

    private getFileDownloadUrl() {
        return `url-for-download${this.item.text}`;
    }
}

На мой взгляд выглядит очень даже приятно, не слишком многословно, даже если вы не фанат TS.
К тому же все это замечательно тестируется как Unit-тестами, так и Е2Е.


Продолжай AngularJS развиваться, как тот же React, и будь он побыстрее, можно было бы и по сей день продолжать писать крупные проекты на нем.


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


Стало — средний проект на Angular


Так мы и поступили, рационально выбрав Angular 2 (позже 4) для нашего нового проекта несколько месяцев назад.


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


К сожалению, как теперь стало понятно, многие из этих проблем заложены в архитектуру и не изменятся в ближайшее время.


А вот пример компонента из проекта на Angular:


import {Component} from '@angular/core';

import FileService, {ContentType, IFile} from "../file.service";
import AlertService from "shared/alert.service";

@Component({
  selector: 'app-file',
  templateUrl: './file.component.html',
  styleUrls: ['./file.component.scss']
})
export class FileComponent {

    Input() item: IFile;

    constructor(private fileService: FileService, private alertService: AlertService) {
    }

    public isVideo() {
        return this.item.contentKeyType === ContentType.VIDEO;
    }

    public downloadFile() {
        this.fileService.download(this.getFileDownloadUrl()).subscribe(() => {
            this.alertService.success();
        });
    }

    private getFileDownloadUrl() {
        return `url-for-download${this.item.text}`;
    }
}

Возможно чуть чуть более многословно, но гораздо чище.


Плюсы


Angular CLI — единственное реальное преимущество перед AngularJS



Первое, что вы установите при разработке нового Angular 4 приложения это Angular CLI


Нужен он CLI для того, чтобы упростить создание новых компонентов/модулей/тестов итд.
На мой взгляд это едва ли не лучшее, что есть в новом Angular. Тула действительно очень удобная в использовании и сильно ускоряет процесс разработки.


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


Конечно CLI тоже имеет ряд недостатков в части настроек и конфигурации "под себя", но все же он на голову выше аналогичных утилит для React (create-react-app) или Vue (vue-cli). Хотя второй, благодаря своей гибкости, становится лучше с каждым днем.


Минусы или "За что я перестал любить Angular"


Изначально я не хотел писать очередную хейтерскую статью вроде Angular 2 is terrible (нашелся даже перевод).


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


В целом не совсем разделяю взгяд автора на RxJS, т.к. библиотека невероятно мощная.


An Ajax request is singular, and running methods like Observable.prototype.map when there will only ever be one value in the pipe makes no semantic sense. Promises on the other hand represent a value that has yet to be fulfilled, which is exactly what a HTTP request gives you. I spent hours forcing Observables to behave before giving up using Observable.prototype.toPromise to transform the Observable back to a Promise and simply using Promise.all, which works much better than anything Rx.js offers.

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


Но суровая правда в том, что Object.observe нативно мы все же не увидим:


After much discussion with the parties involved, I plan to withdraw the Object.observe proposal from TC39 (where it currently sits at stage 2 in the ES spec process), and hope to remove support from V8 by the end of the year (the feature is used on 0.0169% of Chrome pageviews, according to chromestatus.com).

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


Также не соглашусь в целом по поводу TypeScript'а, так как это все же замечательный язык, но об этом ниже.


Статья крайне рекомендуется к ознакомлению, если вы уже используете или планируете использовать Angular


Однако все же изложу несколько собственных мыслей (к сожалению, все больше негативных), не упомянутых в статье выше.


TypeScript в Angular


Пожалуй самое болезненное разочарование для меня — это то, во что превратили работу с TypeScript'ом в Angular.


Ниже несколько примеров наиболее неудачных решений.


Ужасные API


Одной из основных проблем использования TypeScript в Angular я считаю крайне спорные API.
Сам по себе TypeScript идеально подходит для написания максимально строгого кода, без возможностей случайно сделать шаг не в ту сторону. Фактически он просто создан для того, чтобы писать публичный API, но команда Angular сделала все, чтобы данное преимущество превратилось в недостаток.


Примеры:


HttpParams

По какой-то причине команда Angular решила сделать класс HttpParams иммутабельным.
Иммутабельность это здорово, но если вы думаете, что большинство классов в Angular являются таковыми, то это вовсе не так.


Например код вида:


let params = new HttpParams();
params.set('param', param);
params.set('anotherParam', anotherParam);
...
this.http.get('test', {params: params});

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


Только открыв сам класс в TypeScript можно найти комментарий


This class is immuatable — all mutation operations return a new instance.

Конечно, это совершенно неочевидно.


В вот и вся документация про них:


http
  .post('/api/items/add', body, {
    params: new HttpParams().set('id', '3'),
  })
  .subscribe();

RxJS operator import

Начнем с того, что документация по Angular вообще не имеет толкового разбора и описания Observable и того, как с ними работать.


Нет даже толковых ссылок на документацию по RxJS. И это при том, что Rx является ключевой частью фреймворка, а само создание Observable уже отличается:


// rx.js
Rx.Observable.create();
vs
// Angular
new Observable()

Ну да и черт с ним, здесь я хотел рассказать о Rx + TypeScript + Angular.


Допустим вы хотите использовать некий RxJS оператор, вроде do:


observable.do(event => {...})

В коде никакой ошибки не произойдет, это сработает и замечательно запустится.


Вот только, во время выполнения возникнет такая ошибка:


ERROR TypeError: observable.do is not a function

Потому что вы очевидно (потратили кучу времени на поиск проблемы) забыли заимпортировать сам оператор:


import 'rxjs/add/operator/do';

Почему это ломается в рантайме, если у нас есть TypeScript? Не знаю. Но это так.


Router API

Претензий к новому ангуляровскому роутеру у меня накопилось уже великое множество, но его API — одна из основных.


Events

Теперь для работы с параметрами предлагается подписываться на события роутера. Ок, пускай, но приходят всегда все события, независимо от того, какие нам нужны. А проверять предлагается через instanceof (снова новый подход, отличный от большинства других мест):


this.router.events.subscribe(event => {
  if(event instanceof NavigationStart) {
    ...
  }
}


В очередной раз странным решением было сделать всю работу с роутами командами — причем массивом из них. Простые и наиболее распространенные переходы будут выглядеть как-то так:


this.router.navigate(['/some']);
...
this.router.navigate(['/other']);

Почему это плохо?


Потому что команды в данном случае имеют сигнатуру any[]. Для незнакомых с TypeScript — это фактически отключение его фич.


Это при том, что роутинг — наиболее слабо связанная часть в Angular.


Например мы в нашем AngularJS приложении наоборот старались типизировать роуты, чтобы вместо простых строк они были хотя бы enum. Это позволяет находить те или иные места, где используется данный роут без глобального поиска по строке 'some'.


Но нет, в Angular это преимущество TypeScript не используется никак.


Lazy Load

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


{
  path: 'admin',
  loadChildren: 'app/admin/admin.module#AdminModule',
},

Forms API

Для начала — в Angular есть два типа форм: обычные и реактивные.


Само собой, работать с ними нужно по-разному.


Однако лично меня раздражает именно API reactive forms:


// Зачем нужен первый пустой параметр?
// Почему name это массив c валидатором??
this.heroForm = this.fb.group({
  name: ['', Validators.required ],
});

или из документации


// Почему пустое поле это имя??
this.heroForm = this.fb.group({
  name: '', // <--- the FormControl called "name"
});

и так далее


this.complexForm = fb.group({   
  // Почему понадобился compose ?
  // Неужели нельзя без null ??
  'lastName': [null, Validators.compose([Validators.required, Validators.minLength(5), Validators.maxLength(10)])],
  'gender' : [null, Validators.required],
})

А еще — нельзя просто использовать атрибуты типа [disabled] с реактивными формами...


Это далеко не все примеры подобных откровенно спорных решений, но думаю, что для раздела про API этого хватит


__metadata


К сожалению использование горячо любимого мною TypeScript'а в Angular слишком сильно завязано на декораторы.


Декораторы — прекрасная вещь, но к сожалению в рантайме нет самой нужной их части, а именно __metadata.


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


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


Впрочем, мы в нашем AngularJS приложении использовали такие декораторы, например @Component:


export const Component = (options: ng.IComponentOptions = {}) => controller => angular.extend(options, {controller});

Он фактически просто оборачивает наши TypeScript классы в компоненты AngularJS и делает их контроллерами.


Но в Angular, несмотря на экспериментальность фичи, это стало частью ядра фреймворка,
что делает необходимым использование полифила reflect-metadata в совершенно любом случае. Очень спорное решение.


Абстракции


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


Самый яркий пример подобных проблем — это Dependency Injection в Angular.


Сама по себе концепция замечательная, особенно для unit тестирования. Но практика показывает, что большой нужды делать из фронтенда нечто Java-подобное нет. Да, в нашем AngularJS приложении мы очень активно это использовали, но поработав с тестированием Vue компонентов, я серьезно начал сомневаться в пользе DI.


В Angular для большинства обычных зависимостей, вроде сервисов, DI будет выглядеть очень просто, с получением через конструктор:


constructor(heroService: HeroService) {
  this.heroes = heroService.getHeroes();
}

Но так работает только для TypeScript классов, и если вы хотите добавить константу, необходимо будет использовать @Inject:


constructor(@Inject(APP_CONFIG) config: AppConfig) {
  this.title = config.title;
}

Ах да, сервисы которые вы будете инжектить должны быть проанотированы как @Injectable().


Но не все, а только те, у которых есть свои зависимости, если их нет — можно этот декоратор не указывать.


Consider adding @Injectable() to every service class, even those that don't have dependencies and, therefore, do not technically require it.
Here's why:

Future proofing: No need to remember @Injectable() when you add a dependency later.

Consistency: All services follow the same rules, and you don't have to wonder why a decorator is missing.

Почему бы не сделать это обязательным сразу, если потом это рекомендуется делать всегда?


Еще прекрасная цитата из официальной документации по поводу скобочек:


Always write @Injectable(), not just @Injectable. The application will fail mysteriously if you forget the parentheses.

Короче говоря, создается впечатление, что TypeScript в Angular явно используется не по назначению.


Хотя еще раз подчеркну, что сам по себе язык обычно очень помогает в разработке.


Синтаксис шаблонов


Синтаксис шаблонов — основная претензия к Angular. И по вполне объективным причинам.


Пример не только множества разных директив, но еще и разных вариантов их использования:


<div [ngStyle]="{'color': color, 'font-size': size, 'font-weight': 'bold'}">
  style using ngStyle
</div>

<input [(ngModel)]="color" />

<button (click)="size = size + 1">+</button>

<div [class.required]="isReq">Hello Wordl!</div>  
<div [className]="'blue'">CSS class using property syntax, this text is blue</div>
<div [ngClass]="{'small-text': true, 'red': true}">object of classes</div>
<div [ngClass]="['bold-text', 'green']">array of classes</div>
<div [ngClass]="'italic-text blue'">string of classes</div>

Изначально разработчики позиционировали новый синтакисис шаблонов, как спасение от множества директив.


Обещали, что будет достаточно только [] и ().


Binding Example
Properties <input [value]="firstName">
Events <button (click)="buy($event)">
Two-way <input [(ng-model)]="userName">

К сожалению в реальности директив едва ли не больше чем в AngularJS.



И да, простое правило запоминания синтаксиса two-way binding про банан в коробке
из официальной документации:


Visualize a banana in a box to remember that the parentheses go inside the brackets.

Документация


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


Контрпример — доки Vue. Мало того, что написаны подробно и доходчиво, так еще и на 6 языках, в т.ч. русском.


View encapsulation


Angular позволяет использовать так называемый View encapsulation.


Суть сводится к эмуляции Shadow DOM или использовании нативной его поддержки.


Сам по себе Shadow DOM — прекрасная вещь и действительно потенциально позволяет использовать даже разные CSS фреймворки для разных копмонентов без проблем.
Однако нативная поддержка на сегодняшний день совершенно печальна.


По умолчанию включена эмуляция Shadow DOM.


Вот пример простого CSS для компонента:


.first {
  background-color: red;
}
.first .second {
  background-color: green;
}
.first .second .third {
  background-color: blue;
}

Angular преобразует это в:


.first[_ngcontent-c1] {
  background-color: red;
}
.first[_ngcontent-c1]   .second[_ngcontent-c1] {
  background-color: green;
}
.first[_ngcontent-c1]   .second[_ngcontent-c1]   .third[_ngcontent-c1] {
  background-color: blue;
}

Совершенно не ясно зачем делать именно так.


Например Vue делает то же самое, но гораздо чище:


.first[data-v-50646cd8] {
  background-color: red;
}
.first .second[data-v-50646cd8] {
  background-color: green;
}
.first .second .third[data-v-50646cd8] {
  background-color: blue;
}

Не говоря уже о том, что в Vue это не дефолтное поведение и включается добавлением простого scoped к стилю.


Так же хотелось бы отметить, что Vue (vue-cli webpack) подобным же образом позволяет указывать SASS/SCSS, тогда как для Angular CLI нужны команды типа ng set defaults.styleExt scss. Не очень понятно зачем все это, если внутри такой же webpack.


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


В частности мы использовали один из наиболее популярных UI фреймворков — PrimeNG, а он иногда использует подобные селекторы:


body .ui-tree .ui-treenode .ui-treenode-content .ui-tree-toggler {
    font-size: 1.1em;
}

Они по определению имеют больший приоритет нежели стили компонента, который использует в себе тот или иной сторонний элемент.


Что в итоге приводит к необходимости писать нечто подобное:


body :host >>> .ui-tree .ui-treenode .ui-treenode-content .ui-tree-toggler {
  font-size: 2em;
}

Иногда и вовсе приходилось вспомнить великий и ужасный !important.


Безусловно все это связано конкретно с PrimeNG и не является как таковой проблемой фреймворка, но это именно та проблема, которая скорее всего возникнет и у вас при реальной работе с Angular.


К слову о стабильности


В примере выше мы использовали >>> — как и /deep/ это алиас для так называемого shadow-piercing селектора.


Он позволяет как бы "игнорировать" Shadow DOM и для некоторых сторонних компонентов порой просто незаменим.


В одном из относительно свежих релизов Angular создатели фреймворка решили,
в соответствии со стандартом, задепрекейтить /deep/ и >>>.


Никаких ошибок или ворнингов их использование не принесло, они просто перестали работать.
Как выяснилось позже, теперь работает только ::ng-deep — аналог shadow-piercing селектора в Angular вселенной.


Обновление это было отнюдь не мажорной версии (4.2.6 -> 4.3.0), просто в один прекрасный момент наша верстка во многих местах поползла (спасибо и NPM за версии с шапочкой ^).


Конечно, не все наши разработчики ежедневно читают ChangeLog Angular 4, да и за трендами веб разработки не всегда можно уследить. Само собой сначала грешили на собственные стили — пришлось потратить немало времени и нервов для обнаружения столь неприятной особенности.


К тому же скоро и ::ng-deep перестанет работать. Как в таком случае править стили кривых сторонних компонентов, вроде тех же PrimeNG, ума не приложу.


Наш личный вывод: дефолтная настройка — эмуляция Shadow DOM порождает больше проблем чем решает.


Свой HTML парсер


Это вполне потянет на отдельную статью, но вкратце суть в том, что команда Angular действительно написала свой HTML парсер. По большей части это было необходимо для обеспечения регистрозависимости.


Нет смысла холиварить на тему ухода Angular от стандартов, но по мнению многих это довольно странная идея, ведь в том же AngularJS обычного HTML (регистронезависимого) вполне хватало.


С AngularJS нередко бывало такое: добавили вы некий <my-component/> а тест не написали.
Прошло некоторое время и модуль который содержит логику данного компонента был удален/отрефакторен/итд.


Так или иначе — теперь ваш компонент не отображается.


Теперь он сразу определяет неизвестные теги и выдает ошибку если их не знает.


Правда теперь любой сторонний компонент требует либо полного отключения этой проверки,
либо включения CUSTOM_ELEMENTS_SCHEMA которая пропускает любые тэги с -


Сорцы можете оценить самостоятельно


...
const TAG_DEFINITIONS: {[key: string]: HtmlTagDefinition} = {
  'base': new HtmlTagDefinition({isVoid: true}),
  'meta': new HtmlTagDefinition({isVoid: true}),
  'area': new HtmlTagDefinition({isVoid: true}),
  'embed': new HtmlTagDefinition({isVoid: true}),
  'link': new HtmlTagDefinition({isVoid: true}),
  'img': new HtmlTagDefinition({isVoid: true}),
  'input': new HtmlTagDefinition({isVoid: true}),
  'param': new HtmlTagDefinition({isVoid: true}),
  'hr': new HtmlTagDefinition({isVoid: true}),
  'br': new HtmlTagDefinition({isVoid: true}),
  'source': new HtmlTagDefinition({isVoid: true}),
  'track': new HtmlTagDefinition({isVoid: true}),
  'wbr': new HtmlTagDefinition({isVoid: true}),
  'p': new HtmlTagDefinition({
    closedByChildren: [
      'address', 'article', 'aside', 'blockquote', 'div', 'dl',      'fieldset', 'footer', 'form',
      'h1',      'h2',      'h3',    'h4',         'h5',  'h6',      'header',   'hgroup', 'hr',
      'main',    'nav',     'ol',    'p',          'pre', 'section', 'table',    'ul'
    ],
    closedByParent: true
  }),
...
  'td': new HtmlTagDefinition({closedByChildren: ['td', 'th'], closedByParent: true}),
  'th': new HtmlTagDefinition({closedByChildren: ['td', 'th'], closedByParent: true}),
  'col': new HtmlTagDefinition({requiredParents: ['colgroup'], isVoid: true}),
  'svg': new HtmlTagDefinition({implicitNamespacePrefix: 'svg'}),
  'math': new HtmlTagDefinition({implicitNamespacePrefix: 'math'}),
  'li': new HtmlTagDefinition({closedByChildren: ['li'], closedByParent: true}),
  'dt': new HtmlTagDefinition({closedByChildren: ['dt', 'dd']}),
  'dd': new HtmlTagDefinition({closedByChildren: ['dt', 'dd'], closedByParent: true}),
  'rb': new HtmlTagDefinition({closedByChildren: ['rb', 'rt', 'rtc'
  ...

А теперь ключевой момент — все эти ошибки происходят в консоли браузера в рантайме,
нет, ваш webpack билд не упадет, но и увидеть что либо кроме белого экрана не получится.
Потому что по умлочанию используется JIT компилятор.


Однако это решается прекомпиляцией шаблонов благодаря другому, AOT компилятору.
Нужно всего лишь собирать с флагом --aot, но и здесь не без ложки дегтя, это плохо работает с ng serve и еще больше тормозит и без того небыструю сборку. Видимо поэтому он и не включен по умолчанию (а стоило бы).


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


У нас с AOT было множество разнообразных ошибок, в том числе весьма неприятные и до сих пор открытые, например нельзя использовать экспорты по умолчанию


Обратите внимание на элегантные предлагаемые решения проблемы:


don't use default exports :)

Just place both export types and it works

Или нечто подобное описанному здесь (AOT не всегда разбирает замыкания)


Код подобного вида вызывает очень странные ошибки компилятора AOT:


@NgModule({
  providers: [
    {provide: SomeSymbol, useFactor: (i) => i.get('someSymbol'), deps: ['$injector']}
  ]
})
export class MyModule {}

Приходится подстраиваться под компилятор и переписывать код в более примитивном виде:


export factoryForSomeSymbol = (i) => i.get('someSymbol');

@NgModule({
  providers: [
    {provide: SomeSymbol, useFactor: factoryForSomeSymbol, deps: ['$injector']}
  ]
})
export class MyModule {}

Также хотелось бы отметить, что текст ошибок в шаблонах зачастую совершенно неинформативен.


Zone.js


Одна из концептуально очень крутых вещей которые появились в Angular это Zone.js.
Он позволяет отслеживать контекст выполнения для асинхронных задач, но новичков отпугивают огромной длины стактрейсы. Например:


core.es5.js:1020 ERROR Error: Uncaught (in promise): Error: No clusteredNodeId supplied to updateClusteredNode.
Error: No clusteredNodeId supplied to updateClusteredNode.
    at ClusterEngine.updateClusteredNode (vis.js:47364)
    at VisGraphDataService.webpackJsonp.../../../../../src/app/services/vis-graph-data.service.ts.VisGraphDataService.updateNetwork (vis-graph-data.service.ts:84)
    at vis-graph-display.service.ts:63
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:391)
    at Object.onInvoke (core.es5.js:3890)
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:390)
    at Zone.webpackJsonp.../../../../zone.js/dist/zone.js.Zone.run (zone.js:141)
    at zone.js:818
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:424)
    at Object.onInvokeTask (core.es5.js:3881)
    at ClusterEngine.updateClusteredNode (vis.js:47364)
    at VisGraphDataService.webpackJsonp.../../../../../src/app/services/vis-graph-data.service.ts.VisGraphDataService.updateNetwork (vis-graph-data.service.ts:84)
    at vis-graph-display.service.ts:63
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:391)
    at Object.onInvoke (core.es5.js:3890)
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:390)
    at Zone.webpackJsonp.../../../../zone.js/dist/zone.js.Zone.run (zone.js:141)
    at zone.js:818
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:424)
    at Object.onInvokeTask (core.es5.js:3881)
    at resolvePromise (zone.js:770)
    at zone.js:696
    at zone.js:712
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:391)
    at Object.onInvoke (core.es5.js:3890)
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:390)
    at Zone.webpackJsonp.../../../../zone.js/dist/zone.js.Zone.run (zone.js:141)
    at zone.js:818
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:424)
    at Object.onInvokeTask (core.es5.js:3881)

Некоторым Zone.js нравится и наверняка в продакшене нам это еще не раз поможет, но в нашем проекте большой пользы мы пока не извлекли.


А ошибок в консоли зачастую больше одной и поиск сути проблемы постоянно осложняется анализом таких стактрейсов.


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


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



UI frameworks


Еще один пункт, который формально не относится к самому фреймворку — это довольно скудное количество готовых наборов UI компонентов. Думаю, что написание большинства компонентов с нуля — непозволительная роскошь для многих веб-разработчиков. Зачастую проще, быстрее и разумнее взять готовый UI framework вместо написания собственных гридов и деревьев.


Да, я понимаю, что выбирать фреймворк по наличиую UI компонентов в корне неверно,
но при реальной разработке это необходимо.


Вот список основных UI фреймворков для Angular: https://angular.io/resources (раздел UI components).


Рассмотрим наиболее популярные бесплатные варианты.


Angular Material 2



Безусловно, наибольшие надежды я возлагал на Angular Material 2 ввиду того, что разрабатывается он командой Angular и наверняка будет соответствовать всем гайдлайнам.


К сожалению, несмотря на его возраст, набор компонентов крайне мал.


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


Я считаю, что Angular Material 2 подойдет лишь небольшим или, в лучшем случае, средним проектам, т.к. до сих пор нет, например, деревьев. Часто очень нужны компоненты вроде multiple-select, коих тоже нет.


Отдельно стоит сказать про очень скупую документацию и малое количество примеров.


Перспективы развития тоже довольно печальные.


Feature Status
tree In-progress
stepper In-progress, planned Q3 2017
sticky-header In-progress, planned Q3 2017
virtual-repeat Not started, planned Q4 2017
fab speed-dial Not started, not planned
fab toolbar Not started, not planned
bottom-sheet Not started, not planned
bottom-nav Not started, not planned

Bootstrap



По тем же причинам, что и выше не буду останавливаться на Bootstrap фреймворках типа
ng2-bootstrap (получше) и ngx-bootstrap. Они очень даже неплохи, но простейшие вещи можно сделать и обычным CSS, а сложных компонентов тут нет (хотя наверняка многим будет достаточно modal, datepicker и typeahead).


Prime Faces



Это на сегодняшний день наиболее популярый фреймворк содержащий множество сложных компонентов. В том числе гриды и деревья (и даже Tree Table!).


Изначально я вообще довольно скептически относился к PrimeFaces т.к. у меня был давний опыт работы с JSF, и много неприятных воспоминаний. Да и выглядят PrimeNG визуально так же (не очень современно). Но на момент начала нашего проекта достойных альтернатив не было, и все же хочется сказать спасибо разработчикам за то, что в короткие сроки был написан дейтсивтельно широчайший инструментарий.


Однако проблем с этим набором компонентов у нас возникало очень много.


Часто документация совершенно не помогает. Забыли добавить некий модуль — что-то просто молча не работает и никаких ошибок не возникает. Приходится дебажить и выясняется, что сорцы совершенно без комментариев.


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


Clarity



Луч света в темном царстве — это относительно молодая (меньше года от роду) библиотека Clarity от vmware.


Набор компонентов впечатляет, документация крайне приятная, да и выглядят здорово.


Фреймворк не просто предоставляет набор UI компонентов, но и CSS гайдлайны.
Эдакий свой bootstrap. Благодаря этому достигается консистентный и крайне приятный/минималистичный вид компонентов.


Гриды очень функциональные и стабильные, а сорцы говорят сами за себя (о боже, комментарии и юнит тесты, а так можно было?).


Однако пока что очень слабые формы, нет datepicker'а и select2-подобного компонента.
Работа над ними идет в данный момент: DatePicker, Select 2.0 (как всегда дизайн на высоте, и хотя с разработкой не торопятся я могу быть уверен, что делают на совесть).


Пожалуй, "Clarity Design System" — единственная причина почему я еще верю в жизнь Angular
(и вообще единственный фреймворк который не стыдно использовать для enterprise разработки). Как никак VMware серьезнейший мейнтейнер и есть надежда на светлое будущее.


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


Но он лишь один


Да, я считаю что для Angular на сегодняшний день есть лишь один достойный UI фреймворк.
О чем это говорит?


Полноценно разрабатывать такие фреймворки для Angular могут лишь серьезнейшие компании вроде той же VMware. Нужен ли вам такой суровый enterprise? Каждый решает сам.


А теперь давайте посмотрим, что происходит с одним из свежих конкурентов.


Vue UI frameworks



Для сравнения мощные уже существующие фреймворки для Vue.js с теми же гридами:


Element (~15k stars), Vue Material (существенно младше Angular Material 2 но уже содержит в разы больше), Vuetify (снова Material и снова множество компонентов), Quasar, также надо отметить популярные чисто китайские фреймворки типа iView и Muse-UI (iView выглядит очень приятно, но документация хромает).


Вот и простой, но очевидный, пример того, что писать компоненты на Vue гораздо проще.
Это позволяет даже выбирать наиболее приглянувшийся из множества наборов компонентов,
нежели надяться на один, который поддерживает огромная команда.


Какой вывод мы сделали?


Благодаря Clarity есть надежда на то, что наш Angular проект в дальнейшем будет становится только лучше. Однако для нас стало очевидно, что количество всевозможных проблем с Angular, а также многочисленные его усложнения совершенно не приносят пользы даже для больших проектов.


В реальности все это лишь увеличивает время разработки, не снижая стоимость поддержки и рефакторинга. Поэтому для нашего нового проекта мы выбрали Vue.js.


Достаточно просто развернуть базовый webpack шаблон для vue-cli и оценить скорость работы библиотеки. Несмотря на то, что лично я всегда был сторонником фреймворков all-in-one,
Vue без особых проблем делает почти все то же, что и Angular.


Ну и конечно, множество тех же UI framework'ов также играет свою роль.


Единственное чего немного не хватает — чуть более полноценной поддержки TypeScript,
уж очень много головной боли он нам сэкономил за эти годы.


Но ребята из Microsoft уже вот вот вмержает ее. А потом она появится и в webpack шаблоне.


Почему мы не выбрали React? После AngularJS наша команда гораздо проще вошла в Vue,
ведь все эти v-if, v-model и v-for уже были очень знакомы.


Лично мне во многом, но не во всем, нравится Aurelia но уж больно она малопопулярна,
а в сравнении с взрывным ростом популярности Vue она кажется совсем неизвестной.


Надеюсь, что через год-два Angular под давлением community все-таки избавится от всего лишнего, исправит основные проблемы и станет наконец тем enterprise framework'ом, которым должен был. Но сегодня я рекомендую вам посмотреть в сторону других, более легковесных и элегантных решений.


И поверьте, спустя 4 года работы с Angular, вот так бросить его было очень нелегко.
Но достаточно один раз попробовать Vue...

Вы можете помочь и перевести немного средств на развитие сайта



Комментарии (416):

  1. RouR
    /#10409050

    Пробуем Aurelia в одном проекте. Проблема с плагинами, точнее плохой поддержкой typescript определений для плагинов. Документация самой аурелии не все описывает, сейчас уже не вспомню, но проходилось гуглить.

  2. hardex
    /#10409146

    Вроде и статья более-менее объективная, и разложено хорошо, но блин, сложно серьезно воспринимать человека, который $inject руками прописывает.

    • SamVimes
      /#10409148 / +3

      А что с этим не так? Видимо strictDI включен.

        • Andchir
          /#10409200 / +3

          Adds Angular 1.x DI annotations to ES5/ES6

          Здесь рассматривается Angular 2/4. Но, опять же, это вкусовщина. Кому-то нравится использовать стандартный синтаксис без взяких дополнительных приблуд, которые так же нужно изучать (каждому приходящему новому разработчику). По-моему это нормально. Меньше зависимостей — меньше проблем для большого проекта.

    • MooooM
      /#10409296 / +6

      Считаю это как раз хорошим паттерном, пусть и error prone, но зато чище со стороны TypeScript'а. И больше инкапсуляции.
      Если же сравнивать со всякими ng-min и ng-annotate — в крупных проектах всегда есть места где они работают неверно и приводят к трудно-диагностируемым проблемам. Давно отказался от подобного.

      • serf
        /#10409414

        Поддерживаю, приписывать $inject руками это хорошая практика, в отличие от использования всяких ng-annotate подобных поделок. Еще лучше прописывать в $inject импортированные имена (по карйней мере для своих/внутренних сущностей), исключает необходимость копипастить название сущностей.

    • serf
      /#10409392 / +1

      А как автоматом $inject в таком случае прописывается habrahabr.ru/company/ncloudtech/blog/321584/#comment_10243970?

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

  3. Riim
    /#10409156 / +6

    например нельзя использовать экспорты по умолчанию

    я тут с пол года назад думал про эти default и понял, что они не нужны. Import в javascript вообще спроектирован отвратительно, даже не трогая default, например, вот хочу я что-то заимпортировать из какого-то модуля, я пишу import, скобочки, и вот тут в скобочках я должен написать, что хочу, но при этом ни одна IDE мне не подскажет, что есть в модуле потому-что путь к модулю ещё просто не написан. Я должен либо наугад вспоминать, что там импортируется, либо пропускать скобочки, писать from 'путь', а дальше альтом перемещаться назад, а потом снова вперёд. Мелочь конечно, но когда она повторяется 30 раз за день, это начинает напрягать. Понятно, что можно сделать простейший сниппет решающий проблему, но всё же я считаю, что язык должен позволять полностью последовательное написание кода с автодополнением без необходимости прыгать туда-сюда. Например, в dart так:


    import 'dart:ui' show Offset, PointerDeviceKind;

    Default тоже ужасен, например, есть у меня в модуле export default class EventEmitter ..., и теперь даже если я написал путь к модулю, IDE опять же не предлагает мне EventEmitter потому-что якобы я должен придумать это имя. Но зачем? В 99.9% придуманное имя совпадает с импортируемым. В тоже время если бы default не было, то автодополнение нормально сработало бы по первым Ev (скобочки написать не проблема или добавить их в сниппет).
    Ещё часто бывает, что неочевидно был default при экспорте или нет, приходится либо пробовать методом тыка (и иногда ошибаться), либо открывать код модуля.


    В общем, я попробовал полностью отказаться от default и половина проблем исчезли, остальные добил сниппетом и парочкой плагинов для vscode. Так что, возможно, невозможность использовать экспорты по умолчанию — это плюс ангулара :)

    • MooooM
      /#10409306

      Честно говоря никогда руками не пишу import руками, всегда делаю автоимпорт через Alt+Enter. IDE — Idea/WebStorm, в более свежих версиях стало очень удобно работать. Последний vscode не тыкал давно, но расстраивает, что там подобного нет.

      • raveclassic
        /#10409664

        Для TS в VSCode есть плагин для автоимпорта, вполне себе

    • serf
      /#10409420

      default export по хорошему вообще нужно забанить в jslint/tslint.

      • TheShock
        /#10409690

        Аргументируйте

        • raveclassic
          /#10409706

          Так выше ж уже привели аргументы. ИМХО дефолтные импорты/экспорты — худшее, что могло случиться с модульной системой JS.

          • TheShock
            /#10409730 / +1

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


            Может они плохи для редакс-приложений, где куча всего экспортится и нету основного импорта, но для подхода один файл — один класс они вполне ничего.


            Все проблемы с ИДЕ, которые еще есть — должны решаться, я думаю, в самих ИДЕ.


            Хотя я согласен, что они — не идеальные, но называть их худшим, что могло случиться, что их нужно забанить по-умолчанию и так далее — это уже слишком, мне кажется.

            • raveclassic
              /#10410246

              Полностью согласен, пользуюсь исключительно автоимпортом. Однако он не может сопоставить имя импорта (которого еще нет) имени файла, потому как не понятно, что от куда должно импортироваться.

              • TheShock
                /#10410452

                Не совсем понял вас, объясните, пожалуйста

                • raveclassic
                  /#10410948 / +1

                  Ну вот есть файл foo.js с содержимым вида


                  export default {
                    foo: 'bar'
                  }

                  А в другом мы пишем… а что мы пишем? Не понятно. Только руками в начале файла — import Foo from 'foo';


                  Было бы export const Foo = ..., то при упоминании Foo в коде, IDE/editor подсказали бы что к чему

    • raveclassic
      /#10409666 / +2

      es6-модули это вообще классный пример как в tc39 работа идет — хотели как лучше, получилось как обычно

    • alex4e
      /#10410860 / +1

      Попробуйте расширение TypeScript Hero для vscode. Он избавит вас от необходимости вручную писать импорты в большинстве случаев. Или TypeScript Importer, но у него меньше функционал.
      Но несмотря на подобную поддержку со стороны IDE у меня тоже есть претензия к языку, правда в моем случае именно к Type Script. Поскольку тип у него идет после имени переменной (что, видимо, типично для языков с необязательной типизацией), то часто по сути приходится одно и то же слово набирать два раза. Первый раз с маленькой буквы для имени переменной, и второй раз с большой — для имени типа. Например, myFunc(control: Control) {}. Для vscode не нашел расширений, решающих эту проблему.

  4. justboris
    /#10409162 / +8

    Спасибо за хорошую статью, очень полезный опыт!


    По моему мнению, с Angular2 так вышло, потому что его разработчики не пытались завоевать пользователей, что все пользователи AngularJS придут к ним сами.


    В то время как Vue и другим фреймворкам приходится бороться за пользователя, и когда они это делают, их API становятся проще и удобнее, а документация — понятнее.

  5. Zakyann
    /#10409172 / +1

    Мы у себя после некоторых раздумий начали использовать UniGUI.
    Плюсы:
    Фактически связанный фронтэнд + бекэнд в одном приложении.
    Ультра-быстрый дизайн форм и написания приложения.
    Удобная отладка с нормальной средой.
    Хороший саппорт, оперативно исправляют вопросы и, вообще, помогают.
    Вылизанная, безглючная, либа фронт-энда и связка с ней (ExtJS).
    Множество примеров.
    Почти сотня десктоп компонент + около 50ти мобильных.
    Постоянное развитие библиотеки.
    Рекомендую.

    К слову — Идера (текущий владелец Delphi), купила Sencha, изготовителя ExtJS, либо будут свою обвязку её делать, либо купять UniGUI. Радует движение в сторону веба.

    • justboris
      /#10409182 / +5

      Вы забыли упомянуть, что UniGUI стоит от 400 до 900 долларов, в то время как все UI-библиотеки из статьи — опенсорсные и бесплатные

      • Zakyann
        /#10409330

        Да, они стоят от двух недель до месяца зарплаты среднего программиста JS, зато существенно и постоянно экономят время и деньги после покупки, которые всё равно будут уплачены.

    • MooooM
      /#10409310

      Для начала — оно не полностью опенсорсное.
      А покупка сенчей сейчас кажется скорее минусом, нежели плюсом. Считаю, что времена тотального господства ExtJS в enterprise сегменте медленно подходят к концу, а последняя версия библиотеки — монструозный атавизм (ведь по-прежнему все свое — классы, разметка, билд системы и т.д). И да, я много работал с ним и знаком с их прекраснейшими и супер-функциональными компонентами.

      • Zakyann
        /#10409332

        Покупка конкретно для UniGUI не ухудшает его положение. Как сказал Фаршад (основной разработчик либы) OEM соглашение подписано на годы вперед и с лицензиями проблем нет и не будет.

      • nohuhu
        /#10411668 / -3

        монструозный атавизм (ведь по-прежнему все свое — классы, разметка, билд системы и т.д)

        Своя система классов, на порядок более богатая, существенно более вменяемая, чем ES6, а главное, работающая — это, безусловно, атавизм. Нынче в моде псевдо-недофичи, которые бабушки из TC39 писями на воде виляют, приговаривают: то ли примем, то ли нет, транспилятор на обед, вот те grunt, а вот webpack, не сойти б с ума никак.


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

        Наверное, недостаточно знакомы. Я вот сколько ни смотрю на все эти ангуляры и реакты, так грустно становится, туфта на постном масле. :( Виджеты если и есть, то до того убогие, аж оторопь берёт. На grids без кровавых слёз не взглянешь. В Clarity Dataview чуть потыкал, с десяток багов нашёл. Они вообще тестируют эти поделки хоть как-нибудь?


        Вот не флейма ради, а просвещенья для, где вы берёте годный grid с поддержкой редактирования данных, валидации ввода и data binding для Vue или Angular?

        • MooooM
          /#10411720

          А ES6 классы не работают? Вообще очень печально, если вы не можете понять чем хороши все эти новые недо-фичи в сравнении с весьма спорными и давно устаревшими подходами в Ext.
          Про усталость JavaScript'а написано многое, но это не делает webpack менее крутым.

          Ну хотите верьте, хотите нет — работал с Ext не один год. Безусловно такой библиотеки контролов нет и не будет ни для одной из описанных библиотек/фреймворков.
          Ну так зато они не стоят *тысяч долларов*, а бесплатны и опенсорсны.

          А полноценные гриды в серьезных компаниях чаще пишутся либо самостоятельно. Нам в нашем проект Clarity хватило.

          • Zakyann
            /#10411806 / -3

            Странно, что всегда разговор заходит о 'тысячах долларов'. Как будто программисты бесплатные :) Программисты, на длительном промежутке времени, стоят сильно дороже инструментов разработки. Ну если только у вас не рабы за еду работают, конечно :)

            • Zakyann
              /#10412116 / -3

              Попал? Минусующим — работаете за еду? :)

              • Zakyann
                /#10412620 / -5

                Кармадрочерам: больше минусов, больше!!! :)

            • justboris
              /#10412268

              UniGUI это не инструмент разработки, а UI-библиотека. Подписываясь на ее покупку, вы отдаете себя на милость выпускающей компании.


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


              При использовании Angular или другого фронтенд фреймворка все под вашем контролем, какие хотите компоненты, такие и пишите, или готовые можно взять, если найдутся подходящие.


              Да и на рынке труда найти ангулярщика в команду намного проще, чем UniGUI-шника.

              • Zakyann
                /#10412624

                То есть — в случае Унигуя мы отдаёмся на милость, а в случае ангуляра — нет? С логикой как-то сложно.

                • justboris
                  /#10412712 / +2

                  Angular не дает вам никаких компонентов. Съехать с ангуляра на другой фреймворк намного проще. Шансов поменять UniGUI на что-нибудь другое без переписывания с нуля вообще никаких.

                  • Zakyann
                    /#10412842 / -1

                    Тогда, простите, смысл Англуляра? Пилить всё самому и с нуля? :) Или нанимать кого-то (опять же) за деньги, терять время. Сделаешь — и с него же, я так понимаю, тоже никуда не уйти? Или можно сделать какой-то промежуточный слой и перенести на другой фреймворк?

                    «Шансов поменять UniGUI на что-нибудь другое без переписывания с нуля вообще никаких.»

                    Формы поменять только. В коде изменения минимальны. Мы как раз — наоборот — с вин-гуя переписали порядка 50ти форм на уни-гуй. Месяца 1.5 где-то работы.

                    • justboris
                      /#10413090 / +1

                      Кажется, вы живете совсем в другой вселенной. Где веб-приложения пишутся не на веб-технологиях, а на их эмуляции через javascript.


                      Это, безусловно, очень интересно, но не для людей, комфортно чувствующих себя в Javascript.


                      Предлагаю на этом дискуссию и закончить.

                      • Zakyann
                        /#10413364

                        Эмуляция веб-технологии через javascript — сильно, очень сильно :)
                        Нужно понимать простую вещь: веб технологии бывают разные. Очень разные.
                        Ладно, закончим так закончим.

                        • justboris
                          /#10413554

                          да, опечатался. Имелось в виду


                          Где веб-приложения пишутся не на нативных веб-технологиях, а эмуляции декстопных API через javascript.

          • nohuhu
            /#10413132 / -3

            А ES6 классы не работают?

            Кое-как работают, там, где они есть. В IE11 есть? Ой, нет. А что умеют? Ой, почти ничего не умеют. Mixins умеют? Нет. Overrides умеют? Нет. Hooks умеют? Нет. Dependency resolution умеют? Нет. Господи, ну хоть статические свойства классов-то умеют? Неа, всё ручками. Пилите, Шура, пилите...


            Вообще очень печально, если вы не можете понять чем хороши все эти новые недо-фичи в сравнении с весьма спорными и давно устаревшими подходами в Ext.

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


            но это не делает webpack менее крутым.

            Чем конкретно крут webpack? По пунктам, если не трудно; бонусные баллы за объективное сравнение с другими решениями. Подозреваю, что дальше "webpack крут, потому что его Angular же использует!" вы не уйдёте.


            Ну хотите верьте, хотите нет — работал с Ext не один год. Безусловно такой библиотеки контролов нет и не будет ни для одной из описанных библиотек/фреймворков.

            Да чего ж не верить? Верю. Печально, что кроме библиотеки виджетов вы ничего не заметили или не оценили.


            Ну так зато они не стоят тысяч долларов, а бесплатны и опенсорсны.

            Вы мне сейчас напоминаете этот бородатый анекдот про солидную компанию с богатой историей, которая наймёт на пол-ставки студентов на подработку. Обещаем доширак сильно не задерживать!


            А полноценные гриды в серьезных компаниях чаще пишутся либо самостоятельно. Нам в нашем проект Clarity хватило.

            У нас с вами очень разные понятия о полноценности таких интересных компонентов, как grids. И об уровне допустимого качества, очевидно, тоже. И даже, рискну предположить, "сёрьезность" компаний мы воспринимаем весьма по-разному; хотя, на мой взгляд, тут дело скорее в задачах, нежели в компаниях.


            Я бы мог много разных примеров из опыта привести, скажем про одного несолидного немецкого производителя люксовых авто, которому приспичило запихнуть навигацию/просмотр/редактирование базы из ~9 млрд парт-номеров запчастей в один TreeGrid. С "бесконечной" прокруткой, страничной подкачкой по запросу и прочими весёлыми штуками. Ну, вот дураки там сидят, не осилили сами-то запилить.


            Или про один забавный и крайне несолидный НИИ в Швейцарии, который там коллайдеры всякие гоняет туда-сюда, а данных-то с них 100500 терабайт или что-то такое. Визуализировать надо, для обработки и анализа. Тоже идиоты, ха-ха, да плёвое ж дело самим-то налабать.


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


            Мог бы рассказать, но зачем? У вас уже всё солидно, Clarity хватает со всеми багами, значит всем остальным тоже должно хватать.

            • raveclassic
              /#10413146 / +1

              В IE11 есть? Ой, нет.

              При чем тут IE?


              Mixins умеют? Нет.

              Миксины много кто не умеет. Да и можно достичь подобия через анонимные классы и HOF


              Overrides умеют? Нет.

              Все умеют


              Hooks умеют? Нет.

              Какие еще хуки?


              Dependency resolution умеют? Нет.

              Какой еще resolution в динамическом языке?


              Господи, ну хоть статические свойства классов-то умеют? Неа, всё ручками.

              Все умеют

              • nohuhu
                /#10413156 / -2

                При чем тут IE?

                Вообще ни при чём, кроме того, что многие организации до сих пор Windows 7 используют и IE11. И модернизироваться не собираются. А некоторые даже за поддержку Windows XP и IE8 платят, дураки несолидные.


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


                Миксины много кто не умеет. Да и можно достичь подобия через анонимные классы и HOF

                Мне всё равно, кто что не умеет. Я отвечал на вопрос: а чем таким плохая, негодная, архаичная классовая система Ext JS может быть лучше модной, годной, молодёжной ES6. Спрашивали? Отвечаем.


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


                Все умеют

                Условные тоже, и декларативно? Приведите примеры, если не сложно.


                Какие еще хуки?

                Да простые, типа таких: onBeforeClassCreated, onClassExtended, etc. Чем они могут оказаться полезны, объяснить или сами догадаетесь?


                Какой еще resolution в динамическом языке?

                Да вот такой, простой. Класс Foo зависит от класса Bar, и использует Qux. При загрузке класс Foo не создаётся, пока не загрузятся Bar и Qux, со всеми своими зависимостями.


                И в динамическом языке, ага. Работает уже лет 8 как. И инструментарием поддерживается для сборки. А вы дальше там простыни import-ов ручками пишите, удачи.


                Все умеют

                Статические свойства классов. Вы давайте, приводите примеры в ES6, не стесняйтесь. Я-то свои слова подкрепить могу в любой момент, зря что ли этот кусок перелопачивал и тестами закрывал. :P

                • raveclassic
                  /#10413164 / +1

                  Забавно, у вас так бомбит, что вы скатываетесь в обыкновенное плоское хамство. Вы такой тут опытный эксперт, а все кругом плебеи, голова не жмет? :)
                  Я вам тут ничего не продаю и ничего доказывать не собираюсь, научитесь для начала манерам, а потом будем (пытаться) строить диалог.
                  Если же все-таки нужно, гуглите, не стесняйтесь — объяснить как это делается или сами догадаетесь?: Р

                  • nohuhu
                    /#10413172 / -1

                    Забавно, у вас так бомбит, что вы скатываетесь в обыкновенное плоское хамство.

                    Да зачем же скатываетесь, и не выкатывался даже. Это разве не общепринятый в местных пенатах тон? :)


                    Вы такой тут опытный эксперт, а все кругом плебеи, голова не жмет? :)

                    Вы будете смеяться, но таки да, опытный эксперт. :) Про плебеев это вы сами придумали, но мне правда становится чуточку смешно, когда люди начинают спорить со мной о вещах, которые я разрабатывал.


                    Я вам тут ничего не продаю и ничего доказывать не собираюсь

                    Взаимно. На том и закончим беседу, если не возражаете. :) Про гугля не переживайте, разберусь как-нибудь. :)

            • mayorovp
              /#10413300 / +1

              Какое отношение IE имеет к ES6 классам?


              Кстати, держите миксины:


              function fooMixin(base) {
                  return class Foo extends base {
                      // ...
                  }
              }
              
              class Baz extends fooMixin(Bar) {
                  // ...
              }

              • nohuhu
                /#10413344 / -1

                Какое отношение IE имеет к ES6 классам?

                Простое: они в IE не работают и никогда не будут. А используется этот браузер ещё много где, и использоваться будет ой как долго. Ну, вот реальность жизни такая. Если вы хотите писать ES6 код, то вам придётся использовать инструментарий для переваривания этого кода в ES5.


                Классовая система Ext JS появилась задолго до ES6, и работает во всех браузерах. Работает хорошо, протестирована неплохо и сюрпризов не преподносит уже давно.


                А вот теперь внимание, вопрос: если всё равно нужно использовать какой-то инструментарий, и он уже есть свой, то имеет ли смысл кидаться впопыхах заменять его на чей-то чужой, просто ради "совместимости с будущим"?


                Вот товарищ выше утверждает, что очевидно надо. Потому что журавль в небе очевидно лучше синицы в руках, это же JavaScript ZOMG.


                Кстати, держите миксины:

                Спасибо за пример, выглядит забавно. Наследуем от функции, которая возвращает функцию-конструктор.


                Теперь ответный пример:


                Ext.define('FooMixin', {
                    extend: 'Ext.Mixin',
                    mixinConfig: {
                        id: 'foo'
                    },
                    ...
                });
                
                Ext.define('BarMixin', {
                    extend: 'Ext.Mixin',
                    mixinConfig: {
                        id: 'bar'
                    },
                    ...
                });
                
                Ext.define('Baz', {
                    extends: 'Quux',
                    mixins: [
                        'foo',
                        'bar',
                        ...
                    ],
                    ...
                });

                Что лучше читается? А если 10 таких mixin? А если все эти классы не пихать в один файл, а разбить для читаемости на отдельные? Мне-то всё равно, загрузчик зависимости отследит и подкачает в нужной последовательности.


                Но это ещё полбеды, я могу про overrides рассказать и как оно с mixins сочетается. Или как можно в mixin вклиниваться до/после метода в основном классе, и для этого не нужно бодаться с контекстом и замыканиями. Или про то, как можно вклиниться в процесс создания класса и декорировать его по необходимости. Или про то, как родительский класс может делать всякие хитрые штуки с наследником. Или ещё что-нибудь интересное, там много.


                Но вот беда, вся эта полезность ужасно архаична, сомнительна и немодна. Зато работает хорошо. Пичалька.

                • vintage
                  /#10413384 / +4

                  ExtJS уже перестал требовать обмазываться километровыми JSDoc-ами со всех сторон? Я и сам писал раньше свою классовую модель с умными примесями, которые позволяли примешивать конфликтующие примеси, но требовали выбирать реализацию при использовании. Но преимущества TS — решают.


                  Вы описываете, безусловно, приятные мелочи, но..


                  1. Это именно мелочи. Ну то есть и без них не чувствуешь себя калекой.
                  2. Это не стандарт. Даже плохой стандарт лучше его отсутствия. Выражается это в богатстве инструментария, простоте изучения, переноса кода между проектами пр.

                  • nohuhu
                    /#10415244 / -2

                    ExtJS уже перестал требовать обмазываться километровыми JSDoc-ами со всех сторон?

                    Нет, не перестал и вряд ли перестанет. Любая сложная система требует изучения и использования документации, это как бы данность. Когда-нибудь пробовали писать нативное Win32 приложение? DVD с MSDN под руками держать не приходилось? Или томик Advanced Unix Programming вместе с батареей манов, если вы с другой стороны баррикад?


                    Интуитивно! Изучать не надо! Оно всё само! — кричали возбуждённые пионеры от JavaScript, обкурившиеся передовых псевдо-технологий. Няшная картинка, аж слеза наворачивается.


                    Я и сам писал раньше свою классовую модель с умными примесями,

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


                    Это именно мелочи. Ну то есть и без них не чувствуешь себя калекой.

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


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

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


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

                    • vintage
                      /#10415686 / +2

                      Любая сложная система требует изучения и использования документации, это как бы данность.

                      Сравните:


                      /**
                       * @param {string} bar
                       * @param {Function} fn
                       * @return {Function}
                       */
                      function makeMoreFunctions(bar, fn) {
                          /**
                           * @param {Object} baz
                           * @return {string}
                           */
                          return function(baz) {
                              fn();
                              /**
                               * @return {string}
                               */
                              return function() {
                                  return bar;
                              };
                          };
                      }

                      function makeMoreFunctions( bar : string , fn : ()=> void ) {
                          return ( baz : {} )=> {
                              fn();
                              return () => bar;
                          };
                      }

                      Всего-то полмиллиона строк кода в фреймворке надо будет переписать и протестировать

                      Горбатого могила исправит. И горбатость ExtJS далеко не в классовой модели. Более вменяемая архитектура потребовала бы в 10 раз меньше кода для того же объёма функционала.

                • mayorovp
                  /#10413404

                  Простое: они в IE не работают и никогда не будут

                  Это называется "не поддерживается", а не "не работает". И, вообще-то, давно уже существуют способы обойти это ограничение.


                  Вот скажите, а у ваших веб-приложений бакэнды есть? И если есть — на чем они написаны?


                  Если на PHP или каком-нибудь Perl — то вопросов больше нет. А если на других языках программирования — то возникает вопрос, почему необходимость компиляции исходников для бакэнда — это давно уже считается нормальным, а то же самое для фронтэнда — ужас-ужас.


                  Что лучше читается?

                  К чему привык — то и читается лучше, это не показатель. Но вот поддержка со стороны IDE у классов ES6 — лучше.

                  • nohuhu
                    /#10415258 / -2

                    Это называется "не поддерживается", а не "не работает".

                    Цитируя любимого домовёнка: а всё одно, всё едино! Если не поддерживается, то по определению не работает. И не будет.


                    И, вообще-то, давно уже существуют способы обойти это ограничение.

                    Конечно существуют. Один из них мы как раз и используем, а именно, собственную систему классов, написанную на чистом JavaScript и обратно совместимую вплоть до чёрти куда.


                    Вот скажите, а у ваших веб-приложений бакэнды есть? И если есть — на чем они написаны?

                    Есть и на всём, что угодно. Есть на Java и Scala и C#, и на ColdFusion и на PHP, и на всех скриптовых языках, и даже на Go мимо пролетало.


                    У каждого клиента свои предпочтения по тараканам в голове, я стараюсь не судить людей. /s


                    Если на PHP или каком-нибудь Perl — то вопросов больше нет.

                    Ой как я люблю вот такие вот обобщения. Какой-нибудь там PHP или Perl, или там Python или Ruby, несолидные такие штуки, негодные. Круто как, одним махом — эх! Половину индустрии под одну гребёнку и в мусор. Размах!


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

                    Про считается нормальным — это вы вон тем, вышесметённым в мусор расскажите. А потом вас догонят извращенцы, которые на серверной стороне JavaScript пользуют, им тоже расскажите. Потом и я могу свои пять копеек вставить, если желание не отпадёт.


                    К чему привык — то и читается лучше, это не показатель. Но вот поддержка со стороны IDE у классов ES6 — лучше.

                    А у меня в носу козявки больше, бе-бе-бе. Аргумент примерно такого же плана.


                    Лично мне IDE вообще до одного места. Я бОльшую часть времени всё равно у браузера в отладчике живу, ну и в консоль одним глазом посматриваю.

                    • mayorovp
                      /#10415386

                      Перестаньте читать между строк то, чего там не написано.


                      PHP я упомянул как пример интерпретируемого языка, которому не нужна стадия компиляции.

                      • nohuhu
                        /#10415408

                        Перестаньте читать между строк то, чего там не написано.

                        Не имею такой привычки. Зато сарказм иногда через край капает, прошу прощения, если невзначай обидел. В намерения не входило. :)


                        PHP я упомянул как пример интерпретируемого языка, которому не нужна стадия компиляции.

                        Про PHP я не в курсе, не эксперт. Когда-то пришлось несколько месяцев ковырять исходники vBulletin, обе руки отвалились креститься наотмашь — закодировался, завязал и больше не пробовал, тьфу*3.


                        А вот как минимум про Perl и Python вы глубоко ошибаетесь: это языки динамические, но стадию компиляции они проходят ещё как. Ruby тоже, если мне склероз не изменяет.

                        • Azoh
                          /#10415412 / +1

                          Не имею такой привычки. Зато сарказм иногда через край капает, прошу прощения, если невзначай обидел. В намерения не входило. :)

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

                          • nohuhu
                            /#10415426

                            Спасибо за спонтанный сеанс психоанализа, премного благодарен. Куда чек прислать? :)

                    • Druu
                      /#10415390 / +2

                      > Лично мне IDE вообще до одного места. Я бОльшую часть времени всё равно у браузера в отладчике живу, ну и в консоль одним глазом посматриваю.

                      Получается, в ваши основные задачи написание кода не входит. Может, в этом причина несогласия?

                      • nohuhu
                        /#10415420 / -2

                        Получается, в ваши основные задачи написание кода не входит. Может, в этом причина несогласия?

                        Почему же, ещё как входит. Просто как-то так получилось, что на меня обычно падают задачи архитектурного плана, которые требуют переворошить половину кода. Все люди разные, кому-то нравится блестящие виджеты полировать, а мне вот по душе выжать соки из набора тестов и сделать, чтобы прогон pull request занимал не час, а полчаса. Или отбить в тряпочку все компоненты, чтобы поймать утечки памяти и заткнуть дырки, чтобы больше не текло. Или добавить поддержку accessibility там, где оно в принципе не росло.


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


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


                        Хотя вот иногда и без IDE трудно. Приблуда, которая тесты через WebDriver гоняет, написана на Java, и надо и её тоже переворошить, чтобы результаты стабильнее возвращались. Глаза в кучу...

                    • vintage
                      /#10415702 / +3

                      Лично мне IDE вообще до одного места. Я бОльшую часть времени всё равно у браузера в отладчике живу, ну и в консоль одним глазом посматриваю.

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

                      • TheShock
                        /#10416132 / +1

                        Категорически согласен. Уже несколько лет не приходилось серьезно пользоваться отладчиком.

            • MooooM
              /#10413472

              Скажу лишь, что в данном случае большинство проблем описанных вами как раз решаются использованием TypeScript. И будут классы, хоть в IE8.

              • nohuhu
                /#10415268 / -1

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

                • raveclassic
                  /#10415274

                  Вам бы книги писать.


                  А по делу, то вам IE поддерживать надо, то не надо? Или инструмент расово неверный и религия не позволяет?

                  • nohuhu
                    /#10415320 / -1

                    Писать бы, да времени нет. Вот работать надо, а я тут всякую фигню строчу. :)


                    А по делу, IE нам поддерживать надо и поддерживаем. Даже распоследняя версия фреймворка работает в IE8 и тесты проходят (большей частью). Потому что клиенты требуют, а кто платит $$, тот и прав.


                    А вот TypeScript нам нафиг не упал по многим разным причинам, в т.ч. по причине наличия своей системы классов, с блекджеком и всем прочим. И я пытаюсь донести простую мысль, что не надо пытаться чесать всех под одну гребёнку и уповать на панацею от абсолютно всех болячек имени доброго и бескорыстного доктора Майкрософта.


                    Просто ради понимания моей перспективы, представьте что всё наборот, я работаю в Microsoft и жить не могу без TypeScript. Теперь продайте мне ES6 + Flow.

                    • raveclassic
                      /#10415324 / +1

                      Как-то вы так лихо перескочили с фразы "большинство проблем решаются с помощью TS" на "всем TS, я создал, кто не в TS, тот лох".
                      TS вполне себе годный инструмент (хоть это и MS) и со своими задачами справляется ну просто на ура. Никто никому ничего не продает и уж тем более не гонит на святую сенчу :)


                      А вот вы пишите, TS не упал. И я знаю, что вы таки знаете толк в велосипедах :) не пробовали типизацию внедрять какую-нибудь? все-таки на динамике библиотечный код так себе пишется...

                      • nohuhu
                        /#10415388

                        Как-то вы так лихо перескочили с фразы "большинство проблем решаются с помощью TS" на "всем TS, я создал, кто не в TS, тот лох".

                        Ага, ну давайте в риторику тоже поиграем. :) С самого начала:


                        1. Товарищ MooooM размашисто, сплеча обзывает небезызвестный фреймворк "монструозным архаизмом". Годный революционный тон, что характерно, без какой-либо аргументации (даёшь отмечание столетия!)
                        2. Я выступаю и слегка язвительно парирую тем, что монструозный атавизм, на минуточку, работает и таки вполне неплохо себя чувствует. И давно уж.
                        3. Товарищ MooooM невинно изумляется крамольной мысли о том, что кому-то может не хватать блистательных возможностей сиятельного ES6.
                        4. Я на пальцах объясняю, что таки нет, не хватает, и таки да, вот по пунктам.
                        5. Товарищ MooooM делает разворот на 180 и начинает уповать уже на TypeScript, хотя и несколько менее размашисто, чем в п.1.
                        6. Я позволяю себе вежливо усомниться в весомости аргументов в пользу оного TypeScript, из которых я до сих пор слышал только дифирамбы Майкрософту и титанам мысли, решившим уже за нас, сирых и убогих, ну просто все-все-все проблемы, только нужно расписаться вот здесь. Да, кровью, а вы не в курсе что ли?

                        Так что нет уж, пардоньте. Это не я прыгаю. :) Я просто пытаюсь отбиваться от товарищей, назойливо тыкающих в лицо разными Авторитетными Решениями.


                        TS вполне себе годный инструмент (хоть это и MS) и со своими задачами справляется ну просто на ура.

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


                        Никто никому ничего не продает и уж тем более не гонит на святую сенчу :)

                        Да богов побойтесь, Сенча ни разу не святая и Ext JS полный говна кусок. Никакого другого мнения вы от меня никогда не услышите. :)


                        Тут только это, маленький ньюанс… (с) Всё остальное ещё хуже. Я проверял. :(


                        А вот вы пишите, TS не упал. И я знаю, что вы таки знаете толк в велосипедах :) не пробовали типизацию внедрять какую-нибудь? все-таки на динамике библиотечный код так себе пишется...

                        Не совсем понимаю спектр вопроса. Лично я пробовал, или команда Ext JS? Лично я начинал когда-то с нацистско-типизированного Паскаля, проходил огонь C и медные трубы C++, так что с идеалами статической типизации в некотором роде знаком. Правда, потом открыл для себя свет исуса прелести полностью динамической типизации, переметнулся на тёмную сторону и взад больше не смотрел. Остальные товарищи по команде тоже пороху нюхали изрядно; начальник наш вообще эксперт по Java, большой поклонник C# и адепт Microsoft по самое не балуйся.


                        И внедрять пробовали, точнее играться. И с TypeScript, и с другими штуками. Не дают они никаких весомых преимуществ с нашей позиции: мы не можем контролировать среду и код клиентов, а стало быть все наши предположения по поводу того, как код будет использоваться, автоматически идут лесом. Единственный безопасный выход, это оставаться в рамках ES5 и не рыпаться хотя бы до момента, когда старые браузеры отвалятся.


                        Да чего далеко за примерами ходить, ребята из соседнего отдела уже года три как периодически порываются выкинуть нафиг YUI compressor и заменить его на хвалёный Google Closure compiler. Баги лезут как зелёные черти после пол-литры, аж в глазах рябит. Это мы как бы только о минификации/оптимизации ES5 говорим, да? ES6-то тоже поддерживать надо, но как это сделать, чтобы не сломать весь мир — это как раз и есть вопрос на миллион.

                    • symbix
                      /#10415338 / +1

                      Я extjs в последний раз видел в третьей версии (и с тех пор больше видеть не хочу :-), но по тому, что помню, es201x + flow вполне беспроблемно туда ложится.

                      • nohuhu
                        /#10415396

                        Я вам ничего продавать не собираюсь, просто ради исторической справедливости отмечу, что Ext JS 3 и Ext JS 6.5 (последний) — это вещи настолько разные, что похожи только названием.


                        Поэтому ваши впечатления, хоть и вполне заслуженные, от нынешнего состояния дел весьма оторваны.

        • vintage
          /#10411804 / +2

          где вы берёте годный grid с поддержкой редактирования данных, валидации ввода и data binding

          Есть мнение, что грид не должен всего этого уметь. Берёте грид, помещаете в него поля ввода и всё.

          • Zakyann
            /#10411812

            Очень-очень многое можно сделать с нуля. Только зачем в десятитысячный раз делать велосипед, если всё есть готовое и из коробки? Хоть и платное. Один фиг пока программеры с нуля сделают и тестировщики оттестируют то выйдет, как минимум, не дешевле.

            • vintage
              /#10411866 / +4

              Ну если готовое из коробки работает ровно как вам нужно — это замечательно. Но зачастую требования немного другие и допиливание такого "швейцарского ножа" под себя сравнимо по трудоёмкости с написание велосипеда.

              • Zakyann
                /#10412112 / -2

                Но зачастую требования немного другие и допиливание такого «швейцарского ножа» под себя сравнимо по трудоёмкости с написание велосипеда.

                Вот! В том числе поэтому бывает сильно дешевле и быстрее купить платное и пинать саппорт (что мы с унигуем и делаем :) ) Чем возится самим с допиливанием с нуля хоть до какого-то рабочего состояния.

          • nohuhu
            /#10413138 / -2

            Есть мнение, что грид не должен всего этого уметь. Берёте грид, помещаете в него поля ввода и всё.

            При всём заочном уважении, есть мнение, что мсье не знает, о чём говорит. От слова "чуть более, чем полностью". И всё.

            • vintage
              /#10413348

              Мисье, представьте себе, тоже разрабатывал. Так более аргументированно вы не можете ответить?

              • nohuhu
                /#10413370 / -1

                Могу, конечно. Зачем? Ваш категоричный тон и авторитетные пассы руками два сообщения назад говорят о том, что вы очевидно уверены в своём глубочайшем знании предмета и полной непогрешимости. Т.е. слушать и обмениваться опытом не горите желанием.


                А членами меряться мне недосуг, извините.


                Хотя если я всё же ошибся и вам действительно интересно, то могу объяснить, почему нельзя просто взять и поместить поля ввода в grid, и всё. С подробностями и путями решения проблем.

                • vintage
                  /#10413406

                  Мне, разумеется, интересно. Иначе бы не спрашивал. Моя уверенность строится не на самомнении или религии, а на анализе различных архитектур. Собственно, несколько ключевых особенностей $mol взято напрямую у ExtJS, но при этом решены основные родовые травмы подобных фреймворков. Поэтому, я думаю, $mol мог бы вам понравиться, когда нарастит побольше мяса из стандартных компонент.

                  • nohuhu
                    /#10415314 / -2

                    Ох, господи. Ну хорошо, давайте меряться тогда уж.


                    Моя уверенность строится не на самомнении или религии, а на анализе различных архитектур.

                    А моя уверенность строится на многолетнем опыте разработки той самой Ext JS, включая практически всю поддержку accessibility: управление фокусированием, поддержку клавиатурной навигации, ARIA, экранных читалок и дисплеев Брайля, и проч. Во всех компонентах, в т.ч. grids, trees, и всём остальном. Фактически в двух разных фреймворках, которые нынче сливаются в один. Которые для поддержки этой accessibility мне пришлось очень глубоко переделывать, иначе ни черта не работало, т.к. изначально всё проектировалось для тыкания мышками или пальчиками.


                    И суммируя этот многолетний опыт каждодневного бития башкой в бетонную стену, я вам говорю: нельзя просто взять и поместить поля ввода в grid, и всё.


                    Достаточно? Дальше уже давайте конструктивно.


                    Так вот, начнём с design pattern. Мы с вами уважаем стандарты, поэтому возьмём за основу WAI-ARIA 1.1 Grid, даже конкретно вот эту секцию: Keyboard interaction, раздел про редактирование данных. Суммируя по-быстрому, нам нужно, чтобы:


                    • Enter или F2 на ячейке включало редактирование
                    • Enter в режиме редактирования подтверждал изменения
                    • Esc в режиме редактирования отменял изменения
                    • Tab и Shift-tab перепрыгивали к следующему/предыдущему полю редактирования, не покидая режим редактирования и сохраняя изменения при покидании ячейки

                    Если вы просто добавите поля ввода в ячейки grid, при этом не озаботившись обработкой событий и состояний, то grid не будет в курсе ни о начале редактирования, ни о конце. Навигация с помощью Tab тоже будет работать только до конца строки с ячейками, и только если не дай бог где-то на странице не случился элемент с tabIndex > 0. Если случился, то пиши пропало — фокус улетел и состояние сломано. Если даже ничего не пропало, то по стандарту рекомендуется заворачивать навигацию с последней ячейки последней строки на первую ячейку первой строки.


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


                    Далее можно упомянуть такие дружественные к разработчику штуки, как возможность определять тип виджета для редактирования ячейки (text input, text area, combo, etc), и картинка усложняется. Далее мы можем вспомнить о том, что данные нужно не просто редактировать в памяти, а ещё неплохо было бы оповещать какие-нибудь сторонние объекты о том, что редактирование записи состоялось. Для этого как минимум нужно понимать, когда у нас редактирование смещается с одной строки на другую, а ещё лучше, иметь возможность организовать транзакционный подход с атомарным подтверждением или отменой изменений. Это тоже чуточку выходит за рамки понимания отдельного поля ввода, даже очень умного. Далее мы можем вспомнить о случаях, когда набор данных не влазит в экран и нужна прокрутка по горизонтали или, ещё хуже, по вертикали с динамической подкачкой данных с сервера. И чтобы табуляция по полям редактирования работала и в этом случае тоже. И что юзеры имеют привычку начать редактировать ячейку, а потом кликнуть мышкой в другую часть страницы и фокус улетает, а это надо отрабатывать без потерь.


                    И это даже без учёта специфичных браузерных приколов, типа отсутствия нормальных фокусных событий в Firefox (до недавнего времени) или идиотской отработки mousedown на scrollbar в IE. И тем более без учёта возможности использовать в качестве редактора какого-нибудь HtmlEditor на базе iframe, а там с фокусными событиями отдельный многоцветный коленкор. Или вот какой-нибудь клиент решит засунуть в grid что-нибудь типа <input type="file"> и вы с ним на%@#тесь и напляшетесь в IE/Edge, потому что оно на голову больное. Или ещё 100500 таких же козырных, но вполне оправданных случаев (потому что клиенты $$ платят).


                    Вот берёте все эти конфликтующие требования, смешиваете, помещаете в горшочек и поливаете-удобряете несколько лет, а на выходе как раз получается что-нибудь типа Ext JS grid. С фичами, плагинами, блекджеком и шлюхами. Безумно сложно, но работает и даже вполне быстро для своих возможностей и уровня совместимости со всем, что движется.


                    Поэтому, я думаю, $mol мог бы вам понравиться, когда нарастит побольше мяса из стандартных компонент.

                    Безумству храбрых… Но вам всё же проще будет, браузеры с тех пор чуточку попрямее стали. :)

                    • Zakyann
                      /#10415496

                      Вот, vintage, берётся, в том числе это всё, за 600$ зеленых повторить на $mol :)

                    • vintage
                      /#10415980 / +1

                      А моя уверенность строится на многолетнем опыте разработки той самой Ext JS

                      А кроме него что пробовали?


                      Фактически в двух разных фреймворках, которые нынче сливаются в один.

                      Это что за фреймворки?


                      Которые для поддержки этой accessibility мне пришлось очень глубоко переделывать

                      Эх, вашу бы самоотдачу, да нормальному фреймворку..


                      Мы с вами уважаем стандарты, поэтому возьмём за основу WAI-ARIA 1.1 Grid, даже конкретно вот эту секцию: Keyboard interaction

                      Только полезные. Конкретно этот я не считаю полезным, ибо слишком ограничивает возможные решения одним конкретным. Давайте попробуем сами запроектировать поведение...


                      Enter или F2 на ячейке включало редактирование
                      Enter в режиме редактирования подтверждал изменения
                      Esc в режиме редактирования отменял изменения

                      Я бы сделал, что при фокусе сразу включается редактирование.


                      Tab и Shift-tab перепрыгивали к следующему/предыдущему полю редактирования, не покидая режим редактирования и сохраняя изменения при покидании ячейки

                      Это стандартное поведение, работающее и вне гридов. Хотя оно и не очень удобное. Мне нравится подход Оперы, где ctrl+стрелка переносят фокус на ближайший контрол в соответствующем направлении.


                      Далее можно упомянуть такие дружественные к разработчику штуки, как возможность определять тип виджета для редактирования ячейки (text input, text area, combo, etc)

                      Какие виджеты помечтил — такие и будут. Может хоть несколько виджетов в одну ячейку помечтить и всё будет работать, так как логика эта не будет привязаня ко гриду.


                      неплохо было бы оповещать какие-нибудь сторонние объекты о том, что редактирование записи состоялось.

                      Для этого есть реактивное программирование, которое в ExtJS не завезли.


                      Для этого как минимум нужно понимать, когда у нас редактирование смещается с одной строки на другую, а ещё лучше, иметь возможность организовать транзакционный подход с атомарным подтверждением или отменой изменений.

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


                      Далее мы можем вспомнить о случаях, когда набор данных не влазит в экран и нужна прокрутка по горизонтали или, ещё хуже, по вертикали с динамической подкачкой данных с сервера.

                      Обычный ленивый рендеринг, реализованный в гриде.


                      отсутствия нормальных фокусных событий в Firefox

                      Да там небольшой воркэраунд с useCapture нужен и всё.


                      идиотской отработки mousedown на scrollbar в IE.

                      Речь про перенос фокуса? Ну это не страшно.


                      И тем более без учёта возможности использовать в качестве редактора какого-нибудь HtmlEditor на базе iframe

                      Да нафиг оно такое надо :-) У нас будет нормальный встраиваемый богатый редактор.


                      Или вот какой-нибудь клиент решит засунуть в grid что-нибудь типа и вы с ним на%@#тесь и напляшетесь в IE/Edge, потому что оно на голову больное.

                      Что там с ним не так?


                      Вот берёте все эти конфликтующие требования, смешиваете, помещаете в горшочек и поливаете-удобряете несколько лет

                      Единоразовая задача на не более чем месяц.


                      а на выходе как раз получается что-нибудь типа Ext JS grid.

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

              • Zakyann
                /#10413396

                Вопрос разрабатывавшему: вы, если что, возьметесь запилить за 600 бакинских на ангуляре аналог унигуевских дбгридов, дб деревьев и чартов (хотя бы)? Нужен фронт + бэк. Язык бэка на выбор.

                • vintage
                  /#10413418

                  На Ангуляре — нет. А на $mol — вполне. Как раз за вчера сделал кроссплатформенное приложение, которое берёт OLAP куб, строит по ним табличку/графики с возможностью фильтрации по размерностям из этого куба.

                  • Zakyann
                    /#10414010

                    Ок, буду иметь в виду, мало ли :)

        • justboris
          /#10411872 / +4

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


          То же самое и со стилями. Как только потребуется перекрасить стандартные синие окошки во что-либо другое, начинается ад. Об этом я даже в 2011 году написал статью.


          После того, как я познакомился с Grunt, Webpack и современным фронтенд-стеком в целом, обратно меня уже никакими рассказами про "на порядок более богатые" классы не заманить.

          • nohuhu
            /#10413144

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

            Но ведь, что интересно, удавалось же? Я помню, как примерно в те же года пытался разобраться в Dojo. Вот уж где спагетти было жестокое. После него Ext JS 4 при всей своей лютой, бешеной глючности казался всё же глотком свежего воздуха.


            Об этом я даже в 2011 году написал статью.

            С тех пор чуток воды утекло. Вы считаете нормальным сравнивать фреймворк 6-летней давности с современными решениями?


            После того, как я познакомился с Grunt, Webpack и современным фронтенд-стеком в целом, обратно меня уже никакими рассказами про "на порядок более богатые" классы не заманить.

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


            Сейчас как раз пытаюсь потихоньку выбрать, на чём делать новый личный проект. Ext JS использовать очень не хочется по личным причинам, но всё остальное даже рядом не валялось. Хоть всё бросай и начинай свой фреймворк, с блекджеком и прочими штуками...

            • justboris
              /#10413160

              Но ведь, что интересно, удавалось же?

              Манкипатчингом можно и в JS заниматься, но я не считаю это поводом для гордости. В современных UI-либах (в крайнем проекте использовал react-toolbox) просто нет необходимости где-то там патчить.


              С тех пор чуток воды утекло. Вы считаете нормальным сравнивать фреймворк 6-летней давности с современными решениями?

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


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

              Это Sencha CMD хороший инструмент? Вы серьезно?

              • nohuhu
                /#10413168

                Манкипатчингом можно и в JS заниматься, но я не считаю это поводом для гордости.

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


                Ext JS далеко не идеален, но даже в 2011 читался существенно лучше, чем многие конкуренты по цеху. А с тех пор чуть-чуть улучшился. :)


                В современных UI-либах (в крайнем проекте использовал react-toolbox) просто нет необходимости где-то там патчить.

                Багов в них тоже нет, чтобы не было необходимости патчить?


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

                Это как раз попытка выехать на тренде и заработать денег.


                Это Sencha CMD хороший инструмент? Вы серьезно?

                Я Ext JS имел в виду. Сам не большой фанат Cmd, но этот инструмент тоже легко недооценить. С первого взгляда это кривая и архаичная поделка для склеивания JavaScript файлов, но на самом деле Cmd умеет очень много разных интересных штук. Например, запускать тестовые сессии через WebDriver, с параллелизацией, очерёдностью, сбором статистики, свистелкам и перделками. ~500,000 юнит-тестов за полчаса, и так на каждый pull request. Просто для справки. :)

                • justboris
                  /#10413176

                  Я не monkey patching имел в виду, а читабельность кода.

                  Так или иначе, но возможность переопределить метод у Ext.panel.Panel чтобы show делал совсем не show называется манкипатчингом, каким бы читаемым он не был.


                  Багов в них тоже нет, чтобы не было необходимости патчить?

                  Можно прислать pull-request с фиксом и получить новый релиз в течение 1-2 недель, а не ждать релиза ExtJS раз в квартал. Кстати, а как правильно обновлять версии ExtJS? Из npm его не скачать, в package.json не прописать.


                  но на самом деле Cmd умеет очень много разных интересных штук

                  ничего такого, что нельзя сделать на классическом стеке с Webpack, Mocha, Jest и т.п.


                  Но Sencha Cmd нельзя поставить командой npm install sencha-cmd, что сразу ставит на нем жирный минус.

                  • nohuhu
                    /#10413184

                    Так или иначе, но возможность переопределить метод у Ext.panel.Panel чтобы show делал совсем не show называется манкипатчингом, каким бы читаемым он не был.

                    Переопределение существующих классов это monkey patching, не спорю. Но вместо этого вы можете создать свой класс Foo.panel.Panel, унаследовать его от Ext.panel.Panel и переопределить метод show в своём классе. А это уже классическое ООП.


                    Можно прислать pull-request с фиксом и получить новый релиз в течение 1-2 недель,

                    Правда? https://github.com/angular/angular: 1,699 issues, 249 pull requests. Дальше смотреть лениво.


                    Кстати, а как правильно обновлять версии ExtJS?

                    Cmd и это тоже за вас умеет.


                    ничего такого, что нельзя сделать на классическом стеке с Webpack, Mocha, Jest и т.п.

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


                    Скажем, Mocha я глубоко не копал, а вот Jasmine пришлось переписать практически с нуля. Дважды. Первый раз, чтобы убить титанически мохнатых багов, которые Pivotal фиксить отказались, а второй раз, чтобы стало бегать в разы быстрее. Это к вопросу о качестве модно-хайповых решений.


                    Но Sencha Cmd нельзя поставить командой npm install sencha-cmd, что сразу ставит на нем жирный минус.

                    Конечно, всё должно быть модно-молодёжное на npm и Node.js. Если не на Node.js, то автоматически хлам и говно.


                    Внимание, вопрос: когда завтра появится какой-нибудь "Node killer" и вся ваша инфраструктура в одночасье превратится в хламчинскую тыкву, вы тут же бросите всё и ломанётесь переделывать ради бытия в тренде? А что? Все побежали и я побежал! ©

                    • justboris
                      /#10413188

                      Кстати, а как правильно обновлять версии ExtJS?
                      Cmd и это тоже за вас умеет.

                      А откуда он качает новую версию? В любом случае получается какой-то велосипед вместо NPM.


                      а вот Jasmine пришлось переписать практически с нуля. Дважды. Первый раз, чтобы убить титанически мохнатых багов, которые Pivotal фиксить отказались

                      Ссылки сможете показать? Очень интересно посмотреть, без сарказма.


                      Конечно, всё должно быть модно-молодёжное на npm и Node.js. Если не на Node.js, то автоматически хлам и говно.

                      Если вы пишете на Javascript, то писать сборку не на Node.js будет странно. То же самое и с NPM, стандартный репозиторий пакетов, логично использовать именно его, а не свой велосипед.


                      Внимание, вопрос: когда завтра появится какой-нибудь "Node killer"

                      Node.js это рантайм. Он по определению подчиняется стандартам языка. Поэтому гипотетический Node killer будет более-менее совместим с текущей экосистемой.

                      • nohuhu
                        /#10413204

                        А откуда он качает новую версию?

                        Из репозитория Sencha, конечно.


                        В любом случае получается какой-то велосипед вместо NPM.

                        Безусловно. Как вы представляете себе распространение коммерческих продуктов через NPM?


                        Ссылки сможете показать? Очень интересно посмотреть, без сарказма.

                        Если интересно и без сарказма, то могу не только показать, но и многое рассказать. Мы на базе Jasmine сделали мощнейший QA инструмент, и кроме собственно юнит- и интеграционных тестов проверяем код на утечки памяти, таймеров, Ajax запросов и т.д. Гайки зажимаем, насколько можем дотянуться. Давно уже подумываю статью про это дело написать, но со временем совсем швах.


                        К сожалению, в публичной версии Ext JS этой сборки Jasmine пока нет, но есть в коммерческой. Пробную версию Ext JS можно взять здесь: https://www.sencha.com/products/extjs/evaluate/. Можете ввести какой-нибудь левый, но работающий, e-mail адрес, и потом скачать по ссылке. А дальше открывайте ext/test/lib/jasmine.js.


                        Если вы пишете на Javascript, то писать сборку не на Node.js будет странно.

                        Абсолютно ничего странного, если вы пишете на JavaScript только клиентскую сторону. А с серверной стороны у вас могут быть какие угодно инструменты, и Node/NPM как раз будут казаться ортогональными и неестественными.


                        Поэтому гипотетический Node killer будет более-менее совместим с текущей экосистемой.

                        Это до тех пор, пока какой-нибудь очередной амбициозный пионер не решит заделаться потрясателем ослов основ. А случается это с завидной регулярностью; как говорят буддисты, единственное постоянство — это изменения.

                        • justboris
                          /#10413574

                          Вы говорите, что нашли баги, которые Pivotal фиксить отказались. А ссылки на баг-репорт с ответом про won't fix показать можете?

                          • nohuhu
                            /#10415136

                            Вот один, самый зверский. Если мне память не изменяет, то проблема была в некорректной отработке выхода из waitsFor по таймауту, что приводило к неисполнению блоков afterEach. Ну, и понятным последствиям для всех последующих тестов.


                            Там ещё много чего было, но смысла открывать PR уже не было.

                            • justboris
                              /#10415156 / +1

                              Конечно смысла не было. Надо на Jasmine 2 обновляться, а не пинать труп 1й версии.


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


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

                              • nohuhu
                                /#10415220 / -2

                                Конечно смысла не было. Надо на Jasmine 2 обновляться, а не пинать труп 1й версии.

                                Ваш безграничный оптимизм меня умиляет. Ради мысленного эксперимента попробуйте представить себе масштаб изменений при переходе с псевдо-синхронного API на полностью асинхронное без гарантий выполнения блоков. Теперь шагните чуть дальше и попробуйте представить масштаб трудозатрат на такие изменения. Потом умножьте на 3, потому что проблемы обязательно вылезут.


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


                                Если найдёте, поделитесь пожалуйста. Я не нашёл. Проще было переписать Jasmine, чтобы добавить поддержку их нового API, не теряя старого. Ну и багов вычистить заодно.


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

                                Наш проект это Ext JS. :) Большой, старый. Сам фреймворк ещё ничего по сравнению с приложениями, которые на нём построены.


                                20000 тестов это большая цифра, интересно, как это вообще разрабатывается, и сколько человек это делают.

                                20k тестов было 3 года назад, текущая цифра ~66,500. Всё это добро прогоняется в 10+ браузерах, что даёт в сумме ~500,000 тестов за каждый прогон PR; в ночных сборках больше. Разрабатывается руками и головой, ничего принципиально нового. В основной команде 10 человек, включая меня.


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

                                Самый большой, что я видел своими глазами, состоит из примерно ~5,000,000 строк и компилируется в скрипт примерно 30 mb объёмом. Ничего, работает даже в IE8.


                                Ребята из services хвастались, что бывает и больше.

                                • justboris
                                  /#10415542

                                  Если вы работаете над самим ExtJS то ваша позиция становится понятнее.


                                  Полистал официальный сайт, нашел примеры: http://examples.sencha.com/extjs/6.5.1/examples
                                  А где можно посмотреть их исходники? Вдруг 6я версия действительно стала лучше.

        • MooooM
          /#10415916

          Спасибо. Я уже посмотрел ваш профиль на гитхабе и понял, что вы работаете в Sencha.
          Что объясняет все написанное далее в ветке дискуссии.

  6. magicstream
    /#10409178 / +11

    Меня уже настараживает рост количества статей на тему "почему я перешел с angular2 на vue.js
    Действительно все так плохо? Я нахожусь в процессе изучения angular. Уже написал свое первое приложение. При написании столкнулся с большинством из описанных в недостатков. Меня давно посетила мысль — "стоит ли продолжение изучения". Angular позиционирует себя как фреймфорк но он так и не дал мне слоя для Экшенов. Пришлось внедрять ngrx… так стоит ли все таки продолжать писать на нем? Кто защитит angular?

    • MooooM
      /#10409314 / +11

      Именно для подобных людей я и писал данную статью! Поверьте, подобные статьи появляются не просто так. Надеюсь моя аргументация убедит вас хотя бы попробовать Vue.js

      • magicstream
        /#10409352 / +1

        Что скажете по этому аргументу:
        Angular позиционирует себя как кросплатформенный. Для манипуляции с домом рекомендуется использовать Renderer для поддержки различных устройств.

        Vue.js поддерживает кросплатформенность?

        • MooooM
          /#10409356 / +5

          Да, посмотрите на Weex. Собственно его и разрабатывают одни из основных мейнтейнеров — Alibaba.

      • marshinov
        /#10409458

        А вот бы еще Vue с React'ом сравнить. Мы после первой версии ng 1.5 ушли на React. К React'у тоже много вопросов, наиболее больные: обратная совместимость и обилие реализаций flux. С готовыми компонентами там тоже не сказать, что прям супер. Иногда подумываю, что не смотря на все минусы ExtJs3, по количеству качественных UI-компонентов он оставляет позади многие современные и модные JS-фреймворки.

        Про имхо пишут только хорошее. То ли еще не успели много написать и волну хейта ждать через год, то ли китайцы такие молодцы решительно не понятно, а вкладываться в изучение еще одного фреймворка нет уже моральных сил.

        • Odrin
          /#10410882

          У Vue.js очень понравились однофайловые компоненты. Грубо говоря, в React можно добиться того же эффекта через CSS-in-JS, но подход с разделением компоненты на html + js + css кажется более естественным. Анимации делаются гораздо проще, чем в React. Ну и в целом остается впечатление, что пользоваться vue проще.
          Из недостатков — слабая поддержка IDE (в моем случае WebStorm), не хватает подсказок автодополнения.

    • symbix
      /#10409452

      С ngrx/store и ngrx/effects на Angular писать очень приятно. Более-менее сложное/крупное приложение даже боюсь себе представить без них.

      • magicstream
        /#10409566

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

        Воспользуюсь моментом и задам вам вопрос по angular-у :)

        Могли бы вы мне прояснить как правильно реализовать консистентность компоненты при роутах. Суть в том что компонента каждый раз пересоздаётся при переходе на нее через роутер. Я полагаю что хранить все состояние компоненты в store решает проблему. Правильно ли дублировать все данные компоненты в сторе?

        В частности проблема проявляется при валидации формы на стороне клиента.
        С валидацией на стороне сервера все хорошо, данные пришли в стор — компонента нарисовала ошибки.
        Но как быть с клиентской валидацией, ведь там используется reactive forms?
        т. е. найденные ошибки не сохраняются в store, тем самым при последующем показе компоненты (ну например я сделаю переход по истории назад и вперед) — ошибки исчезнут, так как компонента заново пересоздалась и все данные пропали.

        неужели нужно и клиентскую валидацию перенести в слой effects?

        • raveclassic
          /#10409674 / +2

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

        • symbix
          /#10409708 / +2

          Где заканчивается набор библиотек и начинается фреймворк — это хороший вопрос. Фреймворк может быть монолитным или модульным. Модульный — это и есть набор библиотек по сути. Я думаю, что тут два критерия:


          • наличие штатного процесса bootstrap-а приложения (это вообще такое заметное внешнее отличие фреймворка от библиотеки);
          • согласованность интерфейсов библиотек, таким образом, что в комплекте получается бОльшая ценность.

          Можно считать ngrx опциональным модулем Angular :-) Если со временем его примут в основные репозитории, это будет совсем не удивительно, а даже закономерно.


          В сторе — да, все состояние, но не "вьюшное", а уровня model. И селекторов не жалеть, много — не мало :-)


          При этом store не отменяет стандартную "ангуляровскую" иерархию input-output. Это все комбинируется. В мире react есть термины "presentation component" и "container component". В angular имеет смысл делать точно так же. Presentation components про store не знают, там input-output.


          С формами — надо подумать :-). Вообще может быть плюс-минус два варианта UI. Первое — когда форма редактирует "рабочую копию" (грубо говоря, клон), и есть кнопки типа "сохранить"/"отменить" — тогда по submit-у делается action со всеми изменениями, и потеря изменений при навигации воспринимается естественно. В этом случае проблем нет (и от меня обычно хотели именно такой логики UI). Второй вариант — когда редактируется-валидируется все на лету, тогда, конечно, состояние валидности тоже должно быть в сторе — ведь тогда наверняка есть другие компоненты, которые селектят редактируемое значение, и невалидное им не нужно.


          В эффекты сваливать это точно не надо, в эффекты валятся, мм, сайд-эффекты :) Вот хорошая картинка:
          https://codesequence.github.io/ngrx-workshop/assets/player/KeynoteDHTMLPlayer.html#58


          В идеале, эффект — это цепочка rxjs-операций, на входе один action, на выходе — другой. При хорошем знании rxjs получается в эту логику уложить что угодно. У меня начало хорошо получаться где-то через два месяца :-)


          Ну и раз уж зашла речь про роутер, не могу не упомянуть ngrx/router-store и RouterStateSnapshot.

          • magicstream
            /#10409886

            спасибо.
            можно еще ликбеза :)
            никак не могу понять логику которая скрывается за тем что в redux разделили экшены и редьюсеры. ведь редьюсер можно представить как метод экшена.
            в чем соль этого?

            • Druu
              /#10409920 / +1

              > в чем соль этого?

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

            • mayorovp
              /#10410004

              Соль в том, что action — это DTO и его можно сериализовать и, к примеру, передать на другую вкладку. Или вовсе на другой компьютер через бакэнд.

              • vintage
                /#10410052

                Экземпляры классов тоже можно сериализовывать/десериализовывать.

                • mayorovp
                  /#10410070

                  Но стандартных сериализаторов с такими возможностями — нет. В этом плане "родной" синтаксис JSON сослужил экосистеме плохую службу.

            • symbix
              /#10411230 / +2

              Redux — это такой упрощенный Flux, а Flux — это такой упрощенный CQRS, "спроецированный" на фронтенд. Почитайте про CQRS и получите ответы на все вопросы. ;)

              • raveclassic
                /#10411262

                Поддержу. Обычно в таких ситуациях оставляю ссылку на эту книжку.

                • symbix
                  /#10411500

                  Самое поразительное тут то, что разработчики Flux, по их собственному признанию, понятия не имели про CQRS, но пришли к ровно такому же дизайну (только с другими названиями). Great minds think alike :-)

                  • raveclassic
                    /#10411532

                    У меня слишком много претензий к FB, чтобы сравнивать их с great minds (хоть я и прекрасно понимаю метафору). Однако, стоит, все-же, отдать этим ребятам должное — они знают как правильно делать IT-маркетинг.

                    • symbix
                      /#10411578

                      Да это я скорее в шутку, с таким же успехом можно вспомнить, у кого мысли сходятся :-) Впрочем, не думаю, что в FB программисты занимаются маркетингом.

                  • Druu
                    /#10411746

                    > разработчики Flux, по их собственному признанию, понятия не имели про CQRS

                    Многое говорит о разработчиках Flux.

        • indestructable
          /#10413094

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


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

    • Mikola-BLR
      /#10413478

      Да, всё так печально с Angular 4. Начинал несколько месяцев назад тестовый проект на Angular 4 для изучения сего фреймворка. До этого был вполне приятный опыт с Angular 1.5.x. Но теперь же, за что ни возьмёшься — одна боль. Документация — боль.
      Но где-то месяц назад вскользь посмотрел vue.js и желание возвращаться к Angular 4 отпало.

      Так что, видимо, не на пустом месте у многих людей возникают аналогичные мысли и чувства на счёт перехода на vue.js

  7. LastDragon
    /#10409180 / +1

    По какой-то причине команда Angular решила сделать класс HttpParams иммутабельным.

    А это не только в angular-е, сейчас вообще модно везде пихать иммутабельные объекты… Делается же оно для того чтобы избежать трудновоспроизводимых ошибок в сложном софте (кто-то где-то поменял то что не должен и у нас всё умерло).


    RxJS operator import

    Так а angular то тут причем? (самое забавное что некоторые операторы лежат в других файлах...)


    Navigation

    То что написано это цветочки, самая засада в том что похоже вообще нету именованных роутов, соответственно если есть /object/:id/comments, то везде придется писать this.router.navigate(['other', id, 'comments']);, как потом это поддерживать — загадка (или как-то можно?)


    Вообще писать про документацию Angular даже нет смысла

    А чем дока то не нравится? Она сейчас в виде допиливая реального приложения, вполне неплохо имхо, особенно для начинающих. Думаете абстрактные примеры были бы лучше? Ну а перевод вообще хз зачем нужен — (1) там все очень просто, (2) перевод всегда отстают от оригинала (а у них там постоянно что-то меняется). И кстати на SO обычно всё уже есть (удивительно, но оно даже не сильно путается с angular js).


    Совершенно не ясно зачем делать именно так.

    А какая разница какой css? SCSS кстати включается один раз и навсегда — всего то надо указать соответствующую опцию для cli при создании проекта (а если использовать scss то можно импортировать чужие стили и возможно это бы решило проблему с приоритетами).

    • mnv
      /#10410386

      похоже вообще нету именованных роутов

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

  8. Andchir
    /#10409190 / -17

    Дисклеймер: данная статья строго субъективна...

    Вот никак не понимаю в чём польза субъективных статей? Критика должна быть объективной, а не субъективной.
    Про синтаксис шаблонов вообще не понял в чём ваша претензия.
    Обещали, что будет достаточно только [] и ().… К сожалению в реальности директив едва ли не больше чем в AngularJS.

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

    • raveclassic
      /#10409676 / +2

      Не поверите, но да, выкинуть эти директивы :)

      • Andchir
        /#10410292

        Подробнее можно? Чем заменить?

        • Andchir
          /#10410316

          К примеру, есть два варианта:
          *ngIf="!isHidden"
          или
          [style.display]="isHidden ? 'none' : 'block'"

          У вас есть выбор. Не вижу здесь противоречия — «Обещали, что будет достаточно только [] и ()». Обещание выполнено, если автор его привел дословно. Использовать ngIf вас никто не заставляет. Но с директивой код выглядит приятнее.

          • raveclassic
            /#10410320

            У меня немного другой посыл был: если выкинуть директивы, то и ангуляр уже не нужен.

            • Andchir
              /#10410344

              Опять я должен додумывать. Но я понял о чём Вы. В этом случае тоже надо привести примеры «как должно быть», возможно, из других JS-фреймворков. Тогда критика будет конструктивной.

              • raveclassic
                /#10410350 / +2

                Как бы очередной шквал не поднять, но:


                {!isHidden && <div>hi!</div>}

                • Andchir
                  /#10410368

                  А как будет, если внутри не просто «hi!», а целый шаблон с переменными? Вложенные скобочки?

                  • raveclassic
                    /#10410376 / +1

                    {!isHidden && (
                      <ul>
                        {items.map((item, i) => (
                          <li key={i}>{item}</li>
                        )}
                      </ul>
                    )}

                    Вопрос не в синтаксисе (дело привычки), а в том, что можно и без директив интерфейс компоновать

                    • Andchir
                      /#10410420

                      Основная идея Ангуляр — это расширение возможностей HTML, сделать HTML динамическим.

                      HTML is great for declaring static documents, but it falters when we try to use it for declaring dynamic views in web-applications. AngularJS lets you extend HTML vocabulary for your application.

                      То, что вы предлагаете противоречит идеологии Ангуляр. Ну не нравится вам эта идея — ищите другое. Или критикуйте конкретно эту идею.
                      Вопрос не в синтаксисе (дело привычки), а в том, что можно и без директив интерфейс компоновать

                      По-моему вы критикуете именно синтаксис. Или вам не нравится название «директива»?

                      • raveclassic
                        /#10410954

                        Ну я и критикую идею Ангуляр и вместе с ним критикую HTML. Как бы тут все не начали на перебой доказывать, что HTML — суть веба, у меня со временем сложилось другое мнение: HTML — это огромный кусок легаси, который упал нам на хвост, и приходится его везде за собой таскать. Неудобный, устаревший, с кучей костылей.


                        Мне не нравится, что я добавляю примеси компоненту снаружи этого компонента. Я его натурально патчу добавлением какой-то неведомой ерунды через *directive. Я нарушаю инкапсуляцию компонента, тогда как все возможные примеси должны быть объявлены внутри компонента, и это нормально. Ненормальны все эти костыли с директивами, появившиеся (а изначально в первых RC ng2 их не было) из-за того, что местные компоненты не могли оборачивать другие без дополнительных dom-нод. Вот и портировали директивы из ng1.

                        • Druu
                          /#10410964 / +1

                          > Я нарушаю инкапсуляцию компонента, тогда как все возможные примеси должны быть объявлены внутри компонента, и это нормально.

                          Это как это? Примесь по определению должна быть внешней. Максимум — можно требовать, чтобы она применялась только в классам, реализующим определенны нинтерфейс. А «примеси, объявленные внутри компонента» — это уже явно не примеси, может, имелось виду что-то другое?

                          • raveclassic
                            /#10411012

                            Возможно, трейты больше подойдут?


                            EDIT: Ну, то есть, компонент должен быть конечной точкой описания всего его поведения. Различные комбинации этих поведений должны описываться в виде инпутов (флагов), а не солянкой из патчащих директив снаружи

                            • Druu
                              /#10411092

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

                              С таким подходом и НОС убрать придется :)

                              • raveclassic
                                /#10411104

                                С какой стати? :) HOC порождает новый компонент, директива — нет

                                • Druu
                                  /#10411110

                                  > HOC порождает новый компонент, директива — нет

                                  Это на самом деле лишь условность, пронаблюдать которую можно исключительно в определенных граничных условиях из-за особенностей реализации change detection :)

                                  А так вобщем-то никто не запрещает интерпретировать применение директивы как создание новой компоненты.

                                  • raveclassic
                                    /#10411116 / +1

                                    А, вы опять про свои "HOC" в ангуляре, я не их имел в виду :)


                                    Проблема в том, что порядок "применения" HOC (которые настоящие HOC, в Реакте) вы выбираете явно путем композиции, а директивы мешаются в общую кучку. И я кстати не знаю (честно) как разрешается в ng2 порядок применения директив. Вот в ng1 это сделано реально отвратительно, прям как z-index'ы.

                                    • Druu
                                      /#10411658 / +1

                                      > И я кстати не знаю (честно) как разрешается в ng2 порядок применения директив.

                                      Он решается тем способом, что в случае применения неструктурных директив напортачить затруднительно (то есть их применение «почти» коммутативно, или на это следует рассчитывать при их написании), а структурные директивы применяются только по одной к ноде.

                          • vintage
                            /#10411178

                            Да нет, примеси — это именно что изнутри. А снаружи — это плагины.

                            • Druu
                              /#10411660

                              Примесь — эта функция, которая класс приняла и другой класс вернула. Где тут «изнутри»?

                              • vintage
                                /#10411810

                                Вы сейчас описали не примесь, а декоратор. Да, декоратор можно использовать для "примешивания".


                                https://ru.wikipedia.org/wiki/Примесь_(программирование)

                                • Druu
                                  /#10412136

                                  > Вы сейчас описали не примесь, а декоратор.

                                  Это зависит уже конкретно от языка. Важно-то, что в любом случае везде примеси — внешние сущности. В вашем же примере из вики — примесь comparable ничего не знает о классе, к которому применяется, и действует на него «снаружи».

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

                                  • vintage
                                    /#10412378 / -1

                                    Яркий пример примеси:


                                    enum common_fields = "int row; int col;";
                                    
                                    class Person {
                                        mixin( common_fields );
                                        string name;
                                    }

                                    Сама по себе примесь разумеется внешняя сущность. Но примешивает её сама сущность (функция, класс, модуль), а не тот, кто эту сущность использует.

                                    • mayorovp
                                      /#10412398

                                      Это лишь одна из реализаций, причем наверняка еще и в языке со статической типизацией.

                                    • Druu
                                      /#10412692 / +1

                                      > Но примешивает её сама сущность (функция, класс, модуль), а не тот, кто эту сущность использует.

                                      Вы слишком большое внимание уделяете синтаксису (то, что строчка с миксином внутри определения класса), смотрите на семантику (да, к слову, в большинстве вариантов реализации миксин применяется на готовый класс явно, то есть и синтаксически «снаружи»). В вашем случае — миксин не внутри класса, к которому вы его применили. Он внутри класса-результата. А класс, к которому применен миксин — это class _Anonymous { string name; }

                                      • vintage
                                        /#10412714 / -1

                                        Думаю вам стоит отдохнуть и перечитать мой комментарий ещё раз :-)

                        • nohuhu
                          /#10413228

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

                          +100, и мало того: HTML вообще категорически не подходит для создания приложений. Это язык разметки документов, и сколько бы ни тужились W3C, таковым он и останется. Даже WebComponents ситуацию сильно не облегчат, это кривой костыль.


                          Впрочем, само русло таких мыслей уже крамола. Этак можно додуматься до страшных вещей, вроде написания приложений на чистом JavaScript и использования библиотеки компонентов, которая манипулирует HTML где-то под капотом.


                          Но постойте, где-то я это уже видел...

                          • raveclassic
                            /#10414742

                            Имеем, что имеем. GWT-like решения не приживаются.

                            • nohuhu
                              /#10415018

                              Пардон, при чём тут GWT? Я говорил о написании приложений на чистом JavaScript, а не Java.

                              • raveclassic
                                /#10415022

                                Да я понимаю, просто чуть дальше подумал. Кроме HTML у нас ничего нет. Только JS, ворочающий HTML под капотом, который вы "где-то уже видели" :)

                                • nohuhu
                                  /#10415106

                                  Кроме HTML у нас есть DOM API, которое никто не мешает использовать напрямую. Генерации HTML можно избежать практически на 100%.


                                  А речь идёт о том, что вы как разработчик приложений можете просто писать код JavaScript, который просто исполняется в браузере напрямую, в том же виде, в каком вы его написали. Вы создаёте объекты с конфигурацией, дёргаете методы, реагируете на события, и т.д. Что там происходит с DOM вас не волнует, для этого есть специально обученные белки, знающие всю эту дребедень в деталях.


                                  Насчёт "не приживаются" как бы могу поспорить. Коммерческие решения, приносящие многомиллионные выручки каждый год, чуточку противоречат гладкой картине мироустройства.

                                  • raveclassic
                                    /#10415272 / +1

                                    DOM API

                                    угу, такое же неповоротливое легаси, не знаю даже что хуже


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

                                    Могу, но не пишу, ибо я не мазахист и предпочитаю хоть какие-то абстракции.


                                    Что там происходит с DOM вас не волнует, для этого есть специально обученные белки, знающие всю эту дребедень в деталях.

                                    Ну вот вы и описали этот необходимый слой.


                                    Насчёт "не приживаются" как бы могу поспорить.

                                    Насчет "не приживаются" я имел в виду DX, а не продажи. Продажникам вообще похрен, какой длины иголки себе под ногти загоняет разработка, лишь бы затраты на эти иголки были не слишком высоки...

                                    • nohuhu
                                      /#10415434

                                      угу, такое же неповоротливое легаси, не знаю даже что хуже

                                      А вы пробовали его по-настоящему вдумчиво курить? Я пробовал, и оно не такое плохое, как кажется на первый взгляд. Тем более, когда выбора нет. /s


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

                                      Так за чем дело стало? :)


                                      Насчет "не приживаются" я имел в виду DX, а не продажи.

                                      Не знаком с термином. Что означает DX?


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

                                      В нашем случае это ровно наоборот: продажники почти отсутствуют, продукт продаёт сам себя, а процессом рулит инженерия. Не могу сказать, что сам считаю такой подход оптимальным, но порулить мне никто не даёт. Только гайки крутить. :(

                                      • raveclassic
                                        /#10415994

                                        Тем более, когда выбора нет.

                                        Когда выбора нет, все кажется неплохим


                                        Так за чем дело стало?

                                        По-разному, есть проекты на реакте, есть на разных ангулярах.


                                        DX

                                        Developer Experience. Это как UX, только DX.

                    • babylon
                      /#10411548 / +1

                      Вопрос не в синтаксисе (дело привычки), а в том, что можно и без директив интерфейс компоновать

                      Нужно! Именованные скобки (они же теги) должны быть частью выражения.

                • Druu
                  /#10410626 / +2

                  А в чем, собственно, разница? *ngIf же не базовая директива, она реализована поверх фреймворка, а не вшита в него.

                  • raveclassic
                    /#10410956

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

                • movl
                  /#10411218 / +1

                  Очень доставляли подобные шаблоны в Spacebars. Точнее там их юзал в связке с Jade (на тот момент еще), в нем все эти циклы, условия, интерполяция переменных, подстановка компонентов и т. д. вообще выглядели нативно, что мне казалось проявлением чего-то божественного. Типа не может же быть такого, что прочитав 2 страницы документации по jade и еще немного по Blaze, потратив от силы пару часов, можно начинать делать интерфейс, разбивая все на компоненты, и все без боли и страданий, и сразу получая работающий код, с хорошей декомпозицией, и делая все максимально наивным способом.


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

  9. nbelyh
    /#10409204

    Хочу дополнить по поводу библиотек, основанных на bootstrap, в частности, ngx-bootstrap (она же ng2-bootstrap), ng2-select, от valor-software. Увы и ах, хотя и самые распространенные, с продуманностью и глючностью у них есть проблемы, особенно у select2, который выглядит довольно заброшенным. Но бог с ним, с select2, даже modal в виде сервиса появился только этим летом, и то без resolve (без передачи параметров в конструктор). Некоторые глючные стили теперь “вморожены“ и не фиксятся без !important..


    Как альтернатива для bootstrap, еще появилась (imho) более вменяемая ng-bootstrap, от тех людей кто писал angular-ui для angular-js, но там только ещё не выпущенный bootstrap4, и тоже альфа-беты.


    За инфу про VMware спасибо!

    • hardex
      /#10409280

      Эм, в ngx-bootstrap сервис NgbModal был с давних времен, а resolve не нужен — инпуты проставляются через modalRef.componentInstance

      • nbelyh
        /#10409312

        Скорее всего ты говоришь про ng-bootstrap (это другая библиотека, на bootstap 4 альфа — у меня она упоминается во втором абзаце). В ngX-bootstrap добавлен сервис был пару месяцев назад:
        https://github.com/valor-software/ngx-bootstrap/pull/2047

  10. diproart
    /#10409206

    Ссылка на element в статье не работает, element на GitHub.

    • MooooM
      /#10410746 / +1

      Исправлено, спасибо.

  11. symbix
    /#10409212

    С ручными импортами в rxjs — это проблема неработающего в случае с прототипами/объектами/псевдо-неймспейсами tree shaking, по сути временная. Когда-нибудь ее решат, и можно будет импортировать весь Rx, не беспокоясь о размере билда. Конечно, было бы хорошо уметь ругаться на этапе компиляции — но если до такого умения дошли, то можно и tree shaking сразу сделать.

  12. 0x1000000
    /#10409222

    C претензиями к Roter, HttpClient и Forms я соглашусь, но к плюсам ангуляра можно отнести относительную модульность и как результат возможность не использовать эти модули, что мы благополучно и делаем на нашем проекте — у нас свой роутер, свой http клиент и свои Dynamic Forms. Причины почему, так вышло были разные и я не агитирую поступать так же, но, тем не менее, возможность заменить не базовые модули ангуляра есть, если стандартные чем-то не устраивают.

    • MooooM
      /#10409322 / +5

      Раньше я тоже считал, что модульность Angular — большой плюс для Lazy Loading'а. Но задумайтесь — весь минифицированный Vue.js весит 60Кб. Спрашивается, а стоит ли весь этот boilerplate с модулями того?

      • 0x1000000
        /#10409338

        Я имел в виду, что с архитектурной точки зрения основа Ангуляра не привязана к отдельным его модулям и он не принуждает их использовать. Ничто не мешает делать запросы через, например, jQuery или fetch.

  13. vintage
    /#10409226 / -12

    Не смотрели ли вы в сторону $mol, который целиком и полностью написан на TypeScript?


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

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


    В целом не совсем разделяю взгяд автора на RxJS, т.к. библиотека невероятно мощная.

    Но и невероятно неэффективная.


    Но суровая правда в том, что Object.observe нативно мы все же не увидим

    Какое отношение имеет RxJS к Object.observe?


    Потому что вы очевидно (потратили кучу времени на поиск проблемы) забыли заимпортировать сам оператор

    В $mol такой проблемы в принципе нет, так как зависимости подключаются автоматически по факту их использования.


    Теперь для работы с параметрами предлагается подписываться на события роутера.

    Зачем вообще какой-то там роутер, если можно просто прочитать реактивное значение?


    pages() {
        return [
            this.Menu() ,
            ... this.$.$mol_state_arg.value( 'order' ) ? [ this.Order() ] : [] ,
        ]
    }

    в Angular есть два типа форм: обычные и реактивные.

    В $mol всё реактивное и кастомизируемое. У компонент есть свойства, в которые он может писать и из которых читать. В простейшем случае:


    value( next = '' ) { return next } 

    А владелец уже может одно-/дву-сторонне связать его с любым другим по любой хитрой формуле.


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

    От той metadata, что генерирует TS пользы не особо много: никаких интерфейсов, только ссылка на класс. А вот сами по себе декораторы позволяют уменьшить копипаст.


    Dependency Injection в Angular. Сама по себе концепция замечательная, особенно для unit тестирования.

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


    this.$.alert( 'Hello!' )

    Где $ — по умолчанию — глобальный контекст. Но любой компонент в дереве рендеринга может изменить контекст для всех вложенных в него на любую глубину компонент:


    @ $mol_mem()
    context_sub( ) {
        const context = this.context()
        const subContext : $mol_view_context = Object.create( context )
        subContext.alert = ( message ; string )=> this.$.$my_dialogs.alert( message )
        return subContext
    }

    Всё, теперь вложенные компоненты, ничего не зная ни про какой DI, не системный алерт вызывают, а тот, который задали мы, а TS, разумеется, проверяет соответствие сигнатур. Аналогично можно не только функции дёргать/переопределять, но и любые другие сущности: переменные, классы, объекты.


    А вот пример компонента из проекта на Angular:

    Заголовок спойлера
    import {Component} from '@angular/core';
    
    import FileService, {ContentType, IFile} from "../file.service";
    import AlertService from "shared/alert.service";
    
    @Component({
      selector: 'app-file',
      templateUrl: './file.component.html',
      styleUrls: ['./file.component.scss']
    })
    export class FileComponent {
    
        Input() item: IFile;
    
        constructor(private fileService: FileService, private alertService: AlertService) {
        }
    
        public isVideo() {
            return this.item.contentKeyType === ContentType.VIDEO;
        }
    
        public downloadFile() {
            this.fileService.download(this.getFileDownloadUrl()).subscribe(() => {
                this.alertService.success();
            });
        }
    
        private getFileDownloadUrl() {
            return `url-for-download${this.item.text}`;
        }
    }

    • MooooM
      /#10409344 / +8

      Касательно $mol — уже видел ваши комментарии про него ранее, но боюсь размеры community слишком малы, чтобы избрать его для серьезного enterprise приложения. А pet проекты и на Vue делаются супер быстро (опять же размеры community и простота/быстродействие).

      А про упавший билд Clarity — спасибо за юнит тесты, которые действительно что-то проверяют (уверен, что пофиксят в ближайшее время).

      • vintage
        /#10409358 / -8

        А pet проекты и на Vue делаются супер быстро

        На $mol ещё быстрее.


        размеры community

        Какая польза от размера комьюнити? Большой выбор велосипедов? Большой выбор экспертов на SO?


        простота/быстродействие

        $mol ещё проще, модульнее и с глубокой поддержкой ленивого рендеринга.


        упавший билд Clarity — спасибо за юнит тесты, которые действительно что-то проверяют

        Не просто упавший билд, а сломанная мастер ветка со всеми вытекающими.

        • staticlab
          /#10409998 / +3

          Какая польза от размера комьюнити? Большой выбор велосипедов? Большой выбор экспертов на SO?

          Хотя бы, чтобы можно было задать вопрос, и на него ответили адекватно, а не:


          — Рискну предположить, что заодно и без автокомплита и перехода к определению по Cmd+Click.
          — Да нет, всё работает благодаря тайпскрипту.
          — А тайпскрипт как работает без импортов/экспортов?
          — Как положено он работает.

          • vintage
            /#10410068

            А какой более адекватный ответ тут может быть? Вы делаете необоснованные предположения — вам отвечают, что вы не правы. Проверить можете сами, если не верите.

            • staticlab
              /#10410096 / +1

              А причём тут правильность или неправильность? Второй комментатор спросил о том, как отсутствие импорта позволяет IDE перейти к месту определения сущности, вы объяснить не потрудились. Видите, вы и мне предложили бросить всё, развернуть ваш фреймворк и проверить.

              • vintage
                /#10410104

                А как думаете IDE справлялись с ES5, где никаких импортов не было? Сканировали весь проект и всё.

                • staticlab
                  /#10410122

                  А как думаете IDE справлялись с ES5, где никаких импортов не было? Сканировали весь проект и всё.

                  По личному опыту знаю, что очень плохо справлялись. И даже с ES6 плохо справляются в сложном проекте.

                  • vintage
                    /#10410144

                    А c TypeScript отлично и единообразно справляются благодаря Language Services.

                    • staticlab
                      /#10410234

                      Language Services тоже может корректно отрезолвить класс, не импортированный явно?

                      • vintage
                        /#10410262

                        Разумеется, он же обратно совместим с JS.

    • justboris
      /#10409362 / +14

      Да вы с комментариями про $mol уже стали прямо-таки локальным мемом

    • MikailBag
      /#10409478 / +3

      Зачем так много долларов?

      • vintage
        /#10409522

        Вы не любите доллары?

        • babylon
          /#10409656 / +1

          $ вероятно сигнализирует о глобальных планах экспансии продукта, но пока его за trees не видно :))))

  14. mjr27
    /#10409232 / +2

    Что хочу сказать после того, как команда довела до релиза средненького размера проект (SPA, ~40k sloc ): выбором angular довольны.


    Batteries included в широком смысле слова — от инфраструктуры (ng-cli великолепен) до заданной структуры проекта и навязываемой декомпозиции. Сторонних модулей уже (местами) достаточно много.


    Typescript и aot сильно снижают количество регресионных факапов. Спорно (а мне спорить лень), но за годы знакомства с typescript'ом у меня все сильнее растет удивление, что кто-то еще пишет на голом js.


    А главное — практически ни разу ни у кого из команды не возникло чувства "я сражаюсь с фреймворком". Не возникло чувство, что он ограничивает; что есть вещи, которые на vanilla.js были бы проще.


    В плане UI еще в статье забыли @angular-mdl — местами сырая, но очень приятная библиотека.


    Основные минусы (ну куда же без них?):


    • О документации проще сказать что ее не существует. То, что есть — плевок в лицо.
    • Более отвратительной системы роутинга я еще не встречал. Надеюсь, ее сожгут и сделают заново.
    • За организованный репозиторий модулей отдал бы левую ногу

    В целом: для больших SPA пока что иных вариантов не видим. А для мелочи (особенно fire-and-forget мелочи) vue уже очень сильно начитает тащить своим минимальным размером

    • osiykm
      /#10409876 / +1

      А в чем проблема роутинга? Только начал разбирать angular и хочеться узнать про эту проблему подробнее?

      • hardex
        /#10410148

        Скорее всего mjr27 имеет в виду params и queryParams, которые Observable. С другой стороны, они позволяют при смене роута на тот же компонент, но с другими params, обновлять его, не пересоздавая.
        Кроме того, нет нормальных именованных роутов и тупая сигнатура Router#navigate

        • Druu
          /#10410180

          > Кроме того, нет нормальных именованных роутов

          А что подразумевается под «нормальными именованными роутами»?

          • nbelyh
            /#10410242

            Назначение путям имен, например orders => '/items/:xx'. Типк как сделано в ui-router например, или vue-router. Чтобы например можно было поменять путь, не меняя код везде, где этот путь используется. То есть, чтобы можно было например изменить'/items/:xx' на '/foo/orders:xx' не делая поиск-замену по всему проекту.

            • Druu
              /#10410642 / +1

              > Назначение путям имен, например orders => '/items/:xx'.

              const paths = {
                  path: "my/patch",
                  anotherPatch: "another/patch",
                  oneMorePatch: "one/more/patch",
              }
              
              const appRoutes: Routes = [
                  { path: paths.path, component: MyComponent },
                  { path: paths.anotherPatch, component: AnotherComponent },
              ...
              ];
              

              так? или что еще должно быть?

              • mjr27
                /#10411390

                Вот такое должно быть. Без этого грустно


                const appRoutes: Routes = [
                    { path: "language/:lang/category/:category/item/:item", component: MyComponent , name: "itemView" },
                ];
                
                // ...
                
                const url: string = this.router.reverse("itemView",  {lang: this.lang, category: this.categoryId, item: item});

                А в идеале даже


                /* Привет из django */
                 {path: "language/(?P<lang>\s{2,3})/category/(?P<category>\w+)/item/(?P<item>\d+)", component: MyComponent , name: "itemView" }
                

                • Druu
                  /#10411666

                  Ну это все пишется за полчаса. Потому и убрали. Нужен такой функционал достаточно редко, а реализуется — элементарно, причем в том виде, в котором будет нужен в данном конкретном случае.

                  • mjr27
                    /#10412238 / +1

                    Ну это все пишется за полчаса

                    Явно не за полчаса + странный аргумент для "batteries included" фреймворка.


                    Нужен такой функционал достаточно редко

                    Необоснованное предположение. Нам такой функционал был не нужен достаточно редко; обработка валидности входных параметров в контроллере же (как предполагается самим фреймворком) — явное смешивание полномочий.


                    В том виде, в котором будет нужен в данном конкретном случае

                    В самом общем случае урл выглядит как "...[var1:format]...[var2:format]...[var3:format]..." Зачем было искусственно это ограничивать — я так и не понял

                    • Druu
                      /#10412706

                      > Явно не за полчаса + странный аргумент для «batteries included» фреймворка.

                      «batteries included» никогда не означало наличие редко нужного функционала, вопрос реализации которого — сотня строк кода.

                      > обработка валидности входных параметров в контроллере же (как предполагается самим фреймворком) — явное смешивание полномочий.

                      Это правильно, валидность надо проверять в роутере. В ангуляре специально для этого есть canActivate гварды. При этом проверять можно не только формат синтаксиса, а выполнение любых условий. Например, роут foo/:id при несуществующем в базе айдишнике столь же невалиден, сколь и роут с неправильным синтаксисом.

                      > В самом общем случае урл выглядит как "...[var1:format]...[var2:format]...[var3:format]..." Зачем было искусственно это ограничивать — я так и не понял

                      Ваш «общий случай» не учитывает синтаксиса аргументов и именованных аутлетов (как раз тот функционал, который «на коленке» не напишешь), а потому просто не работает.

                      • mjr27
                        /#10412924

                        редко нужного функционала

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


                        canActivate гварды

                        К сожалению, не панацея. Я хочу проверку ссылки в момент ее генерации (о проверке в compile-time я уже не говорю).


                        Или хоть что-либо отличное от каши any[] в [routerLink]


                        роут foo/:id при несуществующем в базе айдишнике столь же невалиден, сколь и роут с неправильным синтаксисом

                        Сильное утверждение. Навскидку


                        https://twitter.com/hashtag/++++++++++
                        https://twitter.com/hashtag/llllllllll3llllllll


                        Ваш «общий случай» не учитывает синтаксиса аргументов и именованных аутлетов

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


                        Данный способ как раз расширяем (e.g "/category-{id}{aux:/item-{id}}"), в отличии от встроенного "вот вам url.split('/'), радуйтесь"


                        P.S: Вообще, думаю, спор на самом деле ни о чем. Вам стандартной схемы хватает, мне однозначно нет. Так что буду плакаться, колоться, и делать велосипед. Спасибо за интересную дискуссию.


                        /off

                        • Druu
                          /#10412954

                          > Или хоть что-либо отличное от каши any[] в [routerLink]

                          Роут нельзя типизировать, потому что это по определению — просто строка. К слову, все ваши предложения с "/category-{id}{aux:/item-{id}}" сразу блокируют в роутерлинке что-либо кроме any[].

                          > К сожалению, не панацея. Я хочу проверку ссылки в момент ее генерации (о проверке в compile-time я уже не говорю).

                          Кто мешает?

                          > Данный способ как раз расширяем (e.g "/category-{id}{aux:/item-{id}}"),

                          А чем вас, собственно, не устраивает /category;id={id}? тем, что ";" вместо "-"?

                          • mjr27
                            /#10413004 / +1

                            Вообще не понял аргумента. Строку нельзя превратить в типизированную структуру? JSON.parse негодует.


                            RouterTypeService.register("int", /\d+/, (val) => typeof val === "number", parseInt, x=>x.toString());
                            RouterTypeService.register("uuid", /[a-f0-9]{32}/, parseUuid, x=>x.toString());
                            {path: "/category-{id:int}{aux:/item-{itemId:uuid}", name: 'test'}


                            this.router.navigate('test, {id: 10, aux: {itemId: 'aa...00'}});


                            Кто мешает

                            Вообще не понял вопроса, если честно.


                            (new UrlBuilderService()).makeCategoryUrl(id, itemId)?


                            А чем вас, собственно, не устраивает /category;id={id}? тем, что ";" вместо "-"?

                            Если коротко — да хотя бы тем, что я хочу именно так а не иначе. Достаточная причина? Система маршрутизации, под которую приходится подстраиваться, веет 2001м годом а-ля category.php?id[]=12&id[]=13


                            Конкретно в текущем проекте у нас полу-статический контентный сайт с давней историей и кучей трафика по прямым ссылкам и букмаркам (да, такое еще существует). И этот сайт по нажатию кнопки "сделать п… то" превращается в современное spa.


                            И я хочу чтобы у ангулара были точно такие же ссылки, какие были уже второй десяток лет.


                            Я много фреймворков перевидал, но пока что это первый в котором, когда настолько примитивная функция сделана настолько "для галочки".

                            • Druu
                              /#10413236

                              > Вообще не понял аргумента. Строку нельзя превратить в типизированную структуру? JSON.parse негодует.

                              И какой тип аргумента navigate у вашего примера? И как его выразить в рамках системы типов ТС?

                              > Вообще не понял вопроса, если честно.

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

                              • mjr27
                                /#10413464

                                как его выразить в рамках системы типов ТС
                                да хоть public navigate<T>(route: string, params: T, options: RequestOptions>. Довести до абсолюта public navigate<T>(params: T, options: RequestOptions> по очевидным причинам не получится.

                                У вас есть ф-я, которая генерит роуты, в чем проблема проверять роут в ней?

                                Два контраргумента:


                                1. Зачем бить "туда" и "обратно" на два разных куска, если это всё можно задать 1 раз декларативно?
                                2. А где должна быть эта функция? Вижу 4 варианта:
                                  • Отправляющий компонент (где создается URL): привет, копипаста; структурно неверно
                                  • Принимающий компонент (куда ведет URL): как достучаться? что если компонент по нескольким схемам URL доступен? Что с использованием в других проектах?
                                  • функция: привет от DI и тестов
                                  • сервис/injectable: ну вроде сильных контраргументов нет

                                А теперь вопрос — зачем мне сервис маршрутизации, когда у меня уже есть сервис маршрутизации?


                                UPD: изменил, парсер съел угловые скобки

                                • Druu
                                  /#10413486 / +1

                                  > да хоть public navigate

                                  И кто помешает мне вызывать navigate(route, anyObject) с anyObject, неподходящим под сигнатуру роута route? Какой толк от типа, который ничего не фиксирует?

                                  > Зачем бить «туда» и «обратно» на два разных куска, если это всё можно задать 1 раз декларативно?

                                  Что бить?

                                  > А где должна быть эта функция?

                                  Там, где вы описываете роут, очевидно.

                                  • mjr27
                                    /#10413636

                                    кто помешает мне вызывать

                                    navigate<T>(route, anyObject), парсер лох


                                    Там, где вы описываете роут, очевидно.

                                    А где я описываю роут, например, в случае lazyLoad? В каком из двух файлов?

                                    • Druu
                                      /#10413812 / +1

                                      > navigate(route, anyObject), парсер лох

                                      Ответ на вопрос-то где? Вот я пишу navigate(route, anyObject), все прекрасно тайпчекается. В чем смысл такого ограничения на типы?

                                      > А где я описываю роут, например, в случае lazyLoad? В каком из двух файлов?

                                      В каком вам удобно, в таком и описывайте.

                                      • mjr27
                                        /#10414282

                                        В тайпскрипте? От navigate<IItemParams>(route, <any>anyObject)? Никто не помешает, ясен перец. Но в первом же кодревью за это накажут.


                                        В каком вам удобно, в таком и описывайте.
                                        Отличный ответ. Лично мне ни в каком не удобно.

                                        Честно, не понимаю о чем разговор. Вас устраивает — пользуйтесь на здоровье. Меня нет, по длинному списку озвученных выше причин. От продолжения спора для меня ничего не изменится, так что удаляюсь.

                                        • Druu
                                          /#10414294 / +1

                                          > От navigate(route, anyObject)? Никто не помешает, ясен перец.

                                          А, так вы тип генерика руками записывать собираетесь? я сразу просто это не понял. Непонятно, чем тогда не устраивает вариант navigate(routeFrom(route, params)).

                                          > Отличный ответ. Лично мне ни в каком не удобно.

                                          Непонятно тогда, зачем вы требуете функционал, который вам будет неудобен.

            • indestructable
              /#10413112 / +1

              Это исчезает из многих роутеров, например, из последнего react-router.


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


              Однако, отсутствие opt-out статического именованного роутинга реально напрягает, сейчас он нужен в 90% случаев.

      • mjr27
        /#10410872

        Да в нем плохо все.


        • негибкость: урлов типа /[id:\d+]-[section:\w+]-[name:\w+].html существовать не может
        • да, отсутствие именованных роутов. Собирать везде ссылки типа ['/content', language, 'section', book] — отдельное удовольствие. А менять еще более отдельное
        • Бажный lazy routing. Создать несколько аутлетов в корневой компоненте модуля нельзя еще с 2 RC1
        • Цирк при попытках достучаться до параметров родителя (например где-то там наверху есть параметр lang)

        Такое чувство, что авторы Router'а живут в мире, где все урлы выглядят как /about или /hero/:id и какают бабочками

  15. ruslangavrilov
    /#10409376

    Я честно говоря не понимаю, зачем использовать непопулярные библиотеки которые не востребованы на рынке когда есть React + Redux? Это просто как минимум не практично на мой взгляд. Причем даже если закрыть глаза на востребованность, то я не вижу никаких значительных преимуществ Vue перед тем же React.
    Количество вакансий на hh:
    1) Angular 1541
    2) React 1511
    3) Vue 282

    • MooooM
      /#10409390 / +5

      На сегодняшний день это действительно основной минус Vue, если для вас наиболее важно скорое трудоустройство. Но ведь и React когда-то был в таком же статусе? Однако темпы роста популярности Vue.js гораздо выше.

    • serf
      /#10409400

      Вероятно в этой выборке нет разделения на AngularJS и Angular, то есть основная часть уходит к AngularJS.

    • nbelyh
      /#10409430 / +1

      Причиной востребованности иногда может быть вовсе не дизайн библиотеки, а размер компании, стоящей за ней. Бизнес хочет быть уверен что технология, в которую он вкладывается, не исчезнет через пару лет. Отсюда и количество вакансий. То же правило что и у телевизора — кто в эфире, тот и прав. Angular/React соответственно Google/Facebook. Правда у «хипстеров» Гугла в этом плане с кредитом доверия уже есть некоторые проблемы, после того как они всех «доверившихся» прокатили с Angular2, сделав несовместимым с Angualr1.
      А Vue по виду получается простая и удобная — может протоптать себе дорогу из без «катков» в виде мега-корпораций.

      • ruslangavrilov
        /#10409482 / -3

        Сможет ли Vue протоптать себе дорогу покажет только время… а пока… имеем то, что имеем. Лично я сильно сомневаюсь что Vue долго продержится в такой жесткой конкуренции… но это пока что только моё объективное мнение.

        • Skerrigan
          /#10409694 / +8

          Выше говорят, что за vue.js стоит Alibaba. А это «бездонный океан» бюджета и специалистов. Так что «каток даже не паровой, атомный».

          • mnv
            /#10411282 / +1

            Теперь по умолчанию в связке с Vue поставляется небезызвестный Laravel. Это тоже должно повлиять на популярность Vue в том числе и на hh.

    • TheShock
      /#10409702

      Например, потому что Редакс — отвратительная процедурная быдлокодерская поделка, поощряющая копипасту и плохой код, плохо типизируется статически, библиотечные компоненты делают дерево данных кривым, код редюсеров растет как на дрожжах, из-за чего сложность поддержки растет значительно быстрее, чем у более адекватных вещей, а как следствие — на нем крайне сложно поддерживать продукт в длинносрочной перспективе. Плюс у него еще иллюзия простоты, а на самом деле крутая кривая обучения, Как результат — код устаревает с ростом навыка команды слишком быстро, а из-за недо-фп и отрицания хипстерами типизации сложно адаптировать старый код в новом стиле. Я еще, если честно, никогда не видел адекватных юнит-тестов в проектах с ним, но, может кто-то сможет мне такие показать

      • raveclassic
        /#10409710 / +2

        Ну вот опять вы все о том же :)


        Отвратительная — возможно; процедурная — вряд ли; быдлокодерская — стопроцентно; копипаста — вряд ли; плохой код — это какой?; плохо типизируется — отлично типизируется; компоненты делают дерево данных кривым — вряд ли, инкапсуляция ж; код редьюсеров растет — может они не тем занимаются?; сложность поддержки растет — вряд ли; адекватных вещей — это каких?; крайне сложно поддерживать — поддерживаем и норм; иллюзия простоты и кривая обучения — да, наверное; код устаревает — вряд ли; недо-фп — стопроцентно; хипстеры и типизация — стопроцентно; юнит тесты неадекватны — а что с ними не так?


        Кстати, по поводу недо-фп. Я тут играюсь немного, переписал стор под сигнатуру редьюсеров Action -> State -> State вместо стандартной (State, Action) -> State — стало значительно удобней, особенно с интеграцией той же ramda. Вместо объектов теперь оперируем преобразованиями.

        • TheShock
          /#10409726 / +2

          1. Ну не могу я спокойно раз за разом читать комментарии вроде "давайте все переходить на редакс", уж простите.
          2. Процедурная — 100%, смотрим исходники: https://github.com/reactjs/redux/blob/master/src/createStore.js
          3. Типизация: покажите мне пример, где я из стора достаю данные, передаю в компонент через connect и оно проверяет типизацию в компайл-тайм. И вообще — я бы с удовольствием посмотрел на типизированный стор. Или как вы ваш action=>state=>state типизируете?
          4. Код редюсеров растет за счет количества похожих редюсеров, а не за счет увеличения ответственности редюсеров
          5. Вот только инкапсуляция протекает, если такие компоненты необходимо расширять
          6. Я не видел тестов, которые проверяют реальную логику работы. Те тесты которые я видел — бесполезны. Я грешу на недо-фп и болезненную боязнь абстракций, в результате функции становится сложно тестировать. Все-таки простой объект легче покрыть тестами, чем функцию, которая возвращает функцию, которая возвращает функцию.
          7. Мне сейчас очень нравится MobX. В сравнении с редаксом — как на мерс после жигулей пересел. Значительно ниже порог входа — всего три ключевых слова, которые необходимо понять, однонаправленный поток как основное преимущество флакса и никаких недостатков редакса. Код выглядит понятным, легко поддерживается, быстро работает. Один человек может писать слой MobX (модель), выдавать вменяемый и понятный API, а другой использует этот слой в Реакт-слое (view)

          • serf
            /#10409736

            > И вообще — я бы с удовольствием посмотрел на типизированный стор.

            без проблем делается, вот например github.com/ngrx/platform/tree/master/example-app/app,

            > Значительно ниже порог входа

            Редакс ведь тот же паб/саб, то есть порог вхождения не особо высок, но вот код дофига писать это да, загроможденно получается. MobX как раз в связке с React вроде как значительно уменьшает количество шаблонного кода.

            • TheShock
              /#10409742 / +1

              1. Простите, а вы уверены, что это Редакс, а не что-то похожее? Я не зря упомянул не только дерево (которое типизировать несложно, хоть и не очень красиво), но и connect (функция редакса) с компонентом


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

              • serf
                /#10410044

                1. вот первое что нагуглилось spin.atomicobject.com/2017/04/20/typesafe-container-components Хз это ли имеется ввиду, react-connect никогда не использовал.
                2. мне тоже МобХ нравится, и по сути подобная риактивность уже встроена в VueJS.

              • VasilioRuzanni
                /#10410170

                И еще более чем достойная альтернатива: github.com/FormidableLabs/freactal

                Вообще, тренд к «фрактальному стейту» идет — Freactal, Mobx State-Tree, cycle-onionify, Elm Architecture.

          • raveclassic
            /#10410298

            1. Ну да, обсуждали уже
            2. Ммм, но интерфейс-то функциональный, какая разница какая реализация
            3. А неее, это уже react-redux, и там действительно проблемы, потому как TS не может вывести тип возвращаемого значения mapStateToProps и, как следствие, вырезать полученные ключи из пропсов оборачиваемого компонента. Хотя, если ему явно их указать в тайп-аргументе, то все заработает. Кстати, мне-таки удалось заставить вырезаться эти пропсы но только для случаев передаваемого объекта, а не фукнции
              Так, что Action -> State -> State не приносит типизацию в стор, так как там она уже есть, а лишь позволяет писать редьюсеры без упоминания state. Тут корректнее даже запись Action -> (State -> State). В комбинации с линзами просто удобнее возвращать из редьюсера скомпоуженые функции-сеттеры. Следующим шагом хочется попробовать собрать стор чисто из линз, чтобы иметь прямой доступ к ноде в стейте без всяких этих реселектов, дабы не дублировать композицию на чтение и на запись.
            4. Вы про одинаковые редьюсеры под сущности? Ну можно же их и в абстракцию сунуть.
            5. Не, не протекает, если принимать внутренние компоненты через своего рода DI (через контекст), оставляя в defaultProps стандартную реализацию, на которую ссылается модуль. Таким образом можно в сторонке собрать дерево компонентов, а потом через DI подменить нужные компоненты их контейнерами. Инжектор такой собирается на коленке, только вместо мэпа лучше держать какую-нибудь минимально простую реализацию стрима (та же most.js), чтобы работал shouldComponentUpdate.
            6. Если внутри редьюсеров сидит какая-нибудь гадость из серии thunk и promise, то да, это боль. Если же нет, то все вроде бы достаточно удобно.
            7. Что-то он все не заходит у меня никак… Надо наверное, еще один поход организовать

            • TheShock
              /#10410490 / +1

              3) А разве есть альтернативные реализации без этих проблем? Какой смысл обсуждать редакс без контекста связи с реактом? Зачем вся эта головная боль, Если в МобХ все работает легче и нативно?
              4) "Абстракции — зло", все такое.
              5) И сколько либ под редакс позволяют это делать?)
              6) Ну Тханк помоднее тех же саг будет. Какова вероятность, что придя в новую фирму вы там увидите одну или другую надстройку?
              7) Могу через пару дней в личку описать, как мы МобХ готовим, если интересно, может зацепит.

              • staticlab
                /#10410558 / +3

                Могу через пару дней в личку описать, как мы МобХ готовим, если интересно, может зацепит.

                Может, статью?

              • gnaeus
                /#10410610

                Да, давайте статью! Вроде про MobX давно ничего не было. А все что было — на уровне tutorial для начинающих.

                Сам давно к нему присматриваюсь, но никак не удается пробить стену недоверия остальных членов команды :(

                В отличие от Redux, он подкупает своей интуитивностью, и низким порогом входа. И мне, как фуллстеку, проще заходит ООП с SOLID и вот этим всем. Хоть это сейчас и не модно. Также, с ним гораздо удобнее группировать код по фичам, а не по архитектурным слоям.

                А еще, он позволяет хранить presentational state в обычных observable-свойствах компонента. Вместо использования this.setState(...), который ограничен «плоским» объектом, и работает неинтуитивно из-за «отложенного применения».

            • TheShock
              /#10410532 / +1

              Забыл 2) ну dispatch в компонентах с агрессивными сайд-эффектами — тоже обычная процедурщина.

              • raveclassic
                /#10410988

                2) ох, не буду спорить, окей :) в любом случае, я не вижу каких-либо проблем с этим, стор все-равно один, и диспатч к нему один, и спускается он в контейнер в виде зависимости "снаружи", вроде норм
                3) Ну редакс позиционируется отдельно от реакта, и, в принципе, идея мне очень по душе. Вон и в ангуляр портировали, и во вью используют (зачем-то)
                4) Мы же все-равно все их используем
                5) Либ нет, ибо никому (да-да хипстерам) это не нужно. Но я не зря написал, что реализация пишется на коленке. Простейший HOC.
                6) Моднее не моднее, не знаю, не пью смузи гоняюсь за модностью. Танки удобны на туду-листах, шаг чуть дальше и вариантов 2 — саги и обзерваблы.
                7) Может и зацепит, давайте. Но я уже потерян для общества, у меня уже выработалась патологическое отвращение к мутабельности :) Именно отсюда все эти линзы, призмы и ко. Ну а лучше, действительно, статью, прямо с полевой кухни.

                • Druu
                  /#10411106

                  > и обзерваблы

                  Хочу фреймворк, в котором весь стейт (и с внешними сервисами, и с эвентами, и с домом) будет представлен в виде большого обсервабла, а любая компонента, с-но — просто map на нем, который из кусков этого обсервабла эмитит другие обсерваблы и вливает их обратно в общий.

                  • raveclassic
                    /#10411128

                    Выглядит неплохо. Но если вы собрались мапить стейт в UI, то стейт должен отражать иерархию интерфейса, что не очень. Если же у интерфейса своя компоновка то нужны селекторы, и мы получаем redux + reselect. Только стор в виде стрима "на scan'е".

                    • raveclassic
                      /#10411152

                      То есть получаем ngrx + reselect, а это уже где-то было...

                    • Druu
                      /#10411682 / -1

                      > то стейт должен отражать иерархию интерфейса, что не очень.

                      Иерархию должен поддерживать «локальный» стейт. Вообще же суть идеи в том, что главная проблема современных фреймворков — разная модель работы с разными стейтами. Есть дом (вдом), есть локальный стейт (внутренний стейт компоненты), есть глобальный стейт (например, в виде редакса), есть эвенты, есть lifecycle-коллбеки компонент, есть роутер. И для всего для этого какие-то свои способы работы, которые по-разному реагируют на разные вещи. Хорошо видно, допустим, на примере ангуляра — вот у нас есть инпуты, когда вы поменяли инпут, то при чендж детекшоне все, что было в шаблоне с этим инпутом, обновится, то есть дом перестраивается за инпутами. А вот внутренний стейт компоненты — не перестраивается.
                      Или в реакте — компонент представляет ф-ю из локального стейта в вдом-стейт, но эвенты не входят в локальный стейт, по-этому мы не можем написать просто ф-и стейт -> стейт (стейт -> вдом в данном случае, т.к. нам именно этот кусок нужно нагенерить) и скомпозировать, нам надо делать через жо — вешать колбек на эвент и менять стейт, вместо какого-нибудь let $myComponent = $world.byComponent(myComponent); $myComponent.byElement(myButton).byType(Events.LeftClick).withLatestFrom($myComponent.byType(State)).map(([evt, state]) => ...).mergeTo(Render($myComponent))

                      • vintage
                        /#10411832 / -1

                        главная проблема современных фреймворков — разная модель работы с разными стейтами.

                        В $mol такой проблемы нет, присоединяйтесь :-)

                        • Druu
                          /#10412146

                          У вас в $mol есть общий глобальный стейт приложения (world), предоставляющий чисто функциональный интерфейс для взаимодействия? Не думаю.

                          • vintage
                            /#10412446 / -1

                            $mol не про ФП. А при чём тут оно?

                            • Druu
                              /#10412726

                              Тогда как решается проблема работы «по-разному» с разными «кусками» стейта? Как минимум, должна быть возможность одинаково работать с эвентами интерфейса и внутренним стейтом компонента. То есть, они должны быть представлены объектами, реализующими один и тот же интерфейс. Что это у вас за объект и что за интерфейс?

                              • vintage
                                /#10412940

                                Интерфейс один — реактивные свойства (каналы ввода-вывода). Там по ссылке всё разжёвано же.

                                • Druu
                                  /#10412956

                                  Там много непонятных картинок и мало кода. Хотелось бы увидеть следующие примеры:
                                  1. Пользователь кликает по кнопке, некоторая существующая дом-нода удаляется (пусть сама кнопка и удаляется?)
                                  2. Меняется локальный стейт (значение isHidden), дом-нода удаляется
                                  3. Меняется глобальный стейт (значение isHidden), дом-нода удаляется
                                  4. Срабатывает lyfecycle хук (если у ваших компонент они есть) — дом-нода удаляется

                                  • vintage
                                    /#10412988

                                    1 и 2 — одно и то же, ибо существование того или иного узла зависит от какого-то состояния.


                                    $my_app $mol_view
                                        killed?val false
                                        sub /
                                            <= Hero $mol_button_major
                                                click?event <=> kill_me?event null

                                    sub() {
                                        return this.killed() ? [] : [ this.Hero() ]
                                    }
                                    
                                    kill_me( event : Event ) {
                                        this.killed( true )
                                    }

                                    3 — глобальный от локального отличается только расположением. Например, изменим хранение killed с локального для компонента на localStorage:


                                    killed( next? : boolean ) {
                                        return this.$.$mol_state_local.value( 'killed' , next ) || false
                                    }

                                    4 — Можно считать, что их нет, да. Компоненты лениво создаются по мере необходимости и автоматически уничтожаются, когда от них никто не зависит.

                                    • Druu
                                      /#10413238

                                      > 1 и 2 — одно и то же, ибо существование того или иного узла зависит от какого-то состояния.

                                      Нет, не то же. Именно в том и соль, что во втором случае менять локальное состояние руками вы не должны, следует отреагировать на евент.

                                      Естественно, руками можно все стейты смержить в один. Но именно в этом и были мои хотелки — я хочу, чтобы это делал фреймворк, за меня. А я смогу обрабатывать любые варианты юниморфно.

                                      И, да, можно написать указанный код на чистом js? Я не знаю, как парсить ваши ребусы. И реализацию killed для первого случая еще хотелось бы увидеть.

                                      • vintage
                                        /#10413456

                                        Нет, не то же. Именно в том и соль, что во втором случае менять локальное состояние руками вы не должны, следует отреагировать на евент.

                                        Вы уж определитесь, хотите ли вы единообразия или нет :-)


                                        Естественно, руками можно все стейты смержить в один.

                                        Зачем?


                                        И, да, можно написать указанный код на чистом js?

                                        Из того view.tree генерируется примерно следующий ts-класс:


                                        export class $my_app extends $mol_view {
                                        
                                            @ $mol_mem()
                                            killed( val = false ) { return val }
                                        
                                            sub() {
                                                return [ this.Hero() ]
                                            }
                                        
                                            Hero() {
                                                return $mol_button_major.make({
                                                    click : event => this.kill_me( event )
                                                })
                                            }
                                        
                                            kill_me( event : Event = null ) { return event )
                                        
                                        }

                                        $mol_mem — реактивный мемоизатор, сохраняет возвращаемое функцией значение в локальный стейт.

                                        • mayorovp
                                          /#10413488

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


                                          Реактивность же на изменяемых значениях принципиально рассматривает событие как нечто принципиально иное, отличное от состояния.

                                          • vintage
                                            /#10413524

                                            Ну да, у стримов есть только одно направление коммуникации. А у каналов — два. Логически-то в любом случае будет 2 направления движения данных и каждое со своими особенностями.

                                            • mayorovp
                                              /#10413534

                                              Причем тут канал? Разве click : event => this.kill_me( event ) — это канал?

                                              • vintage
                                                /#10413580

                                                Да.


                                                Только затягивающий канал:


                                                value : ()=> this.name()

                                                Двусторонний канал:


                                                value : next => this.name( next )

                                                Двусторонний канал используемый только для проталкивания:


                                                click : event => this.kill_me( event )

                                        • Druu
                                          /#10413494

                                          > Вы уж определитесь, хотите ли вы единообразия или нет :-)

                                          Именно этого и хочу. В вашем же случае работы с эвентами и внутренним стейтом происходит неединообразно.

                                          > Зачем?

                                          Чтобы работать с ними одинаково.

                                          > Из того view.tree генерируется примерно следующий ts-класс:

                                          Ну вот вы руками мержите стейт — вешаете колбек на клик. Именно этого я и хотел бы избежать. Где там, кстати, сама логика сокрытия кнопки?

                                          • vintage
                                            /#10413510

                                            В вашем же случае работы с эвентами и внутренним стейтом происходит неединообразно.

                                            Единообразно. Разница лишь в направлении движения. стейт "затягивается", а ивенты (как и любые новые значения) "проталкиваются". На каком-то уровне (от локального, до глобального) "проталкивание" меняет состояние и далее оно уже "затягивается" в обратную сторону.


                                            Ну вот вы руками мержите стейт — вешаете колбек на клик.

                                            Ничего там не мержится. "проталкивание" ивента приводит к императивному изменению стейта.


                                            Где там, кстати, сама логика сокрытия кнопки?

                                            Вот же:


                                            sub() {
                                                return this.killed() ? [] : [ this.Hero() ]
                                            }

                                            • Druu
                                              /#10413512

                                              > Единообразно. Разница лишь в направлении движения. стейт «затягивается», а ивенты (как и любые новые значения) «проталкиваются». На каком-то уровне (от локального, до глобального) «проталкивание» меняет состояние и далее оно уже «затягивается» в обратную сторону.

                                              Вот этот момент (где проталкивание меняет состояние) я и не хочу делать руками. Я хочу, чтобы «проталкивание» могло сразу менять результат рендера, дом.

                                              > Вот же:

                                              В примере выше — другой sub(). Кроме того — непонятно, где меняется само killed. Давайте вы уже целиком рабочий код приведете?

                                              > Ничего там не мержится. «проталкивание» ивента приводит к императивному изменению стейта.

                                              Вот это и есть тот самый «мерж», о котором я говорю. Вы делаете эвент куском стейта, и делаете это _руками_.

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

                                              • vintage
                                                /#10413564

                                                Вот этот момент (где проталкивание меняет состояние) я и не хочу делать руками.

                                                Где-то вам всё-равно нужно руками объяснить "глупому компьютеру", что вы хотите, чтобы кнопка пропадала по нажатию на неё. Сам он за вас эту логику не напишет.


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

                                                Перепрыгивая все слои абстракции? А если эта кнопка рендерится в canvas или в ymaps? В реактивной архитектуре меняется только источник данных, а зависимые состояния обновляются на его основе. Вот расположение этого источника может быть разным.


                                                В примере выше — другой sub().

                                                Один класс генерится, другой его расширяет и добавляет логику.


                                                Кроме того — непонятно, где меняется само killed.

                                                Вот же:


                                                kill_me( event : Event ) {
                                                    this.killed( true )
                                                }

                                                Вы делаете эвент куском стейта

                                                Да нет, ивент выкидывается, а стейт меняется. Это ж реакция. Странно называть это мержем.


                                                Давайте вы уже целиком рабочий код приведете?

                                                Давайте я вам лучше покажу пример с двусторонним биндингом:


                                                export class $my_hello extends $mol_view {
                                                
                                                    @ $mol_mem()
                                                    name( next = "" ) { return next }
                                                
                                                    @ $mol_mem()
                                                    Name() {
                                                        return $mol_string.make({ 
                                                            hint : () => "Name" ,
                                                            value : next => this.name( next ) ,
                                                        })
                                                    }
                                                
                                                    message() {
                                                        let name = this.name()
                                                        return name && `Hello, ${ name }!`
                                                    }
                                                
                                                    sub() {
                                                        return [ this.Name() , this.message() ]
                                                    }
                                                
                                                }

                                                Результат: http://mol.js.org/app/hello

                                                • Druu
                                                  /#10413846

                                                  > Сам он за вас эту логику не напишет.

                                                  Конечно, не напишет. Однако, он может сам за меня смержить полный стейт.

                                                  > Перепрыгивая все слои абстракции?

                                                  Какое перепрыгивание? Рендер — просто ф-я из стейта в дом. Стейт изменился (кнопка нажата) дом перерендерился. Проблема в том, что по дефолту случившиеся эвенты не входят в стейт, в итоге приходится руками создавать кусок локального стейта и обновлять его в коллбеке на эвент. Вместо того, чтобы просто написать event => dom.

                                                  > Да нет, ивент выкидывается, а стейт меняется. Это ж реакция.

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

                                                  > Один класс генерится, другой его расширяет и добавляет логику.

                                                  Я как должен догадаться, что у вас где генерится и чего меняет? Давайте вы уже напишите нормальный код, который будет полон, понятен и который можно будет обсуждать, а не какие-то куски, требующие прокачанного навыка чтения мыслей для понимания?

                                                  • vintage
                                                    /#10413946

                                                    Вместо того, чтобы просто написать event => dom.

                                                    Вы, конечно, можете написать ваш event => dom :


                                                    sub() {
                                                        return this.kill_me() ? [] : [ this.Hero() ]
                                                    }

                                                    Но это говнокод.


                                                    Сам факт того, что произошел эвент — уже меняет стейт вашего приложения.

                                                    Там много разных ивентов происходит. Далеко не все из них имеют смысл в моём приложении. event-based архитектура имеет кучу недостатков. Лучше иметь data-flow архитектуру.


                                                    Я как должен догадаться, что у вас где генерится и чего меняет? Давайте вы уже напишите нормальный код, который будет полон, понятен и который можно будет обсуждать

                                                    Это полный код приложения по ссылке. Что вам не понятно? Или вам исходники $mol_string и $mol_view ещё нужны?


                                                    Ок, давайте я добавлю коментов:


                                                     // Компонент "приложение Привет"
                                                    export class $my_hello extends $mol_view {
                                                    
                                                        // Изменяемое свойство "имя"
                                                        @ $mol_mem()
                                                        name( next = "" ) { return next }
                                                    
                                                        // Поле ввода имени
                                                        @ $mol_mem()
                                                        Name() {
                                                            return $mol_string.make({ 
                                                    
                                                                // задаём плейсходлдер
                                                                hint : () => "Name" ,
                                                    
                                                                // двустороннее связывание значения поля ввода и имени
                                                                value : next => this.name( next ) ,
                                                    
                                                            })
                                                        }
                                                    
                                                        // Приветственное сообщение
                                                        message() {
                                                            let name = this.name()
                                                            return name && `Hello, ${ name }!`
                                                        }
                                                    
                                                        // Внутри приложения будут отображены поле ввода и приветственное сообщение
                                                        sub() {
                                                            return [ this.Name() , this.message() ]
                                                        }
                                                    
                                                    }

                                                    • Druu
                                                      /#10414206

                                                      > Вы, конечно, можете написать ваш event => dom:

                                                      Это совсем не то, что требуется.

                                                      > Там много разных ивентов происходит. Далеко не все из них имеют смысл в моём приложении.

                                                      Ну так берите только нужные, какие проблемы?

                                                      > Это полный код приложения по ссылке.

                                                      Дайте полный код предыдущей задачи, я не знаю, что должен делать код приложения по ссылке.

                                                      • vintage
                                                        /#10414286

                                                        Выводить приветствие, подставляя в него введённое имя.

            • Druu
              /#10410666

              > Ммм, но интерфейс-то функциональный, какая разница какая реализация

              Итерфейс к стору — функция dispatch. А она не функциональная.

          • indestructable
            /#10413118

            Редакс прекрасно типизируется. С type-guards типизируются редьюсеры. connect вообще-то типизированный, но с отвратительными тайпингами, которые не используют новые фишки Typescript вроде mapped types.

            • indestructable
              /#10413120

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

  16. serf
    /#10409398

    Что касается default exports, считаю это в целом плохим тоном, даже просто потому что потому неубодно это импортировать — нужно каждый раз давать названия которые по хорошему должны быть одинаковыми во всех точках импорта.

    • TheShock
      /#10409704

      А что плохого в одинаковых названиях?

      • serf
        /#10409718

        Дело как раз в том что при импорте из default модуля обычно нужно придумывать название импортируемому, и придумывают его по разному. То есть как раз названия не одинаковые получаются в коде. И авторифакторинг с default не всегда нормально работает.

        • TheShock
          /#10409728

          export default class SpecificName

          Может, недостаток не в самом импорте, а в том, что он может быть неименованным?

          • serf
            /#10409732

            Для полноты картины каким образом потом это импортируется?

            PS не уверен, но возможно default экспорты помимо прочего не тришейкятся нормально, просто предположение.

            • TheShock
              /#10409734 / +1

              import SpecificName from './SpecificName'

              Про ТриШейк, простите, не понял

              • serf
                /#10409738

                > Про ТриШейк, простите, не понял

                Вот первое что нагуглил сейчас github.com/webpack/webpack/issues/2866 То есть предположение похоже оправдалось, хз починили ли.

                > import SpecificName from './SpecificName'

                Здесь проблема что SpecificName вбивается руками (может IDE и заимпортирует, но руками его можно изменить на произвольное, так что по сути руками), вместо SpecificName можно вбить что угодно и это плохо. В случае именованного экспорта было бы {SpecificName} и здесь все однозначно, и аворефакторинг и ришейкинг сработает хорошо тк AST стандартно строится.

                • TheShock
                  /#10409744 / -1

                  Ну, возможно вы и правы, тот дефолт, что есть сейчас в жс — Не очень.

  17. serf
    /#10409402

    Отличная статья, на news.ycombinator.com такому место если бы кто перевел на английский. Там любят срачи фреймвоков.

    • MooooM
      /#10409408 / +2

      Я планировал сразу написать на английском, но не был уверен в востребованности. Переведу через некоторое время.

      • raveclassic
        /#10409680 / +1

        Переводите! Действительно, будет в тему

  18. galochkinkirov
    /#10409410

    В нашей команде мы проспали вспышку, и вовсе, до сего момента, не использовали Angular 2/4. О чем не сожалеем. Когда с ним начали работать, первое что бросилось в глаза это CLI. Дальше были маты, но я люблю Angular 4, зачем было бы делать фреймворк, который уже существует. Каждый из них имеет свои плюсы и минусы, с этим вряд ли можно будет что-то сделать.

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

    • serf
      /#10409418 / -3

      При добавлении хорошей поддержки TypeScript в Vue этот Angular уже не нужен будет, так же как и React.

      • ruslangavrilov
        /#10409422 / +10

        image

        • serf
          /#10409428 / +3

          Ну правда же, ребята как будто академическую/дипломную работу пишут, а не фреймворк для людей :)

          • nbelyh
            /#10409440 / +2

            Именно. Меня впечатлила новаторская идея все построить на Rx.js / Zone.js: map, mergeMap, flatMap, switchMap, concatMap, exhaustMap,… — серьезно? Для индусов, пишуших энтерпрайз? Дорогие разработчики, вы в каком мире живете?

            • hardex
              /#10410162 / +1

              Проблема Ангуляра не в RxJS, а в том, что он используется там, где не нужно. В HttpClient например

              • Druu
                /#10410182 / -1

                > В HttpClient например

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

              • nbelyh
                /#10410188 / +1

                Мне кажется что вот это как раз не такая уж и проблема. Как говорят в армии — лучше пусть безобразно, но однообразно. Еще зоопарка там не хватало :) Беда в том что шпиговали, как китайскую утку, всем новым новым-вкусным, что нашли.

              • rework
                /#10410486

                Что мешает не использовать RxJS и работать с данными как вы привыкли это делать ранее? Просто сделайте обёртку для преобразования ответа от http запроса в Promise.

              • symbix
                /#10411246 / +1

                RxJS он такой, как только его изучишь, хочется пихать везде :-)


                Хотя в случае с HttpClient есть и польза: логика вида "в случае server/network error повторить запрос с таймаутом, но не больше трех раз" на Rx делается тривиально, а с промисами надо городить огород. Ну и с ngrx/effects удобно получается.

      • raveclassic
        /#10409682 / +2

        А могу ли я во vue отрендерить другой компонент в качестве хоста, накидав ему пропсов, без дополнительной dom-ноды?

    • serf
      /#10409442

      Правильно сделали что проспали, даже древнючий AngularJS можно и сейчас нормально готовить. А потом неспеша перейти на чтот-то Vue подобное.

      • galochkinkirov
        /#10409524

        Да, вполне хватает.


        Пока на работу доберешься ещё один фреймрок выйдет или очередная версия.

  19. MOTORIST
    /#10409416 / +1

    Добавьте teradata.github.io/covalent

    • MooooM
      /#10410738

      На самом деле осознанно не добавлял в список, т.к. это лишь надстройка над angular/material2.
      Кстати весьма спорное решение, например с недавнего времени получилось, что есть два разных DataTable. Плюс ко всему ИМХО очень неудачные API.
      Но надо признать, что на момент начала написания данной статьи, компонентов было гораздо меньше, так что работают ребята быстро.

      • MOTORIST
        /#10416416

        Это костыль пока material.angular.io не вырастит.

    • zodchiy
      /#10410930

      Начал использовать недавно, ох и багучая поделка.
      Умудряются в билды добавлять нерабочие imports, не тестируя.
      Одно время использовал, но некоторые компоненты были исправлены своими руками.
      Думал сменить.

  20. rockon404
    /#10409508 / +1

    Очень любил Angular и закрывал глаза на все его недостатки, пока не начал писать на React.

    • indestructable
      /#10413124

      То же самое, первый Ангуляр любил до Реакта. Второй, правда, попробовал еще до Реакта и невзлюбил сразу.

  21. kanarisru
    /#10409510 / -4

    Автор молодец.
    Добавить нечего.
    Полностью поддерживаю.

  22. masquer
    /#10409514 / -1

    А как обстоят дела у Vue c server side rendering? Вот у Angular есть Universal.
    Или progressive web apps? Тут есть Ionic.

  23. spread
    /#10409558

    Какие проблемы использования TS во Vue.js? Тут egghead.io/lessons/write-a-vue-component-as-a-class-in-typescript красиво и подробно рассказывают, что проблем нет

  24. PaulMaly
    /#10409826

    Не первый раз читаю подобные статьи про Angular, React и некоторые другие фронтэнд фреймверки/либы (кстати про Vue пока такое не особо пишут, видимо только пока). Сам уже 4 года использую Ractive и вообще не понимаю этих проблем.

    • ruslangavrilov
      /#10409838

      Идеального ничего нет… во всем можно найти недостатки… Но что реально есть, так это востребованность на рынке определенной технологии.

      • PaulMaly
        /#10410212

        Это правда, есть некоторые вещи которые я бы и в Ractive изменил, но они скорее из разряда «Чувак а не ох*енел ли ты? Совсем ниче делать не хочешь». В остальном все круто. Лично для меня в Ractive 2 минуса: он могу бы быть быстрее и меньше размера (а может и не мог бы, хз), хотя даже так он быстрее многих других либ. Ну и он прям совсем не хайповый и известен по большей части за бугром. Хотя это может даже плюс.

  25. s1im
    /#10409828

    Про ошибки в шаблонах, которые не отображаются при JIT-компиляции. Насколько я читал, разработчики ангуляра к пятой версии хотят сделать быстрые инкрементальные сборки для AOT и выпилить JIT совсем.

    • MooooM
      /#10409884

      Очень жаль, очевидно вы просто мало его использовали.

    • MooooM
      /#10409890 / -1

      Почему-то комментарий добавляется не туда… предполагается к habrahabr.ru/post/337578/#comment_10409828

      Это все здорово конечно, но печально сразу по нескольким причинам:
      1. Я уверен, что иначе работающий AOT для многих будет просто новостью, да да не все знают про --prod.
      2. Наверняка снова будет вагон Breaking Changes
      3. Зачем постоянно делать плохо, чтобы потом исправлять? Может быть стоит чуток посидеть и подумать над архитектурой. Как никак не студенческая лабораторная.

      • s1im
        /#10409922 / -1

        1. Это действительно очень грустно, так как Angular запущенный в dev-режиме не устанет вам напоминать об этом в консоли, а самый простой способ от этого избавиться, используя Angular CLI, запустить с этим самым ключом. Ну и dev/prod-конфиги в папке environment должны наводить на какие-то мысли. Грустно, что разработчики использующие angular, не могут в документацию.
        Я сам использую Angular с 2-rc.1 версии, когда никаким CLI еще не пахло, и уже тогда интересовался, как правильно производить prod-сборку. В официальной документации был и есть на это ответ, с полным описанием разницы между JIT и AOT.
        2. По заверению разработчиков, не будет. Все, что скоро должно устареть, будет помечаться как deprecated и выводиться соответствующие оповещения об этом при сборке.
        3. Я абсолютно не согласен с вами, что разработчики angular-а настолько плохие специалисты, что постоянно делают нам плохо. На мой взгляд, они создали наиболее удобный и универсальный фреймворк, благодаря которому fronted-разработка сильно упростилась и перестала походить на обмазывание BE-костяка скриптами и библиотеками. Да и вообще, большинство претензий как автора статьи, так и комментаторов мне абсолютно не понятны и попахивают вкусовщиной.

        Ну и npm update не переведет ваш проект с 4 на 5 версию автоматически. Предполагается, что при смене мажорной версии, любой разработчик изучает changelog и советы по переходу на новую версию, а не делает это с закрытыми глазами на проде.

      • Druu
        /#10409936

        > Зачем постоянно делать плохо, чтобы потом исправлять?

        Что исправлялось? Писать код в aot-compatible манере было рекомендовано задолго до релиза. А ошибки отображаются через language service, плагины для vsc и вебсторма есть.

  26. DaturInnoxia
    /#10409878 / +3

    Уже на версии 1.5-1.6 было понятно, что в AngularJS много подводных камней. Но с переходом на Typescript для меня Angular закончился. Не потому что Typescript плох, а потому что во многом это искусственная замена JS.

    • s1im
      /#10412156

      Похоже, вы просто не нашли времени познакомиться с TS и прочувствовать на себе преимущества статической типизацией. А если рассматривать сравнение с динамической типизацией, то выяснится, что у DT нет никаких преимуществ перед ST, кроме сомнительного «более низкий порог вхождения в ЯП».

      • TheShock
        /#10412324

        Еще иногда на динамике быстрее и легче писать мелкие скрипты до ста строк.

        • s1im
          /#10412344

          Да, конечно, для небольших скриптов, типа *.sh, это подходит. Но я имел в виду разработку более серьезных приложений. Поэтому, раз уж заикнулся о преимуществах статической типизации, то вкратце их перечислю:

          1. вы всегда уверены что написанный метод и результаты его работы используется вами правильно;
          2. ошибки класса «сравниваем несравниваемое» или «пихаем невпихуемое» исключаются на стадии компиляции;
          3. после перехода на ST (например, при переходе с JS на TS) вы с большой вероятностью обнаружите, что таких ошибок у вас дофига; и даже не ошибок, а скорее досадных опечаток, которых ваш замылившийся глаз в упор не замечает;
          4. нет необходимости заниматься лишними проверками типов самостоятельно; вообще, переход на ST — это довольно дешевый способ повысить качество кода, особенно когда кодовая база растет быстро за счет большой команды;
          5. ваш IDE станет намного дружелюбнее по отношению к вам; а если вы все еще пишете в блокноте, то это дополнительный стимул перейти на IDE;
          6. рефакторинг перестает быть нудным и кропотливым занятием, после которого частенько появляются новые баги; поправив какой-нибудь метод вы не пропустите какое-нибудь место, где он вызывается в дебрях вашего проекта — компилятор услужливо вам напомнит;
          7. читабельность кода заметно повышается.

        • Druu
          /#10412734

          > Еще иногда на динамике быстрее и легче писать мелкие скрипты до ста строк.

          Это вообще верно было пока нормально не проработали системы типов для динамических языков. Сейчас на том же TS 99% идиоматического js-кода прекрасно типизируется безо всяких проблем (разве что проблемы с прототипным наследованием, потому что его никто не изучал особо), а оверхед по объявлению типов — по факту нулевой.

      • MooooM
        /#10412628 / +1

        Я не нашел? Может быть вы невнимательно читали, или это не совсем ясно из статьи (хотя я пытался) — я работаю с TypeScript несколько лет, с самых первых версий, еще когда он работал только в Visual Studio.
        Это невероятно полезный инструмент, и я желаю всем его хотя бы попробовать. Я даже лекцию в одной очень известной российской конторе делал о нем…

        Другое дело — его нужно использовать по назначению.
        Команда Angular по какой-то причине этого делать не захотела.

        • s1im
          /#10412766

          Нет, я писал не вам, а отвечал на этот комментарий

  27. lega
    /#10409880 / +2

    Вот что происходит с проектом когда 20-30 разработчиков должны комитить что-то за зарплату, в относительно не большой проект, он превращатся в монстра. Непонятно зачем гугл вливает туда деньги, даже сам гугл этот ангуляр не использует*.

    • astec
      /#10409904

      Вообще то использует.

      • justboris
        /#10409992

        После того, как пара основных разработчиков Angular ушли в свой стартап, не думаю, что в Google будет ставить на Angular в новых проектах.


        И, кстати, недавно обновленный Youtube теперь на Polymer. Кажется, именно Polymer это новый фаворит Гугла

        • Druu
          /#10410190

          Гугл использует ангуляр для внутренних сервисов.

          • justboris
            /#10410194

            А есть актуальная информация 2017 года? Все что я видел уже устарело как минимум на год.

            • Druu
              /#10410204

              А что за это год могло поменяться?
              console.developers.google.com

              до сих пор на первом ангуляре, например

              • justboris
                /#10410208 / -1

                например, основные разработчики ангуляра покинули Гугл. Как вы думаете, это могло не сказаться на технологиях внутри компании?

                • Druu
                  /#10410218

                  Не за год, конечно же. Это же не твиттер какой-нибудь. Уход разработчиков тут разве что лет через пять может сказаться.

                  • justboris
                    /#10410302

                    изначально тред был об этом:


                    Непонятно зачем гугл вливает туда деньги, даже сам гугл этот ангуляр не использует

                    Поэтому я и спросил что нового запустил Гугл на ангуляре в этом году. Кажется, что ничего такого нет.
                    Получается, что гугл не развивает ангуляр и вливает туда деньги, а просто поддерживает, чтобы уже запущенные проекты были на плаву.

                    • Druu
                      /#10410676

                      Ну так в итоге мы выяснили, что гугл ангуляр использует. Потому и деньги вливает. А то, что «просто поддерживает» — вроде не новость, второй ангуляр изначально был заточен под кровавый тырпрайз, а это на 90% и есть поддержка существующего. Весьма странным выглядит ваше удивление, что утка крякает.

                      • justboris
                        /#10410774

                        А еще Гугл использует GWT. Но сказать, что он туда вливает кучу средств не получится.


                        Вот еще пример: конференция Angular Summit, и Гугла там в спонсорах нет.
                        Зато на Polymer Summit это по сути единственная представленная компания. Мне кажется, что вывод, куда сейчас вкладываются PR-средства, очевиден.

                        • Druu
                          /#10410810

                          > А еще Гугл использует GWT. Но сказать, что он туда вливает кучу средств не получится.

                          А в ангуляр вливает? Насколько больше?

                          > Вот еще пример: конференция Angular Summit, и Гугла там в спонсорах нет. Зато на Polymer Summit это по сути единственная представленная компания.

                          Кажется, ответ очевиден: что требует большей поддержки, то и поддерживается.
                          Зачем слать докладчиков на ангуляр саммит, если и так они туда найдутся? Незачем.

                        • Druu
                          /#10410820

                          с-но, например:
                          www.reactrally.com/speakers

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

  28. carpogoryanin
    /#10409958

    Почему вы не упоминули DevExtreme UI framework? Мы его в работе используем. В целом хватает пока хватает.

    • MooooM
      /#10409964

      Оно не бесплатное и не полностью опенсорсное.

  29. vasIvas
    /#10410206

    Все дело в коммунити. Вот если в js появился spring из java иди .net mvc из c#, то я уверен, что 90% выбрали бы jQuery или vue. Но это же не говорит что с spring и .net mvc что-то не так.

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

    Проблема с ui компонентами мне тоже не понятна, неужели самому сложно написать, ведь для этого и был создан компонентный фраймворк angular. Хотя если проект трешовый, то да, понятно, денеги не окупают затраченное время. Но это же не значит, что angular плох, так как на нем нельзя делать те приложения, которые обычно делают на jQ. На реакте тоже не делают такие сайты.

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

    У меня тоже есть претензии к angular, но после многих лет реакта, я молчу.

    • Druu
      /#10410684

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

      Проблема начнется, когда проект станет немного больше и вообще перестанет собираться с out of memory :)

  30. Kopleman
    /#10410226

    Люблю такие статьи, всегда есть что новую почерпнуть, к тому же это точный маркер того что, у обсуждаемой библиотеки все хорошо в плане ЖЦ, vue.js ждет тоже самое, дайте ему время.
    Лично у меня за время что angular доступен и его текущей реализации, складывается ощущение что они «не много не рассчитали».

  31. JTG
    /#10410876 / +1

    > довольно скудное количество готовых наборов UI компонентов
    И это ещё мягко сказано! В основном в коробке идёт красивая анимированная пальце-тыкательная хромая замена стандартным контролам браузера (которая хорошо если на 50% покрывает возможности стандартных — далеко не везде есть нормальная навигация с клавиатуры, tabindex, ARIA-фичи и т.п.). Время идёт, а готовых комплексных решений для нагруженных интерфейсов не появляется, хотя npm завален гридами разной степени кривости. Да, инструмент гибкий, бери и пиши — но я не готов писать ExtJS или хотя бы что-то вроде EasyUI самостоятельно.

    • Zakyann
      /#10411040 / -2

      UniGUI, потолок вхождения около нуля. И гриды и чарты и кнопки.

    • nohuhu
      /#10411630

      далеко не везде есть нормальная навигация с клавиатуры, tabindex, ARIA-фичи и т.п.

      Вообще нигде нет. Dojo 1 пыталось быть сколько-нибудь доступным, но ниасилило, а больше никто даже не пытался. Accessibility это очень трудно и больно, я вам как доктор говорю. :(

    • s1im
      /#10412316

      В основном в коробке идёт красивая анимированная пальце-тыкательная хромая замена стандартным контролам браузера

      Вы наверное про Angular Material 2? Но она не совсем в коробке, просто Google продвигает данную тему (Material Design) и поэтому рекомендует по-умолчанию. На самом деле UI систем много, часть из них перечислены тут angular.io/resources в разделе UI Components. Рекомендую приглядеться к Semantic UI, Clarity Design System и Prime NG.

      Я лично чаще всего использую голый bootstrap.css без bootstrap.js/jQuery (4 версия наконец-то собирается из SCSS, что делает более простой сборку с помощью Angular CLI).

  32. debounce
    /#10411322

    Такие же чувства. Считаю, Англяр — лучшее, что было с фронтендом. Провел годы с Ангуляром, но 2/4 — нет. Была надежда, что такая извращенна сложность очень понравится энтерпрайзу, ведь там работают особые программисты, да, которые просто тащатся от километровых абстракций и отсутствия документации. Но нет, подтверждений, что взлетело — нет.

    Остаюсь на 1.x и не вижу причин переходить куда-то в ближайшие, скажем, лет 5.

    Реакт — такое я никогда не приму и не пойму.

    render() {
        return (
          <p>
            Hello, my props are {this.first} and {this.last}
          </p>
        );
      }
    

    • raveclassic
      /#10411454 / +2

      Реакт — такое я никогда не приму и не пойму.

      А что не так?

      • nohuhu
        /#10411636 / -4

        Не ОП, но рискну предположить, что сам вид этой дикой белибердической смеси псевдо-JavaScript с псевдо-HTML вызывает рвотные позывы у людей, чьё чувство прекрасного не забито в кровавую тряпочку годами самобичевания с PHP?

        • debounce
          /#10412362 / -1

          С радостью уйду в минуса вместе с вами) Именно так, слово в слово, и лично у меня это как раз после php.

          А кому псевдо-html мало:

          const styles = StyleSheet.create({
            bigblue: {
              color: 'blue',
              fontWeight: 'bold',
              fontSize: 30,
            },
            red: {
              color: 'red',
            },
          });
          


          • justboris
            /#10412374 / +1

            Можно продолжать уходить в минуса, а можно наконец-то рассказать, в чем именно проблема с JSX, кроме слепого следования карго-культу "разметка отдельно от логики".


            Какие проблемы решает ко-локация html и стилей в js-файлах уже не раз обсуждалось.

            • debounce
              /#10412520 / -1

              «Принять» — это про чувства.
              Блевал от этого еще в php и это был конец 90-х, блюю и в 2017. Php долго отмывался от этого, когда его воспринимали не иначе как шаблонизатор с прикрученными скриптами.
              Время шло, на бэкенде урок php кажись усвоили все, поэтому завелось — язык отдельно, шаблонизатор — штука нужная, но это вообще с боку. На фронтенде все это время если и были такие проекты, но чисто академические — а что если сделать так?? уже пихали всё во всё, поверьте, свингеры это просто детский сад, по сравнению с тем, что мы уже делали с этим трио css, html, js. Было весело, но это не мейнстрим.
              До реакта. Я не понимаю, что изменилось, что теперь ребята с горящими глазами снова рассказывают «разметка отдельно от логики», только теперь упорот почему-то я)

              • justboris
                /#10412580 / +1

                Обжегшись один раз, вы дуете на воду. То, как JSX встраивает html в JS-код не имеет ничего общего с текстовыми файлами на PHP. Хотя бы потому, что в JSX вы не можете открыть тег и не закрыть его. У JSX строгий синтаксис, который не позволит вам наделать нелепых ошибок в разметке.


                Некоторое время назад я выложил статью со своим мнением про JSX, может быть вам будет интересно.

                • Druu
                  /#10412746

                  > Хотя бы потому, что в JSX вы не можете открыть тег и не закрыть его. У JSX строгий синтаксис, который не позволит вам наделать нелепых ошибок в разметке.

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

                  По-этому реакция на JSX у подавляющего большинства людей, имеющих серьезный опыт работы с PHP — вполне ожидаема и закономерна. Особенно, когда они видят _реальный_ JSX-код (из реального приложения, а не из примеров) и понимают, что, да, первое впечатление не обмануло — это PHP в худших его проявлениях, как выше сказали — привет из 90-х, все ровно так, будто одел старый разлезшийся свитер.

                  То есть, люди набили шишки, настрадались, прошли этот этап — а теперь им предлагают есть те же какашки, что были в прошлом. Естественно, никто повторять свои страдания не захочет, пусть страдают те, кто еще не настрадался :)

                  • justboris
                    /#10412768 / +1

                    Ну ок, на JSX можно писать говнокод. В разделенном HTML/JS тоже можно.


                    Однако хорошо оформленный JSX удобнее, чем пара JS+шаблон.


                    Если вам так не кажется, то ок — ваше дело. Но писать комментарии в формате "страдайте глупцы" — точно не стоит.

                    • Druu
                      /#10412778 / +1

                      > Однако хорошо оформленный JSX удобнее, чем пара JS+шаблон.

                      Можно увидеть этот самый «хорошо оформленный JSX»? Чтобы там не было кучи ненужных мелких компонент (сильно затрудняющих восприятие разметки в целом) или чего-нибудь вот такого:

                      {!isHidden && (
                        <ul>
                          {items.map((item, i) => (
                            <li key={i}>{item}</li>
                          )}
                        </ul>
                      )}
                      

                      и проблема здесь не в самом факте перегруженности синтаксиса, к синтаксису можно было бы привыкнуть, если бы не одно «но»: в случае с шаблонизатором обычно есть один ясный и понятный способ решить задачу, которую решает данный кусок кода. Вы возьмете 10 программистов и вам 10 напишут одинаково. В случае с JSX — каждый, блин, напишет как-то по-своему.

                      • justboris
                        /#10412790

                        Здесь я вам ничего нового не расскажу. Нормальная разметка, как по мне.


                        В Handlebars будет примерно так же


                        {{#unless isHidden}}
                          <ul>
                            {{#each items}}
                              <li>{{title}}</li>
                            {{/each}}
                          </ul>
                        {{/unless}}

                        На AngularJS будет чуть покороче


                        <ul ng-if="!isHidden">
                          <li ng-repeat="item in items">{{item}}</li>
                        </ul>

                        Но есть и обратная сторона: здесь смешали html и управляющие конструкции. Если на <li> навесить еще class, ng-click, то потом будет сложно беглым взглядом найти ng-repeat. Поэтому очень сомнительная польза от компактности

                        • Druu
                          /#10412830 / +1

                          > Но есть и обратная сторона: здесь смешали html и управляющие конструкции.

                          В варианте на JSX смешали не просто html и управляющие инструкции, а html и большее подмножество JS.

                          > Если на навесить еще class, ng-click, то потом будет сложно беглым взглядом найти ng-repeat.

                          ng-repeat как раз будет отлично виден всегда — именно потому, что это одна из немногих управляющих конструкций. Она всегда выглядит одинаково и используется одинаково. В случае же jsx глазу вообще не за что зацепиться — вам надо распарсить полностью произвольный js код (что на порядок сложнее, чем вычленить один токен) и понять его семантику. Понимаете, в чем разница? Это очевидное преимущество специализированных решений над универсальными. JS — универсальный язык, и он откровенно плох в генерации представления для разметки, потому как никогда для этого предназначен не был, JSX улучшает картину, но несущественно. Шаблонизаторы — лучше, потому что они специально заточены для построения представлений конкретного вида. Именно по-этому даже PHP выигрывает у JSX по удобству описания разметки. Он для этого предназначен, он для этого был спроектирован. JSX — нет.

                      • mayorovp
                        /#10412918

                        А как вам вот такой вариант:


                        <If condition={!isHidden}>
                            {() => {
                                <ul>...</ul>
                            }}
                        </If>

                        Или вот такой:


                        {IF(!isHidden, () => {
                            <ul>...</ul>
                        })}

                        Мне интересно, чем можно разбавить JSX чтобы он смотрелся не как набор js-хаков.


                        Или необходимость этих () => { ... } все портит?

                        • Druu
                          /#10412964

                          > А как вам вот такой вариант:

                          Вы невнимательно прочитали мой пост. Я же специально указал — проблема не в кривом синтаксисе _самом по себе_. Он не очень, но к любому синтаксису привыкаешь. Проблема именно в наличии «а как вам вот так» — в том, что одно и то же можно сделать по-разному. Когда мы работаем с шаблонизатором, то мы видим перед собой уже практически готовую верстку, в которой глаз сразу ухватится за некоторые выделенные токены (вроде ng-repeat), то есть это html + добавка. В случае с JSX мы имеем дело с js + добавка, что на порядок сложнее для разбора. Чтобы понять, что сгенерирует js-код — ну, надо разобрать этот код, понять, что он нагенерит. В случае шаблонизатора — вам и не надо ничего разбирать, вы уже довольно-таки точно видите, что получится в итоге. Шаблонизаторы именно потому хороши, что они используют возможности html, а никто лучше html языка для описания dom не придумал. JS ему сильно в этом проигрывает, именно в силу своей универсальности.

                  • indestructable
                    /#10413140

                    Но вот только в ПХП был серверный код бизнес-логики вперемешку с HTML.


                    Дело не в JSX, конечно же. Есть несколько альтернатив ему, в том числе, и весьма похожие на шаблонизатор Ангуляра, которые позволяют писать как бы HTML, и компилировать его в вызовы createElement.


                    Но их никто не использует. Потому что настоящая мощь Реакта — в том факте, что компоненты — это обычные JS объекты. Я не устаю писать это в каждом комментарии в сраче о JSX.


                    Шаблон Ангуляра — это, конечно, похоже на ХТМЛ (особенно, если ты видел пример из getting started и не видел реальный production код). Но это все-равно строка.


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


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

                    • Druu
                      /#10413242 / +1

                      > Но вот только в ПХП был серверный код бизнес-логики вперемешку с HTML.

                      Ну так в SPA у вас тот же код, который раньше был серверным, теперь на клиенте.

                      > Но их никто не использует. Потому что настоящая мощь Реакта — в том факте, что компоненты — это обычные JS объекты. Я не устаю писать это в каждом комментарии в сраче о JSX.

                      Так их никто не использует, потому что реакт плохо с этим работает. Он заточен под пехепешную модель, т.к. создавался для портирования php-кода на js.

                      > Шаблон Ангуляра — это, конечно, похоже на ХТМЛ (особенно, если ты видел пример из getting started и не видел реальный production код). Но это все-равно строка.

                      Во втором ангуляре шаблоны компилируются в js-объект, точно так же, как jsx.

                      > А вот как взять потомков одного типа, и склонировать их для каждого элемента массива и отрендерить в отдельное место?

                      Легко догадаться, что так делать не надо. Надо описать модель данных, в которой будет «взять, склонировать» и что там еще надо, а потом по этим данным, используя примитивные операции, нагенерить вьюху. В итоге в одном месте вы работаете с чистыми данными (ничего не зная о дом), а в другом — примитивным образом их визуализируете. JSX, как видно, стимулирует мешать все в одну невнятную кучу, да еще и предлагает этот баг в виде фичи.

                      • indestructable
                        /#10413926

                        Ну так в SPA у вас тот же код, который раньше был серверным, теперь на клиенте.

                        С чего бы это серверному коду быть на клиенте? Да и каким образом это возможно, ПХП выполнялся на сервере, реакт и другие — на клиенте. Он при всем желании не полезет в базу, не прочтет файл с диска на сервере и т.п.


                        Легко догадаться, что так делать не надо.

                        Знаете, я был практически уверен, что вы скажете "зелен виноград".
                        Так делать не хочется, пока не попробуешь :) Но это же мощнейший инструмент, который позволяет кучу задач (особенно при разработке библиотек и компонентов) решить изящным способом.


                        По сути, это и есть полноценная композиция компонентов, а не огрызок, как в Ангуляре.


                        Во втором ангуляре шаблоны компилируются в js-объект, точно так же, как jsx.

                        Совсем не так же. В Реакте можно оперировать результатами там же, в коде, то есть это по сути другой вид записи. В Ангуляре результат компиляции коду компонента не доступен.

              • symbix
                /#10412590

                Про PHP (ну, то есть, не совсем PHP): XHP :-)

              • vasIvas
                /#10412608 / -1

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

                В реакте нет html в javascript. или , это обычные объекты, которые если и создают разметку за кулисами, то только потому, что являются частью шаблонизатора. То есть, .jsx, это всего навсего указания шаблонизатору в декларативном стиле. Тем более, если Вы такой старый, а значит, должны быть опытный, то ваши слова идут Вам в минус, так как Вы не осознаете что js это ТОЖЕ представление. Компоненты это часть представления и логика которая в них присутствует, является логикой представления. И можно было бы продолжать до бесконечности, но не нашлось бы даже пикселя, который лег на чашу в поддержку Вашего мнения. Кстати в angular представление тоже за счет js генерируется и это вполне нормаль. Те кто рвал горло раньше, что js это логика, он просто не понимал чего именно, так же как серверисты рвут глотки что у них в обычных приложениях mvc на сервере.

                • vintage
                  /#10412654 / +1

                  Всё клиентское приложение — это представление. И в этом самом представлении стоит разделять html-шаблоны от программной логики. По куче причин. Основная — шаблоны вперемешку с логикой теряют своё основное назначение — возможность буквально видеть результат результат. Без этой возможности шаблоны не нужны и можно просто фигачить объекты, без подражания HTML-у.

                  • raveclassic
                    /#10412938

                    возможность буквально видеть результат результат

                    ну бросьте, ng-repeat вам ничего "буквально" не покажет, придется включить мозги. Какая разница тогда ng-repeat или map?


                    Без этой возможности шаблоны не нужны и можно просто фигачить объекты, без подражания HTML-у

                    Бинго!

                    • mayorovp
                      /#10412946

                      Разница в том, что если не знать про ng-repeat — то останется валидная разметка с одним элементом в списке. А если не знать про map — то в разметке останется какая-то фигня.

                      • raveclassic
                        /#10412952

                        В "разметке" останется JS. Чистый, обычный и валидный

                        • vintage
                          /#10412966

                          Что человеку, новичку в JS не сильно помогает.

                        • Druu
                          /#10412974

                          > В «разметке» останется JS. Чистый, обычный и валидный

                          Который надо в уме исполнить, чтобы понять, чего этот JS нагенерит. А в случае с ng-repeat я сразу вижу готовую ноду, потом надо только отметить, что: «ага, эту ноду размножить, раз там ng-repeat». К слову, таких директив в ангуляре всего-то пара штук (то есть легко запомнить), а сколько есть разных вариантов записи для аналогов for/if в JSX? Да десятки.

                          • raveclassic
                            /#10413022 / +1

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


                            В ангуляре-то пара, а кастомных в природе сколько?


                            для for есть единственный вариант — map
                            для if — && и тернарник, не так уже и много

                            • Druu
                              /#10413248

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

                              Так именно это проблемой и является. В шаблонизаторе вы видите результат преобразования, в JSX — преобразование. Чтобы по преобразованию получить результат — надо его выполнить в уме.

                              > для for есть единственный вариант — map
                              для if — && и тернарник, не так уже и много

                              Ага, конечно. Только вот есть те же «а-ля шаблонизатор», есть сдабривание iife, есть просто подергивание каких-то методов (которые хрен его знает, что могут возвращать, пока не посмотришь, а потому факт наличия цикла вы сразу и не сможете определить).

                              > В ангуляре-то пара, а кастомных в природе сколько?

                              Во втором структурные еще специально звездочкой принято помечать. Так что уж не пропустишь.

                              • raveclassic
                                /#10413788

                                В шаблонизаторе вы видите результат преобразования, в JSX — преобразование. Чтобы по преобразованию получить результат — надо его выполнить в уме.

                                Ну нет же, я ж написал уже, ng-repeat — не результат. А то, что он "проще для восприятия" (что спорно, учитывая безумный dsl внутри аттрибута), не делает его лучше.
                                Не знаю, может, я уже потерян для общества, но я не вижу ни единой проблемы в map, он ровно ничем идеологически от ng-repeat не отличается. А то, что вам гибкости больше дается стандартными средствами, ну, не знаю, по мне так это преимущество.


                                Во втором структурные еще специально звездочкой принято помечать. Так что уж не пропустишь.

                                Но я ж не знаю, что там скрыто в ней? Придется "выполнить ее в уме" :)


                                Ага, конечно. Только вот есть те же «а-ля шаблонизатор», есть сдабривание iife, есть просто подергивание каких-то методов (которые хрен его знает, что могут возвращать, пока не посмотришь, а потому факт наличия цикла вы сразу и не сможете определить).

                                Вы же в коде на это не жалуетесь. А для "посмотреть, что вернет" есть TS и IDE. А факт наличия цикла мне и не нужно определять, особенно, если он спрятан в методе или вообще в подкомпоненте.


                                А чтобы увидеть картину в целом, есть инструменты, например react dev tools, отрисовывающие дерево компонентов вперемешку с DOM. Так что это не проблема JSX. Вы же джавовый байт-код руками не сканите ради "общей картины".


                                А вообще, мне кажется, мы плавно подходим (и кажется, что опять) к проблеме, которую symbix озвучил ниже — любому внятному верстальщику рано или поздно придется апгрейдиться до разработчика. А в этом случае, использование одного языка вместо кучи спорных dsl только на пользу.

                                • vintage
                                  /#10413858

                                  "проще для восприятия" (что спорно, учитывая безумный dsl внутри аттрибута

                                  ng-repeat качественно ничего не меняет по сравнению с результатом. Только количественно. Поэтому его можно просто игнорировать, когда не важно число повторов.


                                  я не вижу ни единой проблемы в map, он ровно ничем идеологически от ng-repeat не отличается

                                  Эти два варианта тоже ничем не различаются?


                                  `Hello, ${name_prefix} ${name}!`

                                  "Hello, " + name_prefix + " " + name + "!"

                                  • raveclassic
                                    /#10413874

                                    Эти два варианта тоже ничем не различаются?

                                    А какое это отношение имеет к ng-repeat/map?

                                    • Druu
                                      /#10413890

                                      Очевидно же, первый вариант — это использование шаблонизатора (ng-repeat), а второй — универсальных инструментов, предоставленных хост-языком (map). Кстати, хороший пример :)

                                      • raveclassic
                                        /#10413906

                                        Эээ, строковые темплейты — фича языка.

                                        • vintage
                                          /#10413956 / +1

                                          Зачем же её ввели, если всё это можно делать и обычным ES5?

                                        • Druu
                                          /#10414210

                                          Это специальный ДСЛ для того, чтобы генерить строки. Ничем не отличается от специального ДСЛя для того, чтобы генерить дом :)

                                          • raveclassic
                                            /#10414720 / -1

                                            Да, только это DSL в комплекте с языком, а не со сторонним двиглом, вот и вся разница.

                                • Druu
                                  /#10413876

                                  > Ну нет же, я ж написал уже, ng-repeat — не результат.

                                  Конечно, результат. Вы смотрите и видите, какая нода получилась. А потом, увидев ng-repeat, понимаете, что там не одна она такая, а их много. гляда на произвольный js-код в JSX вам надо в уме выполнить этот код, чтобы получить ту информацию, которая вслучае шаблонизатора есть _сразу_.

                                  > Но я ж не знаю, что там скрыто в ней? Придется «выполнить ее в уме» :)

                                  Только вот кастомные структурные директивы встречаются в ангуляре примерно раз на несколько тысяч строк. Насколько часто в JSX встречаются кастомные функции? :)

                                  > Вы же в коде на это не жалуетесь.

                                  Потому что код предназначен для другого. Код потому и пишется на тьюринг-полном языке со всякими встроенными свистоперделками, что массив задач, который может решаться при помощи этого кода — очень большой и задачи очень разные. Код шаблона же (или jsx) решает очень узкую задачу (и только одну) — генерация представления дом-дерева (кусков дом-дерева) во вполне конкретном и четко определенном формате.
                                  Это, например, как конечные автоматы. Вы можете написать конечный автомат на любом тьюринг-полном языке (на том же js), но на практике предпочитаете пользоваться узким и специально заточенным языком (регекспами), который специально для описания КА и предназначен.

                                  • raveclassic
                                    /#10413902 / -1

                                    Только вот кастомные структурные директивы встречаются в ангуляре примерно раз на несколько тысяч строк. Насколько часто в JSX встречаются кастомные функции? :)

                                    Зависит от кода. И директив бывает столько, что в глазах рябит и функций. Хотя вот функций обычно меньше, обычно это просто компоненты. Так как можно отрендерить в качестве хоста дру… а, вы знаете, что там дальше.
                                    Ну и получается, что с директивами все-равно нужно маркап прогонять в уме, так что все "преимущества" ng-repeat теряются.

                                    • Druu
                                      /#10414212

                                      > Зависит от кода. И директив бывает столько, что в глазах рябит и функций.

                                      Это можно пример такого кода?

                                      > Ну и получается, что с директивами все-равно нужно маркап прогонять в уме

                                      Раз в несколько тысяч строк — нужно. В остальное время — не нужно :)

                                      • raveclassic
                                        /#10414726

                                        Это можно пример такого кода?

                                        А пожалуйста. Без звездочек правда, но сути не меняет. Что там делают эти магические атрибуты, черт знает.


                                        Раз в несколько тысяч строк — нужно. В остальное время — не нужно :)

                                        Нет, так не честно. Либо прогоняем, либо нет.

                                        • Druu
                                          /#10414768

                                          > Нет, так не честно. Либо прогоняем, либо нет.

                                          На практике важен не сам факт того, что прогоняем, а как раз то, насколько сложно это и как часто приходится делать :)

                                          > Что там делают эти магические атрибуты, черт знает.

                                          Будете смеяться — но ничего не делает :D
                                          И я, блин, серьезно — правда ничего (в плане перестройки dom-дерева).

                                          • raveclassic
                                            /#10414772

                                            На практике важен не сам факт того, что прогоняем, а как раз то, насколько сложно это и как часто приходится делать :)

                                            На практике и map с первого раза в голове оседает. Знаю о чем говорю :)


                                            Будете смеяться — но ничего не делает

                                            По идее по ним там выборка какая-нибудь идет через @ContentChildren какой-нибудь. То же сами кстати, что и распарсить this.props.children, только на своем велосипеде.

                                            • Druu
                                              /#10414824

                                              > На практике и map с первого раза в голове оседает. Знаю о чем говорю :)

                                              Я же говорил — не было бы беды, если бы там ВСЕГДА был map. Но там произвольный js-код. Если ограничить JSX каким-то вменяемым подмножеством JS — он будет вполне ок. Проблема именно в том, что там может использоваться ВЕСЬ JS.

                                              > По идее по ним там выборка какая-нибудь идет через @ContentChildren какой-нибудь.

                                              Но именно атрибуты — ничего не делают, то есть это просто темплейт, в который потом на места let-атрибутов подставляются значения из контекста (контекст применяет уже внешняя директиваб ngx-datatable).

                                              И на самом деле (кстати) это и есть рассахаренный «звездочковый» синтаксис

                                              <ng-template let-row="row" let-value="value" ngx-datatable-cell-template>
                                                          My name is: <i [innerHTML]="row['name']"></i> and <i>{{value}}</i>
                                                          <div>{{joke}}</div>
                                                        </ng-template>
                                              

                                              ->
                                              <ng-container  *ngx-datatable-cell-template="let row=row; let value=value">
                                                  My name is: <i [innerHTML]="row['name']"></i> and <i>{{value}}</i>
                                                  <div>{{joke}}</div>
                                              </ng-container>
                                              

                                              примерно как-то так

                                              • raveclassic
                                                /#10414842

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


                                                {function() {
                                                  const result = [];
                                                  for (let i = 0; i < items.length; i++) {
                                                    const item = <li>{items[i]}</li>;
                                                    result.push(item);
                                                  }
                                                  return result;
                                                }()}

                                                С тем же успехом можно подобной ерунды и на любом DSL наколбасить.


                                                И на самом деле (кстати) это и есть рассахаренный «звездочковый» синтаксис

                                                Да это-то понятно, просто вот вам и пример, что в этом "строгом DSL" тоже есть несколько путей для реализации. Причем первый еще ладно, второй — совсем же дичь, всевдокод внутри строки, о боги :)

                                                • Druu
                                                  /#10414866

                                                  > Естественно, варианты из серии следующего — бред и не принимаются:

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

                                                  > Да это-то понятно, просто вот вам и пример, что в этом «строгом DSL» тоже есть несколько путей для реализации.

                                                  На самом деле не совсем. Мой вариант со звездочкой неточен, т.к. на самом деле раскроется в:

                                                  <ng-template let-row="row" let-value="value" ngx-datatable-cell-template>
                                                      <ng-container>
                                                          My name is: <i [innerHTML]="row['name']"></i> and <i>{{value}}</i>
                                                          <div>{{joke}}</div>
                                                      </ng-template>
                                                  </ng-container>
                                                  

                                                  звездочковый эквивалент тут не написать. Возможно, именно по-этому и выбран рассахаренный вариант :)

                                                  > второй — совсем же дичь, всевдокод внутри строки, о боги :)

                                                  Он не внутри строки :)

                                                  • raveclassic
                                                    /#10414894

                                                    Почему не принимаются?

                                                    Потому что это чушь же :) Хреновая верстка на голом html от аутсорсера/фрилансера может быть такого же градуса бредовости. Если не хуже


                                                    звездочковый эквивалент тут не написать. Возможно, именно по-этому и выбран рассахаренный вариант :)

                                                    Ну то есть можно так, а можно этак


                                                    Он не внутри строки :)

                                                    Строки, строки, аттрибуты — строки.

                                                    • Druu
                                                      /#10414908

                                                      > Потому что это чушь же :) Хреновая верстка на голом html от аутсорсера/фрилансера может быть такого же градуса бредовости. Если не хуже

                                                      Вы опять уходите в сторону обсуждения принципиальной возможности чего-то, когда на практике важна именно количественная оценка. Следуя вашим рассуждениям — неплохо писать на брейнфаке. Потмоу что по факту любой аргумент против брейнфака применим и к другим языкам. Просто в меньшей степени. Иногда — в намного меньшей :)

                                                      > Ну то есть можно так, а можно этак

                                                      Ну какбы нельзя :)
                                                      И даже если бы было можно — опять возвращаемся к количественной оценке.

                                                      > Строки, строки, аттрибуты — строки.

                                                      Ну нет. Не будет там нигде строки «let value blablabla»

                                            • indestructable
                                              /#10416356

                                              А изменение коллекции @ContentChildren как-то повлияет на содержимое компонента?

                                              • Druu
                                                /#10416378

                                                Это неизменяемая коллекция. Точнее, это скорее observable. То есть сама она может измениться (если поменяется содержимое компонента), но поменять ее напрямую нельзя.

                                  • indestructable
                                    /#10413948

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

                                    Ну так вы когда джаваскрипт код читаете, вы его в уме выполняете? С JSX все так же.

                                    • Druu
                                      /#10414214

                                      > Ну так вы когда джаваскрипт код читаете, вы его в уме выполняете? С JSX все так же.

                                      Ттак я и говорю о том, что JSX проигрывает шаблонизаторам из-за того, что приходится выполнять в уме JS-код.

                                • indestructable
                                  /#10413938

                                  Более того, map — это джаваскрипт, npRepeat — это микроязык, свой для каждой директивы.

                                  • Druu
                                    /#10414218

                                    > Более того, map — это джаваскрипт, npRepeat — это микроязык, свой для каждой директивы.

                                    Именно. По-этому ngRepeat значительно проще и удобнее.

                                    • raveclassic
                                      /#10414728 / +1

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

                                      • Druu
                                        /#10414792

                                        Только вот выучить map недостаточно, надо выучить весь js. И это намного сложнее, чем выучить три с половиной директивы :)

                                        • raveclassic
                                          /#10414808

                                          Ну как же недостаточно, я ж сравнивал уже выше, ng-repeat — это map, ng-if — && и ?:
                                          Как же сложнее?

                                          • Druu
                                            /#10414828

                                            Если ограничить JSX так, что другого способа написать эти конструкции в принципе не будет (вообще), то не сложнее. Тогда JSX станет тем же дслем, только с другим синтаксисом.

                                            • raveclassic
                                              /#10414846

                                              Думаю, что можно будет как-нибудь сесть за tslint и написать подобных правил. Добавлю в бэклог

                                        • indestructable
                                          /#10416372

                                          Ну да, Реакт — он для программистов. Впрочем, утверждение, что шаблоны Ангуляра будет делать верстальщик — это, скажем так, самообман.

                  • vasIvas
                    /#10414766

                    Давайте так —

                    1. у Вас есть шаблонизатор, который генерирует html. Шаблонизатор, как любой другой современный шаблонизатор, имеет расширенный синтаксис foreach ifelse и так далее.
                    2. теперь представьте что шаблонизатор настолько продвинут, что позволяет разработчику расширить и так расширенный синтаксис
                    3. теперь представьте что Вы можете создавать композиции из расширений шаблонизатора, как например использование if в for
                    4. теперь представьте что шаблонизатор это реакт-элементы, которые в реальности обычные объекты
                    5. теперь представьте что реакт-компоненты это механизм создания пользовательских расширений шаблонизатора


                    А теперь скажите, какой по Вашему пункт не верен? К сожалению из-за минусов я могу оставлять коменты только раз в день, не обессудьте, я продолжу.

                    Если Вы опять упретесь, что логика в компонентах, то простите меня за настойчивость, какая? Собрать композицию из компонентов, которые являются частью представления? Это по Вашему логика не представления? Или сетевые запросы и бизнес логика? Если да, то простите меня за грубость, какой дурак её там пишет?

                    Вам доводилось создавать интерфейсы (читать представления) c#? jаva? canvas?
                    flex? С чем Вы сравниваете, говоря о правильности компонентов? Мое мнение основано на выше перечисленных технологиях.

                    • Druu
                      /#10414800

                      > теперь представьте что шаблонизатор настолько продвинут, что позволяет разработчику расширить и так расширенный синтаксис

                      Смысл шаблонизатора (как и любого ДСЛя или узкоспециализированного инструмента) ИМЕННО в том, что он ограничен в возможностях. Мы платим универсальностью за более удобное решение задач из узкого класса. Если вы делаете шаблонизатор универсальным — основное преимущество (ограниченность) сразу теряется.

                      • raveclassic
                        /#10414818

                        То-то в рамках этих ограничений стало тесно, и тут же придумали наикостыльнейшие пайпы! Получается, вы все-равно пишете расширения для дубового шаблонизатора, потому-что его базовых возможностей недостаточно. И пишете вы их для того, чтобы эти возможности расширить, чтобы продолжать пользоваться дубовым шаблонизатором, но своими костылями, вместо того, чтобы пользоваться уже языком :)

                        • Druu
                          /#10414838

                          > То-то в рамках этих ограничений стало тесно, и тут же придумали наикостыльнейшие пайпы!

                          Какая теснота? Смысл пайпов исключительно в том, что они бывают pure, и в этом случае пересчитываются только тогда, когда изменится аргумент. Такого поведения затруднительно достичь, не замусорив код, это надо реализовывать на уровне компилятора шаблонов.
                          В противном случае (при отсутствии pure) пайпы были бы совершенно не нужны и ничего бы не давали, можно с тем же успехом дергать обычные функции.

                          • raveclassic
                            /#10414876

                            В противном случае (при отсутствии pure) пайпы были бы совершенно не нужны и ничего бы не давали, можно с тем же успехом дергать обычные функции.

                            Не понял, pure это в кривых реактовских терминах pure? Типа аргумент не меняется, пайп не пересчиваем? Так, казалось бы, почему шаблонизатор должен этим заниматься? Его задача вывести значение, а не накручивать пайплайн преобразований для этого значения. Для этого есть язык, и именно поэтому можно (и нужно) и обычные функции мемоизировать в рамках языка и дергать их с тем же успехом. А если смешивать эти вещи, то вам и шаблонизатор уже не нужен, у вас JSX получился

                            • Druu
                              /#10414882

                              > Не понял, pure это в кривых реактовских терминах pure? Типа аргумент не меняется, пайп не пересчиваем?

                              Значит, чистая функция. В ФП-смысле — без сайд-эффектов, результат зависит только от аргумента.

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

                              Это не будет работать внутри шаблонов. И там речь не о мемоизации. Если аргумент не изменился — пайп просто не запускается, а дом не перестраивается. Это внутренность алгоритма чендж-детекшона и «снаружи» такое поведение, фактически, не получить.

                              • raveclassic
                                /#10414902

                                Значит, чистая функция. В ФП-смысле — без сайд-эффектов, результат зависит только от аргумента.

                                Ну прекрасно, я ж не спроста переспросил. Чистые функции можно и просто дергать.


                                Это не будет работать внутри шаблонов.

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


                                И там речь не о мемоизации. Если аргумент не изменился — пайп просто не запускается, а дом не перестраивается. Это внутренность алгоритма чендж-детекшона и «снаружи» такое поведение, фактически, не получить.

                                Ну вон же сколько ненужных деталей.
                                Если аргумент мемоизированной функции не меняется, возвращается предыдущее значение, а ее тело не запускается заново, такое же ж поведение. А если значение не поменялось, после реконсиляции dom тоже не перестроится. Четче, проще, декларативнее и понятнее, без всяких этих туземских детекшенов с бубнами.

                                • Druu
                                  /#10414916

                                  > Как же, я же могу вызвать метод из шаблона при подстановке значения

                                  И тогда он будет вызван.

                                  > Если аргумент мемоизированной функции не меняется, возвращается предыдущее значение, а ее тело не запускается заново, такое же ж поведение.

                                  Нет, не такое же. Как минимум — при мемоизации надо хранить где-то много значений. Пайп хранит только одно — предыдущее. И, нет, нельзя в самой функции поставить ограничение на одно значение — т.к. пайп может применяться во многих местах, то есть надо мемоизировать по значению на каждый инстанс в шаблоне. По-этому вы мемоизацией то же самое поведение никогда не получите. Теперь представьте, что вам надо мемоизировать большой список. Очень большой. В случае pure-пайпа у вас не будет накладных расходов на хранение списка. А в случае мемоизации — будет. На кучу списков.

                                  • raveclassic
                                    /#10414940

                                    И тогда он будет вызван

                                    И вернет предыдущее значение для известного аргумента, если он мемоизирован. Средствами языка


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

                                    Это детали реализации мемоизирующего декоратора (раз уж мы про методы, то декоратора), а внутри есть доступ к инстансу компонента. Можете там хоть одноуровневый кэш устроить.


                                    А в случае мемоизации — будет. На кучу списков.

                                    Храните-то вы ссылки на эти списки, так что все норм.

                                    • Druu
                                      /#10414942

                                      > Храните-то вы ссылки на эти списки, так что все норм.

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

                                      • raveclassic
                                        /#10414950

                                        Нет, так как, если вы устраиваете хранилище на инстансе компонента, то это хранилище уничтожится при его анмаунте. И нет больше слез утечек

                                        • Druu
                                          /#10414958

                                          > Нет, так как, если вы устраиваете хранилище на инстансе компонента, то это хранилище уничтожится при его анмаунте.

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

                                          • raveclassic
                                            /#10414966

                                            Ну вы же этот грид видите на странице, значит и данные к нему будут в памяти болтаться, значит и ссылку можно хранить. Более того, в пайпах так же должна храниться ссылка на входящий аргумент

                                            • Druu
                                              /#10414978

                                              > Ну вы же этот грид видите на странице

                                              Так вижу я текущий грид, а в кеше мемоизированной функции будет еще мильон старых гридов, которые я уже не вижу :)
                                              Например, я применяю разные фильтры, убираю/добавляю строки, редактирую где-то что-то. В итоге грид меняется, каждый раз вызывается ф-я преобразования (которую мемоизируем), каждый раз она сбрасывает значения в кеш.

                                              > Более того, в пайпах так же должна храниться ссылка на входящий аргумент

                                              В пайпах ничего не хранится — это во View хранятся предыдущие значения биндингов. В случае наличия пайпа, просто в этом месте вместо значения биндинга хранится значение аргумента пайпа, вот все, что делает в этом плане пайп.

                                              • raveclassic
                                                /#10414998

                                                а в кеше мемоизированной функции будет еще мильон старых гридов

                                                Почему мильон? Мы ж про одноуровневый кэш.


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

                                                Так и пайп будет каждый раз перезапускаться


                                                В пайпах ничего не хранится — это во View хранятся предыдущие значения биндингов. В случае наличия пайпа, просто в этом месте вместо значения биндинга хранится значение аргумента пайпа, вот все, что делает в этом плане пайп.

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

                                                • Druu
                                                  /#10415034

                                                  > Совершенно без разницы, где хранится предыдущее значение, оно все-равно хранится

                                                  Оно хранится вместо другого значения. То есть, в итоге оверхеда нет.

                                                  > Так и пайп будет каждый раз перезапускаться

                                                  Но не будет сохранять предыдущее значение.

                                                  > Почему мильон? Мы ж про одноуровневый кэш.

                                                  Почему одноуровневый? А если пайп ф-я в нескольких местах применяется?

                                                  В любом случае, это бессмысленные рассуждения. Я объяснил, зачем конкретно были введены пайпы — для оптимизации, которую иначе (без изменения алгоритма cd) сделать нельзя. Это единственная причина, а какая-то «теснота» или еще там что не при делах. То, что могут быть какие-то другие варианты оптимизации — факт нерелевантный.

                                                  • raveclassic
                                                    /#10415048

                                                    Оно хранится вместо другого значения. То есть, в итоге оверхеда нет.

                                                    Эммм… Как тогда шаблонизатор, не имея обоих значений, понимает, перезапускать ли пайп или нет? Или там при установке значения выполняются (если значение новое) все связанные с ним пайпы?


                                                    Почему одноуровневый? А если пайп ф-я в нескольких местах применяется?

                                                    Так вы же сами захотели одноуровневый. Если нужен одноуровневый в месте применения в шаблоне, а не на инстансе, то, наверное, вы меня все-таки поймали. Но за мою практику с реактом мне ни разу такой не понадобился, хотя в реакте мемоизация здесь и там, особенно с каррированными хэндлерами. Как бы я решал такую ситуацию? Черт его знает, скорей всего через мемоизируемые геттеры, ну да, костыль.

                                                    • Druu
                                                      /#10415402

                                                      > Эммм… Как тогда шаблонизатор, не имея обоих значений, понимает, перезапускать ли пайп или нет?

                                                      Я же говорю, он _вместо_ одного значения (результат ф-и) хранит другое (ее аргумент). Естественно, может быть ситуация, когда аргумент больше результата. Или наоборот. Но это уже вопрос статистику, в среднем будет ± одинаково.

                                                      > Так вы же сами захотели одноуровневый.

                                                      Я просто описывал работу пайпов, а их можно сравнить именно с одноуровневым кешем per instance пайпа.

            • symbix
              /#10412550

              Тут есть две проблемы — одна вымышленная, вторая реальная (но про другое).


              Вымышленная — про разделение труда между верстальщиком и разработчиком. На самом деле, что с JSX, что с html, нашпигованным angular-директивами, так разделять уже не получается, верстальщику нужно "апгрейдиться" до начинающего разработчика в любом случае.


              Реальная (но специфичная для реализации) — в том, что JS с ограничением на expression only не очень-то удобен: приходится вместо очевидных if/foreach либо писать менее очевидные конструкции, либо выносить их отдельно, что зачастую снижает читабельность. Это можно решить небольшим расширением JSX по аналогии с кофескриптом (чтобы if etc возвращали значение).

              • debounce
                /#10412602 / -1

                Реакт — мы засунули html в js, но шаблонизатора нет — поэтому мы встроили js в html — построй свой шаблонизатор на js. Фак.

                Обожаю программирование)
                1.«JS с ограничением на expression only не очень-то удобен[для шаблонов]»
                2. «можно решить небольшим расширением»

                • symbix
                  /#10412644

                  Когда я в первый раз увидел JSX, у меня были ровно такие же ощущения, как у вас, и так было где-то год, пока не поработал с React-проектом. За исключением того момента, что я озвучил, нормально все с JSX, тут главное преодолеть ментальный блок :-)


                  Мне гораздо больше не понравилось, что нельзя использовать DI в конструкторах компонентов. Property injection, конечно, делается, но это хуже: в конструкторе намного заметнее ситуация, когда у компонента слишком много зависимостей.

                  • nohuhu
                    /#10412986

                    нормально все с JSX, тут главное преодолеть ментальный блок :-)

                    Цитируя любимую поговорку моей маман: Если вас ударят в глаз, вы, конечно, вскрикнете. Раз ударят, два ударят, а потом привыкнете.


                    Ну, или можете не мучиться. Ваш выбор.

  33. Alexanqp
    /#10411448

    Спасибо за статью. Столкнулся при освоении в начале с не которыми вышеописанными проблемами, возможно еще придётся столкнутся, но сомневаюсь, что перестану его «любить» )

  34. Zakyann
    /#10415500

    Посмотрел по ссылке:

    github.com/angular/angular/issues?page=2&q=is%3Aissue+is%3Aopen

    1700+ открытых issues 8-(

    Это кто-то в продакшне использует? Жесть какая.

    • staticlab
      /#10415634 / +2

      А в UniGUI сколько открытых issue? :)


      И да, для популярного решения это вполне адекватное число issue. Притом не всё из этого баги.


      Для сравнения, в JetBrains TeamCity 9327 открытых issue, в JIRA — 12192. Вполне себе успешные коммерческие системы, разрабатываемые Full time за немаленькие деньги. "Это кто-то в продакшене использует?"

    • raveclassic
      /#10416000

      Смеяться будете, но они еще и закрывают их в полуавтоматическом режиме, если активности нет 3 месяца.