Skip to content

Commit

Permalink
chore: koa-ssr-demo,内置dva数据流和国际化解决方案 (#5017)
Browse files Browse the repository at this point in the history
* 增加基于koa后端的ssrdemo,内置dva数据流和国际化解决方案

* chore:ssr文档增加示例说明,修改ssr-koa代码,修改ssr-egg代码(增加国际化部分代码)

* Update docs/docs/ssr.md

* Update examples/ssr-koa/package.json

* Update examples/ssr-koa/package.json

* Update examples/ssr-koa/server.js

* Update examples/ssr-with-eggjs/app/web/pages/index.js

Co-authored-by: 信鑫-King <chaolinjin@gmail.com>
  • Loading branch information
williamnie and ycjcl868 committed Jul 13, 2020
1 parent 441bf13 commit 8894af2
Show file tree
Hide file tree
Showing 37 changed files with 738 additions and 60 deletions.
4 changes: 4 additions & 0 deletions docs/docs/ssr.md
Expand Up @@ -343,6 +343,10 @@ app.use(async (req, res) => {
}
```

## 示例

目前做了两个示例分别是基于[koa](https://github.com/umijs/umi/tree/master/examples/ssr-koa)[egg](https://github.com/umijs/umi/tree/master/examples/ssr-with-eggjs)的,示例内置dva数据流和国际化解决方案,代码部分有注释,可参照进行个性化的修改。

## polyfill

Umi 3 默认移除了 DOM/BOM 浏览器 API 在 Node.js 的 polyfill,如果应用确实需要 polyfill 一些浏览器对象,可以使用 `beforeRenderServer` 运行时事件 API 进行扩展
Expand Down
2 changes: 2 additions & 0 deletions docs/docs/ssr.zh-CN.md
Expand Up @@ -337,6 +337,8 @@ app.use(async (req, res) => {
error?: Error;
}
```
## 示例
目前做了两个示例分别是基于[koa](https://github.com/umijs/umi/tree/master/examples/ssr-koa)[egg](https://github.com/umijs/umi/tree/master/examples/ssr-with-eggjs)的,示例内置dva数据流和国际化解决方案,代码部分有注释,可参照进行个性化的修改。

## polyfill

Expand Down
16 changes: 16 additions & 0 deletions examples/ssr-koa/.editorconfig
@@ -0,0 +1,16 @@
# http://editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false

[Makefile]
indent_style = tab
22 changes: 22 additions & 0 deletions examples/ssr-koa/.gitignore
@@ -0,0 +1,22 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/npm-debug.log*
/yarn-error.log
/yarn.lock
/package-lock.json

# production
/dist

# misc
.DS_Store

# umi
/src/.umi
/src/.umi-production
/src/.umi-test
/.env.local
.history
mock
8 changes: 8 additions & 0 deletions examples/ssr-koa/.prettierignore
@@ -0,0 +1,8 @@
**/*.md
**/*.svg
**/*.ejs
**/*.html
package.json
.umi
.umi-production
.umi-test
11 changes: 11 additions & 0 deletions examples/ssr-koa/.prettierrc
@@ -0,0 +1,11 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 80,
"overrides": [
{
"files": ".prettierrc",
"options": { "parser": "json" }
}
]
}
32 changes: 32 additions & 0 deletions examples/ssr-koa/.umirc.ts
@@ -0,0 +1,32 @@
import { defineConfig } from 'umi';

const outputPath = 'dist/'

const env = process.env.NODE_ENV;
const path = env === 'development' ? 'http://127.0.0.1:8000/' : outputPath

export default defineConfig({
ssr: {
devServerRender: false,
},
locale: {
default: 'zh-CN',
antd: false,
title: false,
baseNavigator: true,
baseSeparator: '-',
},
dva: {
immer: true,
// hmr: false,
},
nodeModulesTransform: {
type: 'none',
},
outputPath: outputPath,
publicPath: path,
routes: [
{ path: '/', component: '@/pages/index' },
],

});
31 changes: 31 additions & 0 deletions examples/ssr-koa/README.md
@@ -0,0 +1,31 @@
# umi project d

## Getting Started

Install dependencies,

```bash
$ yarn
```

Start the dev server,

```bash
$ yarn dev
```

Start the prod server

```bash
$ yarn build
$ yarn start
```

# 国际化
目前是按照cookie > 浏览器默认语言 > 默认语言顺序选择
由于服务端获取不到localStorage,所以要通过cookie将
所需信息带到服务端

# 部署
部署时可以用pm2进行部署(注意要采用多进程方式部署)
静态文件最好是放cdn,如果放到服务器上,最好是用nginx直接配置静态目录
Empty file added examples/ssr-koa/mock/.gitkeep
Empty file.
47 changes: 47 additions & 0 deletions examples/ssr-koa/package.json
@@ -0,0 +1,47 @@
{
"private": true,
"scripts": {
"build": "cross-env umi build",
"start": "node server.js",
"dev": "cross-env UMI_UI=none NODE_ENV=development concurrently \"umi dev\" \"nodemon server.js\"",
"postinstall": "umi generate tmp",
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
"test": "umi-test",
"test:coverage": "umi-test --coverage"
},
"bin": {
"umi": "./node_modules/.bin/umi"
},
"lint-staged": {
"*.{js,jsx,less,md,json}": [
"prettier --write"
],
"*.ts?(x)": [
"prettier --parser=typescript --write"
]
},
"dependencies": {
"@ant-design/pro-layout": "^5.0.12",
"@umijs/preset-react": "^1.5.17",
"@umijs/test": "^3.2.9",
"lint-staged": "^10.0.7",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"umi": "^3.2.9"
},
"devDependencies": {
"prettier": "^1.19.1",
"yorkie": "^2.0.0",
"concurrently": "^5.2.0",
"cross-env": "^7.0.2",
"got": "^11.5.0",
"http-proxy-middleware": "^1.0.5",
"koa": "^2.13.0",
"koa-compress": "^5.0.1",
"koa-mount": "^4.0.0",
"koa-static": "^5.0.0",
"koa-websocket": "^6.0.0",
"koa2-proxy-middleware": "^0.0.4",
"nodemon": "^2.0.4"
}
}
75 changes: 75 additions & 0 deletions examples/ssr-koa/server.js
@@ -0,0 +1,75 @@
const Koa = require('koa');
const compress = require('koa-compress');
const mount = require('koa-mount');
const { join, extname } = require('path');
const { parseCookie, parseNavLang } = require('./serverHelper')

const isDev = process.env.NODE_ENV === 'development';

const root = join(__dirname, 'dist');

const app = new Koa();
app.use(
compress({
threshold: 2048,
flush: require('zlib').Z_SYNC_FLUSH,
}),
);


app.use(async (ctx, next) => {
/**
* 扩展global对象
*
* 这里是在服务端处理好cookie,
* 会把所有cookie处理成{}形式
* 赋值到global上面,方便客户端使用
*
* 同时获取浏览器的默认语言,处理好
*/
global._cookies = parseCookie(ctx);
global._navigatorLang = parseNavLang(ctx)

let render
/**
* 这里fix了由于没有使用内部server而造成的缓存问题,
* 原因是require会带有缓存,在修改代码以后会不更新
* 这里判断的环境变量,如果是dev环境,自动删除require
* 缓存,重新获取
*/

const ext = extname(ctx.request.path);
// 符合要求的路由才进行服务端渲染,否则走静态文件逻辑
if (!ext) {
if (!isDev) {
render = require('./dist/umi.server')
} else {
delete require.cache[require.resolve('./dist/umi.server')];
render = require('./dist/umi.server')
}
// 这里默认是流失渲染
ctx.type = 'text/html';
ctx.status = 200;
const { html, error } = await render({
path: ctx.request.url,
mode: 'stream'
});
if (error) {
console.log('----------------服务端报错-------------------', error);
ctx.throw(500, error)
}
ctx.body = html;
} else {
await next();
}
});

/**
* 注意这里的静态目录设置,需要和umi打包出来的目录是同一个
* 这里最好是用nginx配置静态目录,如果是用cdn方式部署,这里可以忽略
*
*/
app.use(mount('/dist', require('koa-static')(root)));

module.exports = app.callback();

41 changes: 41 additions & 0 deletions examples/ssr-koa/serverHelper.js
@@ -0,0 +1,41 @@
const parseCookie = (ctx) => {
let cookies = ctx.get('cookie')
if (!cookies) {
return []
}
cookies = cookies.split(';')
const res = {}
for (const item of cookies) {
const kv = item.split('=')
if (kv && kv.length > 0) {
res[kv[0].trim()] = decodeURIComponent(kv[1]);
}
}
return res;
}

const parseNavLang = (ctx) => {
// 服务端无法获取navigator.language,所以只能通过Accept-Language来判断浏览器语言。
let navigatorLang;
const clientLang = ctx.get('Accept-Language');
if (clientLang.startsWith('zh')) {
navigatorLang = 'zh-CN';
} else if (clientLang.startsWith('en')) {
navigatorLang = 'en-US';
}
return navigatorLang
}










module.exports = {
parseCookie,
parseNavLang
}
47 changes: 47 additions & 0 deletions examples/ssr-koa/src/app.js
@@ -0,0 +1,47 @@

import { isBrowser, setLocale } from 'umi';
import { setCookie, getCookie } from './utils/cookie'

/**
* 在运行时扩展语言plugin,语言顺序,cookie > 浏览器默认语言 > 默认语言
* 切换语言时会同时设置localStorage 和cookie,key保持一致。
* 封装好了cookie方法,同时试用与服务端和客户端,客户端取cookie的方法
* 见serverHelper.js,只是将koa的方法进行扩展,koa试用请自行学习
* 客户端获取cookie的方法见utils/cookie
*
*/
export const locale = {
getLocale() {
let lang;
if (isBrowser()) {
const navigatorLang = window.navigator.language.includes('zh') ? 'zh-CN' : 'en-US'
/**
* 最后默认是中文,这里可以根据自身项目需要修改
* 或者可以将locale单独定义一个config,即给umirc
* 也可以导入到这里,赋值给默认语言,这样修改一个地方
* 就可以完成默认语言的修改
*
*/
lang = getCookie('umi_locale') || navigatorLang || 'zh-CN'
} else {
lang = getCookie('umi_locale') || global._navigatorLang || 'zh-CN'
}
return lang;
},
setLocale({ lang, realReload = false, updater }) {
if (!isBrowser()) {
console.error('---------设置语音失败非浏览器环境--------');
return
}
if (!lang) {
console.error('---------必须输入要切换的语言,否则无法切换--------');
return
}
localStorage.setItem('umi_locale', lang)
setCookie('umi_locale', lang, null, 10000)
if (realReload) {
window.location.reload()
}
updater();
}
}
4 changes: 4 additions & 0 deletions examples/ssr-koa/src/locales/en-US.js
@@ -0,0 +1,4 @@

export default {
'umi': 'hello umi',
};
5 changes: 5 additions & 0 deletions examples/ssr-koa/src/locales/zh-CN.js
@@ -0,0 +1,5 @@


export default {
'umi': '你好 乌米',
};
17 changes: 17 additions & 0 deletions examples/ssr-koa/src/models/test.js
@@ -0,0 +1,17 @@

export default {
namespace: 'test',
state: {
title: null,
},

effects: {
},

reducers: {
test(state, { payload }) {
state.title = 'hello umi';
},
},

};

0 comments on commit 8894af2

Please sign in to comment.