Material-ui: build de production - conflits de noms de classe

Créé le 15 sept. 2017  ·  62Commentaires  ·  Source: mui-org/material-ui


Les définitions de noms de classe css sont dupliquées pour certains composants - dans mon cas, elles sont dupliquées (je suppose d'après mon débogage) pour MuiIconButton et MuiModal - vérifier le comportement actuel

  • [x] J'ai recherché les problèmes de ce référentiel et je pense que ce n'est pas un doublon.

Comportement prévisible

Les noms de classe ne doivent pas être dupliqués entre les composants.

Comportement actuel

Mes styles de boutons:
classnames_conflict
La classe est dupliquée.
Définition des styles:
classnames_conflit_2

Il fonctionne en mode développement:
Mes styles de boutons:
development_class

et trouvé les définitions:
mui-icon-button-dev

et du modal:
mui-modal-dev

Étapes à suivre pour reproduire (pour les bogues)

Je peux essayer de préparer l'environnement pour reproduire le problème mais pour l'instant je voulais juste le signaler ici.

Le contexte


J'essaye de publier mon application avec l'environnement de production.

Votre environnement

| Tech | Version |
| -------------- | --------- |
| Material-UI | 1.0.0-beta.10 |
| Réagir | 15.6.1 |
| navigateur | tout |
| webpack | ^ 3.3.0 |

J'ai besoin de quelques conseils où peut être le problème. Je n'utilise la solution withStyles nulle part - j'utilise des composants stylisés pour remplacer les styles.

bug 🐛

Commentaire le plus utile

J'ai eu les noms de classe en collision et l'ajout d'un préfixe dans les options createGenerateClassName résolu le problème.

Utilisé le grand document complet ici

Tous les 62 commentaires

J'ai déjà vu un problème autour de ce problème. Il était toujours lié à des instances de générateur className dupliquées. Je ne peux pas aider plus sans reproduction.

Je ferme le problème pour l'instant car il n'est pas exploitable. Faites-moi savoir si vous avez un exemple de reproduction.

@oliviertassinari J'ai pu reproduire le problème. Voici le bac du webpack - https://www.webpackbin.com/bins/-KuO6ia3h-JDpBOJncZ3

Dans mon cas, j'ai 2 racines d'application qui sont montées indépendamment sur 2 div différents. Les deux utilisent le même matériau-ui ThemeProvider enveloppé avec JssProvider pour remplacer insertionPoint de _jss_.

generate_classnames_counter

Basé sur la fonction createGenerateClassName , vous utilisez counter pour avoir des noms de classe uniques

export default function createGenerateClassName(): generateClassName {
  let ruleCounter = 0;

  return (rule: Rule, sheet?: StyleSheet): string => {
    ruleCounter += 1;
    warning(
      ruleCounter < 1e10,
      [
        'Material-UI: you might have a memory leak.',
        'The ruleCounter is not supposed to grow that much.',
      ].join(''),
    );

    if (process.env.NODE_ENV === 'production') {
      return `c${ruleCounter}`;
    }

    if (sheet && sheet.options.meta) {
      return `${sheet.options.meta}-${rule.key}-${ruleCounter}`;
    }

    return `${rule.key}-${ruleCounter}`;
  };
}

Et ma capture d'écran confirme que pour une raison quelconque, le compteur est dupliqué.

J'ai besoin d'aide. Je ne sais pas ce que je fais de mal en ce moment.

@darkowic Vous devez partager l'instance jss entre les différents arbres de réaction. Vous devriez être bon avec un tel changement.

@oliviertassinari Je pense que je le fais en utilisant mon ThemeProvider

  <JssProvider registry={context.sheetsRegistry} jss={context.jss}>
    <MuiThemeProvider
      theme={context.theme}
      sheetManage={context.sheetsManager}
      {...props}
    />
  </JssProvider>

J'enveloppe chaque arbre de réaction avec ça.

Ce numéro devrait être ouvert.

Bien sûr, résumons ce que nous savons jusqu'à présent. Ce problème survient dès que vous utilisez plusieurs arborescences de rendu de réaction. Le fournisseur jss va créer deux générateurs de noms de classe, un pour chaque arbre. Par conséquent, nous nous retrouvons avec des conflits de nom de classe.
@kof Devrions-nous étendre le JssProvider de react-jss pour accepter un générateur de nom de classe?

SOLUTION DE CONTOURNEMENT pour l'application côté client: vous pouvez créer votre propre createGenerateClassName et déplacer ruleCounter dehors de la fonction wrapper

import warning from 'warning';

// Returns a function which generates unique class names based on counters.
// When new generator function is created, rule counter is reset.
// We need to reset the rule counter for SSR for each request.
//
// It's an improved version of
// https://github.com/cssinjs/jss/blob/4e6a05dd3f7b6572fdd3ab216861d9e446c20331/src/utils/createGenerateClassName.js
//
// Copied from material-ui due to issue https://github.com/callemall/material-ui/issues/8223

// This counter is moved outside from `createGenerateClassName` to solve the issue
let ruleCounter = 0;

export default function createGenerateClassName() {
  return (rule, sheet) => {
    ruleCounter += 1;
    warning(
      ruleCounter < 1e10,
      [
        'Material-UI: you might have a memory leak.',
        'The ruleCounter is not supposed to grow that much.'
      ].join('')
    );

    if (process.env.NODE_ENV === 'production') {
      return `c${ruleCounter}`;
    }

    if (sheet && sheet.options.meta) {
      return `${sheet.options.meta}-${rule.key}-${ruleCounter}`;
    }

    return `${rule.key}-${ruleCounter}`;
  };
}

Bien, nous avons eu un tel cas d'utilisation sur le serveur et je prévoyais déjà de le faire pour un indice audacieux dans la documentation voir # 5

Mais maintenant, vous avez trouvé une bonne raison de prendre en charge 2 fournisseurs d'exécution parallèles.

Nous devons rechercher s'il existe des cas d'utilisation pour un besoin important de plusieurs fournisseurs JssProviders parallèles. S'il y en a, nous devons penser à quelque chose pour le soutenir.

@kof Vous venez de trouver un cas d'utilisation pour plusieurs JssProviders parallèles côté client. Et je pense que la solution proposée est simple à mettre en œuvre :).

déplacer ruleCounter en dehors de la fonction wrapper

Cela signifie que sur le serveur, ruleCounter ne sera jamais réinitialisé. On ne peut pas faire ça.

Côté serveur, les JssProviders doivent absolument prendre en charge le rendu asynchrone simultané d'un arbre de réaction (besoin fort). Mais l'implémentation actuelle le rend déjà supporté :)

