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