最近,SegmentFault 低调上线了 技术号 功能。何为技术号?其实就是一个小型的方便用户的 后台管理入口,在这里,可以对自己发表的内容(文章和头条)、讲座、专栏等进行简单的设置管理,逐渐以取代之前不集中的一些设置入口。在这个功能的开发中,第一次引入了前端 MV* 框架。
SegmentFault 前端架构
单纯用 Vue.js 来处理这样的一个独立需求是非常容易的,稍显困难的是如何突破思维应用到目前的代码结构中。
SF 是个纯后端路由、后端渲染的网站,事实上,如果切换页面大多数的 tab,网页都是重新渲染的。SF 的后端语言是 PHP,前端方面用的是 Requirejs+jQuery+BootStrap+Gulp 的传统开发套件,上线前,r.js 会将依赖全部打包成一个 js,也就是说,每个后端渲染的页面,除了一些 common 类的 js 外,基本上都只包含了一个打包后的单独的 js(线上一般以 xxx.min.js 命名)。
随着一些竞品网站相继改变架构,引入 MV* 框架以及 Webpack,我也在思考 SF 是否也可以走这条路线,思考的结果却是否定的。 SF 产品线实在太多(十几个?),页面达一百多个,相应地有一百多个 js 文件,如果全站只用一个 MV* 框架解决,个人感觉前端路由还是太重了。而且 js 大多都是 jQuery 操作,我司就两个前端,不可能在业务需求频繁的情况下去整站改变。所以我的思考结果是 一个产品线可以单独用一个 MV* 框架去构建。
技术号
这样思路就逐渐清晰,以技术号为例,按照之前的实现,内容管理(/mp/content
)和 功能管理(/mp/feature
) 为两个独立的后端路由,会被渲染成两个独立的后端页面(比如 content.twig 和 feature.twig),然后这两个页面会分别引入一个 js 作为 Requirejs 的入口(比如 content.js 和 feature.js)。这样如果切换左侧 tab,整个页面就会重新渲染,体验非常差。如果混合采用前端路由,即后端只有一个路由 /mp/
,后端将所有的类似 /mp/*
的路由都指到一个页面,然后在这个页面引入一个 js,在这个 js 里做前端路由的跳转,而这个 js 就是 Vue.js 最后打包成的 js。
实现
本地开发上,之前用的是 Gulp+Requirejs 的开发方案,引入 Vue.js 后很显然要搭配它的好搭档 Webpack,事实上,我用的就是官方提供的最简单的脚手架 webpack-simple。
首先,之前的一些 common 类的 js 都是 AMD 引入的,不多,就十几个,手动将其改成了 CommonJS 的形式(要注意 js 文件中的 AMD 都要改成 CommonJS 形式),通过在 Webpack 中配置 alias 实现用 Webpack 的打包。(所以目前个别文件其实是维护两套方案,AMD 和 CommonJS,因为只是这个子项目用了 Webpack,线上其他项目还是 Requirejs 的方案)
其次是 proxy 的问题。
因为是后端路由的项目,我们在本地可以打开的实际地址是 http://sf.testapp.org/
,之前用 Gulp 起的前端 server 是类似 http://localhost:3000/
形式,很显然要把所有 http://localhost:3000/
发出的请求都代理到 http://sf.testapp.org/
域名下。Gulp 的 browser-sync 插件不仅能起前端 server,还能配置 proxy:
const browserSync = require('browser-sync').create('proxy')
gulp.task('bs', () => {
return browserSync.init({
proxy: "sf.testapp.org"
});
})
这样就 OK 了,浏览器打开 http://localhost:3000
,实际上访问的是 http://sf.testapp.org/
,并且浏览器地址不会跳转,而其他的所有请求(包括 ajax),也会自动代理到 http://sf.testapp.org/
域名下。
而用 Vue.js+Webpack 后呢?我们在 webpack-simple 根目录下启动 npm run dev
命令(本质上是起 webpack-dev-server),这时会在内存中生成一个 bundle.js, 我们只要把这个 js 引入到页面上就可以了,比方说在 http://sf.testapp.org/mp/
页面引入这个 js,那么 js 任何改动都能被 webpack-dev-server 监听到,从而重载页面,而打包用 npm run build
命令即可,开发和打包都不需要额外的配置。从这一方面看,确实比 Gulp 的开发方案方便许多。但是因为模版在后端,引入这个 js 的时候需要把域名和端口号都带上(比如 http://localhost:8080/bundle.js),因为有的时候可能本地起 server 后端口号 8080 被占用,只能用 8081,那么这个绝对路径引入的 js 就 404 了,这个问题暂时还没想到解决办法。
总结
简单总结下,其实这个功能的实现非常简单,我们只需要抓住一点,之前 r.js 打包生成一个 js,现在用 Webpack 还是打包成一个 js,无非是这个 js 是用 Vue.js 开发的而已。
关于 SegmentFault 接下来的挑战,我觉得要尝试的是将整站改为 Webpack 构建,现在的架构中还夹杂着 compass,如何在引入 Webpack 的时候比较好地处理线上的 CSS?我觉得这是 2018 年不小的挑战。