Material-ui: Можно ли упростить набор текста для повышения производительности?

Созданный на 7 янв. 2020  ·  70Комментарии  ·  Источник: mui-org/material-ui

Как было предложено @ eps1lon в # 18128, я создаю эту проблему как место для обсуждения типизаций Material-UI и того, можно ли их упростить, чтобы сократить время, затрачиваемое на их проверку, особенно во время редактирования.

Всегда существует противоречие между наличием наиболее точных типов (которые обеспечивают наилучшие ошибки и завершенные редакторы) и быстрой проверкой типов (дальний конец спектра - any ).
Такие проблемы, как https://github.com/microsoft/TypeScript/issues/34801, предполагают, что Material-UI может выиграть от снижения точности, чтобы вернуть некоторую производительность.

Судя по репродукциям, которые я исследовал до сих пор, большая часть медлительности, похоже, связана с большим количеством имен свойств CSS (см. Https://github.com/mui-org/material-ui/blob/master/packages/ материал-ui-styles / src / withStyles / withStyles.d.ts). Я сам не являюсь активным пользователем CSS, поэтому у меня есть несколько наивных вопросов:

1) Правильно ли я предполагаю, что наличие имени и типа для каждого известного свойства CSS невероятно ценно, и разве мы не можем отказаться от этого?
2) Тип CSSProperties видимому, существует для поддержки «псевдоселекторов и медиа-запросов», которые - согласно моему ограниченному чтению - кажутся названными пакетами дополнительных свойств CSS.
а) Эти пакеты сами рекурсивны или есть только один дополнительный слой? То есть вы переходите от width к foo.width или к foo.bar.width и т. Д.? Если это всего лишь один уровень, то упрощение типов сократит мою локальную репродукцию с 4,6 до 3,6 секунды (т.е. большая победа).
б) Я сам поиграл с типами и не смог придумать ничего лучше, чем BaseCSSProperties[keyof BaseCSSProperties] , но - как я предполагаю, вы знаете - это не очень полезный тип. В основном это говорит о том, что любое свойство CSS может иметь тип любого (другого) свойства CSS - это ненамного лучше, чем any .
3) В StyleRules , если нет свойств, вы получаете либо CSSProperties или () => CSSProperties (которые я небрежно назову "thunked CSSProperties"), что имеет смысл - CSSProperties может быть ленивым. Если есть свойства, вы получите либо CreateCSSProperties<Props> , что имеет смысл - Props может потребоваться для вычисления CSSProperties - либо (props: Props) => CreateCSSProperties<Props> , чего я не делал. Не понимаю, потому что это эффективно вдвойне лениво - вы должны передать Props один раз, чтобы получить CreateCSSProperties а затем еще раз, чтобы получить отдельные свойства. Почему это "двойное проникновение"?

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

Можем ли мы работать вместе, чтобы найти правильный баланс между точностью и производительностью? (Примечание: «просто сделай компилятор быстрее» - очевидная жизнеспособная стратегия, но я бы хотел, чтобы типизация была в хорошем месте, прежде чем мы оптимизируем для нее.) Спасибо!

performance typescript

Самый полезный комментарий

Я начал добавлять Material UI ( 4.9.4 ) в свой проект сегодня, и замедление действительно настолько велико, что я даже не думаю, что смогу использовать его в своем проекте. Просто добавил простой компонент <Slider/> , настроенный с помощью withStyles() .

Мы говорим о переходе от мгновенной обратной связи TypeScript в моей среде IDE к тому, что временами кажется 5-10 секунд (для частей моего кода, которые сейчас даже не взаимодействуют с пользовательским интерфейсом материала - это просто полное замедление TypeScript в файле, который использует компонент). Что-то должно быть не так с этими типами (или, да, слишком сложно), похоже, @amcasey проводит хорошее расследование - надеюсь, вы сможете разобраться в этом!

Пытаюсь найти способ, по крайней мере, исключить все вещи TypeScript для @material-ui на данный момент (в основном сделать весь модуль any ) - но TypeScript, похоже, не делает это достаточно простым.

Все 70 Комментарий

Я не знаком с типами material-ui, но постараюсь ответить на эти вопросы.

  1. Да, полная поддержка всех свойств css, заявленных в реальных веб-стандартах, полезна.
  2. а) В нашем случае мы никогда не используем глубину больше 2, но такие случаи вполне возможны
    Машинопись
    const styles = (тема: Тема) =>
    createStyles ({
    somediv: {
    '&: hover button': {
    видимость: 'видимый',
    непрозрачность: 1,
                ':after': {
                    content: 'x',

                    [theme.breakpoints.up('lg')]: {
                        content: 'close',
                    },
                }
            },
        }
    });
