gulp+webpack自动化构建多页面解决方案

前端工程化已经深入人心,而工程化中必不可少的环节就是构建,所谓构建(bulid)就是基于既定的流程对项目中的文件进行处理,从而得到最终用于发布的文件,协助我们把工作做得更加简单.多页面是指有很多页面是独立的,然后它们引用的js也没有关联性

这里是对gulp和webpack协助工作的初步探讨,webpack作为gulp一个子任务项目根目录下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-source
-css
-images
-js
-product
-EasiCamera.js
-EasiNet5.js
-EasiNote.js
-EasiNote3.js
-EasiNote3C.js
----
-less
-plugins(一些插件)
-views
-products
-EasiCamera.html
-EasiNet5.html
-EasiNote.html
-EasiNote3.html
-EasiNote3C.html
-----

构建后的文件目录

1
2
3
4
5
6
-public
-static
-css
-images
-js
-plugins

views下面的文件输出到./modules/font-end,这个文件夹下

下面是配置文件的结构

1
2
3
4
5
6
7
8
9
10
-gulpfile.js
-gulp-tasks
clean.js
css-compile.js
gulp-webpack.js
packup-libs.js
resources-copy.js
-webpack-config
-webpack.config.dev.js
-webpack.config.pro.js

clean.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

var gulp = require('gulp');
var path = require('path');
var clean = require('gulp-clean');
var gulpSequence = require('gulp-sequence');

gulp.task('clean:all', gulpSequence('clean:views', 'clean:resources'));

gulp.task('clean:views', function(callback){
return gulp.src(path.join(APP_PATH, 'modules', 'front-end', 'views'), { read: false })
.pipe(clean({ force: true }));
});

gulp.task('clean:resources', function(callback){
return gulp.src(path.join(APP_PATH, 'public'), { read: false })
.pipe(clean({ force: true}));
});

gulp.task('clean:rev', function(callback){
return gulp.src(path.join(APP_PATH, 'public', 'rev'), { read: false })
.pipe(clean({ force: true }));
});

css-compile.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

var gulp = require('gulp');
var pump = require('pump');
var plumber = require('gulp-plumber');
var gulpLess = require('gulp-less');
var notify = require('gulp-notify');
var gulpSequence = require('gulp-sequence');
var rev = require('gulp-rev');
var revCollector = require('gulp-rev-collector');
var autoprefixer = require('gulp-autoprefixer');
var minifyCSS = require('gulp-minify-css');

var autopreLess = ['last 10 versions', 'ie >= 8', 'Chrome >= 42', 'ff >= 38', 'Safari >= 7', 'Opera >= 29', 'iOS >= 7.1', 'ie_mob >= 10', 'Android >= 4.4', 'and_uc >= 9.9']

gulp.task('compile:css:dev', function(){
return pump([
gulp.src(['./source/less/**/*.less', './source/css/**/*.css']),
plumber({errorHandler: notify.onError('Error: <%= error.message %>')}),
gulpLess(),
autoprefixer(autopreLess),
gulp.dest('./public/static/css')
])
});

gulp.task('compile:css:pro', function(){
return pump([
gulp.src(['./public/rev/**/*.json', './source/less/**/*.less', './source/css/**/*.css']),
plumber({errorHandler: notify.onError('Error: <%= error.message %>')}),
revCollector(),
gulpLess(),
autoprefixer(autopreLess),
minifyCSS(),
rev(),
gulp.dest('./public/static/css'),
rev.manifest(),
gulp.dest('./public/rev/css')
])
});

gulp-webpack.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

var gulp = require('gulp');
var webpackDevConfig = require(APP_PATH + '/webpack-config/webpack.config.dev.js');
var webpackProConfig = require(APP_PATH + '/webpack-config/webpack.config.pro.js');
var webpack = require('webpack');
var gutil = require('gulp-util');
var pump = require('pump');
var uglifyjs = require('uglify-js');
var minifier = require('gulp-uglify/minifier');
var rev = require('gulp-rev');
var revCollector = require('gulp-rev-collector');
var clean = require('gulp-clean');
var gulpSequence = require('gulp-sequence');