@darkowic a proposé une solution de contournement n'ayant pas accès à la pile sous-jacente. Nous faisons. Nous pouvons faire mieux avec cette flexibilité supplémentaire: accepter une instance de générateur de nom de classe.

Les demandes adressées au même point de terminaison doivent également toujours répondre avec les mêmes noms de classe.

@kof Devrions-nous étendre le JssProvider de react-jss pour accepter un générateur de nom de classe?

  1. Ouais, un moyen possible serait d'autoriser JssProvider à accepter un générateur de nom de classe comme celui-ci:

import {createGenerateClassName} from 'react-jss'

const generateClassName = createGenerateClassName()

<JssProvider generateClassName={generateClassName}>
  <App1 />
</JssProvider>

<JssProvider generateClassName={generateClassName}>
  <App2 />
</JssProvider>

  1. Une autre option potentielle serait de fournir un préfixe, comme un nom d'application. Cela pourrait fonctionner si nous supposons que nous n'avons pas une quantité imprévisible d'applications.

<JssProvider classNamePrefix="app-1">
  <App1 />
</JssProvider>

<JssProvider classNamePrefix="app-2">
  <App2 />
</JssProvider>

Pro 1:

  • L'utilisateur n'a pas besoin de fournir le préfixe

Pro 2:

  • L'utilisateur peut avoir quelque chose de significatif dans les noms de classe DOM qui identifie l'application pendant le développement
  • L'utilisateur a plus de contrôle sur le préfixe.
  • Il est relativement facile d'avoir un préfixe non conflictuel. Soit vous n'avez que quelques sous-arbres et la dénomination est déjà assez simple, soit vous pouvez ajouter votre propre préfixe numérique à ces noms et les réinitialiser à chaque demande.

