前端老牌框架衰退,IMVC(同构 MVC)成未来趋势?

内容来源:2017 年 3 月 11 日,携程研发高级经理古映杰在“携程技术沙龙 | 新一代前端技术实践”进行《IMVC(同构 MVC)的前端实践》演讲分享。IT 大咖说(微信id:itdakashuo)作为独家视频合作方,经主办方和讲者审阅授权发布。

阅读字数:2738 | 7分钟阅读

摘要

随着 Backbone 等老牌框架的逐渐衰退,前端 MVC 发展缓慢,有逐渐被 MVVM/Flux 所取代的趋势。然而,纵观近几年的发展,可以发现一点,React / Vue 和 Redux / Vuex 是分别在 MVC 中的 View 层和 Model 层做了进一步发展。如果 MVC 中的 Controller 层也推进一步,将得到一种升级版的 MVC,我们称之为 IMVC(同构 MVC)。

IMVC 可以实现一份代码在服务端和浏览器端皆可运行,具备单页应用和多页应用的所有优势,并且可在这两种模式里通过配置项进行自由切换。配合 Node.js、Webpack、Babel 等基础设施,我们可以得到相比之前更加完善的一种前端架构。

嘉宾演讲视频及PPT回顾:http://suo.im/4VPTN5

IMVC(同构MVC)

IMVC的“I”指的是ISOMORPHIC ,也就是同构,最初它是数学上的概念,描述两个对象之间的某种一致性。在前端领域中ISOMORPHIC JAVASCRIPT 则是指一段前端代码在客户端和服务端都可运行,它在2012年就已经被提出,算是历史悠久的概念了。

同构的种类

同构分为内容同构和形式同构,内容同构指同样的代码在客户端和服务端做等价的事情。形式同构通过判断所处环境来执行某段代码,也就是说在客户端或者服务端始终有一部分代码没有执行。

同构的层次

同构并不是一种非是即彼的判断,它更像是光谱,既可以是小范围的也可以是大范围。小范围的同构,例如原生的js 在浏览器和Node 中代码并没有差异,只是DOM API 和 Node API 不同而已,这就是函数层面的同构,即代码片段相同。还有一种特性层的同构,指的是业务中不同职能特性的同构,比如Vue 2.0在客户端和服务端都能运行,这就是Vue 这个特性层的同构。另外就是框架层同构,框架基本上包含了需要的所有的层次,而框架层的同构就是实现平衡,判断某个部分是否需要同构,并将同构与非同构部分融洽结合起来。

同构的价值

首先是SEO-friendly 的实现。其次第一次打开网页时不必等待JS 加载完成才能看到内容,页面的交互也能够得到即时响应,这就是速度上的优势。同构的运用使得服务端和客户端都使用同一套代码,有效的降低了维护成本。

同构是未来的趋势

早期客户端 JS 的作用就只是DOM 操作以及表单验证之类的事情,由服务端去实现业务逻辑、路由跳转、页面渲染等方面的事务。现阶段前端变的越发庞大,原先服务端需要处理的事情一部分被交由前端完成。可以发现早期是服务端臃肿,客户端轻便,现阶段则相反。

未来通过同构可以实现部分功能共享,比如页面的跳转、渲染、业务逻辑。让NodeJS去接管渲染层,后端部分向后再退一层,只负责数据持久化以及提供Restful API。

同构的实现策略

同构的第一要旨是全盘同构没有意义,服务端和客户端作为不同的平台,专注解决的是不同的问题,全盘同构会抹杀它们固有的差异,也就无法发挥各自的优势。因此,只需要在有交集的部分进行同构。对于内容同构的代码可以直接复用,内容不同构的封装成形式同构。

形式同构的实现思路

形式同构的实现思路就是抽象,来看下获取User Agent 字符串的例子。客户端通过navigator.userAgent 直接拿到字符串,服务端则使用req.get(“user-agent”) 。要想实现同构,我们可以在服务端构造一个全局的navigator 对象,模拟客户端环境。也可以封装一个 getUserAgent 函数,自行判断从何处取UserAgent 的值。

Cookies处理在我们的场景里,存在快捷通道,因为我们只专注首次渲染的同构,其它的操作可以放在浏览器端二次渲染的时候再处理。

重定向最少有三种以上的实现方式:

  1. 改变前端location 位置
  2. 前端使用pushState 方法,只改变路径并触发函数 ,但是不进行页面渲染
  3. 服务端采用302 重定向,通过封装函数判断环境以及重定向方法

IMVC的目标

