继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

关于Nodejs页面“伪动态化”的初步尝试

花满楼的小前端a
关注TA
已关注
手记 42
粉丝 111
获赞 2213

自从抛弃Express的Jade模板,加上静态资源服务器,花满楼的小站已经全部静态化了(参见:Nodejs基于Express4的动态页面静态化),速度确实提上来了,目前还剩服务器端的优化加速了;为什么要抛弃Jade(包括Express的其他模板)?其实我也还没能力自己造一套模板,待会说说放弃后如何重新选择,不好意思Jade,可能我要将这条路走到底了;

我是个偏外行的小前端,在业余初学Nodejs这一路来,断断续续,胸无大志的只限于捯饬我这个其貌不扬的博客;讲起前端结构,结合各种工具(什么Grunt、Gulp、Webpack、FIS等),打造一套前端工程化的体系,哈哈,那肯定是我,肯定是我没有发言权啊;不过这确实非常诱人和令人向往的,加油!

一开始,前端我是用的Seajs,加上自己造的和网上copy的,弄了一堆自认为的模块和组件作为基础模块,全站由main.js来代理,作为全站的入口,并由他内部分发各个页面的主模块,各个主模块内require基础模块;后来,逐步优化前端资源,可能基础模块划分的有点过细,你知道的,http请求次数感觉有些超标,不愠不火的spm,有点坑,懒得去用了;然后我就换个思路:用Gulp和browserify,将Javascript引入到Nodejs端;首先是将那堆模块改造为符合Nodejs模块化规范的模块,但是没有改造像jQuery这样的偏大的基础类库和公共模块,防止单个文件体积过大;然后,写好Gulp browserify将各个页面的主模块一键编译,这次不用担心太过细分模块导致http请求次数太多,因为browserify会帮你处理依赖并且合并到一起,good job;最后,你就可以像写Nodejs程序一样去require模块,来写你的前端Javascript了;并且由browserify,NPM模块、内部核心模块、你造的模块之间是可以相互共存、相互调用的;当然,即便这样做了,那个作为全站入口的main.js还是可以用的,作用还是差不多;(参见:关于前端结构调整的一次实践

妈呀,好像跑偏了;想必“伪静态”大多数人都听说过或者实践过吧,我仅仅知道.net的URLRewrite,还有短连接什么的,因为确实挺复杂,而且不好维护和管理;呵呵,初入前端,我只对Nodejs情有独钟;我不是要“伪静态”,我就是要静态;Express有这么好用的Router,咱也不必URLRewrite了;是的,我要真静态,同时做到“伪动态”;那么,问题也就来了,全站是你的静态页面,你又抛弃了内置的模板,这一堆静态页面怎么统一管理呢?还有静态页面的缓存也比较严重,总不能老是提醒访客强刷吧,你以为都像你,老按F5啊;

不曾拥有,谈何抛弃;既然已与Jade擦肩而过,全当是一次美丽的邂逅吧,志在远方,活在当下嘛!我得从新做出选择了,按照大众的做法,提取最基础的Header和Bottom;为了保留熟悉的感觉,页面上仅用<Header></Header>和<Bottom></Bottom>来占位吧;Header、Bottom模块大概这样,原谅我弄的比较粗糙,先实现吧:

module.exports=function(host) {
    return [
        '<header>',
            ......
        '</header>'
    ].join('');
};

这样一来,可能会有三个目录;一个是开发时的静态页面,一个是本地重造的静态页面,另一个是准备上线的静态页面;后两者都是重新生成的,别怕麻烦,重点是将提取的公共部分填充到开发时的静态页面里,再分别生成到后两个目录;这样做并不适合所有情况,只适合静态架子的页面,等页面加载后,ajax请求新数据填充的情况,如果要考虑SEO,就不能单独的生成页面了,最好在请求到达时就拿数据填充,同时生成对应的静态页面,response到客户端访问;先完成独立生成的静态页面吧,这种情况也挺常见的,而且这种情况按照这种做法,还有一大好处就是,每次更新不需要重启服务器,直接本地生成好,直接丢服务器上覆盖就是;呵呵,意外的收获;看看怎么重新生成页面到本地测试和备上线目录吧:

var online=false;
var host="localhost:4000";
var header=require('../templs/header.js')(host);
var bottom=require('../templs/bottom.js')(host);
function createStaticPages(name,html,fn) {
    var path='./path/'+name+'.html';
    if (online) {
        path='./path_online/'+name+'.html';
    };
    var ws=fs.createWriteStream(path);
    ws.write(html,function(err) {
        console.log('writePage:'+path);
        fn&&fn();
    });
    ws.on('drain',function() {
        ws.end();
    });
};
function renderStaticPage(name,online) {
    var rs=fs.createReadStream('./pages/'+name+'.html');
    var body=[],size=0;
    rs.on('data',function(data) {
        body.push(data);
        size+=data.length;
    });
    rs.on('error',function(err) {
        console.log(err);
    });
    rs.on('end',function() {
        var buffer=Buffer.concat(body,size);
        var html=buffer.toString();
        var $=cheerio.load(html);
        if ($('header').html()=='') {
            $('header').replaceWith(header);
        };
        if ($('bottom').html()=='') {
            $('bottom').replaceWith(bottom);
        };
        var _html='<!DOCTYPE html><html>'+$('html').html()+'</html>';
        if (online) {
            var _html='<!DOCTYPE html><html>'+$('html').html().replace(/(localhost:4000)/ig,'cdn.famanoder.com')+'</html>';
        };
        createStaticPages(name,reconvert(_html));
    });
};

不多解释了,一般没什么高大上的写法;

然后执行以下代码就能生成好了,提前设置好最上面的变量即可:

(function(files) {
    for(var i in files){
        (function(name) {
            renderStaticPage(name,online);
        })(files[i]);
    }
})([
        'h5lab',
        'minips',
        'sprite'
    ]);

初步尝试,刚刚上线,可能解释的还不怎么详细,还有就是访问及时生成的情况,以后再讨论吧,其实差不多少;关于页面的静态化涉及到的点挺多的,而且有些复杂,还包括服务器端的一些配置和实现,网上大侠们有好多长篇大论,每次看到都长见识了;我这只是实现了简单的静态资源服务器,为了前端上依然潇洒的zencoding,非逼自己保留了html文件,像上面提到的,只在里面做了占位,然后抛弃了Jade,自己弄堆乱七八糟的,来实现统一的管理;不过那个意外的收获多少还是有些令人欣慰的;至于静态页面的缓存,我想还是在src和href里,每次更新文件后手动加版本号什么的吧?或者在本地加好版本号,再生成一次,然后直接丢服务器吧,本地操作总不能也老是嫌麻烦吧,怎么说服务器不用重启了啊;

折腾来折腾去,现在Express项目骨架里的views目录已被我置空了;替换他的是那堆html页面和一些粗制乱造的templs,原谅我这颗时而躁动时而不安分的心,想安静的做个美男子好难的!想来想去,说的还是不够详细,他日走过来时路,再续!

打开App,阅读手记
13人推荐
发表评论
随时随地看视频慕课网APP

热门评论

看了下你的网站,验证码太无语

我通过jade生成静态页面,关键是服务器有cdn的问题,所有css js都需要hashmap来实现样式或脚本即时刷新,以前上线被cdn坑太多了。这样导致每次有bug或样式修改都需要生成一次。有什么好的解决办法?

查看全部评论