var UglifyOption = {
//不混淆变量名
mangle:{
except: ['jQuery']
},
preserveComments:false,
report: "gzip",
ASCIIOnly: 'true',
beautify: {
beautify: false,
"ascii_only": true
},
compress:{
sequences:true,
dead_code:true,
conditionals:true,
booleans:true,
unused:true,
hoist_funs:false,
join_vars:true,
drop_console:true,
global_defs: {
"DEBUG": false
}
}
};


gulp.task('webpack:dev', function(callback){
webpack(webpackDevConfig, function(err, stats){
if(err) throw new gutil.PluginError("webpack:build-js", err);
gutil.log("[webpack:build-js]", stats.toString({
colors: true
}));
callback();
});
});

gulp.task('webpack:rev', function(callback){
webpack(webpackProConfig, function(err, stats){
if(err) throw new gutil.PluginError("webpack:build-js", err);
gutil.log("[webpack:build-js]", stats.toString({
colors: true
}));
callback();
});
});

gulp.task('min:js', function(){
return pump([
gulp.src(['./public/rev/**/*.json', './public/rev/**/*.js']),
revCollector(),
minifier(UglifyOption, uglifyjs),
rev(),
gulp.dest('./public/static'),
rev.manifest(),
gulp.dest('./public/rev/js')
])
});


gulp.task('webpack:pro',
gulpSequence(
'webpack:rev',
'min:js'
)
)

packup-libs.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

var gulp = require('gulp');
var pump = require('pump');
var gulpConcat = require('gulp-concat');

var sources = ['./source/js/lib/jquery.js','./source/js/lib/mod.js','./source/js/lib/moment.js','./source/js/lib/underscore.js'];

gulp.task('packup:libs:dev', function(){
pump([
gulp.src(sources),
gulpConcat('libs.js'),
gulp.dest('./public/static/js/lib')
])
});

gulp.task('packup:libs:pro', function(){
pump([
gulp.src(sources),
gulpConcat('libs.js'),
gulp.dest('./public/static/js/lib')
])
});

resources-copy.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

var gulp = require('gulp');
var pump = require('pump');
var rev = require('gulp-rev');
var revCollector = require('gulp-rev-collector');
var gulpSequence = require('gulp-sequence');

gulp.task('copy:html', function() {
return pump([
gulp.src('./source/views/**/*'),
gulp.dest('./modules/front-end/views')
])
});
gulp.task('copy:html:pro', function(){
return pump([
gulp.src(['./public/rev/**/*.json', './source/views/**/*.html']),
revCollector(),
gulp.dest('./modules/front-end/views')
])
});


gulp.task('copy:images', function() {
return pump([
gulp.src('./source/images/**/*'),
gulp.dest('./public/static/images')
])
});
gulp.task('copy:images:pro', function(){
return pump([
gulp.src('./source/images/**/*'),
rev(),
gulp.dest('./public/static/images'),
rev.manifest(),
gulp.dest('./public/rev/imgs')
])
});

gulp.task('copy:font', function(){
return pump([
gulp.src(['./source/css/**/icomoon.*']),
gulp.dest('./public/static/css')
])
});
gulp.task('copy:plugins',function() {
return pump([
gulp.src('./source/plugins/**/*'),
gulp.dest('./public/static/plugins')
])
});
gulp.task('copy:favicon.ico',function() {
return pump([
gulp.src('./source/favicon.ico'),
gulp.dest('./public')
])
});
gulp.task('copy:well-known', function() {
return pump([
gulp.src('./source/.well-known/**/*'),
gulp.dest('./public/.well-known')
])
});
gulp.task('copy:seewo-link', function(){
return pump([
gulp.src('./source/doc/**/*'),
gulp.dest('./public/doc')
])
});

gulp.task('copy:dev',
gulpSequence(
'copy:html',
'copy:images',
'copy:plugins',
'copy:font',
'copy:favicon.ico',
'copy:well-known',
'copy:seewo-link'
)
);

webpack.config.dev.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

