#reactjs #webpack #webpack-5
Вопрос:
Создал простую платформу SSR с использованием webpack, react, express. Все работает, за исключением того, что я не могу загрузить изображение PNG. Он просто отображает значок сломанного изображения.
Не уверен, что я делаю неправильно, и могу только предположить, что источник ошибки находится в моих файлах конфигурации webpack.
project
| babel.config.js
| package.json
| webpack.config.js
|
|---server
| express.js
| index.js
|
|---src
| | index.js
| | index.html
| |
| |---assets
| | |
| | |---images
| | | laptop.png
| |
| |---components
| | |
| | |---app
| | | index.js
| | | app.style.scss
babel.config.js
module.exports = function (api) {
api.cache(true);
return {
presets: [
"@babel/preset-env", // This tells webpack to transpile ES6 features into JS code that’s natively supported in Node.js and (most modern) browsers
"@babel/preset-react", // This tells webpack to transpile React JSX into JavaScript code
],
plugins: [
"@babel/plugin-transform-runtime",
"@babel/plugin-transform-async-to-generator",
"@babel/transform-arrow-functions",
"@babel/proposal-object-rest-spread",
"@babel/proposal-class-properties",
],
};
};
Webpack.config.js
const path = require("path");
const HTMLWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
module.exports = {
// webpack optimization mode
mode: "development" === process.env.NODE_ENV ? "development" : "production",
// entry files
entry: [
"./src/index.js", // react
],
// output files and chunks
output: {
path: path.resolve(__dirname, "dist"),
filename: "build/[name].js",
clean: true,
},
// module/loaders configuration
module: {
rules: [
{
test: /.(png)$/i,
use: [
{
loader: "url-loader",
options: {
limit: 100192,
},
},
],
},
{
test: /.jsx?$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
{
test: /.scss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
],
},
// webpack plugins
plugins: [
// extract css to external stylesheet file
new MiniCssExtractPlugin({
filename: "build/styles.css",
}),
// prepare HTML file with assets
new HTMLWebpackPlugin({
filename: "index.html",
template: path.resolve(__dirname, "src/index.html"),
minify: false,
}),
// copy static files from `src` to `dist`
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, "src/assets"),
to: path.resolve(__dirname, "dist/assets"),
},
],
}),
],
// resolve files configuration
resolve: {
// file extensions
extensions: [".js", ".jsx", ".scss"],
},
// webpack optimizations
optimization: {
splitChunks: {
cacheGroups: {
default: false,
vendors: false,
vendor: {
chunks: "all", // both : consider sync async chunks for evaluation
name: "vendor", // name of chunk file
test: /node_modules/, // test regular expression
},
},
},
},
// development server configuration
devServer: {
port: 8088,
historyApiFallback: true,
},
// generate source map
devtool: "source-map",
};
server/index.js
const path = require("path");
// ignore `.scss` imports
require("ignore-styles");
// transpile imports on the fly
require("@babel/register")({
configFile: path.resolve(__dirname, "../babel.config.js"),
});
// import express server
require("./express.js");
server/express.js
const express = require("express");
const fs = require("fs");
const path = require("path");
const React = require("react");
const ReactDOMServer = require("react-dom/server");
// create express application
const app = express();
// import App component
const { App } = require("../src/components/app");
// serve static assets
app.get(
/.(js|css|map|png|ico)$/,
express.static(path.resolve(__dirname, "../dist"))
);
// for any other requests, send `index.html` as a response
app.use("*", (req, res) => {
// read `index.html` file
let indexHTML = fs.readFileSync(
path.resolve(__dirname, "../dist/index.html"),
{
encoding: "utf8",
}
);
// get HTML string from the `App` component
let appHTML = ReactDOMServer.renderToString(<App />);
// populate `#app` element with `appHTML`
indexHTML = indexHTML.replace(
'<div id="app"></div>',
`<div id="app">${appHTML}</div>`
);
// set header and status
res.contentType("text/html");
res.status(200);
return res.send(indexHTML);
});
// run express server on port 9000
app.listen("9000", () => {
console.log("Express server started at http://localhost:9000");
});
src/index.js
import React from "react";
import ReactDOM from "react-dom";
import { App } from "./components/app";
// compile App component in `#app` HTML element
ReactDOM.hydrate(<App />, document.getElementById("app"));
src/components/app/index.js
import React from "react";
import "./app.style";
import { Container, Grid } from "@material-ui/core";
import laptop from "../../assets/images/laptop.png";
// export component
export class App extends React.Component {
constructor(props) {
super(props);
// component state
this.state = {};
}
// render
render() {
return (
<div className="ui-app">
<div className="ui-app__logo">Andrew Kimmel</div>
<Container>
<Grid container spacing={5} alignItems="center">
<Grid item sm={6} xs={12}>
<p>Hello World!</p>
</Grid>
<Grid item sm={6} xs={12}>
<img src={laptop} />
</Grid>
<Grid item sm={6} xs={12}>
<img src="./dist/assets/images/laptop.png" />
</Grid>
<Grid item sm={6} xs={12}>
<img src={require("../../assets/images/laptop.png").default} />
</Grid>
<Grid item sm={6} xs={12}>
<div className="img" />
</Grid>
</Grid>
</Container>
</div>
);
}
}
Репо Git находится здесь: https://github.com/adkimmel/ssr