代码之家  ›  专栏  ›  技术社区  ›  Trace

webpack bundle node express with hot reloading=hell

  •  0
  • Trace  · 技术社区  · 5 年前

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

    以下是我努力实现的目标:

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

    我尝试过许多组合,不推荐使用的教程,不再维护的NPM包,以及下载了不起作用的示例。

    这是我当前的设置:

    web包.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]'
                    }
                }
            ]
        }
    };
    

    index.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——观看
    • node dist/server.js//webpack输出文件夹

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

    欢迎提供所有帮助,或者如果您碰巧有一个可工作的演示。
    我就是做不到。

    最后,我还将热重新加载(重新呈现)我的客户端包,但我想这将是很容易的一部分,因为我已经看到了许多关于这方面的资源。

    0 回复  |  直到 5 年前
        1
  •  0
  •   Christopher Vickers    5 年前

    node.js、babel和webpack一直是我这个月的祸根。应该包括几个组件。您应该有一个名为“package.json”的开始文件。

    内容应如下所示:

    {
      "name": "react-complete-guide",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "start": "webpack-dev-server",
        "build": "rimraf dist && webpack --config webpack.prod.config.js --progress --profile --color"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "autoprefixer": "^7.1.5",
        "babel-core": "^6.26.0",
        "babel-loader": "^7.1.2",
        "babel-plugin-syntax-dynamic-import": "^6.18.0",
        "babel-preset-env": "^1.6.0",
        "babel-preset-react": "^6.24.1",
        "babel-preset-stage-2": "^6.24.1",
        "css-loader": "^0.28.7",
        "file-loader": "^1.1.5",
        "html-webpack-plugin": "^2.30.1",
        "postcss-loader": "^2.0.7",
        "style-loader": "^0.19.0",
        "url-loader": "^0.6.2",
        "webpack": "^3.6.0",
        "webpack-dev-server": "^2.9.1"
      },
      "dependencies": {
        "react": "^16.0.0",
        "react-dom": "^16.0.0",
        "react-router-dom": "^4.2.2"
      }
    }
    

    如果键入“npm start”,则运行代码“start”:“webpack dev server”。这将加载代码预览。 要将内容打包到构建中,请键入“npm run build”并运行代码“build”:“rimraf dist&webpack--config webpack.prod.config.js--progress--profile--color”。该代码将运行“rimraf”,删除“dist”文件夹(如果存在),其余运行Webpack配置文件。

    您应该有两个Webpack文件。一个用于热重载,一个用于生产环境的包装。应调用这些文件:

    “webpack.config.js”和“webpack.prod.config.js”。

    “webpack.config.js”的内容如下:

    const path = require('path');
    const autoprefixer = require('autoprefixer');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
        devtool: 'cheap-module-eval-source-map',
        entry: './src/index.js',
        output: {
            path: path.resolve(__dirname, 'dist'),
            filename: 'bundle.js',
            chunkFilename: '[id].js',
            publicPath: ''
        },
        resolve: {
            extensions: ['.js', '.jsx']
        },
        module: {
            rules: [
                {
                    test: /\.js$/,
                    loader: 'babel-loader',
                    exclude: /node_modules/
                },
                {
                    test: /\.css$/,
                    exclude: /node_modules/,
                    use: [
                        { loader: 'style-loader' },
                        { 
                            loader: 'css-loader',
                            options: {
                                importLoaders: 1,
                                modules: true,
                                localIdentName: '[name]__[local]__[hash:base64:5]'
                            }
                         },
                         { 
                             loader: 'postcss-loader',
                             options: {
                                 ident: 'postcss',
                                 plugins: () => [
                                     autoprefixer({
                                         browsers: [
                                            "> 1%",
                                            "last 2 versions"
                                         ]
                                     })
                                 ]
                             }
                          }
                    ]
                },
                {
                    test: /\.(png|jpe?g|gif)$/,
                    loader: 'url-loader?limit=8000&name=images/[name].[ext]'
                }
            ]
        },
        plugins: [
            new HtmlWebpackPlugin({
                template: __dirname + '/src/index.html',
                filename: 'index.html',
                inject: 'body'
            })
        ]
    };
    

    “webpack.prod.config.js”的内容如下:

    const path = require('path');
    const autoprefixer = require('autoprefixer');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const webpack = require('webpack');
    
    module.exports = {
        devtool: 'cheap-module-source-map',
        entry: './src/index.js',
        output: {
            path: path.resolve(__dirname, 'dist/new'),
            filename: 'bundle.js',
            chunkFilename: '[id].js',
            publicPath: ''
        },
        resolve: {
            extensions: ['.js', '.jsx']
        },
        module: {
            rules: [
                {
                    test: /\.js$/,
                    loader: 'babel-loader',
                    exclude: /node_modules/
                },
                {
                    test: /\.css$/,
                    exclude: /node_modules/,
                    use: [
                        { loader: 'style-loader' },
                        { 
                            loader: 'css-loader',
                            options: {
                                importLoaders: 1,
                                modules: true,
                                localIdentName: '[name]__[local]__[hash:base64:5]'
                            }
                         },
                         { 
                             loader: 'postcss-loader',
                             options: {
                                 ident: 'postcss',
                                 plugins: () => [
                                     autoprefixer({
                                         browsers: [
                                            "> 1%",
                                            "last 2 versions"
                                         ]
                                     })
                                 ]
                             }
                          }
                    ]
                },
                {
                    test: /\.(png|jpe?g|gif)$/,
                    loader: 'url-loader?limit=8000&name=images/[name].[ext]'
                }
            ]
        },
        plugins: [
            new HtmlWebpackPlugin({
                template: __dirname + '/src/index.html',
                filename: 'index.html',
                inject: 'body'
            }),
            new webpack.optimize.UglifyJsPlugin()
        ]
    };
    

    你还需要一个文件来告诉巴贝尔怎么做。如果您使用babel,则该文件称为“.babelrc”。内容如下

    {
        "presets": [
            ["env", {
                "targets": {
                    "browsers": [
                        "> 1%",
                        "last 2 versions"
                    ]
                }
            }],
            "stage-2",
            "react"
        ],
        "plugins": [
            "syntax-dynamic-import"
        ]
    }
    

    这段代码中有很多内容。我强烈建议看一些关于这个的教程视频。

        2
  •  0
  •   Trace    5 年前

    可能需要夜间睡眠。
    我使用StartServerPlugin完成了这个工作(包括React服务器呈现的组件)。
    以下安装程序将热重新加载节点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]'
                    }
                }
            ]
        }
    };
    

    index.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