说明
玩转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服务就可以看到下面的效果