```
b) I do not understand why `BaseCSSProperties[keyof BaseCSSProperties]` is needed there

  1. Я думаю, что (props: Props) => CreateCSSProperties<Props> не нужен, мы исключили этот тип в нашей версии типов material-ui, и ничего плохого не произошло.

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

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

  1. Правильно ли я предполагаю, что наличие имени и типа для каждого хорошо известного свойства CSS невероятно ценно и разве мы не можем отказаться?

Здесь невозможно быть беспристрастным. Я не думаю, что мы можем отказаться от этого, глядя на более широкую экосистему. У Chrome devtools есть эта функция, они реагируют на тип style prop с CSSProperties и т. Д. Я не вижу, как я переключаюсь с IDE на браузер и проверяю, было ли это оформлением текста или шрифтом или текст-преобразование.

  1. [...]
    Эти пакеты сами рекурсивны или есть только один дополнительный слой?

Мне нужно будет проверить решение CSS-in-JS, которое мы используем. Технически медиа-запросы в CSS могут быть рекурсивными. Я бы хотел сократить эту рекурсивность и посмотреть, будем ли мы получать отчеты. Технически вложенные медиа-запросы можно сгладить с помощью оператора and . Однако мы должны ограничить его двумя уровнями: один для медиа-запросов и один для псевдоселекторов. Это все еще должно быть проверено типом IMO:

const styles = {
  root: {
    '<strong i="18">@media</strong> (max-width: 12cm)': {
      ':hover': {}
    }    
  }
}

Это то, что вы видите, когда пишете @oliviertassinari?

  1. [...]
    CSSProperties - или (props: Props) => CreateCSSProperties, которого я не понял, потому что это фактически дважды лениво - вам нужно передать Props один раз, чтобы получить CreateCSSProperties, а затем еще раз, чтобы получить отдельные свойства. Почему это "двойное проникновение"?

Если сам аргумент не является набором свойств, а функцией, тогда ему требуется тема. Стили могут зависеть от двух разных типов пакетов свойств: темы (доступной через контекстный API React) или реквизита (непосредственно передаваемых компоненту):

makeStyles({ root: { color: 'blue' }}); // A
makeStyles(theme => ({ root: { color: theme.color } })); // B
makeStyles({ root: props => ({ color: props.color})}); // C
makeStyles({ root: { color: props => props.color } }); // D: same as C, only exists for dev ergonomics
makeStyles(theme => ({ root: props => ({ color: props.color || theme.color }) })); // E: what you called "double-lazy"

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

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

Есть один случай, когда это используется:

Учитывать

const useStaticStyles = makeStyles({ root: { color: 'blue' } });
const useDynamicStyles= makeStyles({ root: { color: props =>  props.color } })
function Component() {
  const staticClasses = useStaticStyles(); // No error
  const throwingClasses = useDynamicStyles(); // $ExpectError
  const dynamicClasses = useDynamicStyles({ color: 'blue' });
}

Чтобы вывести сигнатуру вызова функции, возвращенной из makeStyles (т.е. ловушка названа чем-то вроде useSomeStyles ). Нам нужно проверить, какой тип пакета стилей передается в makeStyles . У нас уже есть помощник для определения типов реквизита, используемых в сумке style . Если пакет стилей является статическим, то есть TS определяет тип {} . Затем мы проверяем предполагаемый тип Props с помощью IsEmptyInterface и для одной ветви мы используем сигнатуру вызова с 0 параметрами, а для другой ветви мы используем сигнатуру вызова с 1 параметром, который равен предполагаемому типу props ( см. StylesRequireProps и StylesHook .

Вкратце: нам не нужно писать useStaticStyles({}) или useStaticStyles(null as any) . Он был представлен на https://github.com/mui-org/material-ui/pull/14019, чтобы закрыть https://github.com/mui-org/material-ui/issues/14018. Полагаю, мы можем короткое замыкание при определении сигнатуры звонка. Может быть, перегрузить сигнатуру вызова вместо использования условных типов?

Проблема с этой «функцией» в том, что у опытных пользователей нет проблем с использованием null as any если они понимают, почему. Возможно, даже передача пустого объекта допустима, даже если она не нужна. Однако это очень сбивает с толку / разочаровывает, когда не используется Material-UI или TypeScript. Тем более, что большая часть стиля в любом случае основана не на реквизите.

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

Я могу сканировать больше репозиториев, чтобы конкретно посмотреть на использование withStyles или makeStyles . Пока я смотрел только на использование реквизита.

Это то, что вы видите, когда пишете @oliviertassinari?

@ eps1lon У нас есть несколько случаев такого вложения в базу кода (например, с <strong i="8">@media</strong> (hover: none) ). Но для основных компонентов такое случается нечасто. Думаю, это тот же пользовательский мир. Это определенно могло быть частью компромисса.

@beholderrk

  1. Я так и думал, но подумал, что могу спросить.
  2. а) Глубина два должна быть выразимой - просто будет немного больше дублирования, чем глубины один.
    б) Мне потребовалось довольно много времени, чтобы осмыслить это, и я хотел бы объяснить это лично, а не в тексте. По сути, подпись индекса говорит, что все свойства имеют один и тот же тип. Это может работать, только если он указывает тип, который работает для всех из них. Один из способов сделать это - построить объединение всех типов свойств, BaseCSSProperties[keyof BaseCSSProperties] - тогда будет верно, что каждое свойство имеет совместимый тип. Например, предположим, что единственными свойствами, которые вы могли иметь в CSS, были name: string и width: number . Один из способов указать подпись индекса, которая работает с обоими свойствами, - это сказать, что каждое свойство является string | number . Это не здорово - name никогда не будет number а width никогда не будет string - но это работает. Настоящая проблема в том, что то, что вы хотите, на самом деле невозможно выразить (по крайней мере, насколько мы смогли определить - это может быть «умный» хакер). На самом деле вы хотите сказать, что ваш тип содержит name: string , width: number или x: CSSProperties , где x - это что угодно, кроме name или width - это "чего угодно, только не", которого не хватает. Надеюсь, это немного яснее.
  3. Похоже, @ eps1lon что-то

Было бы очень полезно использовать заведомо надежный исходный уровень. У вас случайно есть ссылка?
Изменить: нашел.

@ eps1lon Рад участвовать в разговоре. Быстрые, правильные типы хороши для всех. 😄

  1. Здесь нет аргументов - я просто подумал, что спрошу заранее, потому что это могло бы прервать весь разговор.
  2. Два слоя кажутся выполнимыми (с заметной оговоркой, что типы по-прежнему будут в значительной степени бесполезны). Я посмотрю, смогу ли я что-нибудь набросать.
  3. Из-за отсутствия контекста было непонятно, что темы и реквизит разные. Если да, то структура имеет смысл. Спасибо за разъяснения.

Что касается isEmptyInterface , не могли бы вы просто сделать параметр свойств (например) на useStaticStyles необязательным? Это было бы менее правильно в том смысле, что вызывающие абоненты могли бы опустить их, когда они ожидали, но было бы намного дешевле ввести проверку. Как я уже сказал, у меня нет цифр или чего-нибудь для вас - это просто предположения с моей стороны.

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

Что касается isEmptyInterface, не могли бы вы просто сделать параметр свойств (например) необязательным для useStaticStyles?

Я хотел бы сначала поэкспериментировать с перегрузкой сигнатуры вызова и посмотреть, повлияет ли это на какое-либо влияние. Затем мы попробуем сделать его менее звуковым, сделав его всегда необязательным. Кажется более безопасным, чем обычно, сделать его менее звуковым, поскольку почти все варианты использования вызывают его только один раз, поэтому вы, скорее всего, сделаете ошибку только один раз, и она появится довольно быстро. Будет сложно продать его, если он не принесет нам большой производительности. Я буду использовать репозиторий, созданный для исходного выпуска (https://github.com/microsoft/TypeScript/issues/34801#issue-514055289).

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

Пропустил случайно. Я посмотрю на это после эксперимента с IsEmptyInterface.

@ eps1lon Полностью согласен - оставьте isEmptyInterface если устранение этого не дает существенного выигрыша в производительности.

С # 19320 мы избавились от некоторых сложных условных типов, в которых перегрузка функций достигла того же результата (удаление IsEmptyInterface и всех типов логической логики). Хотя, похоже, это не принесло нам многого, кроме меньшего количества кода.

Хочу добавить, что сейчас я переключаюсь между TS 3.2.4 и 3.7.4. Наш набор типовых тестов работает на 50% медленнее в 3.7.4 по сравнению с 3.2.4 (~ 90 с против 50).

Я продолжу исследовать, можем ли мы ограничить глубину CSSProperties и полностью исключить поддержку медиа-запросов и псевдоселекторов. Однако, если они не набраны, это не вариант. Средство проверки типов должно иметь возможность проверить их в разумные сроки.

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

Если вы пришлете мне команды, которые выполняете в 3.2.4 и 3.7.4, я смогу профилировать локально. Однако опыт подсказывает, что причиной, вероятно, будет дополнительная желательная проверка, добавленная с версии 3.2.4. (И я предполагаю, что «0» - это опечатка - возможно, «40» или «50»?)

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

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

(И я предполагаю, что «0» - это опечатка - возможно, «40» или «50»?)

Извините, это 50-е годы.

Если вы пришлете мне команды, которые выполняете в 3.2.4 и 3.7.4, я смогу профилировать локально.

Это просто yarn typescript в корне, которое запускает одну и ту же команду в каждой рабочей области, которая ее реализует. Например, yarn workspace @material-ui/styles run typescript проверяет наши типы с помощью tslint и dtslint $ExpectError . В 3.7.4 мы столкнулись с некоторыми сбоями, и нам пришлось скорректировать наши тесты (см. №19242).

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

Я так и подозревал. Похоже, что то, как мы смешиваем «конкретную» фигуру с объектом с индексной сигнатурой, - это всего лишь обходной путь.

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

Определенно. Я потрачу немного больше времени на нерекурсивные CSSProperties, а затем напишу еще немного тестов, чтобы проиллюстрировать, что мы ищем в этих типах. Я подозреваю, что другие решения для стилизации css-in-js сталкиваются с аналогичными узкими местами в производительности.

Я опробую эти команды завтра (полагаю, мне следует упомянуть, что я нахожусь в тихоокеанском времени и соблюдаю праздники в США).

Похоже, что то, как мы смешиваем «конкретную» фигуру с объектом с индексной сигнатурой, - это всего лишь обходной путь.

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

Я подозреваю, что другие решения для стилизации css-in-js сталкиваются с аналогичными узкими местами в производительности.

Даже очень. Мы надеемся, что все, что мы делаем для вас, можно обобщить для улучшения всей экосистемы.

Я чувствую, что упускаю что-то очевидное, но сейчас я застрял. Во-первых, я отказался от Windows - в Linux все работает лучше. Дайте мне знать, если хотите вникнуть в это. Во-вторых, я могу запустить yarn typescript - насколько я могу судить чисто, - но похоже, что он запускает tslint, а не чистый tsc. Когда я запускаю tsc на том же tsconfig.json (я специально тестирую стили), я получаю ~ 40 ошибок. Что я делаю неправильно? Для целей профилирования было бы очень полезно преобразовать воспроизведение до одного вызова tsc.

@amcasey yarn typescript не о компиляции, а о тестировании наших типов. Мы используем настройку, аналогичную той, что использовалась в репозитории DefininiteTyped. Файлы TypeScript в packages/* почти всегда представляют собой набор операторов, которые должны либо пройти, либо не пройти, что мы перехватываем с помощью $ExpectError .

Я думаю, что лучший "реальный" тестовый пример - это использование tsc в наших документах через yarn workspace docs run tsc -p tsconfig.json после того, как вы добавили skipLibCheck: true и noEmit: true в ./docs/tsconfig.json :

--- a/docs/tsconfig.json
+++ b/docs/tsconfig.json
@@ -3,6 +3,8 @@
   "include": ["types", "src/pages/**/*"],
   "compilerOptions": {
     "allowJs": false,
-    "noUnusedLocals": true
+    "noUnusedLocals": true,
+    "noEmit": true,
+    "skipLibCheck": true
   }
 }

@ eps1lon Спасибо за разъяснения. Я не в восторге от того, что tslint стал медленнее, но я хотел бы сосредоточиться на одной переменной за раз. Я запущу предложенную вами сборку документации с различными версиями машинописного текста и посмотрю, не выскочит ли что-нибудь. Спасибо!

Эта установка идеальна. Я вижу, что время проверки удваивается между 3,3 и 3,4.

| Версия | Проверить время |
| - | - |
| 3.2 | 16,71 с |
| 3.3 | 16,79 с |
| 3.4 | 35,25 с |
| 3.5 | 21,40 с |
| 3.6 | 23.10 с |
| 3,7 | 27,39 с |

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

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

Я считаю, что между 3,5 и 3,7 время, необходимое для выполнения проверки, увеличилось на 6 секунд. Это выглядит довольно солидно.

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

Я переделал его на виртуальной машине Linux, и 3.7 всегда был на 20-25% медленнее, чем 3.5.

Это оказалось довольно сложно разделить пополам, потому что последовательные прогоны одной и той же сборки различаются на ~ 5%, а разница между 3,5 и 3,6 или между 3,6 и 3,7 составляет всего ~ 10%.

Я заметил одну подозрительную вещь: styled-components предоставляет отдельные файлы .d.ts для TS> = 3.7, поэтому сравнение не может быть яблоком с яблоком.

К моему большому удивлению, новые типы styled-components оказались быстрее. Однако сравнение яблок с яблоками все же упростит расследование.

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

@amcasey Спасибо за ваши усилия в

На этом этапе мы были бы счастливы обменять немного безопасности типов в нашем JSS на быструю обратную связь для остальной части библиотеки. Иногда требуется 8-10 секунд ожидания, прежде чем сервер Typescript догонит изменения кода.

Даже со средними значениями трех прогонов данные очень зашумлены. Однако, похоже, наблюдается заметное снижение времени выполнения на https://github.com/microsoft/TypeScript/commit/ad322a561a301ae357da051b9221b2222c13be36 и заметное увеличение (примерно до предыдущего уровня) на https://github.com/microsoft/TypeScript / commit / 480b73915fdd805952fd355e4cf3e1bc803e0878 и общая восходящая тенденция после этого (хотя для меня это выглядит слишком однородным, и я подозреваю, что это факторы окружающей среды), включая конкретный всплеск на https://github.com/microsoft/TypeScript/commit/c533e6d95e9368008904338 Я собираюсь сосредоточиться на первых двух, пока не проведу еще несколько тестов, чтобы подтвердить общую восходящую тенденцию (как она может ухудшаться с каждой фиксацией?).

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

Я увеличил количество прогонов до 10 за одну фиксацию, и теперь в наклонной области есть четыре отчетливых регресса. :улыбка:

https://github.com/microsoft/TypeScript/commit/26caa3793e310e271ddee8adc1804486e5b0749f (~ 700 мс)
https://github.com/microsoft/TypeScript/commit/250d5a8229e17342f36fe52545bb68140db96a2e (~ 500 мс)
https://github.com/microsoft/TypeScript/commit/7ce793c5b8c621af5ce50af0ca3958c7bd6541bf (~ 1300 мс)
https://github.com/microsoft/TypeScript/commit/28050d5c47c6cd7627555f12cf13b1062f80322a (~ 400 мс)

(Общее время до начала регрессии составляло ~ 33 секунды.)

Просто чтобы немного успокоить ожидания: вполне вероятно, что некоторые из этих регрессий окажутся полезными дополнительными проверками, и, даже если бы нам удалось получить все эти проверки бесплатно, мы бы все равно взяли только 20% скидку «слишком долго. ".

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

@ eps1lon Кто-то на этом конце предположил, что может помочь удаление @ts-ignore . Обычно при обнаружении ошибки предполагается, что главным приоритетом пользователя является получение достоверной информации об ошибке, поэтому вполне возможно, что будет проделана кучу дополнительной работы. Если эта информация впоследствии будет отброшена (из-за @ts-ignore ), то это время будет потрачено зря. (К сожалению, нелегко обнаружить, что ошибку не нужно обнаруживать.) Альтернативная стратегия - добавлять явные утверждения типа (в том числе в any ) до тех пор, пока компилятор не перестанет жаловаться.

@ eps1lon Кто-то на этом конце предположил, что может помочь удаление @ts-ignore .

У нас было только одно использование в docs/ . Все равно удалил на всякий случай: # 19504

Честно говоря, в этом случае звучит так, будто @ts-ignore - это антипаттерн. Он не только не дает вам полезной информации, например, какой у нас тип ошибки, но и является узким местом производительности.

Насколько я могу судить, @ts-ignore полезно только в .js файлах, которые проверяются на тип.

Хм, это почти наверняка не объясняет, почему PR, улучшающий сообщения об ошибках, снижает производительность. Определенно похоже на улучшение. 😄

Ошибки изменений, снижающих производительность:
https://github.com/microsoft/TypeScript/issues/36562
https://github.com/microsoft/TypeScript/issues/36564
https://github.com/microsoft/TypeScript/issues/36565
https://github.com/microsoft/TypeScript/issues/36566
https://github.com/microsoft/TypeScript/issues/36567

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

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

Я предполагаю, что некоторые пользователи (я являюсь одним из них) не сильно используют встроенную систему стилей или полностью избегают ее. Я делаю это главным образом потому, что я гораздо больше знаком с простым CSS или Sass, и у меня действительно нет времени разбираться в том, как эффективно использовать систему стилей JS. Я предпочитаю просто придумывать собственные имена классов, писать отдельный файл таблицы стилей, использовать имена классов внутри моих компонентов React и продолжать. По сути, я стиль, как если бы я писал простой HTML.

При этом возможно / практично добавить флаг, который отключает проверку типов для дорогостоящих частей системы стилей (возможно, условно выполняя такие вещи, как type CSSProperties = any )? Я не знаю статистических данных о количестве людей, использующих систему стилей и не использующих ее, но я полагаю, что это не может принести большого вреда (при условии, что была добавлена ​​проверка для проверки набора текста с этим установленным флагом) , и это был бы быстрый способ повысить производительность по крайней мере для одного сегмента пользователей.

Просто хотел упомянуть общую идею; не стесняйтесь сбивать его. : Little_smiling_face:

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

Новые числа (другая машина, другая метрика времени):

| Версия | Общее время |
| - | - |
| 3.5.3 | 32,5 с |
| 3.7.5 | 35,9 с |
| мастер | 29,9 с |

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

Протестировано 3.8.1 в нашем наборе тестов, и кажется, что они такие же быстрые, как и предыдущие с использованием 3.2.4 (3.7 был значительно медленнее).

Честно говоря, я не могу поверить, сколько производительности мы смогли вернуть, не отказавшись от новой функциональности. : smile: Я думаю, что может быть немного больше провисания (например, https://github.com/microsoft/TypeScript/pull/36754), но я все же подозреваю, что наиболее значительным изменением будет упрощение типов CSSProperties. У вас вообще была возможность поиграть с ними? Похоже, что по крайней мере часть пользователей (например, @embeddedt) была бы счастлива отказаться от проверки типов в обмен на победу в производительности.

Похоже, что по крайней мере часть пользователей (например, @embeddedt) была бы счастлива отказаться от проверки типов в обмен на победу в производительности.

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

Для меня это не совсем проверка типов (инструменты разработчика браузера имеют гораздо лучшие возможности для проверки вашего CSS). Это больше о наличии автозаполнения.

Я поиграю с разными «версиями» и посмотрю, как они работают.

@amcasey Я не думаю, что рекурсивная природа CSSProperties (называемых CSSObject в стилизованных компонентах) является главной проблемой. В противном случае их производительность была бы такой же плохой, как у нас. См. Https://github.com/eps1lon/mui-types-perf/pull/6 и журналы тестов .

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

Я хотел бы упростить сигнатуру типа (так как это ИМО также легче понять разработчикам), но меня явно попросили сопоставить реализацию JSS. Теперь, когда мы его поддерживаем, мы не можем легко откатиться. Особенно, если прирост будет в районе 20%. Не думаю, что это оправдывает поломку.

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

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

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

«Пользовательская настройка», которую я мог видеть, - это исправление пакета при установке. У нас нет пропускной способности для поддержки нескольких версий типизации.

@ eps1lon Извините, я думаю, что мой вопрос мог быть неясным. Я думаю, что CSSProperties в порядке (хотя, очевидно, если бы он был быстрее, если бы он был меньше) - я действительно надеялся, что может быть место для упрощения подтипов в https://github.com/mui-org /material-ui/blob/master/packages/material-ui-styles/src/withStyles/withStyles.d.ts. Например, будет ли у вас меньше завершений, если вы измените этот тип на any ?

Изменить: в моем случае это ускоряет компиляцию проекта docs 15% (с 29,7 до 25,5 с), но я не знаю, как это повлияет на процесс редактирования.
Изменить 2: На самом деле, как только вы отказались от сворачивания в рекурсивной части типа, вы можете просто использовать BaseCreateCSSProperties а любое другое свойство будет иметь тип any (т.е. вы можете сохранить реальные типы свойств CSS).
Редактировать 3: Редактировать 2 не работает из-за избыточной проверки свойств (т.е. произвольные имена свойств не допускаются в объектных литералах).

Ваша точка зрения о завершении и проверке типов была очень интересной, потому что у меня была гипотеза, что некоторые авторы шрифтов могут так думать. @DanielRosenwasser Я думаю, мы хотели сделать что-то подобное, чтобы приспособить шаблон "a" | "b" | string - это куда-то пошло?

Также обратите внимание, что styled-components имеет (мы считаем) тесно связанные проблемы с производительностью проверки.

Что касается возможности более точно указать тип, я подал https://github.com/microsoft/TypeScript/issues/36782.

Похоже, emotion могут быть в одной лодке.

Я начал добавлять Material UI ( 4.9.4 ) в свой проект сегодня, и замедление действительно настолько велико, что я даже не думаю, что смогу использовать его в своем проекте. Просто добавил простой компонент <Slider/> , настроенный с помощью withStyles() .

Мы говорим о переходе от мгновенной обратной связи TypeScript в моей среде IDE к тому, что временами кажется 5-10 секунд (для частей моего кода, которые сейчас даже не взаимодействуют с пользовательским интерфейсом материала - это просто полное замедление TypeScript в файле, который использует компонент). Что-то должно быть не так с этими типами (или, да, слишком сложно), похоже, @amcasey проводит хорошее расследование - надеюсь, вы сможете разобраться в этом!

Пытаюсь найти способ, по крайней мере, исключить все вещи TypeScript для @material-ui на данный момент (в основном сделать весь модуль any ) - но TypeScript, похоже, не делает это достаточно простым.

@lostpebble То же самое происходит при использовании чего-то еще, кроме withStyles для настройки ползунка, например модулей CSS?

@lostpebble В настоящее время у нас нет поддерживаемого способа исключения определенного набора типов. Если вы действительно очень хотите, то можно поэкспериментировать с сопоставлением путей. Вы можете попробовать сопоставление пути, например "@material-ui/*": ["simplemui"] а затем создать simplemui.d.ts содержащий

declare const x: any;
export = x;

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

Я думаю, что мы сделали несколько хороших улучшений (где-то в районе 30%), но похоже, что все, что мы могли сделать прямо сейчас, - это облегчить набор текста.

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

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

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

В моем случае для makeStyles(theme => createStyles(...)) , возврат Record<ClassKey, any> из createStyles(...) почти ~ половин ~ (в моем коде и компьютере примерно ~ 1200 мс -> 750 мс ~ 1400 мс → 1100 мс) encodedSemanticClassifications-full: elapsed time отображается в журнале tsserver (похоже, это не дорогая работа, но, возможно, ожидает завершения проверки типа).

export default function createStyles<ClassKey extends string, Props extends {}>(
  styles: StyleRules<Props, ClassKey>,
): Record<ClassKey, any>;

createStyles(...) проверяет структуру стилей, чтобы мы могли пропустить проверку типа для объединения типа-аргумента-массива в makeStyles и объединения-типа-возврата в массиве createStyles.

~ (И закомментировал весь код makeStyles: 650 мс) ~

@ypresto createStyles требуется только для версий машинописного текста без утверждений const . Если вы можете использовать { display: 'block' as const } в своей кодовой базе (ts> = 3.4), используйте это вместо createStyles .

@ eps1lon Мы заметили это и попытались переключиться в docs но результаты были не впечатляющими.

@ eps1lon с const и без createStyles IntelliSense больше не отображает контекстно-зависимых кандидатов: cry:

@ypresto Должен. У вас есть пример фрагмента кода?

@amcasey

Добавление as const к внешнему объекту или свойству эффективно убивает его. Я не хочу размещать это на каждой собственности.

const useStyles = makeStyles(theme => ({
  root: {
    // no IntelliSense
  }
} as const))

Также без createStyles у него есть небольшое ограничение на завершение строки.

const useStyles = makeStyles(theme => ({
  root: {
    direction: '|', // no IntelliSense at | (works with createStyles)
    direction: | // IntelliSense works at |
  }
}))

@ypresto Под «убивает» вы имеете в виду «заставляет его работать так же, как createStyles »?

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

@amacleay Я имел в виду kills IntelliSense : молитесь :.

Извините, я пропустил ваши комментарии. Я попробую.

Понятия не имею, почему, но это 1100 мс → 750 мс, что интересно:

 export const DropArea: React.FC<CardProps & {
   active?: boolean
   description: string
   icon?: React.ReactNode
-}> = ({ active, description, icon, children, ...props }) => {
+}> = ({ children, ...props }) => {
   const classes = useStyles()
+  const active = false
+  const icon: React.ReactNode = null
+  const description = ''
   return (
     <Card {...props} className={clsx(classes.root)} variant="outlined">

Удаление CardProps & из FC дает почти тот же результат. Возможно, это потому, что CardProps расширяет PaperProps, который расширяет большие HTMLAttributes.

ОБНОВЛЕНИЕ И ВАЖНО: Оказалось, что замена CardProps на HTMLAttributes<HTMLDivElement> также сокращает время (не измеряется).

Наконец, я нашел самый большой, 750 мс → 130 мс:

Удаление style={...} из двух Typographys.

-<Typography variant="subtitle2" component="div" noWrap style={{ width: '26ch' }}>...</Typography>
+<Typography variant="subtitle2" component="div" noWrap>...</Typography>
-<Typography variant="caption" component="div" noWrap style={{ width: '20ch' }}>...</Typography>
+<Typography variant="caption" component="div" noWrap>...</Typography>

Но почему? Добавление того же стиля к <div> не снижает производительности. Может, OverridableComponent слишком сложно ..?

(Я использую TypeScript 3.8.3, @material-ui/core 4.9.1)

AFAIK способ, которым Material-UI обрабатывает локальные стили компонентов, отличается от того, как React обрабатывает его для элементов HTML.

@embeddedt На уровне типа он преобразуется в React.CSSProperties что совпадает с опорой стиля div.

@ypresto Я поправляюсь. Прости.

Привет, ребята, не уверен, стоит ли открывать для этого новый выпуск, поэтому я опубликую его здесь, поскольку он связан с правильностью / производительностью типов. Сообщите мне, если я должен вместо этого открыть вопрос.
Следуя документации по добавлению пользовательского шрифта , я получаю следующую опечатку:
Type 'string' is not assignable to type 'FontFaceFontDisplayProperty'

Это странно, потому что типизация csstype 2.6.9 кажется допустимой, а другие атрибуты допустимы (с использованием MUI 4.9.5).

const sourceSansPro = {
  fontFamily: "'Source Sans Pro'",
  fontStyle: "normal",
  fontDisplay: "swap", // won't work
  fontWeight: 400,
  src: `
    url('/static/fonts/Source_Sans_Pro/SourceSansPro-Regular.ttf') format("truetype")
  `
};

Свойство темы:

  overrides: {
    MuiCssBaseline: {
      "@global": {
        "@font-face": [sourceSansPro]
      }
    }

Тип: type FontFaceFontDisplayProperty = "auto" | "block" | "fallback" | "optional" | "swap";

@ eric-burel Это проблема с автоматическим расширением типов машинописных текстов. Пытаться

- fontDisplay: "swap", // won't work
+ fontDisplay: "swap" as "swap",

Спасибо, что это работает, и я узнал новую концепцию «расширение типа» :) Странно, что fontStyle например, не затрагивается, это не единственное свойство CSS, определенное как перечисление, но когда я впервые нажимаю на это .

Изменить: хорошо, плохо, это хорошо документировано: https://material-ui.com/guides/typescript/#using -createstyles-to -break-type-widening

Наконец, я нашел самый большой, 750 мс → 130 мс:

Удаление style={...} из двух Typographys.

-<Typography variant="subtitle2" component="div" noWrap style={{ width: '26ch' }}>...</Typography>
+<Typography variant="subtitle2" component="div" noWrap>...</Typography>
-<Typography variant="caption" component="div" noWrap style={{ width: '20ch' }}>...</Typography>
+<Typography variant="caption" component="div" noWrap>...</Typography>

Но почему? Добавление того же стиля к <div> не снижает производительности. Может, OverridableComponent слишком сложно ..?

(Я использую TypeScript 3.8.3, @material-ui/core 4.9.1)

Вы заметили, что это влияет на время сборки или просто на время, необходимое intellisense, чтобы быть полезным? У меня проблема со сборкой (нехватка памяти), и в некоторых компонентах нашего кода TS установлена ​​тонна style={someStyle} для компонентов. Интересно, является ли это частью нашей проблемы.

@ yatrix7 , вообще говоря, я ожидал, что такое долгое время проверки повлияет на время отклика как сборки, так и редактора.

Я кто-нибудь сейчас занимается этим? Я знаю, что были некоторые улучшения в отношении времени проверки типа машинописного текста в предыдущих обновлениях версии. Однако это все еще медленно.
Был бы не против разобраться в этом и сам.

Был бы не против разобраться в этом и сам.

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

На данный момент добавлен сравнительный анализ, чтобы помочь в расследовании: https://github.com/mui-org/material-ui/pull/22110

@FabianKielmann Что

Если у вас есть время потратить на это, вы также можете попробовать что-то вроде https://github.com/microsoft/TypeScript/issues/38583.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги