PNGs прерываются / не отображаются с помощью «актив/ресурс»

#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