[Webpack] [React] В SSR с разделением кода, как я могу получить список фрагментов, необходимых для страницы?

У меня есть приложение React с отлично работающим SSR и разделением кода Webpack.

Мой webpack.config.js выглядит так:

const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ServerMiniCssExtractPlugin = require("./server/utils/serverMiniCssExtractPlugin");

module.exports = [{
  name: 'react-app',
  mode: 'development',
  devtool: 'eval',
  cache: true,
  entry: {
    main: [
      'babel-polyfill',
      'webpack-hot-middleware/client',
      './react/index.tsx',
    ],
  },
  output: {
    path: `${__dirname}/dist/__build__`,
    filename: '[name].js',
    chunkFilename: '[name].js',
    publicPath: '/__build__/',
  },
  module: {
    rules: [{
      test: /\.(ts|js)x?$/,
      loader: 'babel-loader',
      exclude: [/node_modules/],
    }, {
      test: /\.scss$/,
      oneOf: [{
        resourceQuery: /^\?raw$/,
        use: [MiniCssExtractPlugin.loader, {
          loader: 'css-loader',
          options: {
            modules: true,
            sourceMap: true,
            camelCase: false,
            localIdentName: '[local]',
          },
        }, 'sass-loader', 'postcss-loader'],
      }, {
        use: [MiniCssExtractPlugin.loader, {
          loader: 'css-loader',
          options: {
            modules: true,
            sourceMap: true,
            camelCase: true,
            localIdentName: '[path]___[name]__[local]___[hash:base64:5]',
          },
        }, 'sass-loader', 'postcss-loader'],
      }]
    }],
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js'],
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        CLIENT: JSON.stringify(true),
      },
    }),
    new webpack.IgnorePlugin(/^vertx$/),
    new MiniCssExtractPlugin({
      filename: "style.css",
      chunkFilename: "style.chunk.[id].css"
    }),
  ],
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /node_modules/,
          name: 'vendor',
          enforce: true
        },
      },
    },
  },
}, {
  name: 'server-side rendering',
  mode: 'development',
  devtool: 'eval',
  cache: true,
  entry: [
    './react/ssr.tsx',
  ],
  target: 'node',
  output: {
    path: `${__dirname}/dist/__server__/`,
    filename: 'ssr.js',
    publicPath: '/__server__/',
    libraryTarget: 'commonjs2',
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js'],
  },
  module: {
    rules: [{
      test: /\.(ts|js)x?$/,
      exclude: [/node_modules/, /.+\.config.js/],
      loader: 'babel-loader',
    }, {
      test: /\.scss$/,
      oneOf: [{
        resourceQuery: /^\?raw$/,
        use: [ServerMiniCssExtractPlugin.loader, {
          loader: 'css-loader',
          options: {
            modules: true,
            sourceMap: true,
            camelCase: false,
            localIdentName: '[local]',
          },
        }, 'sass-loader', 'postcss-loader'],
      }, {
        use: [ServerMiniCssExtractPlugin.loader, {
          loader: 'css-loader',
          options: {
            modules: true,
            sourceMap: true,
            camelCase: true,
            localIdentName: '[path]___[name]__[local]___[hash:base64:5]',
          },
        }, 'sass-loader', 'postcss-loader'],
      }]
    }],
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        SERVER: JSON.stringify(true),
      },
    }),
    new webpack.IgnorePlugin(/^vertx$/),
    new ServerMiniCssExtractPlugin({
      filename: "style.css",
      chunkFilename: "style.chunk.[id].css"
    }),
  ],
}];

... и он генерирует фрагменты как для js, так и для css, которые с помощью приложения загружаются правильно при переходе с разных страниц, все они отображаются с помощью response-router.

Проблема в том, что когда я перезагружаю одну из страниц, необходимые фрагменты css загружаются после рендеринга и не связаны напрямую на странице из SSR, поэтому на секунду у меня есть FOUC.

Поскольку я хотел бы использовать React-Helmet для вставки в заголовок страницы необходимых фрагментов css, когда я использую SSR приложение, как я могу получить в коде список имен файлов фрагментов, которые необходимы для страницы, которую я перезагружаю?

Допустим, для страницы нужны: 0.js 2.js style.chunk.0.css style.chunk.2.css

Как мне получить список этих файлов, чтобы динамически создавать ссылки в заголовке страницы?

Спасибо.


person StefS    schedule 18.12.2018    source источник


Ответы (1)


Используйте webpack-manifest-plugin, чтобы сгенерировать файл manifest.json, который будет включать список всех ваших фрагментов.

В вашем webpack.config.js:

var ManifestPlugin = require('webpack-manifest-plugin');

module.exports = {
    // ...
    plugins: [
      new ManifestPlugin()
    ]
};

Это сгенерирует файл manifest.json в корневом каталоге вывода с сопоставлением всех имен исходных файлов с соответствующими файлами вывода, например:

{
  "mods/alpha.js": "mods/alpha.1234567890.js",
  "mods/omega.js": "mods/omega.0987654321.js"
}
person prograhammer    schedule 11.08.2019