FE-tool-template

自己攒了个前端开发模板,目的是提高前端开发效率,前后端分离

可改进地方还有很多,还请各位给些建议~~

使用gulp作为自动化构建工具

yeoman生成项目文件代码结构

bower做包管理器

handlebarsjs模板引擎

添加php server环境,方便前端mock假数据

用less做CSS预处理

准备工作

安装nodejs

  1. windows系统下安装nodejs及环境配置

    • 下载nodejs,官网http://nodejs.org/download/,选择适合你电脑配置的版本下载

    • 下载完成后双击无脑安装,装好后在cmd控制台输入:node -v,控制台打印出版本号,则安装成功。

    • npm安装 新版nodejs已经集成npm,在cmd控制台输入npm -v,打印出版本号,则安装成功。

    • 接下来便可以使用npm命令安装模块了

      安装:npm install <module name>

      全局安装:npm install -g <Module Name>

      卸载模块:npm uninstall <Module Name>

      显示当前目录下安装的模块:npm list

  2. mac系统下安装nodejs

顺便列两个常用命令行

cd 定位到目录

ls 列出文件列表

安装gulp

npm install -g gulp

输入gulp -v,查看版本号确保正确安装

安装yeoman

yeoman:在web项目立项阶段用来生成项目的文件、代码结构,包括代码校验、测试和压缩等功能。

npm install -g yo

安装bower

bower:web的包管理器

npm install -g bower

正式开始

将gulp安装到项目

npm install --save-dev gulp

这里使用--save-dev来更新package.json文件,更新devDependencies值,表明项目需要依赖gulp

用gulp-webapp生成项目目录

安装gulp-webapp

npm install -g generator-gulp-webapp

在项目目录下,输入命令行

yo gulp-webapp 项目名

安装时会提示是否安装sass,bootstrap和modernizr,除了sass,另外两个都选中安装。(项目主要用less,所以不安装sass)

此时项目下已生成项目目录



按照项目习惯,将app下的styles改为css,scripts改为js,images改为img,.tmp下的styles改为css。

修改后的目录如下:



此时别忘了修改gulpfile.js中的相应目录。最下面会给出最终的gulpfile.js文件内容。

目录说明:

  • .tmp:临时目录
  • app:开发的源代码目录
  • bower_components:通过bower下载下来的包
  • dist:生成用于发布的项目
  • node_modules:nodejs依赖包
  • test:测试文件的目录
  • .bowerrc:bower属性
  • .editorconfig:对开发工具的属性配置
  • .gitattributes:git属性的配置
  • .gitignore:git管理文件的配置
  • .jshintrc:JSHint配置
  • bower.json:bower依赖管理
  • gulpfile.js:gulp开发过程管理
  • package.json:项目依赖文件

app目录下的结构说明:

  • css: 存放css文件
  • font:存放字体资源
  • img:存放图片资源
  • js:存放js源文件
  • templates(自己添加):存放模板文件 后面会详细说明
  • mock(自己添加):存放模拟后台假数据的php 后面会详细说明

添加php环境

在gulp中添加php开发环境,方便前端mock假数据

使用gulp插件gulp-connect-php

神器啊简直~~

注意:使用这个插件需要php在5.4.0以上

npm安装gulp-connect-php

1
$ npm install --save-dev gulp-connect-php

其实只添加上面的插件,再在gulpfile里配置好就已经有了php环境了,但会造成引用样式路径出错,导致加载不了css等文件

为了解决这个问题,需要gulp插件http-proxy,安装

1
$ npm install --save-dev http-proxy

综合上述两点,在gulpfile中添加如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
var connect = require('gulp-connect-php');
var httpProxy = require('http-proxy');

