Material-ui: As digitações podem ser simplificadas para melhorar o desempenho?

Criado em 7 jan. 2020  ·  70Comentários  ·  Fonte: mui-org/material-ui

Conforme sugerido por @ eps1lon em # 18128, estou criando esta edição como um lugar para discutir as tipificações da IU do Material e se elas podem ser simplificadas para reduzir a quantidade de tempo gasto para verificá-las, especialmente durante a edição.

Sempre há uma tensão entre ter os tipos mais exatos (que fornecem os melhores erros e conclusões do editor) e ter a verificação de tipo rápida (a extremidade do espectro sendo any ).
Problemas como https://github.com/microsoft/TypeScript/issues/34801 sugerem que o Material-UI pode se beneficiar relaxando a exatidão para recuperar algum desempenho.

Pelas reprografias que investiguei até agora, muito da lentidão parece vir do grande número de nomes de propriedades CSS (consulte https://github.com/mui-org/material-ui/blob/master/packages/ material-ui-styles / src / withStyles / withStyles.d.ts). Não sendo um usuário ativo de CSS, tenho algumas perguntas ingênuas:

1) Estou correto ao presumir que ter um nome e tipo para cada propriedade CSS bem conhecida é incrivelmente valioso e não é algo de que poderíamos renunciar?
2) O tipo CSSProperties parece existir para suportar "pseudo seletores e consultas de mídia", que - de acordo com minha leitura limitada - parecem ser nomes de pacotes de propriedades CSS adicionais.
a) Essas bolsas são recursivas ou há apenas uma única camada adicional? Ou seja, você vai de width para foo.width ou para foo.bar.width , etc? Se for apenas um nível, simplificar os tipos corta minha reprodução local de 4,6 segundos para 3,6 segundos (ou seja, grande vitória).
b) Eu mesmo brinquei com os tipos e não consegui pensar em nada melhor do que BaseCSSProperties[keyof BaseCSSProperties] , mas - como estou supondo que você sabe - esse não é um tipo muito útil. Basicamente, ele diz que qualquer propriedade CSS pode ter o tipo de qualquer (outra) propriedade CSS - que é apenas um pouco melhor do que any .
3) Em StyleRules , se não houver propriedades, você obtém CSSProperties ou () => CSSProperties (que irei desleixadamente chamar de "propriedades CSS thunked"), o que faz sentido - o CSSProperties pode ser preguiçoso. Se houver propriedades, você obtém CreateCSSProperties<Props> , o que faz sentido - Props pode ser necessário para calcular CSSProperties - ou (props: Props) => CreateCSSProperties<Props> , o que eu não fiz não entendo porque é duplamente preguiçoso - você deve passar Props uma vez para obter CreateCSSProperties e novamente para obter propriedades individuais. Por que é "double thunked"?

Separadamente, eu suspeito, mas ainda não demonstrei que IsEmptyInterface é muito caro para o benefício que fornece. No entanto, é bem possível que eu não entenda totalmente os benefícios, então seria útil ouvir mais.

Podemos trabalhar juntos para encontrar o equilíbrio certo entre precisão e desempenho? (Observação: "apenas tornar o compilador mais rápido" é obviamente uma estratégia viável, mas eu gostaria de colocar as digitações em um bom lugar antes de otimizá-las.) Obrigado!

performance typescript

Comentários muito úteis

Comecei a adicionar Material UI ( 4.9.4 ) ao meu projeto hoje, e a lentidão é realmente tão significativa que acho que não posso nem mesmo usá-la no meu projeto. Acabei de adicionar um componente <Slider/> simples, personalizado usando withStyles() .

Estamos falando de um feedback instantâneo do TypeScript no meu IDE para o que parece ser de 5 a 10 segundos às vezes (para partes do meu código que nem mesmo estão interagindo com o Material UI agora - é apenas uma desaceleração completa do TypeScript no arquivo que usa o componente). Algo deve estar significativamente errado com esses tipos (ou sim, excessivamente complexo), parece que @amcasey está fazendo algumas boas investigações - espero que você possa chegar ao fundo disso!

Tentando encontrar uma maneira de pelo menos excluir todo o material do TypeScript por @material-ui por enquanto (basicamente tornar o módulo inteiro any ) - mas o TypeScript não parece tornar isso fácil o suficiente.

Todos 70 comentários

