Skip to content

Commit 0b9e1d6

Browse files
committed
提交
1 parent 431155e commit 0b9e1d6

28 files changed

+7643
-539
lines changed

README.md

Lines changed: 118 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -414,9 +414,11 @@ app.listen(9001, () => {
414414
console.log('监听9001端口');
415415
})
416416
```
417-
## 8、异常处理和请求转发
418-
### 异常处理
419-
header页面接口报错,其它页面也能显示正常。解决方案:在axios里面需要捕获错误
417+
### 8、异常处理和请求转发
418+
#### 异常处理
419+
header页面接口报错,其它页面也能显示正常。解决方案:
420+
421+
(1)在axios里面需要捕获错误
420422
```js
421423
export const getUserInfo = () => {
422424
return (dispatch) => {
@@ -430,20 +432,124 @@ export const getUserInfo = () => {
430432
}
431433
}
432434
```
433-
### 请求转发
435+
(2)服务端给每个loadData包装成新的Promise
436+
```js
437+
if (match) {
438+
const { loadData } = route.component;
439+
if (loadData) {
440+
// 规避报错
441+
const promise = new Promise((resolve, reject) => {
442+
loadData(store).then(resolve).catch(resolve)
443+
});
444+
promises.push(promise);
445+
}
446+
}
447+
```
448+
#### 请求转发
434449
每次让服务端请求数据(转发),不需要客户端去请求数据,避免跨域。解决方案:使用```http-proxy-middleware```
435450
```js
436451
// 使用http-proxy-middleware进行请求转发,防止出现跨域的问题
437452
const proxy = require('http-proxy-middleware')
438453
app.use('/api/*', proxy({ target: 'http://localhost:8082', changeOrigin: true }));
454+
```
455+
### 9、将axios和redux结合
456+
(1)首先在store.js里面,创建服务端和客户端的实例,然后传入thunk.withExtraArgument的参数里面
457+
```js
458+
// 引入axios
459+
import axios from 'axios'
460+
461+
const serverAxios = axios.create({
462+
baseURL: 'http://localhost:8081'
463+
})
439464

440-
// const match = matchPath(req.url, route);
441-
// if (match && route.component.loadData) {
442-
// promises.push(route.component.loadData(store))
443-
// }
465+
const clientAxios = axios.create({
466+
baseURL: '/'
467+
})
444468

445-
// 取消客户端拉取数据的行为,全部由服务端拉取
446-
if (route.component.loadData) {
447-
promises.push(route.component.loadData(store))
469+
// 获取客户端的store
470+
export const getClientStore = () => {
471+
// 通过window对象来获取服务端获取的数据
472+
const defaultStore = window.__store ? window.__store : {};
473+
console.log('客户端defaultStore', defaultStore);
474+
return createStore(reducers, defaultStore, applyMiddleware(thunk.withExtraArgument(clientAxios)))
475+
}
476+
// 获取服务端的store
477+
export const getServerStore = () => {
478+
return createStore(reducers, applyMiddleware(thunk.withExtraArgument(serverAxios)))
448479
}
449-
```
480+
```
481+
(2)index.js里面使用$axios即可
482+
```js
483+
export const getIndexList = () => {
484+
return (dispatch, getState, $axios) => {
485+
return $axios.get('/api/course/list').then(res => {
486+
const { list } = res.data
487+
dispatch({ type: GET_LIST, list })
488+
}).catch(e => {
489+
// 在这里需要捕获错误,才不会出现所有页面都挂了的情况
490+
console.log(e)
491+
})
492+
}
493+
}
494+
```
495+
### 10、css处理
496+
用style-loader和css-loader,服务端需要用isomorphic-style-loader
497+
### 11、错误页面状态码支持
498+
### 12、放弃SEO的降级渲染的实现
499+
(1)server/index.js,服务端判断是否需要进行csr渲染,需要的话,就读取html模板文件
500+
```js
501+
function csrRender(res) {
502+
const filePath = path.resolve(process.cwd(), 'public/index.csr.html');
503+
return res.send(fs.readFileSync(filePath,'utf-8'));
504+
}
505+
506+
// 使用*监听所有路由
507+
app.get('*', (req, res) => {
508+
if (req.query.mode == 'csr') {
509+
console.log('csr参数开启')
510+
return csrRender(res);
511+
}
512+
//省略.....
513+
```
514+
(2)client/index.js,客户端判断是否有window.__store变量,有的话用hydrate,没有的话用render
515+
```js
516+
if (window.__store) {
517+
ReactDom.hydrate(page, document.getElementById("root"))
518+
} else {
519+
ReactDom.render(page, document.getElementById("root"))
520+
}
521+
```
522+
(3)webpack.client.js,用html-webpack-plugin将bundle注入到HTML模板里面
523+
```js
524+
plugins:[
525+
new HtmlWebpackPlugin({
526+
filename:'index.csr.html',
527+
template:'src/index.csr.html',
528+
inject:true
529+
})
530+
]
531+
```
532+
### 13、css细节优化
533+
组件内部样式渲染,开始css module
534+
```js
535+
{
536+
test: /\.css$/,
537+
use: ['style-loader', {
538+
loader: 'css-loader',
539+
options: {
540+
modules: true // 开启css module的支持
541+
}
542+
}]
543+
}
544+
```
545+
组件内使用模块化引入css的方式
546+
```js
547+
import React from 'react'
548+
import styles from './about.css'
549+
function About(props) {
550+
return <div className={styles.title}>关于页面</div>
551+
}
552+
553+
export default About
554+
```
555+
### 14、puppeteer实现ssr

build/bundle.js

Lines changed: 151 additions & 16 deletions
Large diffs are not rendered by default.

client/index.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,9 @@ const page =
1515
{routes.map(route => <Route {...route}></Route>)}
1616
</BrowserRouter>
1717
</Provider>
18-
ReactDom.hydrate(page, document.getElementById("root"))
18+
19+
if (window.__store) {
20+
ReactDom.hydrate(page, document.getElementById("root"))
21+
} else {
22+
ReactDom.render(page, document.getElementById("root"))
23+
}

mock.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ app.get('/api/course/list', (req, res) => {
1616
]
1717
})
1818
})
19-
app.get('/api/user/info1', (req, res) => {
19+
app.get('/api/user/info', (req, res) => {
2020
// res.setHeader('Access-Control-Allow-Origin','*')
2121
// res.setHeader('Access-Control-Allow-Methods','GET,POST,DELETE,PUT')
2222
// res.setHeader('Content-Type','application/json')

0 commit comments

Comments
 (0)