javascript - 带有热重载的 Webpack 捆绑 Node Express = hell

标签 javascript node.js reactjs webpack

我不想承认这一点,但我已经花了三个漫长的晚上来尝试做 - 我认为做起来很简单的事情。我终于到了我受够了它的阶段,坦率地说,我很沮丧,因为“它就是行不通”。

这是我努力实现的目标:

  1. 将我的 Express 服务器与 Webpack 捆绑在一起(虽然我当前的代码只是在浏览器中呈现一个字符串,但它应该编译服务器呈现的 React 组件,并使用 Babel 编译)
  2. 将包保存在内存中(如果没有其他方法,则保存在磁盘上)
  3. 运行 webpack/dev/hot middleware 来为我的 Node Express 应用程序提供服务,服务器呈现页面(将是 React 组件)的更改将在浏览器中自动更新。

我尝试过多种组合、已弃用的教程、不再维护的 npm 包以及下载的示例,但它们根本不起作用。

这是我目前的设置:

webpack.server.config.js:

const path = require('path');
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');

module.exports = {
    name: 'server',
    mode: 'development',
    target: 'node',
    externals: nodeExternals(),
    entry: [ './src/server/index' ],
    output: {
        path: path.resolve(__dirname, 'dist'),
        // path: "/",
        filename: '[name].js',
        publicPath: '/assets/',
        libraryTarget: 'commonjs2'
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ],
    module: {
        rules: [
            {
                test: /.js$/,
                loader: 'babel-loader',
                include: path.resolve(__dirname, 'src/'),
                exclude: /node_modules/,
                options: {
                    presets:
                        [['@babel/preset-env', { modules: 'false' }], '@babel/preset-react'],
                    plugins: [
                        ['@babel/plugin-proposal-object-rest-spread', { useBuiltIns: true }],
                        '@babel/plugin-proposal-class-properties'
                    ]
                }
            },
            {
                test: /\.scss$/,
                loader: 'ignore-loader'
            },
            {
                test: /\.css$/,
                loader: 'ignore-loader'
            },
            {
                test: /\.(jpg|png|svg|gif|pdf)$/,
                loader: 'file-loader',
                options: {
                    name: '[path][name].[ext]'
                }
            }
        ]
    }
};

索引.js:

import http from 'http';
import fs from "fs";
import express from "express";
import favicon from 'serve-favicon';
// import renderer from "./renderer";
import renderApp from './welcome';


const app = express();

app.use(favicon('./public/favicon.ico'));
app.use(express.static("public"));


if (process.env.NODE_ENV !== 'production') {

    const webpack = require('webpack');
    const webpackDevMiddleware = require('webpack-dev-middleware');
    const webpackHotMiddleware = require('webpack-hot-middleware');
    const serverConfig = require('../../webpack.server.config');

    const compiler = webpack(serverConfig);

    app.use(webpackDevMiddleware(compiler, {
        stats: {colors: true},
        headers: { "Access-Control-Allow-Origin": "http://localhost"},
        publicPath: serverConfig.output.publicPath
    }));

    app.use(require("webpack-hot-middleware")(compiler));

}

app.get("*", function(req, res) {
    fs.readFile("./src/server/html/index.html", "utf8", function(err, data) {
        const context = {};
        const html = renderApp();
        //const html = renderer(data, req.path, context);

        res.set('content-type', 'text/html');
        res.send(html);
        res.end();
    });
});

const PORT = process.env.PORT || 8080;

app.listen(3000);

坦率地说,我也很困惑这应该如何工作。
是否应该执行以下步骤?:

  • webpack webpack.server.config.js --watch
  • node dist/server.js//webpack 输出文件夹

这会神奇地热重载我的服务器吗?

欢迎所有帮助,或者如果您碰巧有一个工作演示。
我只是无法完成这项工作。

最后,我还将热重载(重新渲染)我的客户端包,但我想这将是比较容易的部分,因为我已经看过很多很多关于它的资源。

最佳答案

可能需要晚上 sleep 。
我使用 StartServerPlugin 实现了这个功能(包括 React 服务器渲染组件)。
以下设置热重载 Node Express 服务器:

const path = require('path');
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');
const StartServerPlugin = require('start-server-webpack-plugin');

module.exports = {
    name: 'server',
    mode: 'development',
    target: 'node',
    externals: nodeExternals({
        whitelist: ['webpack/hot/poll?1000']
    }),
    entry: [ 'webpack/hot/poll?1000', './src/server/index' ],
    output: {
        path: path.resolve(__dirname, 'dist'),
        // path: "/",
        filename: 'server.js',
        publicPath: '/assets/',
        libraryTarget: 'commonjs2'
    },
    plugins: [
        new StartServerPlugin({'name': 'server.js', nodeArgs: ['--inspect']}),
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.DefinePlugin({
            "process.env": {
                "BUILD_TARGET": JSON.stringify('server')
            }
        })
    ],
    module: {
        rules: [
            {
                test: /.js$/,
                loader: 'babel-loader',
                include: path.resolve(__dirname, 'src/'),
                exclude: /node_modules/,
                options: {
                    presets:
                        [['@babel/preset-env', { modules: 'false' }], '@babel/preset-react'],
                    plugins: [
                        ['@babel/plugin-proposal-object-rest-spread', { useBuiltIns: true }],
                        '@babel/plugin-proposal-class-properties'
                    ]
                }
            },
            {
                test: /\.scss$/,
                loader: 'ignore-loader'
            },
            {
                test: /\.css$/,
                loader: 'ignore-loader'
            },
            {
                test: /\.(jpg|png|svg|gif|pdf)$/,
                loader: 'file-loader',
                options: {
                    name: '[path][name].[ext]'
                }
            }
        ]
    }
};

索引.js:

import http from 'http'
import app from './server'

const server = http.createServer(app)
let currentApp = app;

const PORT = process.env.PORT || 8080;

server.listen(PORT);

if (module.hot) {
    module.hot.accept('./server', () => {
        server.removeListener('request', currentApp);
        server.on('request', app);
        currentApp = app;
    })
}

服务器.js:

import http from 'http';
import fs from "fs";
import express from "express";
import favicon from 'serve-favicon';
import renderer from "./renderer";
import renderApp from './welcome';


const app = express();

app.use(favicon('./public/favicon.ico'));
app.use(express.static("public"));


app.get("*", function(req, res) {
    fs.readFile("./src/server/html/index.html", "utf8", function(err, data) {
        const context = {};
        //const html = renderApp();
        console.log('test');
        const html = renderer(data, req.path, context);
        res.set('content-type', 'text/html');
        res.send(html);
        res.end();
    });
});

export default app;

运行:

rm -rf ./dist && webpack --config webpack.server.config.js --watch

关于javascript - 带有热重载的 Webpack 捆绑 Node Express = hell ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56246917/

相关文章:

javascript - Reactjs setState() 不会立即改变 this.state,我应该如何解决它?

javascript - react 笑话和 MSAL 得到 BrowserAuthError

javascript - 替代一百万个 IF 语句

javascript - 从 localStorage 存储/加载修改后的 HTML5 页面

javascript - Nodejs获取不到返回值?

mysql - 错误 : Cannot enqueue Query after fatal error in mysql node

javascript - Node http-proxy-middleware 不能将本地服务器作为目标

javascript - 正则表达式 JavaScript。使用当前正则表达式解析日志文件

javascript - 将 TEXTAREA 内容写入文本文件

reactjs - 如何使用 React Native 将 React-Native-Linear-Gradient 应用于整个应用程序背景