我有这个要在服务器端渲染的应用程序。一切正常,直到我尝试向其添加Material UI。
我的目录结构是这样:
app/
build/ * This is created by webpack
server_bundle.js
public/
client_bundle.js
fonts/
images/
src/
client/
Client.tsx
server/
server.tsx
shared/
App.tsx
routes.tsx
webpack.config.js
这是我的文件内容:
webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
target: 'node',
entry: {
server: path.resolve(__dirname, 'src/server/server.tsx'),
"public/client": path.resolve(__dirname, 'src/client/client.tsx')
},
output: {
filename: '[name]_bundle.js',
path: path.resolve(__dirname, 'build'),
publicPath: '/build'
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
},
module: {
rules: [{
test: /\.(tsx|ts)?$/,
loader: 'awesome-typescript-loader',
options: {
jsx: 'react'
}
},
{
test: /\.(scss|sass|css)$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
]
},
{
test: /\.(ico)$/,
loader: 'file-loader',
options: { outputPath: '/public', publicPath: '/public', name: '[name].[ext]' }
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/,
loader: 'file-loader',
options: { outputPath: '/public/images', publicPath: 'images' }
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader',
options: { outputPath: '/public/fonts', publicPath: 'fonts' }
},
]
},
optimization: {
},
plugins: [
new MiniCssExtractPlugin({
filename: 'public/styles_bundle.css',
chunkFilename: "public/styles/[id].css"
})
]
}
server.tsx
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 App from "../shared/App";
import routes from '../shared/routes';
const app = express();
const PORT = process.env.PORT || 3000;
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());
app.use(express.static("build/public"));
app.get('*', (req, res, next) => {
const activeRoute = routes.find(route => !!matchPath(req.url, route)) || {path: "/"};
const now = new Date();
console.log(`GET ${now} - ${req.url}`);
const context = {}
const content = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);
const helmet = Helmet.renderStatic();
const html = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
${helmet.title.toString()}
${helmet.meta.toString()}
<link rel="stylesheet" href="styles_bundle.css">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
</head>
<body>
<div id="root" style="overflow-x: hidden; width: 100%; margin: 0;">${content}</div>
<script src="client_bundle.js"></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 } from "react-router-dom";
import App from "../shared/App";
// Because it's already been rendered, we only need to hydrate event
// handlers and wire things up.
ReactDOM.hydrate(
<BrowserRouter>
<App />
</BrowserRouter>,
document.querySelector("#root")
);
App.tsx
import * as React from 'react';
import routes from "../shared/routes";
import { Helmet } from 'react-helmet';
import { Switch, Route } from "react-router";
import 'typeface-roboto';
class App extends React.Component {
render() {
return (
<React.Fragment>
<Switch>
{routes.map(({path, exact, component: C}) => {
return <Route
path={path}
exact={exact}
render={(props) => <C {...props}/> }
/>
})}
</Switch>
</React.Fragment>
)
}
}
export default App;
最后, routes.tsx
import * as React from 'react';
import { Button } from '@material-ui/core';
const routes = [
{
name: "Home",
exact: true,
path: "/",
component: (props:any) => {return (
<Button variant="contained" color="primary">
Hello World
</Button>
)}
}
];
export default routes;
我在浏览器控制台中遇到此错误,并且显然没有任何实质性的ui样式:
client_bundle.js:44 Uncaught ReferenceError: global is not defined
at Object.<anonymous> (client_bundle.js:44)
at n (client_bundle.js:1)
at Object.<anonymous> (client_bundle.js:1)
at n (client_bundle.js:1)
at Object.<anonymous> (client_bundle.js:17)
at n (client_bundle.js:1)
at Object.<anonymous> (client_bundle.js:17)
at n (client_bundle.js:1)
at Object.<anonymous> (client_bundle.js:36)
at n (client_bundle.js:1)
client_bundle.js
的那部分看起来像这样:
... __esModule",{value:!0});global.CSS;t.default=function(e){return e}} ...
您认为这里可能会发生什么?
答案 0 :(得分:1)
try this workaround in your
plugins: [
new webpack.DefinePlugin({
'global': {} // webpack workaround
}),
new MiniCssExtractPlugin({
filename: 'public/styles_bundle.css',
chunkFilename: "public/styles/[id].css"
})
]