webpack进阶篇(二十七):webpack实现SSR打包(下)

说明

玩转webpack学习笔记

webpack ssr 打包存在的问题

1、浏览器的全局变量 (Node.js 中没有 document, window)

  • 组件适配:将不兼容的组件根据打包环境进⾏适配
  • 请求适配:将 fetch 或者 ajax 发送请求的写法改成 isomorphic-fetch 或者 axios

2、样式问题 (Node.js ⽆法解析 css)

  • ⽅案⼀:服务端打包通过 ignore-loader 忽略掉 CSS 的解析
  • ⽅案⼆:将 style-loader 替换成 isomorphic-style-loader

如何解决样式不显示的问题?

使⽤打包出来的浏览器端 html 为模板

设置占位符,动态插⼊组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="root"><!--HTML_PLACEHOLDER--></div>
</body>
</html>

首屏数据如何处理?

服务端获取数据

替换占位符

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="root"><!--HTML_PLACEHOLDER--></div>

    <!--INITIAL_DATA_PLACEHOLDER-->
</body>
</html>

实现

由于上一节我已经将 如何解决样式不显示的问题? 这个问题已经处理,这一节就简单实现 首屏数据如何处理?

1、在上一节的基础上添加<!--INITIAL_DATA_PLACEHOLDER-->占位符

<!DOCTYPE html>
<html lang="en">
<head>
    <%= require('raw-loader!./meta.html') %>
    <title>Document</title>
    <script><%= require('raw-loader!babel-loader!../../node_modules/lib-flexible/flexible.js') %></script>
</head>
<body>
    <div id="root"><!--HTML_PLACEHOLDER--></div>
    <script type="text/javascript" src="https://11.url.cn/now/lib/16.2.0/react.min.js"></script>
    <script type="text/javascript" src="https://11.url.cn/now/lib/16.2.0/react-dom.min.js"></script>
    <!--INITIAL_DATA_PLACEHOLDER-->
</body>
</html>

2、在server文件夹里添加 data.json 文件,然后在server文件夹的 index.js 里引入

data.json

{
	"error": [],
	"extra": [],
	"data": {
		"list": [
			[{
				"sub_count": 5556,
				"column_type": 1,
				"id": 192,
				"column_price_market": 9900,
				"column_bgcolor": "#F6F7FB",
				"column_title": "SQL必知必会",
				"column_cover_small": "https:\/\/static001.geekbang.org\/resource\/image\/1c\/38\/1c5a5b154b543af952312eef33217438.jpg",
				"column_cover": "https:\/\/static001.geekbang.org\/resource\/image\/c7\/0d\/c7ee0aabbcb6d2da09a1b4a56c1a730d.jpg",
				"had_sub": false,
				"price_type": 2,
				"column_unit": "45讲",
				"is_experience": false,
				"column_ctime": 1559640855,
				"update_frequency": "每周一 \/ 三 \/ 五更新",
				"is_onboard": true,
				"author_intro": "清华大学计算机博士",
				"column_sku": 100029501,
				"column_cover_wxlite": "https:\/\/static001.geekbang.org\/resource\/image\/cd\/f0\/cd26b744d388dbd4387dcfaa66dd8bf0.jpg",
				"column_price": 6800,
				"column_price_sale": 6800,
				"author_name": "陈旸",
				"column_subtitle": "从入门到数据实战"
			}]
		],
		"nav": [{
			"id": 1,
			"name": "专栏",
			"color": "#5ba6ff",
			"icon": "https:\/\/static001.geekbang.org\/resource\/image\/dd\/9e\/dd8cbc79f017d1b01f643c7ea929d79e.png"
		}, {
			"id": 3,
			"name": "视频课程",
			"color": "#79c109",
			"icon": "https:\/\/static001.geekbang.org\/resource\/image\/4a\/c3\/4aebe8fb752fa21a0fd989a45d9847c3.png"
		}, {
			"id": 2,
			"name": "微课",
			"color": "#5ba6ff",
			"icon": "https:\/\/static001.geekbang.org\/resource\/image\/9c\/f1\/9c223ccae33c5245a3009857582f1df1.png"
		}]
	},
	"code": 0
}

index.js

if (typeof window === 'undefined') {
  global.window = {};
}

const fs = require('fs');
const path = require('path');
const express = require('express');
const { renderToString } = require('react-dom/server');

const SSR = require('../dist/search-server');
const template = fs.readFileSync(path.join(__dirname, '../dist/search.html'), 'utf-8');
const data = require('./data.json'); // 引入数据

const renderMarkup = (str) => {
  const dataStr = JSON.stringify(data);
  return template.replace('<!--HTML_PLACEHOLDER-->', str)
    .replace('<!--INITIAL_DATA_PLACEHOLDER-->', `<script>window.__initial_data=${dataStr}</script>`);
};

const server = (port) => {
  const app = express();

  app.use(express.static('dist'));

  app.get('/search', (req, res) => {
    console.log('SSR-----------》', SSR);
    console.log('renderToString(SSR)------>', renderToString(SSR));
    const html = renderMarkup(renderToString(SSR));
    res.status(200).send(html);
  });

  app.listen(port, () => {
    console.log(`Server is running on port:${port}`);
  });
};

server(process.env.PORT || 3000);

3、添加好了之后我们重启node服务就可以看到下面的效果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凯小默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值