php - 使用 Webpack Express 和 React 进行服务器端渲染

标签 php node.js reactjs webpack server-side-rendering

我正在尝试学习 React,在多次尝试运行 React 服务器端渲染的配置后,我已将代码简化为最简单的示例,但我仍然无法理解为什么它不起作用。

案例

我的 Controller :

$router = $container->get(Router::class);
$router->get('/test/{name:.*}', function ($request) use ($container) {
    /** @var $request \GuzzleHttp\Psr7\ServerRequest **/
    $client = new Client(['base_uri' => 'http://localhost:3000']);
    $response = $client->post('/', [
        'query' => ['module' => 'App'],
    ]);
    $contents = $response->getBody()->getContents();

    return $contents;
});

我正在使用 GuzzleHttp 库

我的服务器配置:

/path/to/project/resources/server.js =>/path/to/project/server.js

import express from 'express'
import React from 'react'
import ReactDOMServer from 'react-dom/server'

let app = express()

app.use('/', (request, response) => {
  try {
    let App = require('../public/dist/js/' + request.query.module)
    response.send(
      ReactDOMServer.renderToString(<App/>)
    )
  } catch (error) {
    response.status(500).send(error.message)
  }
})

app.listen(3000)

我的组件

/path/to/project/resources/assets/js/App.jsx =>/path/to/project/public/dist/js/App.js

import React from 'react';

class App extends React.Component {
  render () {
    return <h1>Hello World!</h1>;
  }
}

module.exports = App;

我的 webpack 配置

const path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const UglifyJsPlugin = require ('uglifyjs-webpack-plugin');

function assets(path) {
  return './resources/assets/' + path;
}

const config = {
  entry: [
    assets('js/App.jsx'),
    assets('sass/app.scss')
  ],
  output: {
    path: path.resolve(__dirname, 'public/dist'),
    filename: 'js/App.js',
    publicPath: '/dist/'
  },
  resolve: {
    extensions: ['.js', '.jsx']
  },
  module: {
    rules: [
      { // es2015
        test: /\.(js|jsx)/,
        use: ['babel-loader'],
        exclude: [/node_modules/]
      },
      { // css / sass / scss loaders
        test: /\.(css|sass|scss)$/,
        use: ExtractTextPlugin.extract({
          use: ['css-loader', 'sass-loader'],
        })
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin({
      filename: 'css/[name].bundle.css',
      allChunks: true
    }),
    new UglifyJsPlugin()
  ]
};

const server = {
  entry: [
    './resources/server.js'
  ],
  output: {
    path: path.resolve(__dirname, '.'),
    filename: 'server.js',
    publicPath: '/dist/'
  },
  resolve: {
    extensions: ['.js', '.jsx']
  },
  module: {
    rules: [
      { // es2015
        test: /\.(js|jsx)/,
        use: ['babel-loader'],
        exclude: [/node_modules/]
      }
    ]
  },
  plugins: [
    //new UglifyJsPlugin()
  ],
  target: 'node'
};

module.exports = [config, server];

Babelrc 配置

{
  "presets": ["es2015", "react"]
}

结果

  1. 我在使用 Guzzle 时遇到错误

500 Internal Server Error response: element.type.toLowerCase is not a function

  • 使用 NodeJS 时遇到的错误
  • Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports. in Unknown

  • 捆绑文件后我会得到什么:
  • Webpack output

    我尝试了很多不同的方法,但我不明白为什么会抛出错误。

    <小时/>

    编辑:

    通过此配置,我能够使事情正常工作,问题似乎来自导入部分:

    import express from 'express'
    import * as React from 'react'
    import ReactDOMServer from 'react-dom/server'
    
    let app = express()
    
    class App extends React.Component {
      render () {
        return <h1>Hello World!</h1>;
      }
    }
    
    const component = <App />;
    
    app.use('/', (request, response) => {
      try {
        response.send(
          ReactDOMServer.renderToString(component)
        )
      } catch (error) {
        response.status(500).send(error.message)
      }
    })
    
    app.listen(3000)
    

    编辑2:

    这是我从 .npm 检索的日志

    0 info it worked if it ends with ok
    1 verbose cli [ '/usr/bin/node', '/usr/bin/npm', 'start' ]
    2 info using npm@5.6.0
    3 info using node@v8.9.4
    4 verbose run-script [ 'prestart', 'start', 'poststart' ]
    5 info lifecycle Framework@1.0.0~prestart: Framework@1.0.0
    6 info lifecycle Framework@1.0.0~start: Framework@1.0.0
    7 verbose lifecycle Framework@1.0.0~start: unsafe-perm in lifecycle true
    8 verbose lifecycle Framework@1.0.0~start: PATH: /usr/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/home/dev/www/node_modules/.bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
    9 verbose lifecycle Framework@1.0.0~start: CWD: /home/dev/www
    10 silly lifecycle Framework@1.0.0~start: Args: [ '-c', 'node server.js' ]
    11 silly lifecycle Framework@1.0.0~start: Returned: code: 1  signal: null
    12 info lifecycle Framework@1.0.0~start: Failed to exec start script
    13 verbose stack Error: Framework@1.0.0 start: `node server.js`
    13 verbose stack Exit status 1
    13 verbose stack     at EventEmitter.<anonymous> (/usr/lib/node_modules/npm/node_modules/npm-lifecycle/index.js:285:16)
    13 verbose stack     at emitTwo (events.js:126:13)
    13 verbose stack     at EventEmitter.emit (events.js:214:7)
    13 verbose stack     at ChildProcess.<anonymous> (/usr/lib/node_modules/npm/node_modules/npm-lifecycle/lib/spawn.js:55:14)
    13 verbose stack     at emitTwo (events.js:126:13)
    13 verbose stack     at ChildProcess.emit (events.js:214:7)
    13 verbose stack     at maybeClose (internal/child_process.js:925:16)
    13 verbose stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:209:5)
    14 verbose pkgid Framework@1.0.0
    15 verbose cwd /home/dev/www
    16 verbose Linux 4.9.0-4-amd64
    17 verbose argv "/usr/bin/node" "/usr/bin/npm" "start"
    18 verbose node v8.9.4
    19 verbose npm  v5.6.0
    20 error code ELIFECYCLE
    21 error errno 1
    22 error Framework@1.0.0 start: `node server.js`
    22 error Exit status 1
    23 error Failed at the Framework@1.0.0 start script.
    23 error This is probably not a problem with npm. There is likely additional logging output above.
    24 verbose exit [ 1, true ]
    

    最佳答案

    在您的组件中尝试。

    import * as React from 'react';
    
    class App extends React.Component {
      render () {
        return <h1>Hello World!</h1>;
      }
    }
    
    module.exports = App;
    

    可能只是从 react 包中选择默认导出。

    关于php - 使用 Webpack Express 和 React 进行服务器端渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48755979/

    相关文章:

    php - 设置每节动态数据集的 mysql 查询

    node.js - 我的 typescript 编译器有什么问题? `tsc --version` 什么都不返回

    javascript - 如何使用 JavaScript 在浏览器中加密数据并使用 Node.js 在服务器端解密

    javascript - 修改数据时setState不会触发重新渲染

    javascript - karma 单元测试 : Module name "react" has not been loaded yet for context: _. 使用 require([])

    javascript - 在 React 测试库中发现多个元素错误

    PHP + MySQL 使用 while 循环导致结果缓慢

    PHP:如何创建链接到我的搜索脚本的搜索表单

    php - php 脚本中每 24 小时执行一次不同的 sql 查询

    node.js - Express.js 路由错误 : Can't set headers after they are sent