写这篇的原因是我在撸钱包项目的时候总结了原来的经验搭了一个架子,我认为挺有趣的想分享给大家
一千个人有一千个哈姆雷特 - -。我不敢保证是最优雅的但肯定不是最烂的
本文涉及了如何解耦路由文件,vuex文件和快速搭建一个mock server
为什么要解耦?懒就是生产力啊 建好文件自动帮我引入岂不是美滋滋?
目前我的项目架构:
-src
-api axios配置和接口
-plugins 插件
-components 公用组件
-store Vuex
-views 页面
-route 路由
复制代码
-
解耦路由
- 在vue官网文档里建议将所有的路由信息全部写到router.js里,猛的一看没有任何问题。但是随着项目的庞大和模块的增多,你就要维护一个特别庞大的路由文件。这就导致不能快速的定位问题和解决问题。(人也是够无聊的,项目小了想聚合,项目大了想解耦)
-
// 先展示router.js 文件
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'app',
redirect: '/app',
component: () => import('./App')
},
...(r => {
return r.keys().map(key => r(key).default);
})(require.context('./views', true, /\/route\.js$/))
]
})
现在就要给大家介绍今天的主角:require.context()
require.context()是webpack提供的一个api,用来管获取模块的(组件其实也属于模块的一种)。
require.context()有三个参数:一个要搜索的目录,一个标记表示是否还搜索其子目录, 以及一个匹配文件的正则表达式
说到这也就明白了,require.context就是用来获取模块在导出的(我认为神似 node里的fs和path模块)
现在就可以解释下面的三行代码了:
...(r => {
return r.keys().map(key => r(key).default);
})(require.context('./views', true, /\/route\.js$/))
1. 首先是一个自执行函数并传入了参数 require.context('./views', true, /\/route\.js$/)
2. require.context('./views', true, /\/route\.js$/)的意思是获取views目录下(最下面我会展示views文件夹)所有的route.js文件
3. 大家可能看到 r.keys().map(key => r(key).default) 这一句有点懵逼。下面我贴webpack的源码来说明
var map = { // 这是我项目里的路由信息 由webpack生成
"./Acount/route.js": "./src/views/Acount/route.js",
"./Invoices/route.js": "./src/views/Invoices/route.js",
"./Order/route.js": "./src/views/Order/route.js",
"./Payment/route.js": "./src/views/Payment/route.js"
};
function webpackContext(req) {
var id = webpackContextResolve(req);
return __webpack_require__(id);
}
function webpackContextResolve(req) {
var id = map[req];
if(!(id + 1)) { // check for number or string
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
return id;
}
webpackContext.keys = function webpackContextKeys() {
return Object.keys(map);
};
4. 因为Object.keys返回的是一个数组,我用展开运算符将其展开就变成一项一项的了
复制代码
-
// views
-views
-Admin
-index.vue
-route.js
-User
-xxx
复制代码
-
// route.js
export default {
path: '/admin',
name: 'admin',
component: () => import('./index.vue'),
children: []
}
复制代码
-
解耦 Vuex
- 我本人还是很喜欢用Vuex的,使用频率也非常高。所以将Vuex按照功能分成了不同模块并使用了Vuex内的namespaced属性
- 原理还是基于require.context 不多说了直接上代码
-
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
function importStore(r = require.context('../store', true, /[^(index)].js$/)) {
const cache = {}
r.keys().map(key => cache[key.replace(/(.*\/)*([^.]+).js/ig,"$2")] = r(key).default)
return cache
}
// 不一样的地方是我这里的获取除index.js文件外其他所有js文件。(index是主文件没必要获取)
export default new Vuex.Store({
modules: importStore() // modules字段是Vuex内的modules功能。详情可看文档
})
复制代码
-
上述所说的**namespaced**并不是每个文件都要开启。我在项目中留了一个root.js来存放使用频率最高的state和methods
// root.js文件并没有声明namespaced字段
export default {
state: {
windowWidth: null
},
mutations: {
setWindowWidth(state, payload) {
state.windowWidth = payload
}
},
actions: {
},
getters: {
shouldPC: state => {
if(state.windowWidth == null) {
const width = document.body.clientWidth || document.documentElement.clientWidth
return width > 768? true : false;
}
return state.windowWidth > 768? true : false;
}
}
}
复制代码
-
如何搭建一个 mock server
- mock server是指在本地启动一个服务器并将代理指向该服务器。就能实现前后端分离
- 本项目的mock基于 Koa2 concurrently
- concurrently是一个可以启动多条命令的插件,我们可以基于此命令同时启动vue-server和Koa
-
"scripts": {
"serve": "VUE_APP_RUNNING_SERVICES=dev vue-cli-service serve --mode development",
"build": "VUE_APP_RUNNING_SERVICES=pro VUE_APP_API_ENV='' vue-cli-service build",
"build-pre": "VUE_APP_RUNNING_SERVICES=pre VUE_APP_API_ENV=pre. vue-cli-service build",
"mock": "concurrently 'hotnode server/index.js' 'VUE_APP_RUNNING_SERVICES=mock vue-cli-service serve --mode mockserver'"
}
当执行 npm run mock时便会启动两个服务。根据启动的命令不同会创建不同的env,根据env不同会代理到不同的端口
复制代码
- 如何定义返回数据需要参考Koa文档
-
顺便给大家展示一下我的Koa项目目录
-
-routers
-users.js 功能模块
-index.js 主文件
-books.js 功能模块
复制代码
-
// index.js文件的意义是通过fs导入其他js文件并通过koa-compose组合成一个大的路由文件并注入到中间件
const { resolve } = require('path');
const { resolve } = require('path');
const fs = require('fs');
const compose = require('koa-compose');
const files = fs.readdirSync(resolve(__dirname, './')).filter(file => file !== 'index.js');
const routes = files.map(file => {
return require(resolve(__dirname, './', file)).routes();
});
module.exports = compose(routes);
koa-compose是koa的一个插件,作用是将零散的路由文件集中成一个大的路由文件。这样我就实现了只需要新建js文件 index.js会自动帮我引入所有功能模块并注入在中间件中
复制代码
复制代码
关于项目架构更详细的部分可以看gitlab上的Payment项目
转载于:https://juejin.im/post/5c9efb3ef265da30cb0c3c35