Pular para o conteúdo

🎉 Material UI v5 is out now! Check out the announcement blog post

Minimizando o tamanho do pacote

Saiba mais sobre as ferramentas que você pode usar para reduzir o tamanho do pacote.

Tamanho do pacote importa

O tamanho do pacote do Material-UI é levado muito a sério. Fotos contendo o tamanho do pacote são feitas em cada commit e partes críticas dos pacotes(veja a última foto). Combinado com dangerJS podemos inspecionar alterações detalhadas no tamanho do pacote em cada solicitação de Pull Request.

Quando e como usar tree-shaking?

Tree-shaking no Material-UI funciona de uma forma moderna. Material-UI expõe sua API completa na importação de nível superior material-ui. Se você estiver usando módulos ES6 e um bundler que suporta tree-shaking (webpack >= 2.x, parcel com uma propriedade definida) você pode usar com segurança importações nomeadas e ainda assim, obter automaticamente um tamanho otimizado do pacote:

import { Button, TextField } from '@material-ui/core';

⚠️ As instruções a seguir são somente necessárias se você deseja otimizar o tempo de startup em desenvolvimento ou se você esta utilizando um bundler antigo que não suporte tree-shaking.

Ambiente de desenvolvimento

Os pacotes de desenvolvimento podem conter a biblioteca completa que pode deixar o tempo de inicialização mais lento. Isso é especialmente perceptível se você importar de @material-ui/icons. Os tempos de inicialização podem ser aproximadamente 6 vezes mais lentos do que sem utilizar importações nomeadas da API de nível superior.

Se isso é um problema para você, tem várias opções:

Opção 1

Você pode usar as importações de caminho para evitar puxar módulos não utilizados. Por exemplo, use:

// 🚀 Rápida
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';

em vez de importações de nível superior (sem um plugin do Babel):

import { Button, TextField } from '@material-ui/core';

Esta é a opção que apresentamos em todas as demonstrações, pois não exige qualquer configuração. É o mais recomendável para autores de biblioteca que estendem os componentes. Vá até Opção 2 para uma abordagem que produz uma melhor DX e UX.

Ao importar diretamente dessa maneira acima, não utiliza as exportações em @material-ui/core/index.js, esse arquivo pode servir como uma referência útil para quais módulos são públicos.

Esteja ciente de que apenas damos suporte para as importações de primeiro e segundo nível. Qualquer coisa em níveis mais profundos é considerado privado e pode causar problemas, como a duplicação de módulos em seu pacote.

// ✅ OK
import { Add as AddIcon } from '@material-ui/icons';
import { Tabs } from '@material-ui/core';
//                                 ^^^^ 1° ou nível superior

// ✅ OK
import AddIcon from '@material-ui/icons/Add';
import Tabs from '@material-ui/core/Tabs';
//                                  ^^^^ 2° nível

// ❌ NÃO OK
import TabIndicator from '@material-ui/core/Tabs/TabIndicator';
//                                               ^^^^^^^^^^^^ 3° nível

Se você estiver usando eslint você pode capturar está problemática de importações com a regra no-restricted-imports. A configuração .eslintrc a seguir irá capturar as problemáticas das importações dos pacotes @material-ui:

{
  "rules": {
    "no-restricted-imports": [
      "error",
      {
        "patterns": ["@material-ui/*/*/*", "!@material-ui/core/test-utils/*"]
      }
    ]
  }
}

Opção 2

Esta opção fornece a melhor Experiência do Usuário e Experiência do Desenvolvedor:

  • UX: O plugin Babel permite tree-shaking de nível superior, mesmo se o seu bundler não suporte.
  • DX: O plugin Babel torna o tempo de inicialização no modo de desenvolvimento tão rápido quanto a opção 1.
  • DX: Essa sintaxe reduz a duplicação de código, exigindo apenas uma única importação para vários módulos. Em geral, o código é mais fácil de ser lido, e é menos provável que você cometa um erro ao importar um novo módulo.
    import { Button, TextField } from '@material-ui/core';