Não estou familiarizado com os tipos de interface de usuário de material, mas tento responder a essas perguntas.

  1. Sim, o suporte completo para todas as propriedades css declaradas em padrões da web reais é útil.
  2. a) Em nosso caso, nunca usamos uma profundidade maior que 2, mas casos como este são bem possíveis
    `` `texto datilografado
    estilos const = (tema: Tema) =>
    createStyles ({
    somediv: {
    '&: botão de foco': {
    visibilidade: 'visível',
    opacidade: 1,
                ':after': {
                    content: 'x',

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

  1. Acho que (props: Props) => CreateCSSProperties<Props> não é necessário, excluímos esse tipo em nossa versão dos tipos material-ui e nada de ruim aconteceu.

Pode valer a pena olhar para a implementação de tipos na versão 3.9.3, porque nesta versão, a verificação de tipo foi rápida o suficiente e a digitação foi boa.

Em primeiro lugar, gostaria de agradecer por entrar em contato e examinar isso. É extremamente útil ter alguém comparando quais partes dos tipos são lentos ou não.

  1. Estou correto ao presumir que ter um nome e tipo para cada propriedade CSS conhecida é incrivelmente valioso e não é algo de que poderíamos renunciar?

É impossível ser imparcial aqui. Não acho que podemos desistir disso olhando para o ecossistema mais amplo. Os devtools do Chrome têm esse recurso, o próprio reage digita o style prop com CSSProperties etc. Não consigo me ver mudando de IDE para navegador e verificar se foi text-decoration ou font-decoration ou transformação de texto.

  1. [...]
    Esses sacos são recursivos ou existe apenas uma única camada adicional?

Eu precisaria verificar a solução CSS-in-JS que estamos usando. Tecnicamente, as consultas de mídia em CSS podem ser recursivas. Eu estaria disposto a cortar essa recursividade e ver se obtemos relatórios. Consultas de mídia tecnicamente aninhadas podem ser simplificadas com o operador and . Devemos limitá-lo a dois níveis: um para consultas de mídia e outro para pseudo seletores. Isso ainda deve ser verificado por tipo IMO:

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

Isso é algo que você se vê escrevendo @oliviertassinari?

  1. [...]
    CSSProperties - ou (props: Props) => CreateCSSProperties, que não entendi porque é efetivamente duplamente preguiçoso - você deve passar nos Props uma vez para obter CreateCSSProperties e, em seguida, novamente para obter propriedades individuais. Por que é "double thunked"?

Se o argumento em si não for um saco de propriedades, mas uma função, ele exigirá um tema. Os estilos podem depender de dois tipos diferentes de bolsas de propriedades: o tema (disponível por meio da API de contexto do React) ou os adereços (passados ​​diretamente para o componente):

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"

Tem menos a ver com avaliação preguiçosa para melhorar o desempenho, mas mais com ter que esperar que o contexto e os acessórios estejam disponíveis.

Separadamente, eu suspeito, mas ainda não demonstrei que IsEmptyInterface é muito caro para o benefício que fornece. No entanto, é bem possível que eu não entenda totalmente os benefícios, então seria útil ouvir mais.

Há um caso em que isso é usado:

Considerar

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' });
}

Para inferir a assinatura de chamada da função retornada de makeStyles (ou seja, o gancho nomeado algo como useSomeStyles ). Precisamos verificar que tipo de bolsa de estilo é passada para makeStyles . Já temos um ajudante para inferir os tipos de adereços usados ​​na bolsa de estilo . Se a bolsa de estilo for estática, isto é, TS infere o tipo {} . Em seguida, verificamos o tipo inferido dos Props com IsEmptyInterface e para um ramo usamos uma assinatura de chamada com 0 parâmetros e para o outro ramo usamos uma assinatura de chamada com 1 parâmetro que é igual ao tipo de props inferido ( veja StylesRequireProps e StylesHook .

Resumindo: evitamos escrever useStaticStyles({}) ou useStaticStyles(null as any) . Ele foi apresentado em https://github.com/mui-org/material-ui/pull/14019 para fechar https://github.com/mui-org/material-ui/issues/14018. Acho que podemos causar um curto-circuito determinando a assinatura da chamada. Talvez sobrecarregue a assinatura de chamada em vez de usar tipos condicionais?

O problema com esse "recurso" é que os usuários avançados não têm problema em usar null as any se entenderem o porquê. Talvez até mesmo passar um objeto vazio esteja ok, embora não seja necessário. No entanto, é muito confuso / frustrante quando não está acostumado com Material-UI ou TypeScript. Especialmente porque a maior parte do estilo não é baseada em adereços de qualquer maneira.

Parece que na maioria das vezes o verificador de tipos está ocupado com a solução de estilo? Eu teria esperado a assinatura de chamada para nossos componentes, ou seja, quais adereços são possíveis na maior parte do tempo.

Posso rastrear mais repositórios para observar especificamente o uso de withStyles ou makeStyles . Até agora, olhei apenas para o uso de adereços.

Isso é algo que você se vê escrevendo @oliviertassinari?

@ eps1lon Temos algumas ocorrências desse aninhamento na base de código (por exemplo, com <strong i="8">@media</strong> (hover: none) ). Mas não é muito frequente para os componentes principais. Imagino que seja o mesmo userland. Definitivamente, poderia ser parte da troca.

@beholderrk

  1. Achei isso, mas achei melhor perguntar.
  2. a) A profundidade dois deve ser expressável - haverá apenas um pouco mais de duplicação do que a profundidade um.
    b) Levei um bom tempo para entender isso e gostaria de poder explicar pessoalmente, em vez de por texto. Basicamente, a assinatura do índice indica que todas as propriedades têm o mesmo tipo. Isso só pode funcionar se especificar um tipo que funcione para todos eles. Uma maneira de fazer isso é construir a união de todos os tipos de propriedade, BaseCSSProperties[keyof BaseCSSProperties] - então, será verdade que cada propriedade tem um tipo compatível. Por exemplo, suponha que as únicas propriedades que você poderia ter no CSS fossem name: string e width: number . Uma maneira de especificar uma assinatura de índice que funcione com ambas as propriedades seria dizer que cada propriedade é string | number . Não é ótimo - name nunca será um number e width nunca será um string - mas funciona. O verdadeiro problema é que aquilo que você deseja não pode realmente ser expresso (pelo menos, até onde fomos capazes de determinar - pode haver um hack "inteligente" que o faça). Você realmente quer dizer que seu tipo contém name: string , width: number ou x: CSSProperties , onde x é qualquer coisa menos name ou width - é o "tudo menos" que está faltando. Espero que esteja um pouco mais claro.
  3. Parecia que @ eps1lon tinha algo a dizer sobre isso, mas ainda estou analisando sua resposta.

Uma linha de base em bom estado seria muito útil. Por acaso você tem um link?
Editar: encontrei.

@ eps1lon Feliz por fazer parte da conversa. Tipos rápidos e corretos são bons para todos. 😄

  1. Sem discussão aqui - eu apenas pensei em perguntar mais cedo porque isso teria causado um curto-circuito em toda a conversa.
  2. Duas camadas parecem viáveis ​​(com a notável ressalva de que os tipos ainda serão em grande parte inúteis). Vou ver se consigo fazer um rascunho.
  3. Com a minha falta de contexto, não estava claro se os temas e acessórios eram diferentes. Se forem, a estrutura faz sentido. Obrigado por esclarecer.

Com relação a isEmptyInterface , você poderia apenas tornar o parâmetro de propriedades (por exemplo) useStaticStyles opcional? Seria menos correto, no sentido de que os chamadores poderiam omiti-los quando fossem esperados, mas seria muito mais barato digitar cheque. Como eu disse, não tenho números nem nada para você - é apenas especulação da minha parte.

Qual é sua opinião sobre 2 (b)? Parece que esse tipo não está fornecendo muito valor, pois basicamente diz que qualquer nome de propriedade será aceito e o tipo de retorno pode ser um de um grande número de coisas.

Com relação a isEmptyInterface, você poderia apenas tornar opcional o parâmetro de propriedades para (por exemplo) useStaticStyles?

Eu gostaria de experimentar sobrecarregar a assinatura da chamada primeiro e ver se isso tem algum impacto. Em seguida, tentaremos torná-lo menos sonoro, tornando-o sempre opcional. Parece mais seguro do que o normal torná-lo menos sonoro, já que quase todos os casos de uso o chamam apenas uma vez, então você provavelmente cometerá o erro apenas uma vez e ele aparecerá muito rapidamente. Vai ser difícil vendê-lo se não nos render muito desempenho. Usarei o repositório criado para o problema original (https://github.com/microsoft/TypeScript/issues/34801#issue-514055289).

Qual é sua opinião sobre 2 (b)? Parece que esse tipo não está fornecendo muito valor, pois basicamente diz que qualquer nome de propriedade será aceito e o tipo de retorno pode ser um de um grande número de coisas.

Pulei isso acidentalmente. Vou dar uma olhada depois do experimento IsEmptyInterface.

@ eps1lon Concordo totalmente - mantenha isEmptyInterface se eliminá-lo não for um ganho de desempenho substancial.

Com # 19320, nos livramos de alguns tipos condicionais complexos em que a sobrecarga de função alcançava a mesma coisa (removendo IsEmptyInterface e qualquer tipo de lógica booleana). Embora pareça que isso não nos rendeu muito além de ter menos código.

Quero acrescentar que atualmente estou alternando entre TS 3.2.4 e 3.7.4. Nosso conjunto de testes de tipo funciona 50% mais lento no 3.7.4 em comparação com o 3.2.4 (~ 90s vs 50s).

Vou continuar investigando se podemos limitar a profundidade de CSSProperties e remover o suporte para consultas de mídia e pseudo seletores inteiramente. No entanto, não ter esses dados digitados é realmente uma opção. O verificador de tipo deve ser capaz de verificá-los em um tempo razoável.

Pode ser que o verificador de tipo seja o gargalo real. Talvez possamos investigar em qual versão o desempenho foi atingido.

Se você me enviar os comandos que está executando no 3.2.4 e 3.7.4, posso criar o perfil localmente. No entanto, a experiência sugere que a causa provavelmente será adicional, verificação desejável adicionada desde 3.2.4. (E presumo que "0s" seja um erro de digitação - provavelmente "40s" ou "50s"?)

Com relação às CSSProperties, concordo que manter os nomes e tipos de propriedade é extremamente valioso. No entanto, acho que há mais do que verificá-los em um período de tempo razoável - o primeiro problema é que o sistema de tipos não pode realmente expressar a forma que você deseja. Acho que provavelmente vamos gastar algum tempo trabalhando em uma solução geral para o problema - posso presumir que você esteja interessado em participar dessa discussão?

Temos scripts para comparar várias versões do compilador, portanto, se você puder identificar um teste razoavelmente estável que gostaria que executássemos, podemos calcular a lentidão ao longo do tempo.

(E presumo que "0s" seja um erro de digitação - provavelmente "40s" ou "50s"?)

Desculpe, são 50 anos.

Se você me enviar os comandos que está executando no 3.2.4 e 3.7.4, posso criar o perfil localmente.

É apenas yarn typescript na raiz que executa o mesmo comando em cada área de trabalho que o implementa. Por exemplo, yarn workspace @material-ui/styles run typescript testa nossos tipos com tslint e dtslint $ExpectError . Em 3.7.4 encontramos algumas falhas e tivemos que ajustar nossos testes (ver # 19242)

o primeiro problema é que o sistema de tipos não pode realmente expressar a forma que você deseja.

Eu suspeitei disso. Parece que a maneira como misturamos uma forma "concreta" com um objeto com uma assinatura de índice é apenas uma solução alternativa.

posso presumir que você estaria interessado em participar dessa discussão?

Com certeza. Vou gastar um pouco mais de tempo com CSSProperties não recursivas e, em seguida, escrever um pouco mais de testes para ilustrar o que estamos procurando nesses tipos. Eu suspeitaria que outras soluções de estilo css-in-js atingiram gargalos de desempenho semelhantes.

Vou experimentar esses comandos amanhã (acho que devo mencionar que estou no tempo do Pacífico e observo os feriados dos Estados Unidos).

Parece que a maneira como misturamos uma forma "concreta" com um objeto com uma assinatura de índice é apenas uma solução alternativa.

Obrigado, tenho lutado para encontrar a melhor forma de expressar isso. Sim, você está correto ao dizer que a assinatura do índice não está fazendo o que você deseja. Temos algumas ideias sobre uma variante que pode, mas precisamos explorar as implicações de desempenho.

Eu suspeitaria que outras soluções de estilo css-in-js atingiram gargalos de desempenho semelhantes.

Muito mesmo. Esperamos que tudo o que fizermos por você possa ser generalizado para melhorar todo o ecossistema.

Sinto que estou perdendo algo óbvio, mas no momento estou preso. Primeiro, desisti do Windows - as coisas parecem funcionar melhor no Linux. Avise-me se quiser se aprofundar nisso. Em segundo lugar, posso fazer com que yarn typescript seja executado - de forma limpa, pelo que posso dizer - mas parece estar executando tslint, em vez de tsc puro. Quando executo o tsc no mesmo tsconfig.json (estou testando especificamente com estilos), recebo cerca de 40 erros. O que estou fazendo errado? Para fins de criação de perfil, baixar o repro para uma única chamada tsc seria muito útil.

@amcasey yarn typescript não é sobre compilação, mas sim testar nossos tipos. Estamos usando uma configuração semelhante à usada no repositório DefinitelyTyped. Os arquivos TypeScript em packages/* são quase sempre apenas um monte de instruções que devem ser aprovadas ou reprovadas, que capturamos com $ExpectError .

Acho que o melhor caso de teste do "mundo real" é usar tsc em nossos documentos por meio de yarn workspace docs run tsc -p tsconfig.json depois de adicionar skipLibCheck: true e noEmit: true a ./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 Obrigado por esclarecer. Não estou feliz que o tslint tenha ficado mais lento, mas gostaria de me concentrar em uma variável de cada vez. Vou rodar a compilação de documentos que você sugeriu com várias versões do texto datilografado e ver se alguma coisa sobressai. Obrigado!

Esta configuração é perfeita. Estou vendo o tempo de verificação dobrar entre 3,3 e 3,4.

| Versão | Verifique o tempo |
| - | - |
| 3,2 | 16,71s |
| 3,3 | 16,79s |
| 3,4 | 35,25s |
| 3,5 | 21,40s |
| 3,6 | 23,10s |
| 3,7 | 27.39s |

Eu vou cavar um pouco mais, mas fui informado que a implementação do 3.3 dos tipos condicionais estava incompleta, a implementação do 3.4 era lenta e a implementação do 3.5 é boa. Então, infelizmente, isso é provavelmente esperado.

Especificamente, suspeito que essa mudança introduziu a desaceleração conforme descrito neste bug .

Acho preocupante que entre 3,5 e 3,7 houve um aumento de 6 segundos no tempo que leva para executar a verificação. Isso parece muito substancial.

@embeddedt Esses números são de execuções únicas com cada versão, então provavelmente há um pouco de ruído. No entanto, vou cavar para ver se consigo encontrar alguma coisa.

Eu o refiz em uma VM Linux e o 3.7 era consistentemente 20-25% mais lento do que o 3.5.

Isso provou ser bastante difícil de dividir ao meio porque execuções consecutivas da mesma construção variam em ~ 5% e a diferença entre 3,5 e 3,6 ou entre 3,6 e 3,7 é de apenas ~ 10%.

Uma coisa suspeita que notei é que styled-components fornece arquivos .d.ts separados para TS> = 3.7, portanto, a comparação pode não ser justa.

Para minha surpresa, os novos tipos styled-components parecem ser mais rápidos. Comparar maçãs com maçãs ainda tornará a investigação mais fácil.

Não consegui pensar em uma solução inteligente, então vou traçar o tempo de compilação mesclagem por mesclagem e procurar picos. Espero ter números amanhã.

@amcasey Obrigado por seus esforços em investigar isso! É muito legal ver os membros da equipe de TS e a IU de materiais trabalhando juntos. Eu tropecei neste problema do Github tentando descobrir por que nossa experiência de editor com a interface do usuário do material é tão lenta (estamos usando em dois projetos no trabalho). Posso definitivamente confirmar que estamos vendo um impacto bastante significativo no intellisense e usabilidade dentro do VsCode.

Neste ponto, ficaríamos felizes em trocar um pouco de segurança de tipo em nosso JSS por um feedback rápido para o resto da biblioteca. Às vezes, leva de 8 a 10 segundos de espera antes que o servidor Typescript alcance as alterações de código

Mesmo com médias de três execuções, os dados são muito barulhentos. No entanto, parece haver uma queda perceptível no tempo de execução em https://github.com/microsoft/TypeScript/commit/ad322a561a301ae357da051b9221b2222c13be36 um aumento notável (de volta para aproximadamente o nível anterior) em https://github.com/microsoft/TypeScript / commit / 480b73915fdd805952fd355e4cf3e1bc803e0878 e uma tendência geral para cima depois disso (embora pareça muito uniforme para mim e eu suspeite de fatores ambientais), incluindo um pico específico em https://github.com/microsoft/TypeScript/commit/c5e62440a930048a033868297d. Vou me concentrar nos dois primeiros até executar mais alguns testes para confirmar a tendência geral de aumento (como isso poderia ficar uniformemente pior a cada commit?).

A tendência ascendente está sujeita a um exame minucioso e não tenho ideia do que pode causar isso. Talvez as desacelerações discretas sejam tão próximas que o ruído as faça parecer uma única curva.

Aumentei até 10 execuções por confirmação e agora existem quatro regressões distintas na área inclinada. :sorriso:

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

(O tempo total antes do início das regressões foi de ~ 33s.)

Apenas para moderar um pouco as expectativas: é bem provável que várias dessas regressões se revelem cheques adicionais valiosos e, mesmo se conseguíssemos receber todos esses cheques de graça, ainda teríamos apenas 20% de desconto "por muito tempo "

Edit: Eu atualizei os links. Como estava retrocedendo no tempo, fiquei confuso e sinalizei a fusão _antes_ de cada regressão.

@ eps1lon Alguém nesse sentido sugeriu que remover @ts-ignore pode ajudar. Basicamente, quando um erro é detectado, presume-se que a principal prioridade do usuário é obter boas informações sobre o erro, portanto, é possível que um monte de trabalho extra seja feito. Se essa informação for descartada posteriormente (por causa de @ts-ignore ), então esse tempo será perdido. (Infelizmente, não é fácil detectar que um erro não precisa ser detectado.) Uma estratégia alternativa é adicionar asserções de tipo explícitas (incluindo any ) até que o compilador pare de reclamar.

@ eps1lon Alguém nesse sentido sugeriu que remover @ts-ignore pode ajudar.

Só tivemos um único uso em docs/ . Eu o removi de qualquer maneira, apenas no caso: # 19504

Para ser honesto, parece que @ts-ignore é um antipadrão nesse caso. Não apenas não fornece informações úteis, ou seja, que tipo de erro temos, mas também é um gargalo de desempenho.

Pelo que eu posso dizer, @ts-ignore só é útil em .js arquivos que estão sendo verificados.

Hmm, isso quase certamente não explica por que as mensagens de erro de melhoria de RP regrediram o desempenho. Definitivamente parece uma melhoria. 😄

Eu sou muito novo no mundo do TypeScript, especialmente quando se trata de soluções de estilo em JS, mas tenho seguido este tópico discretamente no último mês e estava curioso para ouvir a opinião das pessoas sobre uma possível solução alternativa, em pelo menos no curto prazo.

Presumo que alguns usuários (eu sendo um) não fazem uso pesado do sistema de estilo embutido, ou o evitam totalmente. Faço isso principalmente porque estou muito mais familiarizado com CSS simples ou Sass e não tive tempo para me aprofundar em como usar efetivamente o sistema de estilo JS. Eu prefiro apenas inventar meus próprios nomes de classe, escrever um arquivo de folha de estilo separado, usar os nomes de classe dentro de meus componentes React e continuar. Essencialmente, eu estilo como se estivesse escrevendo HTML puro.

Dito isso, é possível / prático adicionar um sinalizador que desativa a verificação de tipo para as partes caras do sistema de estilização (possivelmente fazendo coisas condicionalmente como type CSSProperties = any )? Eu não sei as estatísticas para o número de pessoas que usam o sistema de estilo vs. não usá-lo, mas eu acho que isso não pode causar muito dano (desde que uma verificação tenha sido adicionada para testar as digitações com aquele conjunto de sinalizadores) , e seria uma maneira rápida de melhorar o desempenho de pelo menos um segmento de usuários.

Queria apenas mencionar a ideia geral; sinta-se à vontade para derrubá-lo. : ligeiramente_smiling_face:

@embeddedt De um modo geral, marcar algo explicitamente como any é uma boa maneira de desabilitar a verificação de tipo para aquele símbolo. Dito isso, não consigo me lembrar se você pode simplesmente eliminar uma declaração anterior ou, como sugeriu, você precisaria de suporte do compilador para evitar problemas de declaração duplicada.

Novos números (máquina diferente, métrica de tempo diferente):

| Versão | Tempo total |
| - | - |
| 3.5.3 | 32,5s |
| 3.7.5 | 35.9s |
| mestre | 29.9s |

Alguns dos problemas que postei acima ainda estão abertos, mas basicamente voltamos ao desempenho de 3,5 (para este benchmark). Obviamente, ainda é muito mais lento do que gostaríamos, mas o próximo lote de alterações provavelmente será no lado do material-ui.

Testado 3.8.1 em nosso conjunto de testes e parece que eles são tão rápidos quanto os anteriores usando 3.2.4 (3.7 era significativamente mais lento).

Sinceramente, não consigo acreditar em quanta performance fomos capazes de recuperar sem abrir mão da nova funcionalidade. : smile: Acho que pode haver um pouco mais de folga (por exemplo, https://github.com/microsoft/TypeScript/pull/36754), mas ainda suspeito que a alteração mais impactante seria uma simplificação dos tipos CSSProperties. Você já teve a chance de brincar com eles? Parece que pelo menos um subconjunto de usuários (por exemplo, @embeddedt) ficaria feliz em desistir de algum tipo de verificação em troca de uma vitória de desempenho.

Parece que pelo menos um subconjunto de usuários (por exemplo, @embeddedt) ficaria feliz em desistir de algum tipo de verificação em troca de um ganho de desempenho

Alguém da equipe de TS não tweetou recentemente que, para cada usuário que deseja tipos mais rígidos, há um que quer tipos mais flexíveis? :sorriso:

Para mim, não se trata realmente de verificação de tipo (devtools de navegador têm recursos muito melhores de verificar seu CSS). É mais sobre ter o preenchimento automático disponível.

Vou brincar com as diferentes "versões" e ver como elas funcionam.

@amcasey Não acho que a natureza recursiva de CSSProperties (chamada CSSObject em componentes estilizados) seja o principal problema. Caso contrário, o desempenho deles seria tão ruim quanto o nosso. Consulte https://github.com/eps1lon/mui-types-perf/pull/6 e os registros de benchmark .

Pode ser mais um problema com a quantidade de "sobrecarga" que fazemos. styled-components permite apenas um objeto estático enquanto permitimos uma versão thunked, bem como cada propriedade sendo uma thunk. Eu não tenho certeza embora.

Eu adoraria simplificar a assinatura de tipo (uma vez que é IMO também mais fácil para os desenvolvedores entenderem), mas fui explicitamente solicitado a corresponder à implementação JSS. Agora que oferecemos suporte, não podemos reverter facilmente. Principalmente se o ganho for na região de 20%. Não acho que isso justifique a ruptura.

Os tipos podem ser condicionalmente menos precisos (com base na configuração do usuário)? Isso não deve quebrar nenhum código existente (porque a configuração pode estar desativada por padrão) e permitir que usuários como eu, que não precisam dos tipos complexos, vejam rapidamente um aumento de desempenho.

permitiria que usuários como eu, que não precisam de tipos complexos, vissem rapidamente um aumento de desempenho.

Nem mesmo está confirmado que você ganharia uma diferença perceptível. Eu vi 15% de vitórias de desempenho, mas é questionável se isso é reconhecível.

A "configuração do usuário" que pude ver é corrigir o pacote na instalação. Não temos largura de banda para manter várias versões das digitações.

@ eps1lon Desculpe, acho que minha pergunta pode não ter sido clara. Acho que CSSProperties está bem (embora, obviamente, se fosse mais rápido se fosse menor) - Na verdade, eu esperava que houvesse espaço para simplificar os subtipos em https://github.com/mui-org /material-ui/blob/master/packages/material-ui-styles/src/withStyles/withStyles.d.ts. Por exemplo, você obteria menos conclusões se alterasse esse tipo para any ?

Editar: na minha caixa, isso torna a compilação do projeto docs 15% mais rápida (29,7s para 25,5s), mas não sei o efeito na experiência de edição.
Edição 2: Na verdade, uma vez que você desistiu de dobrar na parte recursiva do tipo, você pode apenas usar BaseCreateCSSProperties e qualquer outra propriedade terá o tipo any (ou seja, você pode manter os tipos reais das propriedades CSS).
Edit 3: Edit 2 não funciona devido ao excesso de verificação de propriedade (ou seja, nomes de propriedades arbitrárias não são permitidos em literais de objeto).

Seu ponto sobre conclusões vs verificação de tipo foi superinteressante porque eu tive a hipótese de que alguns autores de tipo poderiam se sentir assim. @DanielRosenwasser Acho que pensamos em fazer algo assim para acomodar o padrão "a" | "b" | string - isso funcionou?

Observe também que styled-components está tendo (acreditamos) problemas de desempenho do verificador intimamente relacionados.

Quanto a ser capaz de especificar o tipo de forma mais exata, solicitei https://github.com/microsoft/TypeScript/issues/36782.

Parece que emotion pode estar no mesmo barco.

Comecei a adicionar Material UI ( 4.9.4 ) ao meu projeto hoje, e a lentidão é realmente tão significativa que acho que não posso nem mesmo usá-la no meu projeto. Acabei de adicionar um componente <Slider/> simples, personalizado usando withStyles() .

Estamos falando de um feedback instantâneo do TypeScript no meu IDE para o que parece ser de 5 a 10 segundos às vezes (para partes do meu código que nem mesmo estão interagindo com o Material UI agora - é apenas uma desaceleração completa do TypeScript no arquivo que usa o componente). Algo deve estar significativamente errado com esses tipos (ou sim, excessivamente complexo), parece que @amcasey está fazendo algumas boas investigações - espero que você possa chegar ao fundo disso!

Tentando encontrar uma maneira de pelo menos excluir todo o material do TypeScript por @material-ui por enquanto (basicamente tornar o módulo inteiro any ) - mas o TypeScript não parece tornar isso fácil o suficiente.

@lostpebble O mesmo acontece usando algo diferente de withStyles para personalizar o controle deslizante, digamos módulos CSS?

@lostpebble No momento, não temos uma maneira compatível de excluir um determinado conjunto de tipos. Se você realmente quiser, experimente mapeamentos de caminho. Você pode tentar um mapeamento de caminho como "@material-ui/*": ["simplemui"] e, em seguida, criar um simplemui.d.ts contendo

declare const x: any;
export = x;

Isso tornaria efetivamente todos os tipos de interface do usuário material any . É definitivamente um hack e não algo que eu possa recomendar, mas pode desbloquear sua experiência de edição.

Acho que fizemos algumas melhorias boas (em algum lugar na área de 30%), mas parece que tudo o que podemos fazer agora é tornar as digitações mais flexíveis.

Isso absolutamente requer propostas concretas, por exemplo, com qual código errado você concordaria para ser aceito pelo verificador de tipo. Em seguida, precisaríamos fazer um benchmark e ver se isso causa uma diferença significativa.

Você tem que entender que regressões introduzidas propositalmente adicionam muito trabalho para os mantenedores, uma vez que temos que explicar isso aos consumidores da biblioteca e é bastante estressante no geral.

Portanto, esta não é uma prioridade para mim no momento, a menos que alguém tenha um intelecto acionável. Do contrário, terei que dedicar muito tempo a pouco retorno.

No meu caso para makeStyles(theme => createStyles(...)) , retornando Record<ClassKey, any> de createStyles(...) quase ~ metades ~ (no meu código e computador, cerca de ~ 1200ms -> 750ms ~ 1400ms → 1100ms) encodedSemanticClassifications-full: elapsed time mostrado no log do tsserver (não parece um trabalho caro, mas talvez esperando a verificação de tipo ser concluída).

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

createStyles(...) verifica a estrutura de estilo para que possamos pular a verificação de tipo para argumento-tipo-de-união massiva de makeStyles vs retorno-tipo-de-união massiva de createStyles.

~ (E comentando todo o código makeStyles: 650ms) ~

@ypresto createStyles só é necessário para versões datilografadas sem const asserções. Se você pode usar { display: 'block' as const } em sua base de código (ts> = 3.4), use isso em createStyles .

@ eps1lon Percebemos isso e tentamos fazer a troca em docs mas os resultados não foram impressionantes.

@ eps1lon com const e sem createStyles , o IntelliSense não mostra mais candidatos cientes do contexto: chore:

@ypresto Deveria. Você tem um exemplo de trecho de código?

@amcasey

Adicionar as const ao objeto externo ou à propriedade efetivamente o mata. Não quero colocá-lo em todas as propriedades.

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

Além disso, sem createStyles, ele tem uma pequena limitação para conclusão de string.

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

@ypresto Por "mata-lo", você quer dizer "faz com que funcione da mesma maneira que createStyles "?

É uma chatice colocá-lo em todos os lugares, mas não é mais chato do que colocar createStyles todos os lugares.

@amacleay, eu quis dizer kills IntelliSense : pray :

Desculpe, eu perdi seus comentários. Vou tentar.

Não tenho ideia do porquê, mas isso é 1100ms → 750ms, curiosamente:

 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">

Remover CardProps & do FC é quase o mesmo resultado. Talvez seja porque CardProps estende PaperProps, que estende os grandes atributos HTMLAt.

ATUALIZAÇÃO E IMPORTANTE: Descobriu-se que substituir CardProps por HTMLAttributes<HTMLDivElement> também reduz o tempo (não medido).

Finalmente, encontrei o maior deles, 750ms → 130ms:

Removendo style={...} de duas tipografias.

-<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>

Mas por que? Adicionar o mesmo estilo a <div> não afeta o desempenho. Talvez OverridableComponent seja muito complicado ..?

(Estou usando TypeScript 3.8.3, @material-ui/core 4.9.1)

AFAIK, a maneira como o Material-UI lida com os estilos locais em componentes é diferente da maneira como o React lida com os elementos HTML.

@embeddedt No nível de tipo, ele resolve para React.CSSProperties que é o mesmo que o prop de estilo de div.

@ypresto , estou corrigido. Desculpe.

Oi pessoal, não tenho certeza se vale a pena abrir um novo fascículo para isso, então vou postar aqui pois está relacionado a tipos de correção / desempenho. Avise-me se, em vez disso, devo abrir um problema.
Ao seguir a documentação para adicionar uma fonte personalizada , acabo com o seguinte erro de digitação:
Type 'string' is not assignable to type 'FontFaceFontDisplayProperty'

É estranho, porque csstype 2.6.9 tipificações parecem válidas e outros atributos estão ok (usando 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")
  `
};

