05月02日
后庭花1.0 网站重构经验分享

揭秘 vue ssr 的在中小型项目中的同构策略以及 webpack4 , react 、 smox ……

简介

后庭花是一家 一言难尽【哗||】的 acg 网站,它的类型决定了它的交互,我们在符合“套路”的同时,会进行一些“创新”

重构背景

前端世界的变天,导致里世界现有技术栈没有了逼格……加上我个人的尿性……
我利用比较新的技术,对里世界进行重写,也就是现在的后庭花……

技术栈

  • webpack4
  • koa2
  • vue2.5
  • vuex
  • vue-router
  • react16.3
  • react-router4
  • smox

重点

1.后庭花架构是怎样的……如何做到 vue 和 react 的两端共存?

2.既然后庭花是 pc 端,那如何解决多页问题,ssr 具体的混合方案?

嗯……后庭花是 pc 端的网站, pc 端多页是符合用户的直觉,同时也有利于 seo 的……
解决方案就是 ssr,我们 pc 端是使用的 vue 的,但是 vue 的虚拟 dom 在服务端是比较吃力的,该如何两端代码合理混合,达到体验与成本都 ok 的?

3.后台管理端, react16.3 如何良好的使用新的 context api ,以及 smox 的存在?

我们都知道新的 context api 是可以代替大部分 redux 的,让我们造一个新轮子来实践它

4.不常见的小细节?

1.后庭花架构

这个我真的一言难尽呀o(╥﹏╥)o平时我说, pc 端使用的是 vue ,后台端使用的是 react ,还有人不懂,说后台不是 koa 吗?
其实这个后台是指的【后台管理系统】的前端

为此我 p 了一张图……
图片

其实很好解释的啦,就是我们 pc 端用的 vue ssr ,是和 node 端( koa )同构的,然后 admin 端用了 react ,是 spa ……
整套架构中, vue 和 react 的配合,比如两端共享 cookie , nginx 反向代理……

cookie 的操作是后台做的,设置 domain 为跟域名,即可实现二级域名的 cookie 共享

ctx.cookies.set(
      'id', id, {
        domain: 'idanmu.cc'
      }
    )

nginx 反代,主要是对接口的代理和对 spa 中*的路由指向 index.html ,意思是交由前端来处理路由,这样就不会刷新404了

 location / {
  root /root/www/server/admin/;
  index index.html;
  try_files $uri $uri/ /index.html;
 }

我们这套架构中, vue + vuex + reac t+ smox,一言难尽呀o(╥﹏╥)o我个人是不介意你们也这么干

这之中 vue ssr 同构,无疑是重点,我们接下来谈谈它……

2. 后庭花的同构

同构这个词,字面意思就是浏览器端和服务端跑同一套代码,原理上就是后端 renderToString 返回给前端,虽然我一句话将它给通俗的描述了……
但是同构还真不是个一言能尽的东西o(╥﹏╥)o

一言难尽呀o(╥﹏╥)o

普通的同构,后端生成了 string ,返回给前端,然后前端就可以展示了,这听上去很不可思议,网上一搜也一堆 “ vue ssr 性能差” 这种文章……
其实本质上就是虚拟 dom 肯定不如传统的模板引擎性能呀(⊙o⊙)…但是性能差,服务器压力大,不影响很多网站还是这么干

但是更多的人在思考,各种的“混合”方案……
无非解决的问题就是——

减少服务端压力,提高渲染性能

好吧我不多说了,我发现我又说不下去了o(╥﹏╥)o

说不下去,就上图!
图片

图中是后庭花的同构方案,可以看到,首次请求到服务端,返回过来的是一个 spa ,然后后续的浏览器端的交互,都是在 spa 中完成的……
这样一来就能减少很多很多服务端的请求,服务器压力也降低了……

同时,因为 spa ,渲染的性能也是很可以接受的

嗯……虽然原理很简单,但是还是很绝望呀o(╥﹏╥)o过程中坑还是有的

* webpack4

