前言
作为一名前端开发者,刀耕火种的年代随着 NodeJS 等工具的出现,已经一去不复返了。如果你还停留在写着冗长的HTML代码,不断重复着复制粘贴,那么你应该继续学习了。
之所以写这篇文章,是源于前段时间我的一个Github个人主页项目。因为是要放在Github上的,所以只能是静态站点,那么所有静态页面如果一个一个手写的话,是很痛苦的。没有了后台程序,如何去定义模板文件?总不至于每个页面中都写上相同的 header 和 footer 吧。可以使用 Sass 去写 CSS 吗?可以使用 CoffeeScript 去写 JavaScript 吗?可以使用 Markdown 去写HTML内容吗?可以使用 Jade 去写HTML结构吗?
带着这些疑问,我将一步一步实现一个自动化的前端静态站点项目。
环境准备
Mac 或 Linux,不推荐Windows下开发,因为你会遇到很多蛋疼的问题,从本质上来说,你应该开始在Linux下做开发了。
如果你像我一样还在使用 Windows,可以安装一个Ubuntu虚拟机,然后通过 Samba 共享文件,用 SSH 和 Windows做连接,最终就能实现在你熟悉的 Windows下做开发(编辑文件),而运行环境却是 Linux。
1、创建项目
不管做什么开发,我们都应该遵循一定的规范,创建项目同样要注意文件夹的名字和结构。首先创建一个如下的基础项目结构,暂且就将项目命名为 auto-web:
![](https://box.kancloud.cn/2016-02-29_56d3fe805f83e.jpg)
简单解释一下:
/src 源文件所在地。开发过程中的各种CSS和JS源文件都往这里面放。
/dist 目标文件所在地。上线前通过工具生成的CSS和JS目标文件都输出到这里。
/images 图片文件。
/vendor 第三方的 CSS、JS 和字体文件都存放到这里。
/views HTML 视图文件。
当然目前我们是手动创建的,可以设想一下,利用NodeJS,我们是完全可以做到一条命令创建出这样的文件夹结构。
2、从 index.html 开始
首先我们习惯性地创建一个 index.html 页面
<!DOCTYPE html><html>
<head>
<meta charset="utf-8" />
<title>Hello world</title>
</head>
<body>
<h2>这是我的个人主页</h2>
</body></html>
3、我想用 Jade
什么是 Jade ? - Jade 是 Node 的一个模板引擎,一句话就是让我们能够更快更简便地写HTML,大家可以去 Jade 的 官网,由于其主要是靠缩进来定义结构,所以一般都能够很快地学会这种写法。
类似的模板引擎在 Rails 里面也有一个叫 Slim 。当然有很多开发者是不喜欢用类似的方式去开发,不过我们这里仅作为一个示例,具体用还是不用取决于你自己。
OK,咱们来将 index.html 换成 Jade。
首先,咱们在 /views 文件夹下创建一个 index.jade 文件,然后输入下面的内容:
doctype htmlhtml
head
meta(charset="utf-8")
title Hello world
body
h2 这是我的个人主页
这和上面的 index.html 是完全一样的。那么我们可以对比一起两种写法:
![](https://box.kancloud.cn/2016-02-29_56d3fe806f5c3.jpg)
在 HTML 代码量越大的情况下,Jade 的写法就越有优势了。当然还是那句话,用与不用都取决于你自己的爱好。
OK,到此为止,我们已经写好了一个 HTML的模板引擎。
直接点击 index.jade 能运行吗?肯定是不行的。在这里我得强调一下,我们所要做的额外的工作,不是为了运行项目,而是为了开发项目。就好比我们都要去北京,只不过你是走路去的,而我是坐飞机去的,目的一致,优化了开发流程而已。
明白了这一点,我们就知道,应该将 index.jade 转换成 index.html 了。
该如何转换呢?这必然得用上工具了,咱们需要一门后台语言的命令行工具,Ruby?Python? 对,他们都能完成这份工作。但我们是前端,自然最佳选择就是 NodeJS 了。
4、该 NodeJS 出场了
相信大家也都对 NodeJS 有过一定的了解,咱们先不要求精通,只要知道怎么使用即可。
首先咱们去 NPM 中查找要用到的 jade 包,找到 mmand Line 命令行,首先按照文档说的安装(必要时前面加上 sudo):
$ npm install jade -g
这里的 npm 是 Node 的一个包管理器,也就是通过类似上面的命令去安装程序中需要用到的包。
然后通过 jade --help 可以看到如何将一个 Jade 文件转换成 HTML:
jade views/index.jade -o ./
这样就能在我们的项目根目录下生成一个 index.html 了,而且它的内容是压缩过的。
好像还不错,咱们可以书写 *.jade 文件,然后通过命令生成 *.html 。
5、母版页
网站不可能只有一个页面,但是我们肯定会有公共的头部和底部,不可能每个页面都去写一遍。
有两种方式达到这种目的,一种是母版页,通过占位符和填坑的方式实现,也就是接下来我们要讲的。还有一种是在每个页面中去引入公共部分。当然得根据自己的需要来决定了。
首先我们在 views/ 下创建一个 layouts/layout.jade 母版页:
doctype html
html
head
meta(charset="utf-8")
title Hello world
body
header
| 这是头部
block con
footer
| 这是底部
注意这里的 block con 是关键,意思是创建一个标识为 con 的坑,等着其它具体页面来填内容。
那么该怎么填内容呢?我们来改写views/index.jade 文件
extends ./layouts/layout.jade
block con
div 这是主页
首先是通过 extends 引入模板文件,然后再在 block con 下面去填充首页的具体内容。
这样,以后添加任何新页面都可以通过上面的格式来了,不用去管公共部分。
6、该写 CSS 了
页面没有样式是不行的,那么我们接下来就来写样式文件。不过我们这里希望用 Sass 来写。
Sass 是一个 CSS 预处理器,简单点说就是用另外一种方式去书写 CSS(增加了包括变量、嵌套等等新写法),最终同样通过工具转换成原始的 CSS文件。不了解的同学可以大致看一下 官网,也都是很容易学会的。
好了,咱们在 /src/sass 中创建一个 main.scss 文件:
body{
background-color: #EEE;
h2{color: Red}}
作为演示,咱们这只用到了其中的嵌套规则。
上面说到,*.scss 也是不能直接引用的,需要先转换成 *.css。怎么转换呢?首先还是安装 Sass:
gem install sass
然后执行下面的命令将 /src/main.scss 输出到 /dist/css/main.css 中
sass src/sass/main.scss dist/css/main.css
大家可以看到,在 /dist/css/ 中实际上生成了 main.css 和 main.css.map 两个文件,当然咱们可以不用管 main.css.map 这个文件,因为我也没去看到底这个文件有什么作用。
OK,大功告成。接下来我们就在 views/layouts/layout.jade 中将 main.css 引入。
修改 views/layouts/layout.jade:
doctype html
html
head
meta(charset="utf-8")
title Hello world
link(href="dist/css/main.css" rel="stylesheet")
body
header
| 这是头部
block con
footer
| 这是底部
然后重新执行
jade views/index.jade -o ./
打开新生成的 index.html 文件,是不是应用上了我们的样式了?
7、该写 JavaScript 了
同样滴,JavaScript 也有自己的预处理,那就是 CoffeeScript 了。这样你就可以写 JavaScript 写得很爽了。不了解的同学可以看看 教程 很简单。
类似上面的 CSS,首先在 src/coffee 下创建一个 main.coffee 文件,然后写上测试代码:
hello = ()->
console.log("your coffee is work")
hello()
然后
npm install -g coffee-script
接着编译 src/*.coffee 到 dist/js/*.js:
coffee -c -o src/coffee/main.coffee dist/js/
这里在测试中好像是不能输出来的,不过文档是这样写的,先不用管这个,暂时可以直接将其编译到当前目录下,然后手动复制到 dist/js/*.js 下面:
coffee -c src/coffee/
接下来我们就在 views/layouts/layout.jade 中将 main.js 引入。 修改views/layouts/layout.jade:
doctype html
html
head
meta(charset="utf-8")
title Hello world
link(href="dist/css/main.css" rel="stylesheet")
script(src="dist/js/main.js")
body
header
| 这是头部
block con
footer
| 这是底部
然后重新执行
jade views/index.jade -o ./
打开新生成的 index.html 文件,F12看看是不是输出了 your coffee is work。
8、该创作了
估计很多同学都想利用 Github 个人主页(下面会讲到)来写博客,如果是有后台程序,那么一般是将博客内容存到数据库中,然后在一个指定的页面中读取显示出来。
那么全静态站点该如何做呢?我们没有数据库。的确,但是我们仍然可以把博客内容剥离出来,放到一个单独的文件中,然后通过命令去生成单个的博客页面。
这里我们使用 Markdown 格式来写内容,我们新建一个文件夹 views/blog/ 文件夹用于存放所有博客文件。首先我们新建一个 views/blog/index.jade 的页面用于显示文章:
extends ../layouts/layout.jade
block con
article
include:marked hello.md
注意这里是通过 include:marked 指令来将 Markdown 文件引进来并解析成 HTML,这是 Jade 为我们提供的功能。
然后创建一个 hello.md 的文章:
### 这是标题
这是内容
[链接文字](链接地址)
最后就会生成一个 blog/index.html。
这里我们是把 include:marked hello.md 写死了,事实上我们是要实现在 views/blog/ 下添加很多的 Markdown 格式的博客内容文件,然后执行 gulp 即可在 blog/下面生成对应的 HTML 文件。
大家可以思考一下这个问题,我这里就不做了,也许会在后面的文章中来进行补充。
到此为止,整个项目已经初具成效了。
那么我们每次修改内容的时候,都得去执行相应的命令,是不是有点繁琐呢?程序员一定要懒,能程序做的就别自己手动去做。那么有这种工具可以帮我们完成这一系列动作吗?
9、自动化构建
所谓的自动化构建就是将多个开发中的操作整理到一起,简化我们的整个开发过程。简单点说就是配置一系列的命令语句,然后一行命令就搞定所有的CSS、JavaScript等处理工作。
当然构建工具的选择还是蛮多的(查看 完整列表)。这里我们选择的是 gulp,因为使用和配置都比较简单。
首先是安装 gulp
npm install --global gulp
然后在你的项目根目录下创建一个 gulpfile.js 文件,内容如下:
var gulp = require('gulp');gulp.task('default', function() {
// place code for your default task here});
然后执行
gulp
可以看到默认的任务执行了,只是没有做任何工作:
[14:18:31] Starting 'default'...[14:18:31] Finished 'default' after 79 μs
下面我们就来配置 gulp 来完成我们的自动化任务,这里咱们先以编译 Sass 文件作为示例。
首先得引入 Sass 的处理包,注意这里不再是 sass ,而是 gulp 的 Sass 插件,可以在 npm 上面找到(点击这里)然后我们可以看看它的大致用法。
首先是引入:
var sass = require('gulp-sass');
然后是创建一个任务:
gulp.task('styles',function(){
gulp.src('./src/sass/*.scss')
.pipe(sass())
.pipe(gulp.dest('./dist/css'))})
这里我们通过 src 指定 *.scss 源文件的位置,然后传入 pipe(自动化流程中的处理管道)最后通过 dest 指定输出路径。整个过程其实是很好理解的。
完了你的 gulpfile.js 文件就会是这个样子:
var gulp = require('gulp'),
sass = require('gulp-sass');gulp.task('styles',function(){
gulp.src('./src/sass/*.scss')
.pipe(sass())
.pipe(gulp.dest('./dist/css'))})
接下来同样需要安装 gulp-sass
npm install -g gulp-sass
最后,我们执行
gulp
可以看到,Sass 文件已经编译成功了。
对于 coffee 和 jade 文件,我们同样创建各自的任务和处理管道,这里就不重复说了,可以直接看代码。
这里还有一个 clean 任务,用于每次新编译的时候把老文件清空掉
gulp.task('clean',function(cb){
del(['./dist'],cb)})
因为执行 gulp 命令默认是取的 default 任务,所以我们需要创建该任务,并把其它任务都给加进去
gulp.task('default',['clean'],function(){
gulp.start('styles','scripts','templates');})
可以看到这里是保证在 clean 任执行完成后再去执行我们的 'styles','scripts','templates'任务。
在实际的开发过程中,不管我们修改什么文件,只需要 gulp 一下即可,方便了很多。但是仍然每次修改都得执行一下。可不可以让 gulp 来监听我们的文件变化,然后自动重新执行编译任务呢?
答案是可以的。只需要将这些任务加入监控 watch 就行了:
gulp.task('watch',function(){
gulp.watch('./src/sass/*.scss',['styles']);
gulp.watch('./src/coffee/*.coffee',['scripts']);
gulp.watch('./views/*.jade',['templates']);})
然后执行
gulp watch
这样,gulp 就开始监听文件了,不管我们做了什么修改,都不用再次执行 gulp 了。
源码 中我用到了更多的包(压缩、合并、重命名等等)大家可以了解一下,不懂的可以去 npm 上查一下用法文档。
10、开发环境
如果要是在别人的环境中运行该项目,那么我们之前安装的包都得重新安装一遍,是不是很麻烦。别怕,我们有 package.json,用来管理我们这些包的依赖,换了环境只需要执行一下 npm install 即可将我们之前的包都给安装上了,相当省事。
需要手动创建 package.json 吗?NO,只需执行
npm init
接下来我们就可以按照提示创建自己的 package.json 了。 里面包含了该项目的一些信息,咱们找到 dependencies 这一行,这便是该项目要用到的包。正常情况下应该是这种格式:
"dependencies": {
"gulp": "^3.9.0",
"gulp-sass": "~2.0.4",
....}
但是很遗憾,里面什么都没有,这意味着我们必须一个个手动往里面添加我们上面用到的包了。
心好累...
难道就不能自动给我们加上去吗?不能,不过我们如果在开始安装每个包的时候在命令结尾加上 -save 参数,那么后面这些依赖便可以自动加到 dependencies 下了,如:
npm install coffee-script -save
所以下次开发的时候,别忘了在安装包的时候加上这个参数。
11、版本控制
现在项目已经完成了,我们应该将它纳入版本控制了。什么叫版本控制呢?通俗点说就是充分管理你的代码日志,你对代码做的任何增删改,只要你提交过,就会记录下来,而且可以随时回退到之前的任何状态,从而保证整个开发过程不会断层。
目前我们基本上都会使用Git来完成版本控制,Git只是一种协议,而具体则有Github、Bitbucket、Gitlab之类的实现。而 Github 则是开源项目的不二选择。
1、首先我们在项目根目录下执行
git init
这里是初始化,会创建一个 .git 文件夹,里面包含了所有跟版本控制相关的数据。所以,如果你想把该项目和Git断开,直接删除该文件夹即可。
2、添加一个 README.md (可选)用于描述项目
touch README.md
注意这里是 Markdown 格式的。
3、忽略某些文件
在提交代码之前,我们需要将某些文件排除在外,比如由 npm 产生的 node_modules 文件夹,这是开发环境下用到的,可以通过 npm install 在新环境下安装依赖。所以理应不纳入版本管理,还有缓存之类的都应该排除掉。
那么我们就创建一个名为 .gitignore 的文件,内容就如下:
.DS_Store
node_modules
.sass-cache
上面只是一个大致的内容,实际开发的时候你得根据自己的需求去忽略某些文件。
4、提交代码到本地
git add .git commit -m "init project"
注意,这里仅仅是将代码提交到了本地。
5、提交到 Github
首先我们在Github上创建一个项目 auto-web
![](https://box.kancloud.cn/2016-02-29_56d3fe8085d59.jpg)
Create repository 到下一个页面上,复制那句
git remote add origin git@github.com:awesomes-cn/auto-web.git
(这里是我的,你得复制你自己的) 然后回到项目根目录执行该命令。
最后执行提交
git push -u origin master
去你的 Github 上,可以看到该项目的所有文件已经传上去了,而那些忽略掉的文件则没有上去。
感兴趣的同学可以 cat .git/config 一下:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true[remote "origin"]
url = git@github.com:awesomes-cn/auto-web.git
fetch = +refs/heads/*:refs/remotes/origin/*[branch "master"]
remote = origin
merge = refs/heads/master
这就是本地与远程连接的一个配置,由 remote 和 branch 组成,即通过【远端源+分支】来精确定位到最终提交的地址。如果我们直接修改这个文件,也会和用命令一样达到相同的配置效果。
起初是没有这些内容的,当我们执行 git remote add origin ... 时则添加了
[remote "origin"]
url = git@github.com:awesomes-cn/auto-web.git
fetch = +refs/heads/*:refs/remotes/origin/*
而 git push -u origin master 则指定了
[branch "master"]
remote = origin
merge = refs/heads/master
所以如果只有 master 分支,后面的提交就直接可以 git push 了。
如果这是你在公司做的,回到家了想继续开发,只需
git clone git@github.com:awesomes-cn/auto-web.git
然后
cd auto-web
npm installgulp watch
开发环境就绪,继续吧....
免费个人主页
如果你想把该项目作为一个个人主页项目,也就是直接浏览静态页面。Github 给每个用户提供了一个特殊的库,那就是 <github用户名>.github.io ,因为这个项目是可以直接在浏览器中浏览的。一般的前端库都会将文档页面或者演示页面放到该主页上,这样就没必要自己搭服务器来做了。
那么很简单,只需要把该项目的名字改成 <github用户名>.github.io 比如我的是 awesomes-cn.github.io。
然后就可以在浏览器中通过 http://<github用户名>.github.io 访问了。
如此,一个个人主页就诞生了,可以用来做个人简历和博客,完全不用服务器和数据库参与,而且不需要花一分钱的费用。
如果网站中有大量的资源图片,要是放在 Github 上势必会影响访问速度。所以可以将图片放到云存储上面,比如七牛云存储,个人最多有15G的免费流量,完全够用了。
总结
上面的每个部分,我讲得都不是很深入,如果按照我所说的,整个流程都走通了,那么你现在可以对自己感兴趣的部分去做深入了解和学习了。
当前的前端发展是很快的,但某些思想却是不变的,我们必须学会以不变应万变。打好基础,将来不管什么新的框架或者工具都可以快速上手。
附 Github 源码: https://github.com/awesomes-cn/auto-web
原文:http://www.awesomes.cn/source/9
- PHP技术文章
- PHP中session和cookie的区别
- php设计模式(一):简介及创建型模式
- php设计模式结构型模式
- Php设计模式(三):行为型模式
- 十款最出色的 PHP 安全开发库中文详细介绍
- 12个提问频率最高的PHP面试题
- PHP 语言需要避免的 10 大误区
- PHP 死锁问题分析
- 致PHP路上的“年轻人”
- PHP网站常见安全漏洞,及相应防范措施总结
- 各开源框架使用与设计总结(一)
- 数据库的本质、概念及其应用实践(二)
- PHP导出MySQL数据到Excel文件(fputcsv)
- PHP中14种排序算法评测
- 深入理解PHP原理之--echo的实现
- PHP性能分析相关的函数
- PHP 性能分析10则
- 10 位顶级 PHP 大师的开发原则
- 30条爆笑的程序员梗 PHP是最好的语言
- PHP底层的运行机制与原理
- PHP 性能分析与实验——性能的宏观分析
- PHP7 性能翻倍关键大揭露
- 鸟哥:写在PHP7发布之际一些话
- PHP与MySQL通讯那点事
- Php session内部执行流程的再次剖析
- 关于 PHP 中的 Class 的几点个人看法
- PHP Socket 编程过程详解
- PHP过往及现在及变革
- PHP吉祥物大象的由来
- PHP生成静态页面的方法
- 吊炸天的 PHP 7 ,你值得拥有!
- PHP开发中文件操作疑难问答
- MongoDB PHP Driver的连接处理解析
- PHP 杂谈《重构-改善既有代码的设计》之二 对象
- 在php中判断一个请求是ajax请求还是普通请求的方法
- 使用HAProxy、PHP、Redis和MySQL支撑10亿请求每周架构细节
- HTML、HTML5、XHTML、CSS、SQL、JavaScript、PHP、Web Services 是什么?
- 重构-改善既有代码的设计
- PHP场景中getshell防御思路分享
- 移动互联时代,你看看除了PHP你还会些什么
- 安卓系统上搭建本地php服务器环境
- PHP中常见的缓存技术!
- PHP里10个鲜为人知但却非常有用的函数
- 成为一名PHP专家其实并不难
- PHP 命令行?是的,您可以!
- PHP开发提高效率技巧
- PHP八大安全函数解析
- PHP实现四种基本排序算法
- PHP开发中的中文编码问题
- php.get.post
- php发送get、post请求的6种方法简明总结
- 中高级PHP开发者应该掌握哪些技术?
- 前端开发
- web前端知识体系大全
- 前端工程与性能优化(下)
- 前端工程与性能优化(上)
- 2016 年技术发展方向
- Web应用检查清单
- 如何成为一名优秀的web前端工程师
- 前端组件化开发实践
- 移动端H5页面高清多屏适配方案
- 2015前端框架何去何从
- 从前端看“百度迁徙”的技术实现(一)
- 从前端看“百度迁徙”的技术实现(二)
- 前端路上的旅行
- 大公司里怎样开发和部署前端代码?
- 5个经典的前端面试问题
- 前端工程师新手必读
- 手机淘宝前端的图片相关工作流程梳理
- 一个自动化的前端项目实现(附源码)
- 前端代码异常日志收集与监控
- 15年双11手淘前端技术总结 - H5性能最佳实践
- 深入理解javascript原型和闭包系列
- 一切都是对象
- 函数和对象的关系
- prototype原型
- 隐式原型
- instanceof
- 继承
- 原型的灵活性
- 简述【执行上下文】上
- 简述【执行上下文】下
- this
- 执行上下文栈
- 简介【作用域】
- 【作用域】和【上下文环境】
- 从【自由变量】到【作用域链】
- 闭包
- 完结
- 补充:上下文环境和作用域的关系
- Linux私房菜