背景
最近需要开发一套有通用流程的页面, 但是有各自的样式和交互, 不能直接通过css
来实现, 所以需要研究动态加载的方案. 同时这个页面又是直接给到外部用户使用的, 所以选择服务端渲染比较好, 最终选择Next.js
来实现这套框架
流程图
graph LR
A[用户] -->|访问| B1(站点A)
A[用户] -->|访问| B2(站点B)
A[用户] -->|访问| B3(站点C)
B1 --> C(Next.js)
B2 --> C
B3 --> C
C -->|请求| D[Node Server]
D -->|请求| E[Backend]
开发环境解决方案
面临的主要的问题有:
- 使用同一套前端公用组件库
- 前端
web
只需要部署一套
- 前端封装一个通用的请求, 所有页面复用, 便于维护
看了文档之后, 发现Next
自带dynamic
方法解决动态加载组件的问题, 于是问题就比较简单了, 生成一份对应的配置文件即可, 访问的时候本地配置Host
指定域名访问就行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import dynamic from 'next/dynamic';
export default { sites: { siteA: { hosts: ['site-a.local.com:3000'], page: dynamic({ loader: () => import('./views/site-a'), }), }, siteB: { hosts: ['site-b.local.com:3000'], page: dynamic({ loader: () => import('./views/site-b'), }), }, }, };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import React from 'react'; import Head from 'next/head'; import Link from 'next/link'; import axios from 'axios'; import config from '../site.config';
function getSiteIdFromHost(host) { for (const site of Object.keys(config.sites)) { const hosts = config.sites[site].hosts; if (hosts.includes(host)) { return site; } } return null; }
export default class extends React.Component { static async getInitialProps(props) { const { isServer, req } = props; const site = getSiteIdFromHost(req ? req.headers.host : window.location.host); return { site, }; } render() { const { site } = this.props; const SitePage = config.sites[site]; return ( <div> <SitePage /> <Link href='/cowsay' prefetch> <a>cowsay</a> </Link> </div> ); } }
|
正式环境打包部署
最初是直接把next
部署到服务器上提供访问, 那么和开发版本没有多大区别, 但是后面后期优化想要打包成静态文件的版本, 那么就需要解决打包时的站点区分了, 实现原理很简单, 通过环境变量指定打包的项目, 并分别输出即可
1 2 3 4 5 6 7 8 9 10 11 12
| let host = '';
if (process.env && process.env.BUILD_HOST) { host = process.env.BUILD_HOST; } if (!host && req && req.headers && req.headers.host) { host = req.headers.host; } if (!host) { host = window.location.host; }
|
1 2 3
| "export-site-a": "cross-env BUILD_HOST='site-a.local.com' next export -o ./out-site-a", "export-site-b": "cross-env BUILD_HOST='site-b.local.com' next export -o ./out-site-b",
|
这样打包过后, 不同站点部署在不同文件夹就没问题了, 接口层再统一通过 nginx 转发, 达成首页秒开的效果. 但是最后存在一个不够完美的地方, next
的webpack
在打包输出的时候, 会将其他站点的.js
文件同样打包出来, 虽然不会实际加载到, 但是会影响打包速度, 以后有空了可以看看如何通过webpack
插件解决这个问题