vue ssr 文档中全程是 webpack3 ,后端是 express 的,实际上这俩都比较过时,现在 webpack 已经4.6了,不可能继续使用3
express 也是同理
当然,用 webpack4 的另一个原因是,它是天生为了异步而生的

啊这里插播一句,关 spa 的加载问题,首屏加载慢,首屏白屏什么的,其实只要搞好异步,就不会慢!
这一点将会在我们的 app 写完后的文章分享,如何做到异步+本地离线,实现完全的不白屏一触即发,敬请期待~

回到正题, webpack4 提供的俩新的 api ,是为了异步而生的……
主要就是 optimization 这俩新的 api

    optimization {
        splitChunks: {
            cacheGroups: {                  // 这里开始设置缓存的 chunks
                commons: {
                    chunks: 'async',      // 必须三选一: "initial" | "all" | "async"(默认就是异步)
                    minSize: 0,             // 最小尺寸,默认0,
                    minChunks: 2,           // 最小 chunk ,默认1
                    maxInitialRequests: 5   // 最大初始化请求书,默认1
                },
                vendor: {
                    test: /node_modules/,   // 正则规则验证,如果符合就提取 chunk
                    chunks: 'async',      // 必须三选一: "initial" | "all" | "async"(默认就是异步)
                    name: 'vendor',         // 要缓存的 分隔出来的 chunk 名称
                    priority: 10,           // 缓存组优先级
                    enforce: true
                }
            }
        },
        runtimeChunk: true
    }

可以看到……默认就是异步呀……
我个人是建议都升级 webpack4 的,不信你试试,同样的异步组件,webpack3 各种的压缩插件还是不如 webpack4 的 minimized

然后 webpack 的另一个问题就是 css 的打包……
注意啦注意!
如果做了异步打包,extract-text-webpack-plugin 这个插件是不能用的!next 也不行!因为它用到了浏览器的js对象, node 端木有!所以我们需要用 mini-css-extract-plugin ,这里有个坑,就是 minicss 插件, vue-loader 还不支持分离打包,可以继续关注 vue-loader ,next 版本应该就可以了

* webpack compiler

ssr 开发过程中,我们同样要启服务的,而且要配置热更新……
这里也有一个坑,就是异步组件后,报错 can't resolve aysnc component
提示找不到异步组件,因为我们的 dev 环境是写入内存的,不生成硬盘文件, vue-server-renderer 就会找不到……

解决方案就是,我们都知道node端通过 require 找不到的包都会一层层找到 node_modules 里,我可以通过配置 vue-server-renderer 的 baseurl,然后在这个 url 下面建立一个 node_modules 文件夹,作为 webpack 的 output 目录,这样就能找得到啦!

* vuex

在同构过程中,vuex 无疑起到了很大的作用,我们可以在浏览器端和服务端都使用 vuex 来管理 state
但是更理想的状态是,vuex 只是配合内部的 setstate(vue 的 data、props),最理想的状态是……看图……
图片
就是服务端我们只通过 vuex 、 smox 这种状态管理,去 renderToString ……返回给浏览器,然后被搜索引擎抓取到
比如,有些数据我们可以在服务端请求,通过一个标志位函数(这里是 asyncData ),这里也有一个小坑,就是 vuex 的 dispatch 操作不能多个,要想多个的话,可以加个循环遍历它
当然也可以如下, Promise.all 包一包

asyncData({store}) {
      return Promise.all([
        store.dispatch('getAnime'),
        store.dispatch('getComic'),
        store.dispatch('getGame'),
        store.dispatch('getAuthor'),
        store.dispatch('getNews')])
    }

客户端的一些小的交互,登录注册啥的,我们可以只在客户端,组件内部去 setstate ,也就是修改 data ,这样后端实际上没有做这些交互,服务器压力也会减少很多

但是这里又有一个坑了……就是 vue 本身的机制和 react 不一样,它每次修改 state 并不会重新 render ……
我们可以考虑通过 watch 来做一些事情,这里看具体的业务逻辑而定啦

好的,大概套路俺通俗的给说完啦……

