midway + vue-cli 从零构建部署前后端分离框架

4,817 阅读2分钟

前言

前端框架和服务端框架搭配的形式多种多样,最近服务端框架在使用 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');
    }
  };
};

到这里就结束了!