En fait, il est logique d'avoir les deux accessoires classNamePrefix et generateClassName . Premièrement pour le débogage, deuxièmement pour l'unicité automatisée des noms de classe.

J'ai rencontré ce problème via https://github.com/facebookincubator/create-react-app/issues/3173 (et le cas de test réduit lié).

Dans mon cas, un composant matériel dépendant de l'interface utilisateur (v1.0.0-beta.11) a été inclus dans une application qui utilise également material-ui (mêmes versions). En développement, cela fonctionne bien, mais en production, la mise en page est interrompue en raison de noms de classe conflictuels.

Je ne suis pas sûr que cela soit considéré comme "plusieurs arbres de rendu de réaction" et que vous déplacez var ruleCounter = 0; avant createGenerateClassName() _n'a pas contourné_ le problème, mais en commentant ce qui suit, _did_ fonctionne:

https://github.com/callemall/material-ui/blob/2361339fd6df9bfbb85ed2ee4da9d42ee6fee71c/src/styles/createGenerateClassName.js#L26 -L28

Désolée, je ne pouvais pas fournir plus d'informations au moment où j'ai ouvert # 7855.😊
Ce commentaire couvre essentiellement le problème auquel j'ai été confronté lors de l'exécution de la version de production.

Une solution de contournement pour cela dans le pipeline?

Création d'un PR qui devrait résoudre ce problème dans react-jss https://github.com/cssinjs/react-jss/pull/155

Alors résumons.

  • @darkowic 'problèmes de cause racine est décrite ici: https://github.com/callemall/material-ui/issues/8223#issuecomment -331076580 et sera fixé grâce à @kof' s PR: cssinjs / réagissent-jss # 155 et un nouvel avertissement sera ajouté pour éviter cette situation à l'avenir: # 8341.

  • Les symptômes du problème de @tlvince sont les mêmes, mais la cause première est différente. Vous utilisez un seul arbre de rendu de réaction. Il peut être lié à une version de Material-UI dupliquée installée. Vérifiez vos avertissements et si vous pouvez comprendre exactement ce qui se passe, veuillez ouvrir un autre problème.

  • La question de @Robophil est trop vague pour être exploitable.

J'ai eu les noms de classe en collision et l'ajout d'un préfixe dans les options createGenerateClassName résolu le problème.

Utilisé le grand document complet ici

@oliviertassinari merci pour le résumé!

Dans une seule arborescence de rendu de réaction, ce problème est probablement causé par différentes versions de Material-ui dans votre build. Assurez-vous de vérifier votre arborescence de dépendances et de vérifier les versions de Material-ui utilisées.

yarn list | grep material-ui

Ma configuration webpack est la suivante

module.exports = {
    entry: {
        FirstComp: path.join(paths.JS, '/components/FirstComponent/MyFirstComp.js'),
        SecondComp: path.join(paths.JS, '/components/SecondComponent/MySecondComp.js'),
    },
}

J'ai ces deux composants et un composant commun qui est construit à l'aide de l'option splitChunks.
J'ai enveloppé le composant exporté par défaut dans MyFirstComp et MySecondComp à l'aide de JSSProvider.
Comment utiliser le JSSProvider autour du composant commun?

@Sewdn Je pense aussi que cela peut être causé par différentes versions de Material-ui. Ce problème de conflit de nom de classe a été introduit dans mon application hier lorsque j'ai commencé à migrer vers les hooks et le hook useStyles créé par makeStyles à partir de @ material-ui / styles qui est à 3.0.0-alpha.1
J'utilisais aussi "@ material-ui / core" qui est à 3.6.0

Soudainement, mes classes d'application et les classes material-ui ont toutes deux commencé avec jss1, comptant en parallèle. Cela mélangerait tout. Mon en-tête par exemple avec jss5 a également été stylisé avec le jss5 de disons MuiListItem.

Après avoir suivi cette solution https://github.com/mui-org/material-ui/issues/8223#issuecomment -412349569 par @iamhosseindhv, les classes des mui-components ont été préfixées avec ac et le problème a été résolu.

@christiaanwesterbeek Utilisez -vous correctement l'étape d'installation? Nous utilisons l'injection de dépendances. install() appel

