Universal-webpack服務端渲染

nelson2016發表於2019-02-16

Universal-webpack

幫助搭建用於同構,即同時可以在客戶端和服務端使用的Webpack。

Demo

我的Demo:universal-webpack + koa + react + webpack。
官方Demo

Webpack 2

目前僅支援Webpack2.

npm install webpack --save
npm install extract-text-webpack-plugin --save   

使用

以往我們會建立一個標準的 webpack.config.js 。
此時,我們需要建立另外兩個配置檔案:webpack.config.client.babel.js 和 webpack.config.client.babel.js。如下:

webpack.config.client.babel.js

import { client } from `universal-webpack/config`
import settings from `./universal-webpack-settings`
import configuration from `./webpack.config`

export default client(configuration, settings)

代替webpack.config.js來完成客戶端的打包。

webpack.config.server.babel.js

import { server } from `universal-webpack/config`
import settings from `./universal-webpack-settings`
import configuration from `./webpack.config`

export default server(configuration, settings)

universal-webpack-settings.json

{
    "server":
    {
        "input": "./source/server.js",
        "output": "./build/server/server.js"
    }
}

output所對應的檔案由input對應的檔案使用Webpack根據webpack.config.server.babel.js中的配置生成。

server.js

伺服器啟動,官方Demo如下:

// express.js
import path from `path`
import http from `http`
import express from `express`
import http_proxy from `http-proxy`

// react-router
import routes from `../client/routes.js`

// Redux
import store from `../client/store.js`

// The server code must export a function
// (`parameters` may contain some miscellaneous library-specific stuff)
export default function(parameters)
{
    // Create HTTP server
    const app = new express()
    const server = new http.Server(app)

    // Serve static files
    app.use(express.static(path.join(__dirname, `..`, `build/assets`)))

    // Proxy API calls to API server
    const proxy = http_proxy.createProxyServer({ target: `http://localhost:xxxx` })
    app.use(`/api`, (req, res) => proxy.web(req, res))

    // React application rendering
    app.use((req, res) =>
    {
        // Match current URL to the corresponding React page
        // (can use `react-router`, `redux-router`, `react-router-redux`, etc)
        react_router_match_url(routes, req.originalUrl).then((error, result) =>
        {
            if (error)
            {
                res.status(500)
                return res.send(`Server error`)
            }

            // Render React page

            const page = redux.provide(result, store)

            res.status(200)
            res.send(`<!doctype html>` + `
` + ReactDOM.renderToString(<Html>{page}</Html>))
        })
    })

    // Start the HTTP server
    server.listen()
}

但這個檔案不是真正的入口檔案,需要另一個檔案,我們需要另一個檔案來啟動服務。

start-server.js

var startServer = require(`universal-webpack/server`)
var settings = require(`../universal-webpack-settings`)
// `configuration.context` and `configuration.output.path` are used
var configuration = require(`../webpack.config`)

startServer(configuration, settings)

呼叫這個入口檔案,實質上是呼叫了通過Webpack打包之後的server.js。

開發環境的啟動命令大致如下:

webpack-dev-server --hot --inline --config "./webpack.config.client.babel.js" --port XXXX --colors --display-error-details
//啟動一個webpack-dev-server,真正的Development Server會從這裡請求一些靜態檔案(比如:boundle.js)。
//Universal-webpack不會再服務端釋放任何資源,所有資源都在客戶端)。
webpack --watch --config "./webpack.config.server.babel.js" --colors --display-error-details
//打包服務端程式碼
nodemon "./source/start-server" --watch "./build/server"
啟動伺服器

生產環境的啟動命令大致如下:

webpack --config "./webpack.config.client.babel.js" --colors --display-error-details
webpack --config "./webpack.config.server.babel.js" --colors --display-error-details
node "./source/start-server"

Chunks

返回webpack最終所輸出的檔案資訊:

build/webpack-chunks.json

{
    javascript:
    {
        main: `/assets/main.785f110e7775ec8322cf.js`
    },

    styles:
    {
        main: `/assets/main.785f110e7775ec8322cf.css`
    }
}

相關文章