2

我正在尝试使用webpack-dev-middlewarewebpack-hot-middle-ware、express 和 react 启动并运行我的应用程序。但是当我启动我的代码时,系统没有给我 [hash].hot-update.json 文件。当我更改代码中的某些内容时,系统会重建并提供此类文件,但文件名中的哈希值错误。这是我的代码:

开发服务器的入口点:

require('ignore-styles').default(undefined, (module, filename) => {
  if ((['.png', '.jpg'].some(ext => filename.endsWith(ext)) )) {
    module.exports = '/build/' + path.basename(filename);
  }
});
require('babel-register')({
    ignore: [ /(node_modules)/ ],
    presets: ["env", "stage-0", "react"],
    plugins: [
        'dynamic-import-node',
        'syntax-dynamic-import',
        'react-loadable/babel'
    ]
});

const express = require('express');
const path = require('path');
const webpack = require('webpack');
const Loadable = require('react-loadable');
const webpackDevMiddleware = require('webpack-dev-middleware');
const serverRenderer = require('./server').default;

const config = require('../configs/webpack.common.js');
const compiler = webpack(config);

const app = express();
app.use(webpackDevMiddleware(compiler, { serverSideRender: true, publicPath: '/build/', }));
app.use(require("webpack-hot-middleware")(compiler));
app.use(serverRenderer());

Loadable.preloadAll().then(() => {
    app.listen(3000, () => console.log('Development server is running on port 3000'));
}).catch(err => {
    console.log(err);
});

我的 webpack.config.js 文件:

module.exports = [{
    name: 'client',
    mode: 'development',
    target: 'web',
    entry: ['webpack-hot-middleware/client', './app/index.js'],
    output: {
        path: path.join(__dirname, '../build'),
        filename: 'client.js',
        publicPath: '/build/',
        hotUpdateChunkFilename: '[id].[hash].hot-update.js',
        hotUpdateMainFilename: '[hash].hot-update.json',
    },
    devtool: 'source-map',
    plugins: [
        new ManifestPlugin({
          writeToFileEmit: true,
        }),
        new WriteFilePlugin(),
        new webpack.HotModuleReplacementPlugin(),
    ],
    module: {
        rules: [
        {
            test: /\.js?$/,
            loader: 'babel-loader',
            exclude: /node_modules/
        },
        {
            test: /\.scss$/,
            use: ['style-loader', 'css-loader', 'sass-loader']
        },
        {
            test: /\.(png|jpg|gif|ico|jpeg)$/,
            use: [
                {
                    loader: 'file-loader',
                    options: {
                        name: '[name].[ext]',
                    }
                }
            ]
        }
    ],
},
},
{
    name: 'server',
    mode: 'development',
    target: 'node',
    entry: './server/server.js',
    externals: [nodeExternals()],
    output: {
        path: path.join(__dirname, '../build'),
        filename: 'server.js',
        libraryTarget: 'commonjs2',
        publicPath: '/build/',
    },
    plugins: [
        new WriteFilePlugin(),
    ],
    module: {
        rules: [
        {
            test: /\.js?$/,
            loader: 'babel-loader',
            exclude: /node_modules/
        },
        {
            test: /\.scss$/,
            use: [
                {
                    loader: 'style-loader',
                },
                {
                    loader: 'css-loader'
                },
                {
                    loader: 'sass-loader'
                }
            ]
        },
        {
            test: /\.(png|jpg|gif|ico|jpeg)$/,
            use: [
                {
                    loader: 'file-loader',
                    options: {
                        name: '[name].[ext]',
                        emitFile: false
                    }
                }
            ]
        }
    ]
}
}];

我的 package.json 文件:

{
  "name": "xxx",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node server/development.js",
    "build": "rimraf build && NODE_ENV=production webpack --config configs/webpack.production.js --progress --profile --colors",
    "prod": "node server/production.js"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.26.3",
    "babel-loader": "^7.1.4",
    "babel-plugin-dynamic-import-node": "^1.2.0",
    "babel-plugin-syntax-dynamic-import": "^6.18.0",
    "babel-preset-env": "^1.6.1",
    "babel-preset-react": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
    "babel-register": "^6.26.0",
    "css-loader": "^0.28.11",
    "express": "^4.16.3",
    "file-loader": "^1.1.11",
    "ignore-styles": "^5.0.1",
    "mini-css-extract-plugin": "^0.4.0",
    "node-sass": "^4.9.0",
    "react-hot-loader": "^4.1.2",
    "rimraf": "^2.6.2",
    "sass-loader": "^7.0.1",
    "serialize-javascript": "^1.5.0",
    "style-loader": "^0.21.0",
    "uglifyjs-webpack-plugin": "^1.2.5",
    "webpack": "^4.6.0",
    "webpack-cli": "^2.0.15",
    "webpack-dev-middleware": "^3.1.3",
    "webpack-hot-middleware": "^2.22.1",
    "webpack-manifest-plugin": "^2.0.2",
    "webpack-merge": "^4.1.2",
    "webpack-node-externals": "^1.7.2",
    "write-file-webpack-plugin": "^4.3.2"
  },
  "dependencies": {
    "react": "^16.4.0",
    "react-dom": "^16.4.0",
    "react-helmet": "^5.2.0",
    "react-loadable": "^5.3.1",
    "react-redux": "^5.0.7",
    "react-router-config": "^1.0.0-beta.4",
    "react-router-dom": "^4.2.2",
    "redux": "^4.0.0",
    "redux-thunk": "^2.2.0"
  }
}

和我的 server.js 文件:

import React from 'react'
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import { renderRoutes } from 'react-router-config';
import { Provider } from 'react-redux'
import { Helmet } from 'react-helmet';
import Loadable from 'react-loadable';
import serialize from 'serialize-javascript';
import configureStore from '../app/store';
import routes from '../app/routes';
import template from './template';

const store = configureStore();

const normalizeAssets = (assets) => {
    return Array.isArray(assets) ? assets : [assets]
};

const searchModuleFiles = (modules, assets) => {
    return modules.map(module => {
        let files = [`${module}.js`, `${module}.css`];
        return files.map(file => ({ file: assets[file] }));
    })
};

export default (stats = null) => (req, res) => {
    const context = {};
    const modules = [];
    let devStats = [];
    let mainScript = null;

    const content = renderToString(
        <Provider store={store}>
            <StaticRouter context={context} location={req.url}>
                <Loadable.Capture report={moduleName => modules.push(moduleName)}>
                    {renderRoutes(routes)}
                </Loadable.Capture>
            </StaticRouter>
        </Provider>
    );

    if(!stats) {
        let chunks = res.locals.webpackStats.toJson().children.filter(item => item.name === 'client')[0].assetsByChunkName;
        devStats = normalizeAssets(modules.map(module => chunks[module])[0]).map(item => ({ file: `/build/${item}` }));
        mainScript = { file: '/build/client.js' };
    } else {
        mainScript = { file: stats['main.js'] };
    }

    let bundles = stats ? searchModuleFiles(modules, stats)[0] : devStats;
    let scripts = bundles.filter(bundle => bundle.file.endsWith('.js'));
    let styles = bundles.filter(bundle => bundle.file.endsWith('.css'));

    const helmet = Helmet.renderStatic();
    const data = serialize(store.getState());

    res.status(200).send(template({ content, data, mainScript, scripts, styles, helmet }));
}

还需要有关服务器端渲染的任何帮助。

4

0 回答 0