多网页应用,一直以来都是比较常见的,但如何更高效的开发,自动的构建多页应用?以下是我在网页开发中的最佳实践。github演示源代码:build-multi-page-webapp-boilerplate

什么是multi-page 网页应用

我认为multi-page 网页应用就是:网页是多个页面(HTML)组成的,页面之间的切换是通过超链接完成的。

这通常也是最传统的开发模式。

随着移动互联网,APP迅速发展,网页开发者似乎更热衷于程序APP化,也就是单页化,模块化,但是多页应用仍然在很多领域具有难以替代的优势,更利于SEO,更利于分工协作… 比如内容类的网站,商城,社交平台,开发模式已经很多年,后端程序员书写逻辑,前端程序员写页面UI,最后前后合并,并通过服务器模版渲染。

现阶段前端程序员通常做法

每个页面重复引用公用的css(比如bootstrap…),js(比如jquery…)

这种做法是很偷懒的方式,也是比较随意的方式,但到最后你会发现以后代码会很难进行维护管理。

一般来说,服务器端模版引擎都支持模版extend以及include,比如freemarkerJinja2…,我们将公用的代码写在base里,所有模版都继承base,可以更容易对基础模版更改,而不用动所有page.

网页里混杂各种style以及script

网页里混写着各种行样式、段落样式,以及script,这样看上去没什么问题,但是HTML似乎变得更乱,难于维护。如果HTML文件里style,script超过10行建议还是单独写入文件中,然后在HTML里引入,有人会说单独俩文件,会多出两次HTTP请求,实际上互联网最占带宽的是图片、视频,您一个几K的文件基本上可以忽略不计,况且带宽是可以按需购买,同时又有各种缓存技术方案(CDN…)

开发完成后(手动或者通过改变程序version)去更改style,script文件版本号

经常会看到类似:

1
2
3
<link rel="stylesheet" href="http://xxxx/index.css?t=1468316716781">
...
<script src="http://xxxx/index.js?v=20111107" type="text/javascript"></script>

在引入的文件后面加入版本号,为的是防止客户端缓存文件,而得不到最近的更新。 这种做法非常容易出错,下面会讲到如何用inject工具来解决这个问题。

multi-page建议开发模式

利用服务端模版引擎extendinclude, 减少重复HTML代码

nunjucks模版为例,我们通常会定义一个基础模版base.html,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"/>
<title>{% block title %}{% endblock %}</title>
{% block style %}{% endblock %}
</head>
<body>
{% block header %}
<header></header>
{% endblock %}
{% block content %}{% endblock %}
{% block script %}{% endblock %}
</body>
</html>

然后每个页面继承自base,程序员只写本页面关注的内容(去掉重复书写<!DOCTYPE html>等内容)。以index.html为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{% extends "base.html" %}
{% block title %}Home Page{% endblock %}
{% block style %}
<link rel="stylesheet" href="http://xxxx/index.css?t=1468316716781">
{% endblock %}
{% block content %}
<div class='viewport'>
<div>This is home page</div>
</div>
{% endblock %}
{% block script %}
<script src="http://xxxx/index.js?v=20111107" type="text/javascript"></script>
{% endblock %}

分离出每个页面的style,script

我们将每个页面的style,script分离到单独的文件中,然后用Gulp来集中管理。

利用Gulp构建整个项目

说到项目构建,从最初的gruntgulp到现在更流行的webpack,都是为了更好将组织前端代码,提高生产力。运用gulp我们可以将每一个页面都当成一个Task,到时我们只需要运行脚本执行每一个Task,就完成了整个项目的构建。
说白了,每个页面可能含有多个css,js文件,我们可以提取出css,js文件,用gulp分别对其进行合并,压缩,注入。

  1. 合并

    假设一个页面,含有N个js文件,N个css文件,我们先将这N个js, N个CSS按顺序合并.

  2. 压缩

    我们将上一步合并的文件,进行ugly压缩,去除注释,空格,替换变量等。

  3. 注入

    也就是注入到HTML,我们将上一步压缩过的代码,重命名(加hash后缀),然后通过inject工具gulp-inject,注入到HTML中(代码不是通过script,或link引入的,而是inject注入进去的)。

预编译CSS

既然用了Gulp来构建整个项目,严重推荐使用预编译语言stylus, scss, less 来编写样式,最后集成到gulp项目里。因为css语言特性太不智能,例如不支持变量、嵌套,继承, mixin…,当项目大时候,对整个项目的开发是一种拖累。

总结

本文只是提供了一种思路,具体请查看github演示源代码:build-multi-page-webapp-boilerplate