Material UI: Class 开发中的名字被丑化了

Material UI: Class names in development are uglified

我有一个 material ui 设置和 SSR。我工作正常...

我的问题是,当我编译我的代码时,material-ui 生成了一些奇怪的 class 名称,例如 jss116jss19

在开发中检查我的代码时,这真的很烦人。我想要(在我的开发环境中)更有意义的 class 名称。这可能吗?

server.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}`)
})

client.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'),);

您可以根据环境将 generateClassName 道具值更改为您的自定义生成器。在生产中,你可以只使用通常的 createGenerateClassName.

例如:

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>

此示例取自 CSS-in-JS Docs

通过在构建工具中正确设置 NODE_ENV,您应该能够在开发中获得有意义的名称。

我终于通过 运行 webpack 解决了这个问题,如下所示:

webpack --mode=development ./server.ts

事实证明,出于某种原因,webpack 不听 NODE_ENV

我 运行 解决了这个问题,并通过使用 createGenerateClassName 函数并将 disableGlobal 选项设置为 true 来修复它。

const generateClassName = createGenerateClassName({
    disableGlobal: true,
});

const App = () => ({
    <StylesProvider generateClassName={generateClassName}>...</StylesProvider>
});