Views&Static

這章節的教學將會包含如何使用使用views中間件渲染模板,動態的產生網頁內容。另一個主題是設定static中間件,讓我們可以簡單的傳送一些靜態物件,如圖片、音效、影片、腳本等等。

Views

前面幾個教學到現在我們總是簡單的回傳一些字串給前端

    
router.get('/', async (ctx) => {
    ctx.body = "<h1>Hello Koa</h1>";
});

在第一章的時候,我們也曾經使用readFile的方式,載入預寫好的html檔案,但是這種方式難以架構一個具有大型規模的網站。我們網頁上的資訊必須動態產生,如先讀取資料庫後動態的調整頁面的內容。如果我們用傳統的方式的話,光是字串處理的時間就會消磨掉一大半。幸運的是在Javascript龐大的模組庫中,我們有許多種模板引擎可以進行選擇。所謂的模板就是,我們先預定好一些html,並且在其中設定幾個空格,我們僅需要告訴模板引擎這些空格該填些什麼,模板引擎會幫我們把html渲染好,回傳回前端。

本文中使用的模板語言是pug(jade),但是不會特別的去說明如何撰寫pug
詳細pug的撰寫方法可以參考 Pug getting Started

安裝koa-views以及pug

    
yarn add koa-views @types/koa-views

準備需要渲染的模板

這個部分我們預計做出一個讓YouTube循環播放的網頁。當瀏覽/loop/YJSpGXxkCqE時我們會重複播放YJSpGXxkCqE這個影片。

首先我們在專案底下新增一個views的資料夾,這個資料夾是專門用來放置模板的。

    
mkdir views

先來觀察一下內嵌循環播放的html長怎樣。

    
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Youtube Looper</title>
</head>
<body>
    <h1>Awesome Youtube Looper</h1>
    <iframe src="https://www.youtube.com/v/YJSpGXxkCqE?version=3&loop=1&playlist=YJSpGXxkCqE" frameborder="0"></iframe>
</body>
</html>

觀察第11行iframe的src參數https://www.youtube.com/v/YJSpGXxkCqE?version=3&loop=1&playlist=YJSpGXxkCqE,我們需要動態調整的地方為兩個YJSpGXxkCqE的部分。

因此我們撰寫一個模板looper.pug放置在views資料夾

    
<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        meta(http-equiv="X-UA-Compatible", content="ie=edge")
        title My awesome youtube looper
    body
        h1 Awesome Youtube Looper
        iframe(src=`https://www.youtube.com/v/${VideoID}?version=3&loop=1&playlist=${VideoID}`, frameborder="0" allowfullscreen)

這個模板會根據我們傳送給他不同的VideoID變數,渲染出不同的網頁。

使用koa-views中間件

既然有了模板,那我們可以使用routing

    
// views.ts
import Koa = require('koa');
import Router = require('koa-router');
import Path = require('path');
import Views = require('koa-views');

const app = new Koa();
const router = new Router();

app.use(Views(Path.join(__dirname, 'views'), {
    extension: 'pug',                   // 預設模板的副檔名為.pug
    map: {
        pug: 'pug',                     // 映射.pug檔到pug模板引擎
    },
}));

router.get('/loop/:VideoID', async (ctx) => {
    await ctx.render('index', {         // 因為我們有設定預設副檔名為.pug,所以不需要打index.pug
        VideoID: ctx.params.VideoID,    // 將變數傳給模板引擎
    });
});

app.use(router.routes()).use(router.allowedMethods());

app.listen(3000);


References:
1. queckezz/koa-views
2. koajs/static 3. pug 所有範例中的程式碼皆放置在koa-tutorial-sample專案中