var webpack = require('webpack'),
CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin"),
path = require('path'),
fs = require('fs'),
srcDir = path.resolve(process.cwd(), 'source');//cwd方法返回进程的当前目录(绝对路径)

//获取多页面的每个入口文件,用于配置中的entry
function getEntry() {
var jsPath = path.resolve(srcDir, 'js','product');//path.resolve方法用于将相对路径转为绝对路径。
var dirs = fs.readdirSync(jsPath);
//判断是一个目录还是一个对象
var matchs = [], files = {};
dirs.forEach(function (item) {
matchs = item.match(/(.+)\.js$/);
if (matchs) {
files[matchs[1]] = path.resolve(srcDir, 'js','product',item);
}
});
return files;
}

module.exports = {
entry: getEntry(),
output: {
path: path.join(APP_PATH, 'public', 'static', 'js'),
filename:'[name].js'
},
module: {
loaders: [
{
loader: 'babel',
test: /\.jsx?$/,
exclude: /node_modules/,
query: {
presets: ['es2015','stage-2']
}
},
]
}
}

webpack.config.pro.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

var webpack = require('webpack'),
CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin"),
path = require('path'),
fs = require('fs'),
srcDir = path.resolve(process.cwd(), 'source');//cwd方法返回进程的当前目录(绝对路径)

//获取多页面的每个入口文件,用于配置中的entry
function getEntry() {
var jsPath = path.resolve(srcDir, 'js','product');//path.resolve方法用于将相对路径转为绝对路径。
var dirs = fs.readdirSync(jsPath);
//判断是一个目录还是一个对象
var matchs = [], files = {};
dirs.forEach(function (item) {
matchs = item.match(/(.+)\.js$/);
if (matchs) {
files[matchs[1]] = path.resolve(srcDir, 'js','product',item);
}
});
return files;
}

module.exports = {
entry: getEntry(),
output: {
path: path.join(APP_PATH, 'public', 'rev', 'js'),
filename:'[name].js'
},
module: {
loaders: [
{
loader: 'babel',
test: /\.jsx?$/,
exclude: /node_modules/,
query: {
presets: ['es2015','stage-2']
}
},
]
}
}

以上用到的插件有;

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

"require-dir": "^0.3.1",
"webpack": "^1.14.0"
"babel-loader": "^6.2.10",
"gulp": "^3.9.1",
"gulp-autoprefixer": "^3.1.1",
"gulp-clean": "^0.3.2",
"gulp-concat": "^2.6.1",
"gulp-connect": "^5.0.0",
"gulp-css-base64": "^1.3.4",
"gulp-css-spriter": "^0.3.3",
"gulp-cssmin": "^0.1.7",
"gulp-file-include": "^1.0.0",
"gulp-less": "^3.3.0",
"gulp-md5-plus": "^0.2.5",
"gulp-minify": "0.0.14",
"gulp-minify-css": "^1.2.4",
"gulp-notify": "^2.2.0",
"gulp-open": "^2.0.0",
"gulp-plumber": "^1.1.0",
"gulp-rename": "^1.2.2",
"gulp-rev": "^7.1.2",
"gulp-rev-collector": "^1.1.1",
"gulp-sequence": "^0.4.6",
"gulp-sourcemaps": "^1.9.1",
"gulp-uglify": "^2.0.0",
"gulp-util": "^3.0.7",
"gulp-watch": "^4.3.11",
"pump": "^1.0.2",
"uglify-js": "^2.7.5"

image
image

开发的路径用绝对路径(就是根目录下输出的public下面的路径),所以一般source目录的结构和public目录结构相同

开发阶段功能

  1. 文件的清除
  2. 文件的复制输出
  3. less,css编译报错高亮
  4. webpack的打包(webpack入口的配置,es6的配置)
  5. 浏览器的前缀自动补全
  6. 实时刷新编译

上线阶段

  1. 文件的清除
  2. 文件的复制输出
  3. less,css编译报错高亮
  4. webpack的打包(webpack入口的配置,es6的配置)
  5. css 压缩
  6. js压缩
  7. css,js,image加版本号,md5
  8. 浏览器的前缀自动补全

gulp学习系列