前端重构之路(组件化)

2,765 阅读6分钟
原文链接: imochen.com

距离前端重构之路(技术选型篇)已经过去了近半个月。之前提到说

服务端使用ThinkJS已经可以确定了,一些配套模块也都写差不多了。前端还在Vue,Novajs,还是手动实现中徘徊。

期间对NovajsVuejs进行了大量的调研,也针对业务调整了相关的开发方式。最终确定了使用Vuejs来进行组件开发,也使用Vuejs玩出了一套可按需加载的基础组件开发模式。

要解决的问题

  • 组件化开发
  • 按需且支持并行加载
  • 数据驱动
  • 服务端渲染
  • web component使用方式

为什么组件化开发?
低耦合、高复用、便开发、易维护、代码清晰、结构明确等等。结合电商活动的特质,没有理由拒绝组件化。

按需且支持并行加载
按需加载目的是为了不同组件可以随意进行组合,而无需加载多余的资源。并行加载是指可以让组件资源同时进行加载,而无需使用require等方式异步加载,在加载速度上会有些许提升。

数据驱动
组件化,明确点说是UI组件。既然是UI组件,必然会有一些DOM类的操作。数据驱动可以让这些操作变的简单,且考虑到业务中某些场景,数据单双向绑定的用处也是不可忽视的。

服务端渲染
这个带来的性能提高不言而喻。组件不必通过JS去解析,用户在访问页面时已经是渲染好的页面了。当然服务端渲染不仅是输出页面,类似事件绑定,数据绑定之类在渲染后要依然生效。

web component使用方式
在组件的使用上,更偏向简单化,无需做太多的操作就可以使用一个功能丰富的组件。


下面这张图是最初我们对组件的期望,和大多数组件化方案一致。有些区别的是增加了颗粒组件,主要用于存储可复用代码片段,节省开发成本。最终打包为一个js和css,js中包含html(模版)。而隔离了css是为了在使用中灵活的根据文件类别进行打包合并。

基于Vuejs的基础组件开发

最初尝试的是novajs,整体上没有太大的问题,在scss编译这块遇到了一些问题,不过作者很快解决了,让我十分感动,然后含着泪选择了Vuejs。(此处主要因为团队原因没有选择novajs,感兴趣的童鞋可以研究下novajs.com/,轻量级web component还是很有优势的)

在官方给出的示例中,使用webpack+vue-loader开发打包,均使用的是全量打包。我们希望组件更灵活,且能根据需要去加载,这种全量打包显然是不合适的。如上篇文章中提到的,要将这种开发打包进行一定的修改,否则是无法使用的。

webpack确实存在打包完文件大,全量不可分割的问题,但它绝对不是这么弱,否则也不可能受到开发者的青睐。所以拆分打包的问题是可以解决的。

另外,Vuejs是可以使用Vue.component方法进行组件注册,而先不去实例化,在需要用到的组件全部注册完后,再进行实例化。

这个思路明确了,来看一下,怎么注册组件

import Vue from 'vue';
import titleTest from './title-test.vue';
Vue.component('title-test' , titleTest );

webpack编译后,在作用域内,Vue对象是同一个。那么问题就简单了,无论我们注册多少个组件,最终都在一个Vue对象上,只需要对Vue进行实例化即可。

webpack编译的时候,每个组件都会带一个Vue.js,可以使用插件将其提取出来作为公共部分。看一下webpack.config.js的内容。

//webpack主要配置
entry : {
	'components/title-test' : 'src/components/title-test/index.js',
	'components/banner-test' : 'src/components/banner-test/index.js'
},
output : {
	path: './build',
	publicPath: 'build/',
	//按entry配置生成js
	filename: '[name]/index.js'
},
plugins : [
	//公共部分抽离,主要是Vuejs
    new webpack.optimize.CommonsChunkPlugin('bootstrap/basic.js'), 
    //css抽离,一个组件一个样式
    new ExtractTextPlugin('[name]/index.css')
]

这样,打包完出现了另外一个问题,我们把所有组件都注册了,但是并没有实例化,而经过打包后的Vue在局部作用域,全局下是无法访问的。搞个启动器将其暴漏到window下,方便随时调用。

import Vue from 'vue';
let init = false;
let luna = {
	start( el ){
		if( init ){
			console.log('luna已经启动,不能重复start');
		}else{
			init = true;
			luna.vm = new Vue({
				el : el || 'body'
			})
		}
	}
}
window.luna = luna;

简单处理了一下,只暴漏必要的东西,启动方法和实例化对象,假设需要实例化多个对象,经过简单改造也是可以满足的。这样的话。webpack.config.js的entry也对应调整一下。最终经过打包后是酱紫的。

├── bootstrap #启动器相关
│   ├── basic.js #包含vuejs及组件标识
│   └── index.js #启动器
└── components #组件文件夹
    ├── title-test
    │   ├── index.css
    │   └── index.js
    └── banner-test
        ├── index.css
        └── index.js

因为Vue.js在basic中,所以我们要先加载basic。而启动器文件(bootstrap/index.js)我们最好还是让这个文件在组件加载后在加载,从流程上也更清晰。

享受组件的乐趣

通过针对各个问题的解决。这些个组件可以在任意地方使用,而最后仅需解决的一个问题就是,根据所使用的组件进行打包,js和js打包到一起,css和css打包到一起,或者使用combo合并请求。

但是仍然存在一个问题,Vuejs目前是不支持服务端渲染的,在Github上也有人写了一个叫Vue-server的服务端渲染工具,但是目前为止,它只能渲染静态数据,一些Vuejs的特性及方法在渲染后将会失效。这就意味着,页面的解析要在用户端进行,经压测,500以下的组件解析是可以接受的。而SEO上会受到较大的影响,如需解决SEO问题,在没有服务端渲染的情况下也有其他方法,由于博主没有尝试就不乱讲了。

综合考虑之下,暂时无法服务端渲染也可以接受。这样的基础组件可以配合常规开发模式进行开发,也可以组件化组装。经过压缩后,基础文件仅70k。GZIP后大概20k多些,使用简单,灵活多变。












方案的确定走出了第一步,仅仅确定以上方式是远远不够的。在团队中,怎么去协作开发?怎么保证统一规范?怎么最大化节省开发成本?怎么最快速度上手?这些都是要考虑的内容。

篇幅有限,关于团队化组件开发工具,日后再作单独的介绍。预览版已经放到了博主的Github和NPM了,感兴趣的同学可以去看下。

-- EOF --

本文链接:imochen.com/2016/01/09/…

发表于2016-01-09 21:58:28,并被添加「 Vuejs前端重构组件化 」标签,最后修改于2016-01-10 12:47:40