做一个CLI版的时间管理工具(13)
前言
在前一篇文章中加入了一个启动Web服务的指令timec page
本期就继续完善这个指令的效果
本期效果预览
功能开发
Web侧
拟采用Vue3开发页面
安装项目依赖
sh
yarn add vue@next @vue/compiler-sfc @vitejs/plugin-vue
快速创建一个基于Vite+Vue3的模板项目
sh
npm init vite@latest my-vue-app --template vue
完成后的目录结构如下
sh
my-vue-app
├── index.html
├── package.json
├── public
| └── favicon.ico
├── src
| ├── App.vue
| ├── assets
| ├── components
| └── main.js
└── vite.config.js
我们将vite.config.js
,main.js
,components
,App.vue
,index.html
这五部分的内容拷贝到我们项目的src/page
目录下
拷贝完后的目录如下
sh
├── App.vue
├── assets
| └── logo.png
├── components
| └── HelloWorld.vue
├── index.html
├── main.js
└── vite.config.js
接着改造一下timec page
指令中的逻辑:
- 定位到
vite.config.js
文件的位置 - 使用
--config
指定配置文件的位置 - 在
spawn
调用的方法中传入设置配置文件的参数
js
const cwd = path.resolve(__dirname, '../');
const viteConfigPath = path.join(cwd, 'src/page/vite.config.js');
const serveService = spawn('node_modules/.bin/vite', ['src/page', '--host', '--config', viteConfigPath], {
cwd,
stdio: 'inherit',
});
// 。。。code
到这一步前端工程的基本内容算搭好了,页面展示需要的数据,需通过Node相关的API才能获取,这里有两种方案:
- 页面使用SSR(服务端渲染)方案
- 添加一个后端服务,通过接口调用传递所需要的数据
项目采用第二种方案,下面展开介绍一下简单后端服务的搭建
服务端
这里使用自己DIY的玩具框架flash-wolves
安装依赖
sh
yarn add flash-wolves
编写基本调用逻辑,在src/page下创建一个文件server.js
- 使用
Node
执行这3行代码,这样一个简单的后端服务就在3001端口启动了
js
const { Fw } = require('flash-wolves');
const app = new Fw();
app.listen(3001);
编写2个接口:
- 获取配置文件
- 获取所有的数据(按天区分)
js
app.get('/json', (req, res) => {
const config = getConfig();
const { recordFilepath } = config;
if (fs.existsSync(recordFilepath)) {
res.success(getJSON(getFileContent(recordFilepath)));
return;
}
res.fail(500, 'not set default recordFilepath');
});
app.get('/config', (req, res) => {
const config = getConfig();
res.success(config);
});
在什么时候启动这个服务?
当然是和启动Web服务的时候一起启动
这就需要我们在timec page
指令中添加启动后端服务的逻辑:
- 同样使用
spawn
创建子进程启动后端服务 - 在客户端服务关闭的时候,杀死这个后端服务的子进程
js
const server = spawn('node', ['src/page/server.js'], {
cwd,
stdio: 'inherit',
});
serveService.on('close', (code) => {
server.kill('SIGSTOP');
process.exit(code);
});
客户端如何访问这些接口?:
- 为了降低项目复杂性,这里直接调用fetch方法获取后端接口的数据
- 单独建立一个文件
src/page/api.js
存放这些逻辑
js
export function getConfig() {
return fetch('http://localhost:3000/config');
}
export function getEveryDayData() {
return fetch('http://localhost:3001/json').then((res) => res.json());
}
由于Web会受同源策略限制,这里在Fw
实例化函数里加入以下逻辑开启CORS,解决跨域问题
js
const app = new Fw((req, res) => {
// 开启CORS
const { method } = req;
// 允许跨域
res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
// 跨域允许的header类型
res.setHeader('Access-Control-Allow-Headers', '*');
// 允许跨域携带cookie
res.setHeader('Access-Control-Allow-Credentials', 'true');
// 允许的方法
res.setHeader('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
// 设置响应头
res.setHeader('Content-Type', 'application/json;charset=utf-8');
// 对预检请求放行
if (method === 'OPTIONS') {
res.statusCode = 204;
res.end();
}
});
这样简单的前后端逻辑就都写好了,下面就是一键启动
sh
timec page
最后
由于每天空闲时间有限,本文就先到这,下一期将继续完善timec page
指令
如果读者还感觉意犹未尽,敬请期待后续更新,或持续关注一下仓库的状态
欢迎评论区提需求,交流探讨
本系列会不断的更新迭代,直至产品初代完成