现在来看下IMVC 所需要实现的目标:

  1. 用法简单,初学者也能快速上手
  2. 只维护一套ES2015+ 的代码
  3. 既是单页应用,优势多页应用(SPA + SSR)
  4. 可以部署到任意发布路径(Basename / RootPath)
  5. 一条命令启动完备的开发环境
  6. 一条命令完成打包 / 部署过程

IMVC的技术选型

IMVC 只是一个架构上的理念,理论上并不要求使用特定的技术栈,只需要实现期望的目标就行了。但是,要达成目标还是要做出一些选择,下面是我们现在的选择,当然未来可能升级或者做出改变。

1、Router: create-app = history + path-to-regexp

2、View: React = renderToDOM || renderToString

3、Model: relite = redux-like library

4、Ajax: isomorphic-fetch

为什么不直接使用 REACT 全家桶

可以看到我们的技术选型中使用了很多的React相关的技术,但是却并没有直接使用React 全家桶。

目前的React 全家桶其实是野生的,Facebook 官方并不会使用,只是认知度比较高而已。React-Router的理念也难以满足要求,查看view-source 会发现它没有实现同构。另外Redux 适用于大型应用,而我们的主要场景是中小型。

无论是Redux 还是 React-Router 升级都非常频繁,导致学习成本过高,需要封装一层更简洁的API。

用create-app 替代 React-Router

面对社区千变万化的框架,正确的做法应该是业务开发使用一层专属的封装,底层运行时使用社区流行的方案。用create-app 替代 React-Router并不代表需要全盘重写,而是引用需要的部分,抛弃原本的理念。来看下Create-app的组成就了解了。

  1. history 是react-router 依赖的底层库
  2. path-to-regexp 是 expressjs 依赖的底层库
  3. 在View(React) 层和Model 层之外实现Controller 层

我们认为React 和 Redux 分别对应MVC 的 View 和 Model,它们都是同构的,我们需要的是实现 Controller 层的同构。

Create-app的同构理念

  1. 服务端和客户端进行 URL 的输入,Router 解析 URL 匹配对应的mvc组件
  2. 调用模块加载器加载组件,然后初始化 Controller
  3. 调用 Controller.init 方法,返回view 实例
  4. 调用view-engine 将 view 的实例根据环境渲染成 html 或 native-ui 等。

以上就是create-app 的同构理念。

Create-app的配置理念

由于客户端模块是异步加载而服务端是同步加载,要想在他们之间做到平衡就需要实现一个Create-app的配置。

服务端和浏览器端分别有自己的入口文件:client-entry.js 和 server.entry.js。我们只需提供不同的配置即可。

在服务端,加载 controller 模块的方式是 commonjsLoader;在浏览器端,加载 controller 模块的方式则为 webpackLoader。

在服务端和浏览器端,view-engine 也被配置为不同的 ReactDOM 和 ReactDOMServer。每个 controller 实例,都有 context 参数,它也是来自配置。通过这种方式,我们可以在运行时注入不同的平台特性。这样既分割了代码,又实现了形式同构。

Create-app 的服务端渲染

我们认为正确的服务端渲染应该只有唯一的路由表和请求,仅根据输入的URL 和环境信息返回全部的渲染内容。

Create-app 的目录结构

├── src // 源代码目录

│ ├── app-demo // demo目录

│ ├── app-abcd // 项目abcd 平台目录

│ │ ├── components // 项目共享组件

│ │ ├── shared // 项目共享方法

│ │ └── BaseController// 继承基类 Controller 的项目层 Controller

│ │ ├── home // 具体页面

│ │ │ ├── controller.js// 控制器

│ │ │ ├── model.js // 模型

│ │ │ └── view.js // 视图

│ │ ├── * // 其他页面

│ │ └── routes.js // abc 项目扁平化路由

│ ├── app-* // 其他项目

│ ├── components // 全局共享组件

│ ├── shared // 全局共享文件

│ │ └── BaseController // 基类Controller

│ ├── index.js // 全局js 入口

│ └── routes.js // 全局扁平化路由

├── static // 源码 build 的目标静态文件夹

上面展示的是 Create-app 的目录结构,它和Redux 的传统目录结构不同。每个页面都是单独的文件夹,包含Controller、model、view。整个项目页面使用routers 路由表串起来。create-app采取了「整站 SPA」的模式,全局只有一个入口文件index.js。

ISOMORPHIC-MVC的工程化实施

上面谈论的是IMVC 在运行时的功能和特点,下面看下IMVC 的具体工程实施。

  1. node.js 运行时,npm 包管理
  2. expressjs 服务端框架
  3. babel 编译ES2015+ 代码到 ES5
  4. webpack 打包和压缩源码
  5. standard.js 检查代码规范
  6. prettier.js + git-hook 代码自动美化排版
  7. mocha 单元测试

