Egg + Vue 服務端渲染開發指南
1. 專案初始化
安裝腳手架
npm install easywebpack-cli -g
命令列,然後就可以使用easywebpack
或easy
命令命令列執行
easywebpack init
選擇 egg+vue server side render boilerplate 初始化骨架專案
安裝依賴
npm install
1.2 通過骨架專案初始化
git clone https://github.com/hubcarl/egg-vue-webpack-boilerplate.git
npm install
初始化的專案提供多頁面和SPA(vue-router/axios)服務端渲染例項,可以直接執行。
2. 專案執行
2.1 本地執行
npm start
npm start 做了如下三件事情
- 啟動 egg 應用
- 啟動 Webpack 構建, 檔案不落地磁碟,構建的檔案都在記憶體裡面(只在本地啟動, 釋出模式是提前構建好檔案到磁碟)
- 構建會同時啟動兩個 Webpack 構建服務, 客戶端js構建埠9000, 服務端埠9001
- 構建完成,Egg應用正式可用,自動開啟瀏覽器
2.2 釋出模式
- 構建檔案落地磁碟
npm run build 或 easywebpack build prod
- 啟動 Webpack 構建,檔案落地磁碟
- 服務端構建的檔案放到
app/view
- 客戶端構建的檔案放到
public
目錄 - 生成的
buildConfig.json
和manifest.json
放到config
目錄 構建的檔案都是gitignore的,部署時請注意把這些檔案打包進去
- 執行
啟動應用前, 請設定 EGG_SERVER_ENV
環境變數,測試環境設定 test
, 正式環境設定 prod
npm start
3. 專案構建
通過
easywebpack-cli
統一構建,支援 dev,test,prod 模式構建easywebpack-cli
通過專案根目錄下的webpack.config.js
配置檔案構造出 Webpack 實際的配置檔案,配置項請見- 獲取 Webpack 實際的配置檔案, egg-webpack 會使用到該功能。構建會根據
webpackConfigList.length
啟動對應個數的 Webpack 編譯例項,這裡會同時啟動兩個 Webpack 構建服務, 客戶端jsbundle構建,埠9000, 服務端jsbundle構建埠9001。預設埠為9000, 埠依次遞增。
// config/config.local.js 本地 npm start 使用
const EasyWebpack = require('easywebpack-vue');
exports.webpack = {
webpackConfigList:EasyWebpack.getWebpackConfig()
};
- 該專案中,
app/web/page
目錄中所有 .vue 檔案當作 Webpack 構建入口是採用 app/web/framework/vue/entry 的 client-loader.js 和 server-loader.js 模板實現的,這個需要結合webpack.config.js
下的 entry.loader 使用。
entry: {
include: ['app/web/page', { 'app/app': 'app/web/page/app/app.js?loader=false' }],
exclude: ['app/web/page/[a-z]+/component', 'app/web/page/app'],
loader: { // 如果沒有配置loader模板,預設使用 .js 檔案作為構建入口
client: 'app/web/framework/vue/entry/client-loader.js',
server: 'app/web/framework/vue/entry/server-loader.js',
}
}
上面 { 'app/app': 'app/web/page/app/app.js?loader=false' }
這個 loader=false
的含義表示 app/web/page
目錄下的 app/app.js
不使用 entry.loader 模板。因為這個app/app.js是一個SPA服務端渲染Example,實現邏輯與其他普通的頁面不一樣,不能用 entry.loader 模板, 這個功能在自定義entry檔案構建規範時使用。
4. 專案規範
- Vue 專案程式碼放到 app/web 目錄,頁面入口目錄為 page,該目錄的 所有 vue 檔案預設會作為 Webpack 的 entry 構建入口。建議每個頁面目錄的只保留一個vue檔案,vue關聯的元件可以放到widget 或者 compnent目錄。如果非要放到當前目前,請配置
webpack.config.js
entry.exclude 排除 vue檔案。
5. 專案開發
支援多頁面/單頁面服務端渲染, 前端渲染, 靜態頁面三種方式.
5.1 多頁面服務端渲染實現
5.1.1 多頁面前端頁面實現
在app/web/page 目錄下面建立home目錄, home.vue 檔案, Webpack自動根據.vue檔案建立entry入口, 具體實現請見webpack.config.js
- home.vue 編寫介面邏輯, 根元素為layout(自定義元件, 全域性註冊, 統一的html, meta, header, body, 你可以自定義 title,description,keywords SEO資訊,更多資訊請擴充套件layout).
<template>
<layout title="基於egg-vue-webpack-dev和egg-view-vue外掛的工程示例專案" description="vue server side render" keywords="egg, vue, webpack, server side render">
{{message}}
</layout>
</template>
<style>
@import "home.css";
</style>
<script type="text/babel">
export default {
components: {
},
computed: {
},
methods: {
},
mounted() {
}
}
</script>
5.1.2 多頁面後端渲染實現, 通過 egg-view-vue-ssr
外掛 render
方法實現
- 建立controller檔案home.js
exports.index = function* (ctx) {
yield ctx.render('home/home.js', { message: 'vue server side render!' });
};
- 新增路由配置
app.get('/home', app.controller.home.home.index);
5.1.3 多頁面走前端渲染(後端路由)實現, 通過 egg-view-vue-ssr
外掛 renderClient
方法實現
- 建立controller檔案home.js
exports.client = function* (ctx) {
yield ctx.renderClient('home/home.js', { message: 'vue server side render!' });
};
- 新增路由配置
app.get('/client', app.controller.home.home.client);
5.2 HTML靜態頁面前端渲染
直接有easywebpack構建出靜態HTML檔案, 請見
webpack.config.js
配置和app/web/page/html
程式碼實現通過
egg-static
靜態檔案訪問HTML檔案
5.3 單頁面伺服器渲染同構實現
5.3.1 單頁面前端實現
在app/web/page 目錄下面建立app目錄, app.vue, app.js 檔案.
- app.vue 編寫介面邏輯, 根元素為layout(自定義元件, 全域性註冊, 統一的html, meta, header, body)
<template>
<app-layout>
<transition name="fade" mode="out-in">
<router-view></router-view>
</transition>
</app-layout>
</template>
<style lang="sass"></style>
<script type="text/babel">
export default {
computed: {
},
mounted(){
}
}
</script>
- app.js 頁面呼叫入口
import { sync } from 'vuex-router-sync';
import store from 'store/app';
import router from 'component/app/router';
import app from './app.vue';
import App from 'app';
import Layout from 'component/layout/app';
App.component(Layout.name, Layout);
sync(store, router);
export default App.init({
base: '/app',
...app,
router,
store
});
5.3.2 單頁面後端實現
- 建立controller檔案app.js
exports.index = function* (ctx) {
yield ctx.render('app/app.js', { url: this.url.replace(/\/app/, '') });
};
- 新增路由配置
app.get('/app(/.+)?', app.controller.app.app.index);
6. 專案部署
- 正式環境部署,請設定
EGG_SERVER_ENV=prod
環境變數, 更多請見執行環境 - 構建的
app/view
目錄,public
目錄以及buildConfig.json
和manifest.json
等檔案, 都是gitignore
的,部署時請注意把這些檔案打包進去。