個人的には久々に耳にしたSSI。
#include ...
等の記法でHTML内に別のコンテンツを埋め込んだりするものですが、grunt-contrib-connect標準ではSSIに対応しておらず、ローカルで確認しようにもすぐには見ることができません。
このためにローカルにapache立てるのも面倒なので、connectのmiddlewareで対応することに。
node.jsのssi関連は、
等がありますが、#include virtual=...
に対応しているのはnode-ssiだけのようですので、それを採用しました。
node-ssiのインストール
まずは、npmでssiパッケージをインストールします。
npm install ssi --save-dev
Gruntfileの修正
Gruntfileの上部でfs
、util
、ssi
を定義。
Gruntfile.coffee
module.exports = (grunt) ->
require('load-grunt-tasks') grunt
fs = require 'fs'
url = require 'url'
ssi = require 'ssi'
... snipped ...
その後、connectの設定で以下のようにmiddleware
を定義します。
- req(リクエストオブジェクト)からリクエストURLを取得
- 「/」で終わっていたら、「index.html」を足す
- ファイルが存在し、且つファイル名が「.html」「.shtml」で終わっていれば、SSIパース処理をして返す
- そうでなければ、標準のstaticに処理を渡す
Gruntfile.coffee
... snipped ...
connect:
server:
options:
port: 8000
base: '.'
middleware: (conn, opt) ->
opt.base = [opt.base] unless Array.isArray opt.base
middlewares = []
middlewares.push (req, res, next) ->
urlobj = url.parse req.originalUrl
filename = __dirname + urlobj.pathname + if urlobj.pathname.substr(-1) is '/' then 'index.html' else ''
if fs.existsSync(filename) and filename.match(/\.s?html$/)
parser = new ssi(__dirname, '', '')
content = parser.parse(filename, fs.readFileSync(filename, {encoding: 'utf8'})).contents
res.writeHead 200,
'Content-Type': 'text/html'
'Content-Length': Buffer.byteLength content, 'utf8'
res.end content
else
next()
for base in opt.base
middlewares.push conn.static(base)
middlewares
... snipped ...
これで、SSIを使ったコンテンツが来てもとりあえずはローカルでしのげます。
需要があるかは謎。
- 2014/04/21
QueryString対応のため、
urlobj.path
->urlobj.pathname
に修正