@oliviertassinari J'ai bien peur de ne pas savoir à quelle étape vous parlez. De plus, je ne sais pas de quoi install() fait partie et où il doit être appelé. Je serais heureux d'en savoir plus à ce sujet, mais j'ai besoin de savoir où il est documenté.

@christiaanwesterbeek Je fais référence à https://material-ui.com/css-in-js/basics/#migration -for-material-ui-core-users.

@oliviertassinari Semble que install() devrait être appelé dans le fichier de chaque composant? Peut-être avons-nous besoin d'une description plus claire.

Peut-être que je me trompe, l'installation ne peut pas résoudre les conflits.
To switch from the default style implementation to this newest version, you need to execute the following code before importing any Material-UI's components:

import { install } from '@material-ui/styles';

install();

@oliviertassinari Comment l'installer before importing any Material-UI's components ?
l'importation est toujours gérée par babel et tsc statiquement

Les importations de modules lequel elles sont définies. Nous avons été confrontés au même problème avec la documentation Material-UI. La solution était de tout emballer dans un module bootstrap.js et de l'importer en premier:
https://github.com/mui-org/material-ui/blob/cb30b43e9c6cd49f9b16536a125456f5ea3a85c5/docs/src/modules/components/bootstrap.js#L1 -L13
Si le problème persiste, passons à la discussion sur un autre problème.

@oliviertassinari J'ai déplacé la commande d'importation de

// entry index.js
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import CssBaseline from '@material-ui/core/CssBaseline'
import { install } from '@material-ui/styles'

à

import * as React from 'react'
import * as ReactDOM from 'react-dom'
import { install } from '@material-ui/styles'
import CssBaseline from '@material-ui/core/CssBaseline'

le code signale l'erreur Cannot read property 'text' of undefined . En inspectant l'objet de thème, il est vide.
Si je repasse l'ordre d'importation, cette partie fonctionne très bien.

const useStyles = makeStyles(
  (theme: Theme) => ({
    root: {
      flexShrink: 0,
      color: theme.palette.text.secondary,
    },
  }),
)

Le même problème se produit lorsque j'emballe toute l'application avec <StylesProvider>

@zheeeng

le code signale l'erreur Cannot read property 'text' of undefined . En inspectant l'objet de thème, il est vide.

J'ai eu le même problème. Il a été corrigé soit en mettant à jour "@ material-ui / core" vers 3.6.0 ou @ material-ui / styles qui en 3.0.0-alpha.1. J'ai oublié lequel. Mieux vaut faire les deux.

Cependant, le thème exact que la fonction transmettait à makeStyles ne serait pas le thème que j'avais créé avec createMuiTheme. Au lieu de cela, il a obtenu le thème par défaut. Ce que j'ai fini par faire, c'est de ne pas me fier au thème qui serait adopté. Au lieu de cela, j'ai importé le thème dans chaque fichier dont les styles en avaient besoin.

@christiaanwesterbeek J'ai installé @material-ui/[email protected] et @material-ui/styles/.0.0-alpha.2 et j'ai toujours ce problème.

Cela ne semble pas lié à ce problème (8223) à portée de main. Mais voilà quand même. Importez simplement le thème et ne comptez pas sur sa transmission à la fonction que vous passez à makeStyles . Et tu as fini.

Quelqu'un peut-il confirmer si l'étape d'installation est toujours requise avec la v3.7.0 (https://github.com/mui-org/material-ui/releases/tag/v3.7.0)

@christiaanwesterbeek oui, c'est obligatoire. Nous supprimerons l'étape d'installation dans Material-UI v4.

@oliviertassinari hé, je rencontre ce problème avec la dernière v3.9.0, et je n'utilise pas le @ material-ui / styles, j'utilise toujours withStyles from core J'ai deux questions .

  1. devrais-je migrer maintenant vers mui / styes ou attendre la sortie de la v4. (application à grande échelle)
  2. utiliser cette solution de contournement https://github.com/mui-org/material-ui/issues/8223#issuecomment -331081785 est la bonne façon de gérer ce problème? cela fonctionne bien dans la version finale, mais ne semble pas comprendre pourquoi cela se produit en premier lieu.

Merci

Je rencontre ce problème avec la dernière v3.9.0

