J'ai une configuration matérielle d'interface utilisateur avec SSR. Je fonctionne très bien ...
Mon problème est que lorsque je compile mon code, material-ui génère des noms de classe étranges comme jss116
ou jss19
.
C'est vraiment ennuyeux lors de l'inspection de mon code en développement. Je veux avoir (dans mon environnement de développement), des noms de classe plus significatifs. Est-ce possible?
server.tsx
import * as React from "react"; import * as ReactDOM from 'react-dom'; import {BrowserRouter, Router} from "react-router-dom"; import {createStore} from 'redux'; import {Provider} from 'react-redux'; import {appReducer} from '../shared/reducers'; import App from "../shared/App"; import {create} from "jss"; import {createGenerateClassName, MuiThemeProvider, jssPreset} from '@material-ui/core/styles'; import theme from '../shared/MainTheme'; import JssProvider from 'react-jss/lib/JssProvider'; import configureStore from '../shared/store/index'; declare global { interface Window { __PRELOADED_STATE__ : any } } const preloadedState = window.__PRELOADED_STATE__; delete window.__PRELOADED_STATE__; // const store = createStore(appReducer, preloadedState); // const store = configureStore(appReducer, preloadedState); const store = configureStore(preloadedState); const Main = () => { React .useEffect(function didMount() { const jssStyles = document.getElementById('jss-server-side'); if (jssStyles && jssStyles.parentNode) { jssStyles .parentNode .removeChild(jssStyles); } }, []); return <App/> } const generateClassName = createGenerateClassName(); const jss = create(jssPreset()); ReactDOM.hydrate( <JssProvider jss={jss} generateClassName={generateClassName}> <MuiThemeProvider theme={theme}> <BrowserRouter> <Provider store={store}> <Main/> </Provider> </BrowserRouter> </MuiThemeProvider> </JssProvider>, document.querySelector('#root'),);
client.tsx
import * as path from 'path'; import * as express from "express"; import * as bodyParser from "body-parser"; import * as React from "react"; import * as ReactDOMServer from "react-dom/server"; import {StaticRouter} from "react-router"; import {matchPath} from "react-router-dom"; import {Helmet} from "react-helmet"; import { createStore, Action } from 'redux'; import { Provider } from 'react-redux'; import {SheetsRegistry, create} from 'jss'; import JssProvider from 'react-jss/lib/JssProvider'; import {MuiThemeProvider, jssPreset, createGenerateClassName} from '@material-ui/core/styles'; import App from "../shared/App"; import routes from '../shared/routes'; import theme from '../shared/MainTheme'; const app = express(); const PORT = process.env.PORT || 3000; app.use(bodyParser.urlencoded()); app.use(bodyParser.json()); app.use(express.static("build/public")); console.log("Public path:", path.join(__dirname, "public")); const appReducer = (prevState: any, action: Action) => ({...prevState, message: "Reducer"}); app.get('*', (req, res, next) => { const now = new Date(); console.log(`GET ${now} - ${req.originalUrl}`); const activeRoute = routes.find(route => !!matchPath(req.url, route)) || { path: "/" }; // TODO: Fetch initial state according to the active route. const preloadedState = {activeRoute}; const store = createStore(appReducer, preloadedState as any); const sheetsRegistry = new SheetsRegistry(); const sheetsManager = new Map(); const generateClassName = createGenerateClassName(); const jss = create(jssPreset()); const context = {} const content = ReactDOMServer.renderToString( <StaticRouter location={req.url} context={context}> <JssProvider jss={jss} registry={sheetsRegistry} generateClassName={generateClassName}> <MuiThemeProvider theme={theme} sheetsManager={sheetsManager}> <Provider store={store}> <App/> </Provider> </MuiThemeProvider> </JssProvider> </StaticRouter> ); const helmet = Helmet.renderStatic(); const css = sheetsRegistry.toString(); const html = ` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /> <link rel="icon" href="/favicon.ico" type="image/x-icon" /> <style id="jss-server-side">${css}</style> </head> <body> <div id="root" style="overflow-x: hidden; width: 100%; margin: 0;">${content}</div> <script src="client_bundle.js" type="text/javascript"></script> <script type="text/javascript"> window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')} </script> </body> </html> `; res.send(html); }); app.listen(PORT, () => { console.log(`App is running on port ${PORT}`) })
4 Réponses :
Vous pouvez changer la valeur des accessoires generateClassName
en votre générateur personnalisé en fonction de l'environnement. En production, vous pouvez simplement utiliser le createGenerateClassName .
Par exemple:
let generateClassName = null; if (process.env.NODE_ENV === "production") { // use the default class name creator from mui generateClassName = createGenerateClassName(); } else { // make your own name generator const createGenerateId = () => { let counter = 0; return (rule, sheet) => `pizza--${rule.key}-${counter++}`; }; generateClassName = createGenerateId(); } // ... in render <JssProvider generateClassName={generateClassName} ...> ... </JssProvider>
Cet exemple est tiré de Docs CSS-in-JS .
Vous devriez pouvoir obtenir des noms significatifs en développement en définissant correctement NODE_ENV dans votre outil de compilation.
J'ai finalement réglé ce problème en exécutant webpack comme ceci:
webpack --mode = development ./server.ts
Il s'avère que, pour une raison quelconque, Webpack n'écoute pas NODE_ENV
Où gérez-vous exactement cela? Je ne savais pas que nous devions exécuter webpack séparément lors de l'exécution de notre application react.
Merci Daniel, tu as sauvé la journée, j'ai eu exactement le même problème en mode webpack différent pour le client et le serveur
J'ai rencontré ce problème et je l'ai résolu en utilisant la fonction createGenerateClassName
et en définissant l'option disableGlobal
sur true
.
const generateClassName = createGenerateClassName({ disableGlobal: true, }); const App = () => ({ <StylesProvider generateClassName={generateClassName}>...</StylesProvider> });