gulp.task('php-serve', ['styles', 'fonts'], function () {
connect.server({
port: 9001, //端口号可以自定义
base: 'app/',
open: false
});

var proxy = httpProxy.createProxyServer({});

browserSync({
notify: false,
port : 9000,
server: {
baseDir : ['.tmp', 'app'],
routes : {
'/bower_components': 'bower_components'
},
middleware: function (req, res, next) { //给server添加一个middleware,可以观察在请求时是否需要代理
var url = req.url;

if (!url.match(/^\/(css|fonts|bower_components)\//)) {
proxy.web(req, res, { target: 'http://127.0.0.1:9001' });
} else {
next();
}
}
}
});

// watch for changes
gulp.watch([
'app/*.html',
'app/mock/*.php', //mock是自己建的文件夹,放置.php文件
'app/js/**/*.js',
'app/img/**/*',
'.tmp/fonts/**/*'
]).on('change', reload);

gulp.watch('app/css/**/*.css', ['styles']);
gulp.watch('app/fonts/**/*', ['fonts']);
gulp.watch('bower.json', ['wiredep', 'fonts']);
});

通过上面的折腾,运行gulp php-serve就可以开一个能运行php的server了~~

接下来添加smarty模板

从官网下载smarty,将文件夹拷贝至app下

在app下新建文件夹templatestemplates_cconfigs,其中templates存放模板文件,configs存放smarty配置文件

configs里添加配置文件smarty.config.php,这样可以方便php引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
//Smarty PHP configuration

define('REAL_PATH', dirname(dirname(__FILE__)));

require_once(REAL_PATH.'/smarty/libs/Smarty.class.php');

$smarty=new Smarty();

$smarty->setCacheDir(REAL_PATH.'\cache');
$smarty->setConfigDir(REAL_PATH.'\configs');
$smarty->setPluginsDir(REAL_PATH.'\plugins');
$smarty->setTemplateDir(REAL_PATH.'\templates');
$smarty->setCompileDir(REAL_PATH.'\templates_c');

//添加Smarty自带的插件库
$smarty->addPluginsDir(REAL_PATH.'\smarty\plugins');

//检测Smarty目录结构配置是否有效
// $smarty->testInstall();
?>

在app下新建mock文件夹,里面主要存放模拟后台php假数据的.php文件

比如新建一个test.php

1
2
3
4
5
6
7
8
9
10
<?php
require('../configs/smarty.config.php');

$smarty->left_delimiter="<%";
$smarty->right_delimiter="%>";

$smarty->assign("num", 100);

$smarty->display('test.tpl');
?>

那么在test.tpl中就可以通过<%num%>来获得从test.php传过去的数据

浏览器中localhost:端口号/mock/test.php,即可出现test.tpl的页面效果,同时含有动态数据。

添加Handlebars作为JS模板引擎

安装依赖

安装gulp插件

npm install --save-dev gulp-handlebars gulp-define-module gulp-declare

gulp-handlebars能够把.hbs模板预编译为JavaScript

gulp-define-module和gulp-declare结合使用,将编译好的JavaScript模板打包到一个命名空间模型中去。

用bower安装Handlerbars

bower install --save handlebars

这样可以把Handlebars runtime添加到页面中,编译过得模板正依赖于此。

添加一个templatestask

在gulpfile.js里添加

1
2
3
4
5
6
7
8
9
gulp.task('templates', function () {
return gulp.src('app/templates/**/*.hbs')
.pipe($.handlebars())
.pipe($.defineModule('plain'))
.pipe($.declare({
namespace: 'MyApp.templates' // change this to whatever you want
}))
.pipe(gulp.dest('.tmp/templates'));
});

这样就会将.hbs文件编译成.js文件,并存放到.tmp目录下

htmlserve里均添加templates依赖

1
2
gulp.task('html', ['styles', 'templates'], function () {
...
1
2
gulp.task('serve', ['styles', 'templates', 'fonts'], function () {
...

编辑servetask

servetask里进行添加,使得.hbs文件的任何更改都会触发templatestask,每当有一个.js文件在.tmp/templates生成,浏览器就会重新加载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 gulp.task('serve', ['styles', 'templates', 'fonts'], function () {
...
gulp.watch([
'app/*.html',
'.tmp/styles/**/*.css',
+ '.tmp/templates/**/*.js',
'app/scripts/**/*.js',
'app/images/**/*'
]).on('change', reload);

gulp.watch('app/styles/**/*.scss', ['styles', reload]);
+ gulp.watch('app/templates/**/*.hbs', ['templates', reload]);
gulp.watch('bower.json', ['wiredep', 'fonts', reload]);
});

同样的,在taskphp-serve里也加上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 gulp.task('php-serve', ['styles', 'templates', 'fonts'], function () {
...
gulp.watch([
'app/*.html',
'app/mock/*.php',
'.tmp/styles/**/*.css',
+ '.tmp/templates/**/*.js',
'app/scripts/**/*.js',
'app/images/**/*'
]).on('change', reload);

gulp.watch('app/styles/**/*.scss', ['styles', reload]);
+ gulp.watch('app/templates/**/*.hbs', ['templates', reload]);
gulp.watch('bower.json', ['wiredep', 'fonts', reload]);
});

使用Handlebars

app/templates里写handlebars文件(.hbs文件),并在需要用到的HTML里像引用.js文件一样引用。

例子

app/templates里写一个foo.hbs文件,内容如下

<p>hello handlebars!</p>

然后在需要引用该模板的页面加上:

1
2
<script src="bower_components/handlebars/handlebars.runtime.js"></script>
<script src="templates/foo.js"></script>

通过下列语句渲染模板

1
2
var tpl = MyApp.templates.foo(); //MyApp.templates作为命名空间,可以在templates task里更改成任意名称
$('#id').html(tpl); //添加到你需要添加的地方

我的效果:



handlebars模板已被引用进来

添加less

1
npm install gulp-less --save-dev

修改gulpfile.js的以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
gulp.task('styles', function () {
return gulp.src('app/css/**/*.less')
.pipe($.sourcemaps.init())
.pipe($.less({
paths: ['.']
}))

.pipe($.postcss([
require('autoprefixer-core')({browsers: ['last 1 version']})
]))

.pipe($.sourcemaps.write())
.pipe(gulp.dest('.tmp/css'))
.pipe(reload({stream: true}));
});


gulp.task('wiredep', function () {
var wiredep = require('wiredep').stream;

gulp.src('app/css/**/*.less')
.pipe(wiredep({
ignorePath: /^(\.\.\/)+/
}))

.pipe(gulp.dest('app/css'));

gulp.src('app/**/*.html')
.pipe(wiredep({
exclude: ['bootstrap/dist'],
ignorePath: /^(\.\.\/)*\.\./
}))

.pipe(gulp.dest('app'));
});

最终的gulpfile.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*global -$ */
'use strict';
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var browserSync = require('browser-sync');
var reload = browserSync.reload;
var connect = require('gulp-connect-php');
var httpProxy = require('http-proxy');

gulp.task('styles', function () {
return gulp.src('app/css/**/*.less')
.pipe($.sourcemaps.init())
.pipe($.less({
paths: ['.']
}))
.pipe($.postcss([
require('autoprefixer-core')({browsers: ['last 1 version']})
]))
.pipe($.sourcemaps.write())
.pipe(gulp.dest('.tmp/css'))
.pipe(reload({stream: true}));
});

gulp.task('jshint', function () {
return gulp.src('app/js/**/*.js')
.pipe(reload({stream: true, once: true}))
.pipe($.jshint())
.pipe($.jshint.reporter('jshint-stylish'))
.pipe($.if(!browserSync.active, $.jshint.reporter('fail')));
});

gulp.task('html', ['styles', 'templates'], function () {
var assets = $.useref.assets({searchPath: ['.tmp', 'app', '.']});

return gulp.src('app/*.html')
.pipe(assets)
.pipe($.if('*.js', $.uglify()))
.pipe($.if('*.css', $.csso()))
.pipe(assets.restore())
.pipe($.useref())
.pipe($.if('*.html', $.minifyHtml({conditionals: true, loose: true})))
.pipe(gulp.dest('dist'));
});

gulp.task('images', function () {
return gulp.src('app/img/**/*')
.pipe($.cache($.imagemin({
progressive: true,
interlaced: true,
// don't remove IDs from SVGs, they are often used
// as hooks for embedding and styling
svgoPlugins: [{cleanupIDs: false}]
})))
.pipe(gulp.dest('dist/img'));
});

gulp.task('fonts', function () {
return gulp.src(require('main-bower-files')({
filter: '**/*.{eot,svg,ttf,woff,woff2}'
}).concat('app/fonts/**/*'))
.pipe(gulp.dest('.tmp/fonts'))
.pipe(gulp.dest('dist/fonts'));
});

gulp.task('extras', function () {
return gulp.src([
'app/*.*',
'!app/*.html'
], {
dot: true
}).pipe(gulp.dest('dist'));
});

gulp.task('templates', function () {
return gulp.src('app/templates/**/*.hbs')
.pipe($.handlebars())
.pipe($.defineModule('plain'))
.pipe($.declare({
namespace: 'MyApp.templates' // change this to whatever you want
}))
.pipe(gulp.dest('.tmp/templates'));
});

gulp.task('clean', require('del').bind(null, ['.tmp', 'dist']));

gulp.task('serve', ['styles', 'templates', 'fonts'], function () {
browserSync({
notify: false,
port: 9000,
server: {
baseDir: ['.tmp', 'app'],
routes: {
'/bower_components': 'bower_components'
}
}
});

// watch for changes
gulp.watch([
'app/*.html',
'.tmp/css/**/*.css',
'.tmp/templates/**/*.js',
'app/js/**/*.js',
'app/img/**/*',
'.tmp/fonts/**/*'
]).on('change', reload);

gulp.watch('app/css/**/*.css', ['styles']);
gulp.watch('app/templates/**/*.hbs', ['templates', reload]);
gulp.watch('app/fonts/**/*', ['fonts']);
gulp.watch('bower.json', ['wiredep', 'fonts']);
});

gulp.task('php-serve', ['styles', 'fonts'], function () {
connect.server({
port: 9001,
base: 'app/',
open: false
});

var proxy = httpProxy.createProxyServer({});

browserSync({
notify: false,
port : 9000,
server: {
baseDir : ['.tmp', 'app'],
routes : {
'/bower_components': 'bower_components'
},
middleware: function (req, res, next) {
var url = req.url;

if (!url.match(/^\/(css|fonts|bower_components)\//)) {
proxy.web(req, res, { target: 'http://127.0.0.1:9001' });
} else {
next();
}
}
}
});

// watch for changes
gulp.watch([
'app/*.html',
'app/mock/*.php',
'.tmp/css/**/*.css',
'.tmp/templates/**/*.js',
'app/js/**/*.js',
'app/img/**/*',
'.tmp/fonts/**/*'
]).on('change', reload);

gulp.watch('app/css/**/*.css', ['styles']);
gulp.watch('app/css/**/*.less', ['styles', reload]);
gulp.watch('app/templates/**/*.hbs', ['templates', reload]);
gulp.watch('app/fonts/**/*', ['fonts']);
gulp.watch('bower.json', ['wiredep', 'fonts']);
});

// inject bower components
gulp.task('wiredep', function () {
var wiredep = require('wiredep').stream;

gulp.src('app/css/**/*.less')
.pipe(wiredep({
ignorePath: /^(\.\.\/)+/
}))
.pipe(gulp.dest('app/css'));

gulp.src('app/**/*.html')
.pipe(wiredep({
exclude: ['bootstrap/dist'],
ignorePath: /^(\.\.\/)*\.\./
}))
.pipe(gulp.dest('app'));
});

gulp.task('build', ['jshint', 'html', 'images', 'fonts', 'extras'], function () {
return gulp.src('dist/**/*').pipe($.size({title: 'build', gzip: true}));
});

gulp.task('default', ['clean'], function () {
gulp.start('build');
});

运行

输入命令行

gulp serve

浏览器会自动打开app下的index.html,localhost:9000



任何文件的改动都会自动刷新浏览器

输入命令行

gulp php-serve

浏览器会自动打开app下的index.php,localhost:8090 (可在gulpfile.js修改端口号)

同样的,任何文件的改动都会自动刷新浏览器

编译文件

gulp build

gulp将build后的文件放入dist目录下