利用gulp解決前後端分離的header/footer引入問題

呂大豹發表於2016-03-26

在我們進行前後端完全分離的時候,有一個問題一直是挺頭疼的,那就是公共header和footer的引入。在傳統利用後端渲染的情況下,我們可以把header、footer寫成兩個單獨的模板,然後用後端語言的include即可在其他頁面中引入。我之前在《一個簡單粗暴的前後端分離方案》這篇文章中說過一種方法,就是用handlebars把header、footer模板預編譯為js檔案,然後在頁面的頭部用document.write寫到頁面中。這種方式的弊端也比較明顯,那就是依賴一個模板引擎。在使用mvvm框架比較普遍的今天,靜態模板的使用率似乎不是那麼高了,所以我們不能過度依賴它。

事實上,如果我們的專案使用了gulp構建,是可以很輕鬆的利用gulp來完成頁面的組建的。我們可以照樣把header、footer寫成兩個模板,然後利用gulp把這兩個模板拼接到各個頁面中,同樣能達到可複用、便於修改的目的。

需要用到的模組有:gulp、fs、gulp-replace這三個,定義一個task如下:

//引入頭部底部
gulp.task('include', function() {
    var htmlDir = './html/';
    fs.readdir(htmlDir, function(err, files) {
        if (err) {
            console.log(err);
        } else {
            files.forEach(function(f) {
                if (f !== '_header.html' && f !== '_footer.html') {
                    gulp.src(htmlDir + f)
                        .pipe(replace(/<!--header-->[\s\S]*<!--headerend-->/, '<!--header-->\n' + fs.readFileSync(htmlDir + '_header.html', 'utf-8') + '\n<!--headerend-->'))
                        .pipe(replace(/<!--footer-->[\s\S]*<!--footerend-->/, '<!--footer-->\n' + fs.readFileSync(htmlDir + '_footer.html', 'utf-8') + '\n<!--footerend-->'))
                        .pipe(gulp.dest(htmlDir))
                }
            });
        }
    });
});

簡單解釋一下,首先利用fs模組來讀取目標目錄下的檔案,我這裡是./html/,然後遍歷各個檔案,把檔案中的佔位符<!--header--><!--headerend-->和<!--footer--><!--footerend-->分別替換為_header.html和_footer.html中的內容,最後在輸出到原目錄下就OK了。

既然是需要替換佔位符,那麼我們的頁面結構應該是這樣的,例如index.html

<!--header--><!--headerend-->
    <div>
        index頁面
    </div>
    <script>
        
    </script>
<!--footer--><!--footerend-->

在頂部和底部分別寫如上的佔位標誌。執行gulp後就會被相應的替換為header模板和footer模板中的內容了。

_header.html中的內容如下,是一個html頁面的上半截:

<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1, user-scalable=no">
        <meta name="apple-mobile-web-app-capable" content="yes">
        <meta name="apple-mobile-web-app-status-bar-style" content="black">
        <link rel="stylesheet" href="/css/main.css">
        <script src="/lib/require.js"></script>
        <script src="/js/common/config.js"></script>
    </head>
    <body>

_footer.html中的內容,則是下半截:

    </body>
</html>

為什麼要用replace替換佔位符的方式,而不用concat直接把內容給追加到頁面呢?這是考慮到gulp任務可能執行多次的情況,重複追加內容無法控制,所以用正則匹配替換內容的方式,無論任務執行多少次都不會重複追加內容。

事實上,為了能夠讓header、footer模板修改的時候,其他頁面也能自動更新內容,我們可以再加一個watch任務:

gulp.task('watch', function() {
    gulp.watch(['./html/_header.html', './html/_footer.html'], ['include']);
});

這樣我們啟動這個watch任務的時候,就可以實時監聽header、footer的改動並且動態更新所有頁面的內容了。

相關文章