Next 动态页面

背景

最近需要开发一套有通用流程的页面, 但是有各自的样式和交互, 不能直接通过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]

开发环境解决方案

面临的主要的问题有:

  1. 使用同一套前端公用组件库
  2. 前端web只需要部署一套
  3. 前端封装一个通用的请求, 所有页面复用, 便于维护

看了文档之后, 发现Next自带dynamic方法解决动态加载组件的问题, 于是问题就比较简单了, 生成一份对应的配置文件即可, 访问的时候本地配置Host指定域名访问就行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// sites.config.js
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
// pages/index.js
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
// 修改获取Host代码, 兼容静态打包生成/服务端渲染/客户端渲染方式
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
# 修改package.json, 添加导出不同站点的命令
"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 转发, 达成首页秒开的效果. 但是最后存在一个不够完美的地方, nextwebpack在打包输出的时候, 会将其他站点的.js文件同样打包出来, 虽然不会实际加载到, 但是会影响打包速度, 以后有空了可以看看如何通过webpack插件解决这个问题

作者

Mosby

发布于

2018-11-13

许可协议

评论