如何实现代码实时热更新

使用webpack 的 node.js API 管理 webpack 进程,客户端采用express + webpack-dev-middleware 在内存里编译,服务端采用memory-fs + webpack + vm-module。服务端的webpack 编译到内存模拟的文件系统,再用 node.js 内置的虚拟机模块执行后得到新的模块。

如何处理 css 按需加载

问题根源:浏览器只在 dom-ready 之前会等待 css 资源加载后再渲染页面

问题描述:当单页跳转到另一个 url,css 资源还没加载完,页面显示成混乱布局

处理办法:将 css 视为预加载的 ajax 数据,以 style 标签的形式按需引入

优化策略:用 context 缓存预加载数据,避免重复加载

如何实现代码切割、按需加载

不使用webpack-only 的语法require.Ensure。在浏览器里require 被编译为加载函数,异步加载。在node.js 里require 是同步加载。

如何处理静态资源的版本管理

以代码的 hash 为文件名,增量发布。用webpack.stats.plugin.js 生成静态资源表。Express 使用stats.json 的数据渲染页面。

如何管理命令行任务

1、使用 npm-scripts 在 package.json 里完成 git、webpack、test、prettier等任务的串并联逻辑

2、npmstart 启动完整的开发环境

3、npmrun start:client 启动不带服务端渲染的开发环境

4、npmrun build 启动自动化编译,构建与压缩部署的任务

5、npmrun build:show-prod 用 webpack-bundle-analyzer 可视化查看编译结果。

今天的分享就到这里,喜欢请点赞~谢谢大家!有问题可以在评论区讨论。

原文发布于微信公众号 - IT大咖说(itdakashuo)

原文发表时间:2018-04-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏沈唁志

在ThinkPHP5框架中使用QueryList4做采集

1853
来自专栏编程微刊

小程序新方法 open-type获取头像昵称

小程序自上线以来,官方一直在调整API,因此也出现了一批被废弃的接口,作为程序员的我们,此时此刻千万不能为这不断的变化而感到头疼,应当与时俱进,不断的更新自己的...

2432
来自专栏企鹅号快讯

卡奇话爬虫使用方法以及下载地址

前不久我给大家分享了CSDN博主虫师的一篇python爬虫编写教程: life is short,u need python. 当时有朋友留言说,并不是每个人都...

2075
来自专栏非著名程序员

强烈推荐:绝对是最好的一个小程序开源框架

小程序到底有多火,看看目前推出的开源框架以及组件库就知道了。由于小程序开发的火爆,大家都在致力于探索如何更好的,更加高效的开发小程序,以至于很多公司都贡献了小程...

1484
来自专栏WeTest质量开放平台团队的专栏

面向亿万级用户的QQ一般做什么?——兴趣部落的Web同构直出分享

所以可以把直出定义为:“以node作为后端语言实现的服务端渲染并输出HTML字符串到客户端的一项技术”。这样浏览器渲染首屏的过程就由非直出下的先请求HTML,再...

952
来自专栏即时通讯技术

IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?

一个完善的IM系统中通常充斥着大量的图片内容,包括:用户头像、图片消息、相册、图片表情等等,那么在做服务端架构设计时该如何存储这些图片呢?

2284
来自专栏极乐技术社区

小灯灯实战系列《三》微信小程序:仿今日头条(下)

接着上一篇  上一篇文章中,我们已经完成了头条的新闻列表、新闻详情功能了,但是还存在一些值得优化的地方,以及评论功能没有加上。  欢迎Star Github开源...

3166
来自专栏ytkah

wamp支持win10吗?怎么设置?

  上周ytkah总算把系统升级到win10了,可怎么设置wamp支持win10呢?启动wampwerver是处于黄色状态,打开本地页面是空白,应该是端口问题。...

3609
来自专栏企鹅号快讯

小程序也有“home”键盘了!

微信小程序最近仿佛是消停了一会儿儿,没有深夜袭击,不过还是有不断地小更新,今天就来给大家唠叨两个新变化。 --小程序安卓用户更新 12月22日,微信更新了安卓版...

2225
来自专栏知晓程序

开发 | 我的小程序开发「踩坑血泪史」

不同于其他的一些实用性娱乐性很强的小程序,我的这款小程序更像是一种「私人定制」,因为它唯一功能,就是用来方便大家浏览我在 deviantArt 上的 CG 作品...

1277

扫码关注云+社区