从零开始搭建React同构应用(四):搭建Koa Server & 完善SS
从零开始搭建React同构应用(四):搭建Koa Server & 完善SSR上一篇我们使用了CLI的方式测试了SSR,这篇文章来讲如何在前文的基础上搭建一个Koa Server,实现真正意义上的SSR。 demo在这 主要内容
Koa搭建新建server/index.js: 我们使用Koa v2.0的版本; npm i koa@next -S; 先搭建一个最简单的服务器 const Koa = require("koa"); const app = new Koa(); app.use(ctx => { ctx.body = 'Hello Koa'; }); app.listen(8088,_ => { console.log('server started') }); 添加一个npm script "scripts": { "start": "node --harmony server/index",//启动HTTP服务器 "watch": "webpack -d -w --progress --colors --bs","test-server": "anywhere -p 18341 -d ./build","dist": "cross-env NODE_ENV='production' webpack -p","test-ssr": "node --harmony test/cli.js" }, 执行 npm run start 这样一个最简单的Koa框架就搭建起来,下面就可以往里面填充东西了。 配置router在添加router之前,我们需要加载webpack编译生成的HTML模板,这里我们没有使用 在server/index.js增加: const cheerio = require("cheerio"); const fs = require("fs"); const path = require("path"); const Promise = require("bluebird"); const serve = require('koa-static-server'); const readFileAsync = Promise.promisify(fs.readFile); /** * 读取HTML模版,返回cheerio实例 * @param path * @return {Promise.<*>} */ async function loadHTMLTemplate(path) { try { let content = await readFileAsync(path); return cheerio.load(content); } catch (e) { console.error(e); return false; } } 我们使用koa-better-router中间件作为路由模块。我们添加一个router,在server/index.js增加: const router = require('koa-better-router')().loadMethods(); router.get('/',async(ctx,next) => { let $ = await loadHTMLTemplate(path.resolve(__dirname,'../build/index.html')); if (!$) { return ctx.body = null; } return ctx.body = $.html(); }); app.use(router.middleware()); 执行 npm run start
我们会发现CSS,JS等文件没有被加载进来,因为没有对应的路由,下面我们配置静态文件服务。 配置静态文件服务我们不可能为所有的资源都写router,因此我们需要配置一个静态文件服务。这里我使用了koa-static-server中间件。 我们以 const serve = require('koa-static-server'); const readFileAsync = Promise.promisify(fs.readFile); const RES_PATH = path.resolve(__dirname,'../build/'); //hfs app.use(serve({rootDir: RES_PATH})); 执行 npm run start
资源可以被正确载入了。 完善SSR逻辑我们先添加一个API接口,方便模拟Node端的接口调用,在server/index.js增加: //API接口 router.get('/api/todo_list',next) => { return ctx.body = ['11','222']; }); 我们还是以 将 const Koa = require("koa"); const app = new Koa(); const router = require('koa-better-router')().loadMethods(); const cheerio = require("cheerio"); const fs = require("fs"); const path = require("path"); const Promise = require("bluebird"); const serve = require('koa-static-server'); const readFileAsync = Promise.promisify(fs.readFile); const RES_PATH = path.resolve(__dirname,'../build/'); const fetch = require("isomorphic-fetch"); router.get('/','../build/index.html')); if (!$) { return ctx.body = null; } let IndexBundle = require("../build_server/index.bundle.js"); //fetch接口数据 let todoList = await(await fetch('http://localhost:8088/api/todo_list')).json(); let initialData = {todoList}; let instance = React.createElement(IndexBundle.default,initialData); let str = renderToString(instance); $('#wrap').html(str); //前后端数据要同步 let syncScript = `<script id="server-data">window._SERVER_DATA=${JSON.stringify(initialData)}</script>`; $('head').append(syncScript); return ctx.body = $.html(); }); 这里要注意前后端数据要同步,我把Node端获取的数据放在 if (process.browser) { //初始数据,用于和server render数据同步 let initialData = window._SERVER_DATA || {}; let store = createStore(reducers,initialData,window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()); let App = connect(_ => _)(Layout);//用connect包装一下,这里只用到mapStateToProps,而且不对state加以过滤 ReactDOM.render( <Provider store={store}> <App/> </Provider>,document.getElementById('wrap')); } 执行 npm run start 访问
可以看到 至此,一个简单的SSR框架已经搭建完成,剩下的工作就是结合工作需要,在里面添砖加瓦啦。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |