Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

专题18: webpack 搭建 ssr #60

Open
luoxue-victor opened this issue Nov 28, 2019 · 0 comments
Open

专题18: webpack 搭建 ssr #60

luoxue-victor opened this issue Nov 28, 2019 · 0 comments
Labels
webpack 专题 一些系列专题

Comments

@luoxue-victor
Copy link
Owner

luoxue-victor commented Nov 28, 2019

webpack 构建 ssr

ssr 就是服务端渲染,做 ssr 的好处就是为了处理 spa 的不足,比如 seo 优化,服务端缓存等问题。

今天主要用 react 的 ssr 来做一个简单的实例,让大家更清晰的入门

本章概要

创建 box build:ssr

老规矩,先来一个 box build:ssr 命令让程序可以执行

执行 box build:ssr 会调用 build/ssr 执行编译

program
  .usage('<command> [options]')
  .version(packageConfig.version)
  .command('build:ssr [app-page]')
  .description(`服务端渲染`)
  .action(async (name, cmd) => {
    const options = cleanArgs(cmd);
    const args = Object.assign(options, { name }, boxConf);
    if (lock) return;
    lock = true;
    require('../build/ssr')(args);
  });

编译 ssr

与其他的编译没有什么区别,值得住的是

  • target 指定为 umd 模式
  • globalObject 为 this
  • 入口改为 ssr.jsx
.libraryTarget('umd')
.globalObject('this')

build/ssr.js

module.exports = function(options) {
  const path = require('path');
  const Config = require('webpack-chain');
  const config = new Config();
  const webpack = require('webpack');
  const rimraf = require('rimraf');
  const ora = require('ora');
  const chalk = require('chalk');
  const PATHS = {
    build: path.join(process.cwd(), 'static'),
    ssrDemo: path.join(process.cwd(), 'src', 'ssr.jsx')
  };

  require('../config/babelLoader')({ config, tsx: true })();
  require('../config/HtmlWebpackPlugin')({
    config,
    options: {
      publicPath: '/',
      filename: 'client.ssr.html'
    }
  })();

  config
    .entry('ssr')
    .add(PATHS.ssrDemo)
    .end()
    .set('mode', 'development') //  production
    .output.path(PATHS.build)
    .filename('[name].js')
    .libraryTarget('umd')
    .globalObject('this')
    .library('[name]')
    .end();

  rimraf.sync(path.join(process.cwd(), PATHS.build));
  const spinner = ora('开始构建项目...');
  spinner.start();

  webpack(config.toConfig(), function(err, stats) {
    spinner.stop();
    if (err) throw err;
    process.stdout.write(
      stats.toString({
        colors: true,
        modules: false,
        children: false,
        chunks: false,
        chunkModules: false
      }) + '\n\n'
    );

    if (stats.hasErrors()) {
      console.log(chalk.red('构建失败\n'));
      process.exit(1);
    }
    console.log(chalk.cyan('build完成\n'));
  });
};

编译 jsx 语法

因为我们是用 react 写的,避免不了会用到 jsx 语法,所以我们需要在 babel-loader 中使用 @babel/preset-react

npm i @babel/preset-react -D

config/babelLoader.js

if (tsx) {
  babelConf.presets.push('@babel/preset-react');
}

入口区分服务端/客户端

区分服务端跟客户端分别渲染

const React = require("react");
const ReactDOM = require("react-dom");

const SSR = <div onClick={() => alert("hello")}>Hello world</div>;

if (typeof document === "undefined") {
  console.log('在服务端渲染')
  module.exports = SSR;
} else {
  console.log('在客户端渲染')
  const renderMethod = !module.hot ? ReactDOM.render : ReactDOM.hydrate;
  renderMethod(SSR, document.getElementById("app"));
}

服务端渲染服务端渲染

module.exports = function (options) {
  const express = require("express");
  const { renderToString } = require("react-dom/server");
  const chalk = require('chalk')
  
  const SSR = require("../static/ssr");
  const port = process.env.PORT || 8080;

  server(port);
  
  function server(port) {
    const app = express();
    app.use(express.static("static"));
    app.get("/", (req, res) =>
      res.status(200).send(renderMarkup(renderToString(SSR)))
    );

    const empty = '    '
    const common = `App running at:
      - Local: http://127.0.0.1:${port}\n`
      console.log(chalk.cyan('\n' + empty + common))
    
    app.listen(port, () => process.send && process.send("online"));
  }
  
  function renderMarkup(html) {
    return `<!DOCTYPE html>
  <html>
    <head>
      <title>Webpack SSR Demo</title>
      <meta charset="utf-8" />
    </head>
    <body>
      <div id="app">${html}</div>
      <script src="./ssr.js"></script>
    </body>
  </html>`;
  }
}

小结

至此 ssr 已经结束了,其实所有看起来很高大上的技术都是从一点一滴积累起来的,只要我们明白原理,你也能做出更优秀的框架


@luoxue-victor luoxue-victor added webpack 专题 一些系列专题 labels Nov 29, 2019
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
webpack 专题 一些系列专题
Projects
None yet
Development

No branches or pull requests

1 participant