koot
Version:
Koot.js - React isomorphic framework created by CMUX
276 lines (210 loc) • 8.29 kB
JavaScript
const path = require('path')
const fs = require('fs-extra')
import cookie from 'cookie'
//
import koaStatic from 'koa-static'
import convert from 'koa-convert'
//
import i18nRegister from '../../i18n/register/isomorphic.server'
import i18nOnServerRender from '../../i18n/onServerRender'
import { changeLocaleQueryKey } from '../../defaults/defines'
//
import { CHANGE_LANGUAGE, TELL_CLIENT_URL/*, SERVER_REDUCER_NAME, serverReducer*/ } from './redux'
import kootClient from '../client/run'
import ReactIsomorphic from '../ReactIsomorphic'
const getDistPath = require('../../utils/get-dist-path')
const cache = {}
const getLocalesDefault = () => {
if (__DEV__) {
const locales = JSON.parse(process.env.KOOT_I18N_LOCALES)
return locales.map(l => ([
l[0],
fs.readJsonSync(l[2], 'utf-8'),
l[2]
]))
}
return JSON.parse(process.env.KOOT_I18N_LOCALES)
}
const doI18nRegister = (
locales = getLocalesDefault(),
i18nType = JSON.parse(process.env.KOOT_I18N_TYPE) || false,
) => {
const availableLocales = []
const localesObj = {}
locales.forEach(arr => {
const [localeId, localeObj] = arr
availableLocales.push(localeId)
localesObj[localeId] = localeObj
})
// 服务器端注册多语言
i18nRegister({
localeIds: availableLocales,
locales: localesObj,
type: i18nType,
})
}
export default async (app, {
// name,
template,
i18n = JSON.parse(process.env.KOOT_I18N) || false,
i18nType = JSON.parse(process.env.KOOT_I18N_TYPE) || false,
locales = getLocalesDefault(),
router,
redux,
client,
server,
}) => {
// if (__DEV__) console.log('\r\nServer initializing...')
// else
console.log(`\r\n \x1b[93m[koot/server]\x1b[0m initializing...`)
// ============================================================================
// 相关检查、赋值
// ============================================================================
const {
inject,
before,
after,
} = server
const onRender = server.render || server.onRender
// 处理 template
if (typeof cache.template === 'string') {
template = cache.template
} else {
if (typeof process.env.KOOT_HTML_TEMPLATE === 'string')
template = process.env.KOOT_HTML_TEMPLATE
if (typeof template !== 'string')
throw new Error('Error: "template" type check fail!')
// if (template.substr(0, 2) === './') {
// // template = require(`raw-loader?` + path.resolve(
// // getCwd(), template
// // ))
// template = fs.readFileSync(path.resolve(
// getCwd(), template
// ), 'utf-8')
// }
cache.template = template
// process.env.KOOT_HTML_TEMPLATE = template
}
if (typeof inject !== 'object')
throw new Error('Error: "server.inject" type check fail!')
// ============================================================================
// 载入目录、相关配置、自定模块等
// ============================================================================
// if (__DEV__) console.log('├─ client code initializing...')
if (__DEV__) console.log(` \x1b[93m[koot/server]\x1b[0m client code initializing...`)
const reactApp = await kootClient({
i18n,
router,
redux,
client
})
// if (__DEV__) console.log('├─ client code inited')
if (__DEV__) console.log(` \x1b[93m[koot/server]\x1b[0m client code inited`)
// ============================================================================
// 对应client的server端处理
// ============================================================================
if (i18n) doI18nRegister(locales, i18nType)
// ============================================================================
// 创建KOA实例
// ============================================================================
if (__DEV__)
console.log(
`\n\n`
+ `\x1b[36m⚑\x1b[0m `
+ `\x1b[93m[koot/server]\x1b[0m `
+ `callback: \x1b[32m${'before'}\x1b[0m`
+ `(app)`
+ `\n`
)
if (typeof before === 'function') {
await before(app)
}
/* 静态目录,用于外界访问打包好的静态文件js、css等 */
app.use(convert(koaStatic(
path.resolve(getDistPath(), './public'),
{
maxage: 0,
hidden: true,
index: 'index.html',
defer: false,
gzip: true,
extensions: false
}
)))
// ============================================================================
// Webpack 打包配置
// ============================================================================
// await app.use(async (ctx, next) => {
// if (!__DEV__) __webpack_public_path__ = process.env.WEBPACK_SERVER_PUBLIC_PATH || ''
// await next()
// })
// ============================================================================
// 同构配置
// ============================================================================
reactApp.isomorphic = new ReactIsomorphic()
const isomorphic = reactApp.isomorphic.createKoaMiddleware({
reactApp,
// react-router 配置对象
routes: reactApp.react.router.get(),
// redux store 对象
configStore: reactApp.createConfigureStoreFactory(),
// HTML基础模板
template,
// 对HTML基础模板的自定义注入
// 例如:<script>//inject_critical</script> 替换为 critical
inject,
onServerRender: async (obj) => {
if (__DEV__) console.log(' ')
let { ctx, store } = obj
store.dispatch({ type: TELL_CLIENT_URL, data: ctx.origin })
if (i18n) {
let lang = (() => {
// 先查看URL参数是否有语音设置
let lang = ctx.query[changeLocaleQueryKey]
// 如果没有,检查cookie
const cookies = cookie.parse(ctx.request.header.cookie || '')
if (!lang && cookies[process.env.KOOT_I18N_COOKIE_KEY] && cookies[process.env.KOOT_I18N_COOKIE_KEY] !== 'null')
lang = cookies[process.env.KOOT_I18N_COOKIE_KEY]
// 如果没有,再看header里是否有语言设置
if (!lang)
lang = ctx.header['accept-language']
// 如没有,再用默认
if (!lang)
lang = 'en'
return lang
})()
if (__DEV__) doI18nRegister()
store.dispatch({ type: CHANGE_LANGUAGE, data: lang })
i18nOnServerRender(obj)
}
if (__DEV__)
console.log(
`\n\n`
+ `\x1b[36m⚑\x1b[0m `
+ `\x1b[93m[koot/server]\x1b[0m `
+ `callback: \x1b[32m${'onRender'}\x1b[0m`
+ `({ ctx, store })`
+ `\n`
)
if (typeof onRender === 'function')
await onRender(obj)
}
})
app.use(isomorphic)
if (__DEV__)
console.log(
`\n\n`
+ `\x1b[36m⚑\x1b[0m `
+ `\x1b[93m[koot/server]\x1b[0m `
+ `callback: \x1b[32m${'after'}\x1b[0m`
+ `(app)`
+ `\n`
)
if (typeof after === 'function') {
await after(app)
}
// if (__DEV__) console.log('└─ ✔ Server inited.\r\n')
// else
console.log(` \x1b[93m[koot/server]\x1b[0m init \x1b[32m${'OK'}\x1b[0m!`)
return app
}