首页 > 解决方案 > Webpack Hot Server Middleware 不使用 Webpack 4 和 SSR 呈现

问题描述

添加 webpack-hot-server-middleware 时,“serverRenderer is not a function”错误会在开发中弹出。下面是我的 express.js 和 config/webpack.dev-ssr.js。Github 上的一些问题建议在编译器返回之前加载 webpack-hot-server-middleware,但我不知道如何验证。

快递.js:

import express from 'express';
import webpack from 'webpack';
import webpackHotServerMiddleware from 'webpack-hot-server-middleware';

import configDevClient from '../../config/webpack.dev-client'
import configDevSsr from '../../config/webpack.dev-ssr'
import configProdClient from '../../config/webpack.prod-client'
import configProdSsr from '../../config/webpack.prod-ssr'

const server = express()

const isDev = process.env.NODE_ENV !== 'production'

if (isDev) {
    const compiler = webpack([configDevClient, configDevSsr])

    const clientDevCompiler = compiler.compilers[0]
    const ssrDevCompiler = compiler.compilers[1]

    const webpackDevMiddleware = require('webpack-dev-middleware')(compiler, configDevClient.devServer)
    const webpackHotMiddleware = require('webpack-hot-middleware')(clientDevCompiler, configDevClient.devServer)

    server.use(webpackDevMiddleware)
    server.use(webpackHotMiddleware)
    // out of const compiler webpack-hot-server-middleware will take compiler with `name: 'server'`
    server.use(webpackHotServerMiddleware(compiler))
} else {
    webpack([configProdClient, configProdSsr]).run((err, stats) => {
        // const staticMiddleware = express.static('dist')
        // server.use(staticMiddleware)
        const render = require('./render')
        // const render = require('../../build/prod-ssr.bundle.js').default
        const expressStaticGzip = require('express-static-gzip')        // Heroku doesn't support gzip on Heroku server level
        server.use(expressStaticGzip('dist', { enableBrotli: true }))

        server.use(render())
    })
}

const port = process.env.PORT || 8080

server.listen(port, () => console.log(`Server's running on http://localhost:${port}.`));

webpack.dev-ssr.js:

const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const nodeExternals = require('webpack-node-externals');

const isProd = process.env.NODE_ENV === 'production';

module.exports = {
        name: 'server',                                                             // preset name for webpack-hot-server-middleware
        entry: {
            server: './src/server/render'
        },
        resolve: {
            extensions: ['.js']                                                 // add extensions to entry files above
        },
        mode   : 'production',
        output : {
            filename  : 'dev-ssr.bundle.js',
            path      : path.resolve(__dirname, '../build'),
            libraryTarget: 'commonjs2'
        },
        // for Node leave all required (with require()) modules as is don't put them to main.bundle.js like for browser
        target: 'node',
        /* Webpack allows to define externals - modules that should not be bundled.
        When bundling with Webpack for the backend you usually don't want to bundle its node_modules dependencies.
        This library creates an externals function that ignores node_modules when bundling in Webpack.
        All Node modules will no longer be bundled but will be left as require('module'). */
        externals: nodeExternals(),
        /* optimization: {
            splitChunks: {
                chunks: 'all',
                cacheGroups: {
                    vendor: {
                        name: 'vendor',
                        chunks: 'initial',
                        minChunks: 2
                    }
                }
            }
        }, */
        devtool: 'source-map',
        module : {
            rules: [
                {
                    test   : /\.js$/,
                    use    : [
                        { loader: 'babel-loader' }
                    ],
                    exclude: /node_modules/
                },
                {
                    test   : /\.ts$/,
                    use    : [
                        { loader: 'awesome-typescript-loader' }
                    ],
                    exclude: /node_modules/
                },
                {
                    test: /\.css$/,
                    use : [
                        {
                            loader: MiniCssExtractPlugin.loader
                        },
                        {
                            loader : 'css-loader',
                            options: {
                                sourceMap: true         // won't work: no separate css file. Styles come from main.bundle.js
                                // minimize: true
                            }
                        }
                    ]
                },
                {
                    test: /\.sass$/,
                    use : [
                        { loader: 'style-loader' },
                        { loader: 'css-loader' },
                        { loader: 'sass-loader' }
                    ]
                },
                {
                    test: /\.styl$/,
                    use : [
                        { loader: 'style-loader' },
                        { loader: 'css-loader' },
                        { loader: 'postcss-loader' },
                        { loader: 'stylus-loader' }
                    ]
                },
                {
                    test: /\.less$/,
                    use : [
                        { loader: 'style-loader' },
                        { loader: 'css-loader' },
                        { loader: 'less-loader' }
                    ]
                },
                {
                    test: /\.html$/,
                    use : [
                        // job of two below modules are done by HtmlWebpackPlugin
                        /* {
                            loader: 'file-loader',
                            options: {
                                name: '[name].html'         // output file name
                            }
                        },
                        {   // extract-loader puts the tested /\.html$/ file to a separate file not adds it to main.bundle.js
                            // extract loader parses the javascript back to an html file
                            loader: 'extract-loader'
                        }, */
                        // html-loader was left cause it exports tested html file as string to src/main.js
                        {
                            loader : 'html-loader',     // exports tested html file to main.bundle.js as string and lints it
                            options: {
                                attrs: ['img:src']          // to add img:src to output file and require all images from its folder
                            }
                            // html template implicitly turns <img src='...' /> in .html page to <img src='require(src)' />
                        }
                    ]
                },
                {
                    test: /\.pug$/,
                    use : [
                        { loader: 'pug-loader' }
                    ]
                },
                {
                    test: /\.hbs$/,
                    use : [
                        {
                            loader: 'handlebars-loader',
                            query : {
                                // hbs template implicitly turns <img src='...' /> in .hbs page to <img src='require(src)' />
                                inlineRequires: '/images/'
                            }
                        }
                    ]
                },
                {
                    test: /\.(png|svg|gif|jpe?g)$/,
                    use : [
                        {
                            loader : 'file-loader',
                            options: {
                                name: '/images/[name].[hash:8].[ext]',      // still emits not the file but its path
                                emitFile: false
                            }
                        }
                    ]
                },
                {
                    test: /\.md$/,
                    use: [
                        /* { loader: 'html-loader' },
                        // markdown loader using 'marked' package. 'Marked' outputs HTML, it's best served with html-loader
                        { loader: 'markdown-loader' } */
                        { loader: 'markdown-with-front-matter-loader' }
                    ]
                }
            ]
        },
        plugins: [
            new MiniCssExtractPlugin({ filename: '[name].[contenthash].css' }),
            new webpack.DefinePlugin({
                'process.env': {
                    NODE_ENV: JSON.stringify('development')
                }
            })
        ]
};

完整的仓库位于https://github.com/ElAnonimo/webpack4

标签: webpack-4

解决方案


此错误的另一个可能原因和解决方案是问题https://github.com/faceyspacey/react-universal-component/issues/148


推荐阅读