前言
前端框架和服务端框架搭配的形式多种多样,最近服务端框架在使用 midway.js ,考虑怎么将前端框架和服务端框架融合在一起花了不少心思。midway.js 相关文档较少,但是它基于 egg.js 开发的,egg关于模版渲染的插件很多。我当时想践行一下自己的想法,就尝试了一下。
之前很多项目前端框架使用的 nuxt ,主要是考虑 nuxt 的服务端直出。但是项目应用场景是千变万化的,nuxt 这个前端框架相对较重,如果我们只是开发一个管理后台,服务端直出的设计理念对我们来说就是完全多余的,于是我就尝试搭配 vue-cli 做了一个前后端分离的初步框架。而且使用 vue-cli 可以灵活的构建前端框架。
相关文档
midway.js官方文档
vue-cli 官方文档
docker 阮一峰入门教程
开始搭建
1. 本地创建一个目录(midway-vue-learn),后面简称 mvl 目录
$ mkdir midway-vue-learn
2. mvl 目录创建好了以后,进入 mvl 文件使用 vue-cli 创建一个 client 目录,该目录是前端服务目录
搭建 vue-cli
$ vue create client
后面的步骤就是脚手架的一些配置选项。这一步骤执行完,就是 vue-cli 的目录结构
3. 创建 server 目录
$ midway-init
4. 在 client 目录创建一个 vue.config.js 文件,该文件是 vue-cli 一个可选的编译配置文件
const path = require('path');
module.exports = {
// 选项...
publicPath: process.env.NODE_ENV === 'production' ? '/public' : '/', // 开发环境和生产环境资源访问地址不一样
outputDir: path.join(__dirname, '../server/src/app/public')
}
5. server 服务配置模版引擎(以 egg-view-nunjucks 为例)
plugin.ts引入插件
nunjucks: {
enable: true, // 是否启用该插件
package: 'egg-view-nunjucks',
}
config.default.ts配置插件
config.view = {
defaultViewEngine: 'nunjucks', // 指定默认模版引擎
mapping: {
'.html': 'nunjucks', // 指定 .html 后缀的文件使用 Nunjucks 进行渲染
},
root: [
path.join(appInfo.baseDir, 'app/public'), // 指定模板文件的根目录
// path.join(appInfo.baseDir, 'path/to/another'),
].join(',')
};
6. 配置渲染 index.html 的路由,新建一个 controller
import { Context, inject, controller, get, provide } from 'midway';
@provide()
@controller('/')
export class HomeController {
@inject()
ctx: Context;
@get('/')
async index() {
await this.ctx.render('index.html');
}
}
到这已经实现前端服务将代码打包到 mdiway 服务的静态目录,通过 controller 将 index.html 渲染出来,当然项目很多地方的配置是需要判断生产与开发环境的,这里主要是演示,接下来我们开始部署了。
开始部署
使用 docker
1. 安装 docker
安装的过程会花点时间
2. 编辑 Dockerfile 文件,该文件与 client、 server 目录同级
# 设置镜像仓库地址
from docker-registry.kuwo-inc.com/alpine-node:latest
# 从上下文目录中复制文件或者目录到容器里指定路径。
add . /app
#设置当前工作目录
workdir /app/client
#安装 npm 包然后打包前端代码
run npm install --registry=https://npm.kuwo-inc.com && npm build
workdir /app/my_midway_app
run npm install --registry=https://npm.kuwo-inc.com && npm build
#服务启动端口
expose 3000
#定义匿名数据卷
volume ["/app"]
#启动服务
cmd ["npm", "start"]
3. 生成镜像
在 Dockerfile 所在目录执行以下命令,创建一个名字为 midway-vue:test 的镜像
$ docker build -t midway-vue:test .
4. 启动镜像
$ docker run -it -p 3001:3000 midway-vue:test
这时候我们的 docker 服务已经起来了,访问地址:localhost:3001 ,发现页面访问显示
折腾了一会时间发现了问题所在,midway 框架打包的时候默认配置是没有将静态目录同步到 dist 目录的,需要在 package.json配置一下
"midway-bin-build": {
"include": [
"app/public" //同步静态目录
]
},
最后,我们再重新创建一下镜像,启动镜像,就可以了
部署相关问题
由于我们项目最终是以 vue 单页面应用形式呈现的, 我们使用 vue-router的时候,你很可能会采用 history 模式,因为 hash 模式很丑,这样我们除了首页以外的所有页面访问都是
这是因为我们只匹配了
/ 路由,像这样的路由 /***,服务是没有定义的,所以就 404。
解决这个问题,我是这样处理的,在我们 midway 服务添加一个中间件,将 /api开头的地址(接口路由)、/public 开头的地址(静态目录)排除后,其他地址都用来渲染页面。
src/app/middleware 目录创建一个 view.ts
module.exports = () => {
return async function auth(ctx, next) {
const url = ctx.request.url;
if (/^\/api|^\/public/.test(url)) {
await next()
} else {
await ctx.render('index.html');
}
};
};
到这里就结束了!