簡單構建 ThinkJS + Vue2.0 前後端分離的多頁應用

語言: CN / TW / HK

最近在使用 ThinkJS + Vue2.0 寫一個簡單的項目,該項目分為用户端和管理界面,分別對應 vue 的兩個頁面indexadmin,用户端、管理界面自身是基於 vue 構建的單頁應用,服務端採用 thinkjs 的提供 api。

項目目錄結構如下:

.
├── README.md
├── client
│   ├── README.md
│   ├── build
│   ├── config
│   ├── package.json
│   ├── src
│   │   ├── components
│   │   ├── modules
│   │   └── pages
│   │       ├── admin
│   │       └── index
│   └── static
└── server
    ├── src
    │   ├── bootstrap
    │   ├── config
    │   ├── controller
    │   │   ├── admin
    │   │   ├── base.js
    │   │   ├── home
    │   │   └── index.js
    │   ├── logic
    │   └── model
    ├── view
    │   ├── admin.html
    │   └── index.html
    └── www
        └── static


複製代碼

client 的配置

直接使用 vue 官方的 vue-cli 創建項目,選擇使用 webpack 構建。

修改config/index.js,給 webpack-dev-server 添加 proxyTable:

    proxyTable: {
      '/api' :  {
        target: 'http://localhost:8360/api/',
        changeOrigin: true,
        pathRewrite: {
          '^/api': '/'
        }
      }
    },


複製代碼

然後參照《使用 Vue-cli 搭建多頁面應用時對項目結構和配置的調整》的方法將其改為多頁應用,具體方法為:

調整項目目錄,創建src/pages/index,將src/assetssrc/routersrc/App.vuesrc/main.js./index.html移動到該目錄中,並將main.js改名為index.js

修改構建腳本build/utils.js,添加:

var glob = require('glob')
    
var HtmlWebpackPlugin = require('html-webpack-plugin')

var PAGE_PATH = path.resolve(__dirname, '../src/pages')
    
var merge = require('webpack-merge')





exports.entries = function() {
    var entryFiles = glob.sync(PAGE_PATH + '/*/*.js')
    var map = {}
    entryFiles.forEach((filePath) => {
        var filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
        map[filename] = filePath
    })
    return map
}



exports.htmlPlugin = function() {
    let entryHtml = glob.sync(PAGE_PATH + '/*/*.html')
    return entryHtml.map((filePath) => {
        let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
        let conf = {
            
            template: filePath,
            
            filename: filename + '.html',
            
            chunks: ['manifest', 'vendor', filename],
            inject: true
        }
        if (process.env.NODE_ENV === 'production') {
            conf = merge(conf, {
                minify: {
                    removeComments: true,
                    collapseWhitespace: true,
                    removeAttributeQuotes: true
                },
                chunksSortMode: 'dependency'
            })
        }
        return new HtmlWebpackPlugin(conf)
    })
}


複製代碼

修改build/webpack.base.conf.js的入口配置:

module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: utils.entries(),

  ...
  ...
}


複製代碼

修改build/webpack.dev.conf.jsbuild/webpack.prod.conf.js的插件配置:

  plugins: [
    ...

    
    ...utils.htmlPlugin(),

    ...
  ]


複製代碼

創建 src/pages/admin 目錄,添加admin.html文件:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta >
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <h1>Admin</h1>
</body>
</html>


複製代碼

創建 src/pages/404 目錄,添加404.html文件:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta >
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>404</title>
</head>
<body>
  <h1>404 Not Found</h1>
</body>
</html>


複製代碼

修改 webpack-dev-server 的路由表:

    historyApiFallback: {
      rewrites: [
        { from: /^\/$/, to: '/index.html' },
        { from: /^\/admin\/?$/, to: '/admin.html' },
        { from: /./, to: '/404.html' }
      ],
    },


複製代碼

至此 client 端的配置就完成了,可以通過 npm start 啟動 client 端,通過 http://localhost:8080 訪問頁面。

server 的配置

直接使用 ThinkJS 官方的 think-cli 創建項目,修改src/config/router.js,添加路由:

module.exports = [
  [/^\/api\/(.*)/i, '/:1'],
  [/^\/$/i, '/'],
  [/^\/admin\/?$/i, '/index/admin'],
  [/\//, 'index/_404', 'get']
];


複製代碼

修改src/controller/index.js渲染模板:

const Base = require('./base.js');

module.exports = class extends Base {
  indexAction() {
    return this.display('index.html');
  }
  adminAction() {
    return this.display('admin.html');
  }
  _404Action() {
    return this.display('404.html');
  }
};


複製代碼

至此服務器的配置完成,啟動 server 端,client 可通過 http://localhost:8080/api 訪問 API。

開發服務端 API

在 server 中任意 controller 暴露的 API 可以通過 /api/controller/action 來訪問,比如:

const Base = require('./base.js');

module.exports = class extends Base {
  indexAction() {
    return this.success('test');
  }
};


複製代碼

可以通過 http://localhost:8080/api/test 訪問:

{
  errno: 0,
  errmsg: "",
  data: "test"
}


複製代碼

添加新頁面 abc

在 client 的 src/pages 目錄下創建新的頁面 src/pages/abc/abc.html,同時修改 webpack.dev.config.js,historyApiFallback 中添加新的頁面路由。

    historyApiFallback: {
      rewrites: [
        { from: /^\/$/, to: '/index.html' },
        { from: /^\/admin\/?$/, to: '/admin.html' },
        { from: /^\/abc\/?$/, to: '/abc.html' },
        { from: /./, to: '/404.html' }
      ],
    },


複製代碼

在 server 的 src/controller/index.js 中創建新的 action

const Base = require('./base.js');

module.exports = class extends Base {
  ...
  abcAction() {
    return this.display('abc.html');
  }
  _404Action() {
    return this.display('404.html');
  }
};


複製代碼

修改 router.js 添加新路由:

module.exports = [
  [/^\/api\/(.*)/i, '/:1'],
  [/^\/$/i, '/'],
  [/^\/admin\/?$/i, '/index/admin'],
  [/^\/abc\/?$/i, '/index/abc'],
  [/\//, 'index/_404', 'get']
];


複製代碼

分別重啟 sever、client 即可。

生產環境構建

生產環境構建非常簡單,直接在 client 下運行npm run build,將dist下生成的文件*.html拷貝到 server 的view目錄下,將dist/static目錄拷貝到 server 的www目錄下,然後將 server 部署到生產環境運行即可。