vgg
vgg是根据vue技术栈的最佳实践总结而来的技术架构,它能以插件的形式扩展框架本身。支持单页面应用 的服务端和客户端渲染。
架构如下:
|--------------------|
| vgg + vgg-plugin-* |
|--------------------|
| egg-vgg |
|--------------------|
| eggjs |
|--------------------|
**重要:**我们基于egg-vgg可快速开始开发。
1. 文件目录结构
- api api service层
- modules api对应的接口模块
- user.js
- index.js api实例扩展
- common 通用资源
- context vue上下文,这里的资源会绑定到vue原型,允许你以this.$的形式访问。
- filter vue filter
- directive vue directive
- plugins vue plugin
- utils vgg.utils工具库
- commponents 全局组件
- index.js
- config 配置
- config.default.js
- config.local.js
- config.stage.js
- config.prod.js
- plugin.json 插件配置
- plugins 插件约定存放文件夹
- plugin_a
- router 路由
- router.js router实例扩展
- routes.js 路由注册
- store vuex store
- modules store对应命名空间的模块
- user.js
- index.js vuex实例扩展
- views 单页面应用视图层
- home.vue
- app.template.html 服务端渲染基础html
- app.vue 根组件
- pages 多页面应用视图层
- page_a.vue
- app.js 根实例扩展
从目录结构我们可以看出,框架分为如下几个重要的部分:
- 配置(config)
- 通用vue资源(common和commponents)
- store
- api服务层
- 路由系统
- 插件系统
2. 环境与配置
根据当前的环境读取对于的配置,运行环境配置参考eggjs运行环境。
配置上的约定也跟eggjs一致,即config.default.js为默认配置,环境配置覆盖默认配置,覆盖采用
_.defaultsDeep
方式。
通过vgg.env获取当前环境,vgg.config获取当前配置。
// config/config.default.js auth: enabled: false mod: 'sso' // config/config.local.js auth: enabled: true // 当在本地开发环境(local)时 vggconfigauthenabled === true; vggconfigauthmod === 'sso';
3. 通用vue资源
框架支持几种vue资源全局性的注入,分别是:
- 组件(componetns)
- 上下文(common/context)
- vue的过滤器、指令、插件
- 工具类库(utils)
只要按照约定,框架会自动注入你配置的资源。
3.1 组件(components)
在components/index.js
中声明组件,key为组件名称,value为需要引入的组件。
// components ; import'./header.vue' MyApp // 也可以使用辅助函数来自动添加前缀。 let components = vggutilsprefix'My' import'./header.vue' import'./app.vue' ; ;
3.2 上下文(common/context)
在common/context/index.js
中声明上下文,key为上下文名称,value为上下文创建函数。
// common/context/index.js ; /** * 创建一个axios实例,并注入上下文。 * @param {[type]} appContext koa app context,是服务端返回的上下文。 * @param {[type]} context 注入好的上下文。 * @return {[type]} 上下文对应的内容。 */ { return axios; }
注入好之后,你能在其他appContext中使用,例如appContext.http,或则在组件中以this.$http来 访问。
框架内置的上下文有:cookies, http, logger。
3.3 vue的过滤器、指令、插件
分别对应这些文件夹:common/filter、common/directive、common/plugin
。
这3类资源跟context的声明方式类似,在各自文件夹下的index.js
中声明,key为资源名称,value为
创建方法,最终都会交给Vue来进行全局性的注入:
// 对于filter Vue; // 对于directive Vue; // 对于plugin Vue;
3.4 工具类库(common/utils)
全局性的工具类库,注入到vgg.utils中。
// 在`common/utils/index.js`中进行注入对应的方法。 {return } // 其他地方使用 ; vggutils;
4. store
store是vuex的实现,文章和架构参考。
4.1 创建store module
在文件夹store/modules
中创建模块,创建之后,即可使用store.register
对模块进行注册,文件
命名采用snake_case
规则。
// 创建store模块 // store/modules/my_book.js { return namespaced: !!namespace { return {} } // getters, // mutations, // actions }
4.2 使用store module
要使用模块,先要使用store.register()
进行模块注册。注册的本质是获取对应的store模块,调用
store.registerModule()
注册到对应的命名空间中。
// 某某组件:my_component.vue async { // 注册模块到指定命名空间上 // store.register(namespace, modulepath, ...args) // 向命名空间example/some添加模块example/some store; // 该语句有个简写 store; } { this$store } methods: ...
其他一些api,参考create_store.js。
- store.register(namespace[, modulepath[, ...args]])
- store.unregister(namespace)
- store.isRegistered(namespace)
- store.once(type, namespace, name[, ...args])
- store.ensure(type, namespace, name)
- store.has(type, namespace, name)
- store.try(type, namespace, name, ...args)
注意点
- 如果模块需要在组件beforeCreate生命周期(包含beforeCreate)前使用,那么这个模块需要在路由 组件的asyncData中注入。参考服务器端数据预取
- 保留命名空间'route'。参考vue-router-sync
5. api服务层
类似于service层,用于跟后端进行数据交互。
5.1 api的创建
api在文件夹api/modules
中创建,创建后可在组件、store中使用,文件名采用snake_case
规范。
// 创建api book。 // 文件:api/modules/book.js // 整个模块的默认格式为如下,其函数返回内容即为这个api的可使用接口。 { return async { return } async { return } }
5.2 api的使用
在store
中,api被注入到上下文appContext中。
{ const api = appContext; return // .... // 某某store actions: async { let data = await ; } }
在组件中可通过$api
这个对象访问:
// 某某组件中 methods: async { let data = await this; } // 但在asyncData方法中,因为组件还没有实例化,所以通过参数进行注入了。 async { let data = await ; }
6. 路由
路由是基于vue-router实现的,在router/routes.js
中添加路由,配置同vue-router
。
在config的router属性中配置路由初始化属性,配置项参考
通过hook系统可扩展router实例本身:
- hook router.alter
- hook router.onError
- hook router.beforeEach
- hook router.afterEach
7. 插件
框架通过插件来扩展自身,可以扩展框架的所有内容。
7.1 使用插件
在文件夹config/plugin.js
中来声明要使用的插件。
// config/plugin.js // 命名空间。(插件的命名空间,使用的时候,因为技术限制,不能自定义命名空间。命名空间是由插件作者指定好的。) pluginA: // 对应插件的包名称或相对地址。例如'./plugin/plugin_a' package: 'plugin-a' // 默认注入组件。关闭之后需要手动注入,这样有助于减少打包体积。 components: true // 默认注入路由。关闭之后需要手动注入,这样有助于减少打包体积。 routes: true // 当components和routes都是需要注入时,配置可以简写: // pluginA: 'plugin-a'
引入其他插件的资源:import('$pluginA/foo/bar')
。这样就是找根目录是插件pluginA
,文件
相对地址是./foo/bar
的模块。
使用插件的api和store:
// api this; // store this$store; // 等同于 this$store;
7.2 创建插件
@todo