3.smox

上面提到了 smox , smox 在我们的项目中担任了除 vuex 以外, react 端的状态管理工作,它是基于 react16.3 的新的 context api 写的一个状态管理
我之前说过 redux 已经没必要了……但是实际上,我在 ssr 过程中,发现 redux 还是有用的,具体就对比刚刚提到的 vuex 在 ssr 中的作用

以前,新的 context api 比 redux ,就缺了一个全局 store ,但是在 ssr 中, redux 很可能承担服务端state管理的角色

不过这方面的事情我还是准备用 smox 去做,后面我会对它进行重写,让它的 api 更加贴切 ssr

趁机我们可以直白的说一下,redux 是个啥

redux 的本质就是一个发布订阅, react-redux 就是一个 hoc

很多人对 redux 的 api 不熟悉,我来说一下 redux 的 api 都是个啥,就是 createStore 先 create 一个 store , reducer 是参数,然后 reducer 定义了几个 action 去操作 state ,然后要调用 action 就 dispatch(action) ,然后页面里通过 subscribe 去订阅 listener ,最终通过 getState 可以取到当前 state ,是不是很直白……一句话把 api 通俗的描述了(⊙o⊙)…

没办法咱就是个直白的人,嘿嘿

smox 也是同理,它唯一不同的是,就是用的 context api 是最新的,2333

4.小细节

其实在开发过程中,小细节还是蛮多的,从设计到编码……

* 设计

pc 端截图:
图片

可以看得到,相当于其他网站的夜间模式了……
其实暗黑的感觉驾驭起来还是不那么好搞的,因为一不小心就容易搞的脏,设计方面原理也是一言难尽,暗黑的感觉可以感受下 steam ……

admin 端截图:
图片

后台的设计其实也是本着精简,先感受下这灰嘟嘟的配色233,而和常规的oa系统布局不同,具体可以到后庭花体验下哈

总体设计原则,其实学过美术都是懂的,颜色不要太纯太火太生太脏,板式要注意处理不要太抢
就可以啦!

* blur 导航

在 css 过程中,有个 blur 模糊的效果,这个网上教程蛮多的,原理很简单,就……其实是两个 div ,然后……通过 blur 和 over:hidden 来搞
图片

div {
    background: #2b2e37;
    height: 200px;
    position: relative
    background:url('bg.jpg')
}
div:before {
    background:url('bg.jpg')
    content: "";
    width: 100%;
    height: 40px;
    position: absolute;
    top: 0;
    bottom: 0;
    background: #2b2e37;
    filter: blur(10px);
    z-index: 0;
}    

以上样式仅供参考,是后庭花的样式,原理就是两个div同一个背景图片,然后……blur 了一个 div , hidden 掉 blur 的那个 div

* vue 的 mixin 的生命周期

vue 的 mixin,和 react 的 hoc 差不多,但是 react 中可以借助 hoc 来重塑生命周期, vue 的 mixin 是混合生命周期,同一个生命周期, mixin 会先执行
这个时候可以通过 updated 生命周期,控制一个 state 的变化,来完成生命周期的重塑

唔,差不多就这些啦,接下来的时候我们会接着写 app 了,会有一些新的实践方案,下一次作文哈!

米娜下次见!

yse69011

11条评论

oo 哦

nnbjia19 天前回复

@Dr_Yao 不考虑的,nuxt的封装太重了,作者强加了一些概念,目录结构不可改,架构层面上这些都是很不靠谱的√

yse20 天前回复

@lixiansky acgzone.org默认解压密码

yse20 天前回复

骚年不考虑用 nuxt 吗

Dr_Yao21 天前回复

@zqgeek 已经上线了,但是没给排名o(╥﹏╥)o地址我戳你

yse25 天前回复

我就想问你 解压密码是啥

lixiansky25 天前回复

少年很骚气啊

lixiansky1 个月前回复

阔以阔以

书一1 个月前回复

"你取什么名字不好"系列

szhshp1 个月前回复

沙发~

yse1 个月前回复