阮三丰的博客

vuePress-theme-reco 阮三丰    2017 - 2023
阮三丰的博客 阮三丰的博客

Choose mode

  • dark
  • auto
  • light
首页
分类
  • JavaScript
  • javascript
  • 杂文
  • 前端
  • python
  • dva
  • umi
标签
时间线
简历
Contact
  • GitHub
author-avatar

阮三丰

21

文章

12

标识

首页
分类
  • JavaScript
  • javascript
  • 杂文
  • 前端
  • python
  • dva
  • umi
标签
时间线
简历
Contact
  • GitHub

我学习ssr的那些事

vuePress-theme-reco 阮三丰    2017 - 2023

我学习ssr的那些事

阮三丰 2020-07-20 12:19:54 JavaScript

# 起因

学习 ssr 还是因为需要加深自己的技能,不然被淘汰了。它的好处相信大家都了解,我也不多说了。对我而言,其实用处也不是很大。你说加载快吧?现在 spa 项目代码分割后其实也可以很快,但是这种东西肯定更快。那么有利于 seo 吧?据说现在大厂的爬虫是有技术可以对 spa 进行爬取信息的,具体不详,但是这应该算是它最大的优势吧。但是存在即合理,学习了上不了当。

# nuxtjs

先说一下 vue 的生态简直太棒了。vue-cli 也好, nuxtjs 也好,都有一套非常完整的脚手架,使用者可以通过脚手架搭建完全符合自己想法的开发体系。nuxtjs 的使用就不多说了。这次主要讲一下 nextjs。

# 初见 nextjs

打开 nextjs 官网简直是无语了。啥玩意儿?在长沙,vue 的使用率大于 react。我相信它们之间的文档也有部分原因。这么烂的文档我怎么学?于是我花了将近大半天的时间自己搭建了一个我个人习惯的 nextjs 的架子。即 nextjs+ts+antd+dva。

# nextjs + ts

ts 现在应该很多前端都已经基本掌握,用起来很香。nextjs 也提供了 ts 的配置,新版本 nextjs 只需要装它的 ts 模块即可。还是挺方便了。

npm i --save next react react-dom @zeit/next-typescript typescript  @types/react @types/node
1

先不管,一把装了,然后在 package.json 中添加

  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },
1
2
3
4
5

接着在最外层目录新建 pages 文件夹,新建一个自己定义的 ts 写 react 吧。关于nextjs的规则我们暂时不说,这次主要谈论这次搭建这个架子的过程。

# antd

antd 还是很不错的。可是按照官方配置和网上搜索的配置都不能配成按需加载。只有重写一下App根组件。

// ./pages/_app.ts
import "antd/dist/antd.css";
import React from "react";
export default ({ Component, pageProps }) => <Component {...pageProps} />;

1
2
3
4
5

将 antd 的所有样式引入才能正常使用。或许我还是没找到正确的方法,还请各位大佬指正。

# dva

之所以是 dva 而不是 redux 是因为我只认识这东西,没接触过 redux。

npm install --save dva-no-router
1

然后自己创建一个 Store 文件,地址为https://github.com/dvajs/dva/blob/master/examples/with-nextjs/utils/store.js ,注意要转为 ts。然后我发现要使用 dva,每个页面也都有一个这么个东西(store 文件存于 utils 文件夹中)

import WithDva from '../utils/store';
....
 static async getInitialProps(props) {}
....
export default WithDva((state) => { return { index: state.index }; })(Page);
1
2
3
4
5

用过 nextjs 的应该都知道这个东西。于是我想办法把他们整合到一起了,省的写那么多代码。大概是下面这个样子

import WithDva from './store'
export const WithComponent = (Components: {
    (props: any): JSX.Element;
    getInitialProps?: (props: any) => Promise<{
        [key: string]: any;
        pathname: string;
        query: { [key: string]: any };
        isServer: boolean;
        dvaStore: { [key: string]: any };
    }>
}, initData?: (props?: Initialprops) => Promise<{ [key: string]: any }> | { [key: string]: any }) => {
    Components.getInitialProps = async (props: Initialprops) => {
        const {
            pathname, query, isServer, store,
        } = props;
        let result: { [key: string]: any } = {};
        // 扩展初始化数据
        if (initData) {
            result = await initData(props);
        }
        return {
            pathname, query, isServer, dvaStore: store, ...result
        };
    };
    return WithDva((state) => state)(Components)
}
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

第一个参数是 react 组件,第二个是原本应该写在 getInitialProps 中的内容。 在组件中使用如下:

export default WithComponent(
  Home,
  (props) =>
    new Promise((res) => {
      setTimeout(async () => {
        // 事先全局渲染
        // await props.store.dispatch({ type: 'index/init' })
        res({ a: 67 });
      }, 0);
    })
);
1
2
3
4
5
6
7
8
9
10
11

其余的 dva 配置我也不多说了,和平时使用一致即可。值得注意的是,这里 dva 依然不支持 await/sync。要使用 yield 和*。这一点确实挺尴尬无语的。

# 动态路由

最后跳转动态路由的时候发现了一个问题,当刷新当前页面的时候,node 端不会重定向,所以会显示 404。这时候就需要用一个 express 了。首先在根目录新建一个 server.js,然后安装 express。将 package.json 代码更改一下

  "scripts": {
    "dev": "node server.js",
    "build": "next build",
    "start": "NODE_ENV=production node server.js"
  },
1
2
3
4
5

server.js 中关键代码如下:

   server.get('/dashboard/:id', (req, res) => {
      return app.render(req, res, '/dashboard', { id: req.params.id })
    })
    server.get('*', (req, res) => {
      return handle(req, res)
    })
1
2
3
4
5
6

同时这里可以做接口的反向代理等等...这样子就比 nextjs 启动项目可扩展性大多了。

# 最后

看上去好像挺简单的,也是花了我大半天各种翻资料和尝试而成的。这是我个人比较喜欢的一套组合。想详细点就去这里 拉下代码看下吧。毕竟也是我学习的阶段写的,肯定问题不少,欢迎各位大佬提出改进。