@ w3nda C'est trop générique, il y a un million de raisons différentes pour que ce problème se produise.

devrais-je migrer maintenant vers mui / styes ou attendre la sortie de la v4. (application à grande échelle)

Nous pourrions inverser la logique de hachage du nom de classe. Bien que cela améliore considérablement les performances sur le serveur, cela a un coût important pour le client. Peut-être que nous fournirons un indicateur pour l'activer à la place. Donc non, je pense que la meilleure option est de résoudre le problème central. Avez-vous essayé cette page https://material-ui.com/guides/server-rendering/#troubleshooting ?

@oliviertassinari Merci pour la réponse rapide, je ne sais vraiment pas comment résoudre le problème et le lien que vous avez mentionné ne me concerne pas car je le sers comme un site statique.
Bien que le commentaire que j'ai mentionné m'a aidé, ne devrait-il pas indiquer la cause de ce problème dans mon cas?

@ w3nda Le site Web statique a le même problème. Vous devez générer le code HTML, il utilisera donc l'API de rendu côté serveur. Si le compteur d'index fuit entre deux pages, le nom de la classe ne sera pas correct. Eh bien, je pense qu'un générateur de nom de classe plus lent est un bon compromis par rapport à la douleur que représente le débogage d'un tel problème (et à sa fréquence). Donc, oui, vous pouvez passer à @material-ui/styles , c'est une simple trappe d'échappement.

J'ai juste eu un problème similaire et c'était une ancienne importation de matériel-ui qui se trouvait dans l'une de nos bibliothèques. Cela a bien fonctionné en mode développement mais a été interrompu en production. Je suis à peu près sûr que cela fonctionnait auparavant, je ne sais pas si un avertissement pourrait être émis dans ce cas, même si c'est clairement de notre faute.
J'ai mis à jour les versions pour les faire correspondre entre les projets et tout a fonctionné à nouveau.

Bonjour, j'utilise du matériel juste pour une seule entrée, bouton et formulaire sur mon site et j'ai dû utiliser un <JssProvider /> suite à ce commentaire https://github.com/mui-org/material-ui/issues / 8223 # issuecomment -331412432

C'est ennuyeux d'avoir besoin de ce fournisseur jss, y a-t-il un autre correctif que nous pouvons faire qui n'augmenterait pas la taille de construction finale?

@kopax Pourquoi utilisez-vous JssProvider ?

Salut @oliviertassinari , Dans production avant de visiter une autre route (nous utilisons react-router):

image

En production après avoir visité un itinéraire ou en development

image

Quelque chose de similaire se produit ici avec un formulaire (ombres de boîtes étranges), nous devons visiter une autre page pour avoir le bon css, cela ne se produit qu'en production:

image

Les deux problèmes sont résolus si nous ajoutons JssProvider . (corrigé: nous avons le même css dans production que dans development )

Je n'ai aucune idée. Je ne peux pas vous aider avec les informations fournies.

Tout est cassé aussi. J'observe le mauvais ordre des classes jssXX en production et par conséquent le mauvais style. Cela se produit après l'actualisation de la page.

Je ne trouve pas encore la raison.

@oliviertassinari peut-être que le numéro de version utilisé par [email protected] que nous utilisons vous aiderait à nous dire ce qui se passe:

        "@material-ui/core": "^1.4.0",
        "@material-ui/icons": "^1.0.0",
        "material-ui-chip-input": "1.0.0-beta.6 - 1.0.0-beta.8",

Pourriez-vous vous assurer que Material-UI n'est groupé qu'une seule

Bien. C'est possible. Nous utilisons react-admin qui a la version recommandée ~ 1.5.

J'ai résolu le bogue sur la production en ajoutant JssProvider . Maintenant, je peux actualiser la page normalement.

import React from "react";
import { Admin, Resource } from "react-admin";
import JssProvider from "react-jss/lib/JssProvider";

const App = () => (
  <JssProvider>
    <Admin dataProvider={dataProvider}>
      <Resource name="trip" list={RequestsList} className="resourceItem" />
    </Admin>
  </JssProvider>
);

export default App;

@andrewkslv c'est exactement ce que nous essayons d'éviter, nous préférerions l'utiliser sans JssProvider car nous n'utilisons qu'un composant Input et Button de @ material-ui , à la place, nous préférons utiliser pour le reste une autre interface utilisateur pour react-admin.