No entanto, você precisa aplicar as duas etapas seguintes corretamente.

1. Configure o Babel

Escolha um dos seguintes plugins:

  • babel-plugin-import com a seguinte configuração:

    yarn add -D babel-plugin-import

    Crie um arquivo .babelrc.js no diretório raiz do seu projeto:

    const plugins = [
      [
        'babel-plugin-import',
        {
          'libraryName': '@material-ui/core',
          // Use "'libraryDirectory': ''," se o seu bundler não suportar módulos ES
          'libraryDirectory': 'esm',
          'camel2DashComponentName': false
        },
        'core'
      ],
      [
        'babel-plugin-import',
        {
          'libraryName': '@material-ui/icons',
          // Use "'libraryDirectory': ''," se o seu bundler não suportar módulos ES
          'libraryDirectory': 'esm',
          'camel2DashComponentName': false
        },
        'icons'
      ]
    ];
    
    module.exports = {plugins};
  • babel-plugin-transform-imports com a seguinte configuração:

    yarn add -D babel-plugin-transform-imports

    Crie um arquivo .babelrc.js no diretório raiz do seu projeto:

    const plugins = [
      [
        'babel-plugin-transform-imports',
        {
          '@material-ui/core': {
            // Use "transform: '@material-ui/core/${member}'," se o seu bundler não suportar módulos ES
            'transform': '@material-ui/core/esm/${member}',
            'preventFullImport': true
          },
          '@material-ui/icons': {
            // Use "transform: '@material-ui/icons/${member}'," se o seu bundler não suportar módulos ES
            'transform': '@material-ui/icons/esm/${member}',
            'preventFullImport': true
          }
        }
      ]
    ];
    
    module.exports = {plugins};

Se você estiver usando Create React App, você precisará usar alguns projetos que permitem a configuração por .babelrc, sem ejetar.

yarn add -D react-app-rewired customize-cra

Crie um arquivo config-overrides.js na pasta raiz:

/* config-overrides.js */
const { useBabelRc, override } = require('customize-cra')

module.exports = override(
  useBabelRc()
);

Se você desejar, babel-plugin-import pode ser configurado através de config-overrides.js ao invés de .babelrc usando esta configuração.

Modifique seu comando start no package.json:

  "scripts": {
-  "start": "react-scripts start"
+  "start": "react-app-rewired start"
  }

Nota: Você pode se deparar com erros como estes:

Module not found: Can't resolve '@material-ui/core/makeStyles' in '/seu/projeto'

Isso acontece porque @material-ui/styles é reexportado através do core, mas a importação completa não é permitida.

Você tem uma importação como essa no seu código:

import { makeStyles, createStyles } from '@material-ui/core';

A correção é simples, defina a importação separadamente:

import { makeStyles, createStyles } from '@material-ui/core/styles';

Desfrute do tempo de inicialização significativamente mais rápido.

2. Converta todas as suas importações

Finalmente, você pode converter sua base de código existente com esse modificador de código top-level-imports. Ele executará as seguintes alterações:

-import Button from '@material-ui/core/Button';
-import TextField from '@material-ui/core/TextField';
+import { Button, TextField } from '@material-ui/core';

ECMAScript

O pacote publicado no npm é transpilado com Babel, para levar em consideração as plataformas suportadas.

Uma segunda versão dos componentes é também publicada, essa versão pode ser encontrada na pasta /es. Toda a sintaxe não oficial é transpilada para o padrão ECMA-262, nada mais. Isso pode ser usado para criar pacotes separados visando diferentes navegadores. Os navegadores mais antigos exigem mais recursos JavaScript para serem transpilados, o que aumenta o tamanho do pacote. Nenhum polyfill está incluído para os recursos de tempo de execução do ES2015. IE11+ e navegadores evergreen suportam todos os recursos necessários. Se você precisar de suporte para outros navegadores, considere usar @babel/polyfill.

⚠️ Para minimizar a duplicação de código nos pacotes de usuários, autores de bibliotecas são fortemente desencorajados de usar a pasta /es.