Propriedade do tema:

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

O tipo é type FontFaceFontDisplayProperty = "auto" | "block" | "fallback" | "optional" | "swap";

@ eric-burel Este é um problema com o alargamento automático de tipo de manuscritos. Experimentar

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

Obrigado, funciona, e eu aprendi um novo conceito de "ampliação de tipo" :) É estranho que fontStyle não seja afetado, por exemplo, não é a única propriedade CSS definida como um enum, mas a primeira vez que acerto isso .

Edit: ok, meu mal, está bem documentado: https://material-ui.com/guides/typescript/#using -createstyles-to-attack-type-widening

Finalmente, encontrei o maior deles, 750ms → 130ms:

Removendo style={...} de duas tipografias.

-<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>

Mas por que? Adicionar o mesmo estilo a <div> não afeta o desempenho. Talvez OverridableComponent seja muito complicado ..?

(Estou usando TypeScript 3.8.3, @material-ui/core 4.9.1)

Você descobriu que isso afeta o tempo de construção ou apenas o tempo que leva para o intellisense ser útil? Estou tendo um problema de compilação (sem memória) e parte do nosso código TS tem uma tonelada de style={someStyle} configurados nos componentes. Querendo saber se isso faz parte do nosso problema.

@ yatrix7 , de modo geral, esperaria que esses longos tempos de verificação afetassem os tempos de resposta de build e editor.

Alguém está olhando para isso? Eu sei que houve algumas melhorias em relação ao tempo de verificação do tipo de texto datilografado em atualizações de versões anteriores. No entanto, ainda é lento.
Não me importaria de examinar isso sozinho.

Não me importaria de examinar isso sozinho.

Isso seria incrível. No momento, não temos conhecimento de itens acionáveis ​​para trabalharmos. Portanto, quaisquer sugestões para gargalos seriam apreciadas.

Adicionados alguns benchmarking por enquanto, para ajudar a investigar: https://github.com/mui-org/material-ui/pull/22110

@FabianKielmann No final do TS, tenho trabalhado em ferramentas de investigação de desempenho que espero que em breve estejam maduras o suficiente para serem aplicadas ao material-ui.

Se você tiver algum tempo para dedicar a isso, também pode tentar algo como https://github.com/microsoft/TypeScript/issues/38583.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

rbozan picture rbozan  ·  3Comentários

ryanflorence picture ryanflorence  ·  3Comentários

chris-hinds picture chris-hinds  ·  3Comentários

revskill10 picture revskill10  ·  3Comentários

newoga picture newoga  ·  3Comentários