@oliviertassinari Je viens de vérifier et j'ai eu des problèmes de dépendances. Je l'ai corrigé mais j'ai toujours les erreurs avec les npm ls @material-ui/core :

├─┬ @bootstrap-styled/[email protected]
│ └── @material-ui/[email protected] 
├── @material-ui/[email protected] 
└─┬ [email protected]
  └── @material-ui/[email protected] 

Après avoir fait:

rm -rf node_modules/@bootstrap-styled/ra-ui/node_modules/@material-ui/
rm -rf node_modules/ra-ui-materialui/node_modules/@material-ui/
npm ls @material-ui/core
├─┬ @bootstrap-styled/[email protected]
│ └── UNMET DEPENDENCY @material-ui/[email protected] 
├── @material-ui/[email protected] 
└─┬ [email protected]
  └── UNMET DEPENDENCY @material-ui/[email protected] 

Ensuite, cela fonctionne (pas de problème css en production). Je suppose que ce n'est pas ce que je veux ...

Dépendances liées project @ material-ui:

Une idée de quoi faire?

@kopax C'est difficile à dire sans quelque chose que je puisse déboguer. Je suis heureux d'entendre que cela fonctionne maintenant.

J'ai remarqué que vous utilisez des composants stylisés avec Material-UI. Si vous avez du temps, j'aimerais discuter de l'intégration sur Gitter.

La solution de travail n'est pas naturelle. Ce qui signifie qu'il s'agit d'une tâche qui ne peut pas être exécutée avec npm. Je ne vais pas l'utiliser, j'ai donné cela comme un indice.

Nous aurons la chance lundi, je rejoindrai la chaîne mui gitter.

Salut @kopax , as-tu réussi à trouver une solution?

Non pas encore. Pas sans le fournisseur. @oliviertassinari Je suis sur gitter.

@andrewkslv Votre solution a vraiment fonctionné pour moi. J'utilise également react-admin et AWS Amplify. Chaque fois que je déploierais mon application de réaction dans un compartiment S3, le style serait complètement cassé et votre solution me sauvait vraiment.

Même problème ici. Pourquoi l'ajout de JssProvider aide-t-il?

J'ai ajouté un avertissement dans la v4 pour avertir lorsque des instances de style dupliquées sont utilisées: # 15422.

Je ne sais pas. J'ai soulevé ce problème dans react-admin lorsqu'ils implémentaient une nouvelle version du matériel ui dans le framework, mais il a été ignoré.

https://github.com/marmelab/react-admin/pull/3102#issuecomment -484228320

Où puis-je trouver la solution à propos de la version de production - conflits de noms de classe # 8223?

Merci,

@oliviertassinari Face à ce problème à nouveau, même si j'ai suivi toutes les instructions. Puisqu'il fonctionne pour d'autres, je suppose qu'il me manque peut-être quelque chose de basique.

https://stackoverflow.com/questions/58938080/jssprovider-not-generating-class-prefix-with-classnameprefix

J'utilise les versions suivantes des packages.

"@ material-ui / core": "^ 4.6.1",
"@ material-ui / icons": "^ 4.5.1",
"réagir": "^ 16.12.0",
"react-dom": "^ 16.12.0",
"react-jss": "^ 10.0.0",
"react-scripts": "3.2.0"

Mise à jour: le problème a été résolu. Désolé de ne pas avoir parcouru la documentation à fond. Cette partie de la documentation a résolu mon problème.

https://material-ui.com/styles/api/#creategenerateclassname -options-class-name-generator

Mais d'une manière ou d'une autre, la solution JSSProvider qui fonctionnait pour tous les autres, ne fonctionnait pas pour moi. Bref, merci :)

Merci @KannugoPrithvi , c'est la bonne solution! https://material-ui.com/styles/api/#creategenerateclassname -options-class-name-generator

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

pola88 picture pola88  ·  3Commentaires

FranBran picture FranBran  ·  3Commentaires

revskill10 picture revskill10  ·  3Commentaires

ghost picture ghost  ·  3Commentaires

anthony-dandrea picture anthony-dandrea  ·  3Commentaires