今天偶然翻到以前写的一篇笔记,是以前在上家公司做的一个打包优化程序,那个时候webpack还没火,大家都是靠gulp、grunt工具来打包发布的。

现在翻出来看到以前的优化笔记感觉有些陌生了,使我产生了一种错觉(我以前竟然能写出像webpack一样的打包程序),那个时候写这个程序对于我来说确实是一项很大的挑战,gulp各种构建功能、node文件操作正则匹配模板解析、结合业务代码结构优化等等,那个时候才刚毕业的我就被迫接下这口大锅。最后在leader的“亲情问候”之下我把它写出来了。

这个打包程序是针对公司项目优化的,所以参考一下就好了,具体我都不记得优化细节了,我就把以前写的笔记内容放在这里,当做一个记录归档。

项目源码已经找不到了,我只记得技术栈是backbone框架(有够老的)、require.js、less、gulp、underscore(模板功能)…… 满满的年代感啊,只能记得这么多了。

追往事,叹今吾,春风不染白髭须。。。咳咳。。在分割线之后就会进入笔记内容:


打包主程序

双手👐奉上打包主程序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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
var project = './www/html';
var browser = './platforms/browser/www/html';
//var baseUrl = 'http://192.168.1.215/tupai/backend/planb/public/'
var baseUrl = 'http://localhost/tupai/backend/planb/public/'
var baseUri = '';


var gulp = require('gulp'),
shell = require('gulp-shell'),
jshint = require('gulp-jshint'),
uglify = require('gulp-uglify'),
clean = require('gulp-clean'),
rename = require('gulp-rename'),
rev = require('gulp-rev'),
revCollector = require('gulp-rev-collector'),
concat = require("gulp-concat"),
less = require("gulp-less"),
cssmin = require('gulp-clean-css'),
livereload = require('gulp-livereload'),
_ = require("underscore"),
minimist= require('minimist'),
amdOptimize = require('amd-optimize'),
foreach = require('gulp-foreach'),
copy = require('gulp-file-copy'),
fs = require("fs");
var knownOptions = {
string: 'env',
default: { env: process.env.NODE_ENV || 'production' }
};
var options = minimist(process.argv.slice(2), knownOptions);


/*解析require依赖打包*/
gulp.task('bundle',function () {
return gulp.src([project + '/src/app/controllers/**/*.js'])
.pipe(foreach(function(stream,file){
var controller = file.path.substr(file.path.lastIndexOf('\\', file.path.lastIndexOf('\\') - 1) + 1).replace('.js','') /*app/dynamic*/
var filename = controller.substr(controller.lastIndexOf('\\')+1) /*dynamic*/

gulp.src([project + '/src/**/*.js'])
.pipe(amdOptimize('app/controllers/'+controller, {
baseUrl: project + '/src/',
configFile: project + '/bundle/config/require-config.js',
findNestedDependencies: true,
include: true,
wrapShim: true,
}))
.pipe(concat(filename+'.js'))
.pipe(gulp.dest(project + '/bundle/controllers/'+controller.replace(filename,'')))
.on('end',function(){
fs.readFile(project + '/bundle/controllers/' + controller + '.js', "utf8", function (error, data) {
if (error) throw error;
var tpl = data.replace('app/controllers', './controllers')/*.replace(/'app\/views/g,'\'/bundle/views')*/.replace(/tpl!app\/views/g,'tpl!src/app/views')
fs.writeFile(project + '/bundle/controllers/' + controller + '.js', tpl, function (err) {
if (error) throw error;
//console.log('修改成功')
});
})
})

return stream
}))

});


/*生成main*/
gulp.task('bundle-main', function () {
return gulp.src([project + '/src/**/*.js'])
.pipe(amdOptimize('../bundle/config/main-bundle', {
baseUrl: project + '/src/',
configFile: project + '/bundle/config/require-config.js',
findNestedDependencies: true,
include: true,
//wrapShim: true,
}))
.pipe(concat('res-main-bundle.js'))
.pipe(uglify())
.pipe(gulp.dest(project + '/bundle/'))
});


/*处理tpl*/
gulp.task('tpl',function(){
//var tpl = 'index/indexHeader/indexHeader.js';

return gulp.src([project + '/bundle/controllers/**/*.js'])
.pipe(foreach(function(stream,file){

var controllerData = fs.readFileSync(file.path, "utf8")
var tplArr = controllerData.split('\'tpl!');
var cssArr = [];
var replaceText = [tplArr[0]]

for(var i = 0,len= tplArr.length;i<len;i++) {
// 分隔后第一个是tpl!左边的部分,从第二个开始才有tpl
var item = tplArr[i]
if (i > 0) {
var index = item.indexOf('\'');
var tplUrl = item.substr(0, index);
item = item.replace(tplUrl+'\'','')

// 读取html对应的less
var cssData = fs.readFileSync(project + '/' + tplUrl.replace('.html','.less'), 'utf8');
cssArr.push(cssData)

var htmlData = fs.readFileSync(project + '/' + tplUrl, 'utf8');
var c = {
evaluate: /<%([\s\S]+?)%>/g,
interpolate: /<%=([\s\S]+?)%>/g
}
var tmpl = '(function(obj){var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
'with(obj||{}){__p.push(\'' +
htmlData.replace(/\\/g, '\\\\')
.replace(/'/g, "\\'")
.replace(c.interpolate, function (match, code) {
return "'," + code.replace(/\\'/g, "'") + ",'";
})
.replace(c.evaluate || null, function (match, code) {
return "');" + code.replace(/\\'/g, "'")
.replace(/[\r\n\t]/g, ' ') + "; __p.push('";
})
.replace(/\r/g, '')
.replace(/\n/g, '')
.replace(/\t/g, '')
+ "');}return __p.join('');})";

replaceText.push(item.replace('{', '{\n var template = ' + tmpl))
}
}


var controller = file.path.substr(file.path.lastIndexOf('\\', file.path.lastIndexOf('\\') - 1) + 1).replace('.js','')/*app/dynamic*/
var filename = controller.substr(controller.lastIndexOf('\\')+1) /*dynamic*/
var dir = controller.replace(filename,'').replace(/\\/,'')


// 改写tpl
fs.writeFile(file.path,replaceText.join('') , function (error) {
if (error) throw error;
gulp.src([file.path])
.pipe(uglify())
.pipe(gulp.dest(project+'/bundle/controllers/'+dir))
});



// 生成css
if(!fs.existsSync(project+'/bundle/css/')){
fs.mkdirSync(project+'/bundle/css/')
}

var exists = fs.existsSync(project+'/bundle/css/'+dir)
if(!exists){
fs.mkdirSync(project+'/bundle/css/'+dir)
}



fs.open('./www/html//bundle/css/'+controller+'.less','w+',function(){
fs.writeFile('./www/html/bundle/css/'+controller+'.less',cssArr.join(''),function(){
gulp.src([ project + '/src/less/*.less','./www/html//bundle/css/'+controller+'.less'])
.pipe(concat(filename+'.less'))
.pipe(less())
.pipe(cssmin())
.pipe(gulp.dest('./www/html//bundle/css/'+dir))
});
})
return stream
}))

})


gulp.task('bundle-release', shell.task([
'gulp bundle-main',
'gulp bundle',
'gulp tpl',
]));


gulp.task('css', function() {
gulp.src([project + '/src/app/views/**/*.less', project + '/src/less/*.less'])
.pipe(concat('main.less'))
.pipe(gulp.dest(project + '/css'))
.pipe(less())
.pipe(gulp.dest(project + '/css'))
});

gulp.task('common-css', function() {
gulp.src([ project + '/src/less/*.less'])
.pipe(concat('commn.less'))
.pipe(gulp.dest(project + '/css'))
.pipe(less())
.pipe(gulp.dest(project + '/css'))
});

gulp.task('page', function() {
var env = 'dev';
var args = minimist(process.argv.slice(2));
if(args.env) {
env = args.env;
baseUrl = 'http://wechupin.com'
}


var html= fs.readFileSync(project + '/src/index.tpl');
var html_app = fs.readFileSync(project + '/src/index-app.tpl');
var html_bundle = fs.readFileSync(project + '/src/index-bundle.tpl');
var tpl = _.template(html.toString());
var tpl_app = _.template(html_app.toString());
var tpl_bundle = _.template(html_bundle.toString());
fs.writeFile( project + '/index.html', tpl({env:env, baseUrl: baseUrl, baseUri: baseUri}));
fs.writeFile( project + '/index-app.html', tpl_app({env:env, baseUrl: baseUrl, baseUri: baseUri}));
fs.writeFile( project + '/index-bundle.html', tpl_bundle({env:env, baseUrl: baseUrl, baseUri: baseUri}));
});

// 监听会变动的文件
gulp.task('watch', function() {
livereload.listen();
console.log('livereload');

gulp.watch([project + '/src/**/*.less'], ['css']);
gulp.watch([project + '/src/index.tpl'], ['page']);

/*gulp.watch([project + '/!**!/!*'], function(url) {
var p = project.substr(2);
var b = browser.substr(2);

var path = url.path.split(process.cwd())[1];
path = path.replace(/\\/g, '/');

var dest = '.' + path.replace(p, b);
var fs = require("fs");
var html= fs.readFileSync(url.path);
fs.writeFile(dest, html.toString());
});
gulp.watch([browser + '/!**!/!*'], function(url) {
console.log(url.type + ':' + url.path);
return gulp.src(url.path).pipe(livereload());
});*/
});

gulp.task('release', shell.task([
'gulp css',
'gulp page --env production',
'node plugins/r.js -o '+project+'/src/build.js dir='+project+'/res optimize=uglify',
'node plugins/r.js -o cssIn='+project+'/css/main.css out=' + project+ '/css/main.css optimizeCss=standard'
]));
gulp.task('build', ['css', 'page']);

打包优化结果记录:

js打包:

amd-optimize,根据依赖关系将关联的模块文件合并到一个文件里,实现一个页面只调用一个业务js,入口js文件同理:将公用的类库合并到一个入口js文件,这样子一个页面只加载入口js文件和业务js文件;
模板打包:
根据业务js里调用的html模板取到html代码,并以字符串的形式赋值给业务js里的template变量,这样就相当于在浏览器访问下不用另外加载模板文件了,同样是按需加载的优化方式。

css打包:

本来是打算分开加载通用样式和业务样式的,但是业务的less有调用通用less的关系,只能合并到一起才能解析,不能分离,所以css打包后就是一个页面里只有一个包含通用样式和当前业务样式的一个css文件;

优化前:

优化前
优化前

优化后:

优化后
优化后

开发优化:

优化前:

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
var sections = [ '_playHeaderItem','_descriptionItem','_productItem', '_teamItem','_unionInvestItem','_commentList' ];
var layoutView = window.app.render(sections);
$('body').attr('data-item-id',item_id);

//出品详情
var items = new window.app.model();
items.url = '/items/app_show/' + item_id;
// console.log(items);
var playHeaderView = new playHeaderItem({
model: items
});
window.app.show(layoutView._playHeaderItem, playHeaderView);
// 审核过后恢复


//电影详情
var itemDetail = new window.app.model();
itemDetail.url = '/itemdetails/'+item_id+'?type=1&summary=1';
var descriptionView = new descriptionItem({
model: itemDetail
});
window.app.show(layoutView._descriptionItem, descriptionView);


descriptionView.on('show',function(){
var detailhref = $('.movie-details-more').attr('href').replace('#movie/detail','#app/moviedetail')
$('.movie-details-more').attr('href',detailhref)
})


// 周边商品
var productItemView = new productItem();
window.app.show(layoutView._productItem, productItemView);
// 审核过后恢复section = _productItem


//团队列表
var member = new window.app.model();
member.url = '/members/app_showmembers?item_id=' + item_id
var teamView = new teamItem({
model: member
});
window.app.show(layoutView._teamItem, teamView);

member.on('show',function(){
$('#teamintroduction_href').hide();
})
//联合出品人
var unionuser = new window.app.model();
//感谢多少位联合投资人接口
unionuser.url = '/itemusers/indexAndshow?item_id='+item_id+'&page=1&size=5';
//联合出品人头像
// unionuser.url = '/itemusers/' + item_id +'&page=1&size=2'
var unionView = new unionInvestItem({
model: unionuser
});
window.app.show(layoutView._unionInvestItem, unionView);

unionView.on('show',function(){
$('#investor_href').addClass('hide')
$('#teamintroduction_href').addClass('hide')

})



//评论
var comment = new window.app.collection();
comment.url = '/comments?target_type=3&target_id='+item_id;
var commentView = new commentList({
collection: comment
});
window.app.show(layoutView._commentList, commentView);

commentView.on('show',function(){
$('.us-ask').addClass('hide')

/*muiscroll({
view: this,
url: '/comments?target_type=3&target_id='+item_id
})*/


var pullhandle = new pullHandle({
container: '#content-section',
view: this,
size: 5,
page: 1,
url: '/comments?target_type=3&target_id='+item_id,
pullUp: true,
//pullDown: true,
})
})
$('#footer-section').addClass('hide')

优化后:

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
$('body').attr('data-item-id',item_id);

var data = window.app.initData({
items : {
type: 'model',
url:'/items/app_show/' + item_id
},
itemDetail : {
type: 'model',
url:'/itemdetails/'+item_id+'?type=1&summary=1'
},
member : {
type: 'model',
url:'/members/app_showmembers?item_id=' + item_id
},
unionuser : {
type: 'model',
url:'/itemusers/indexAndshow?item_id='+item_id+'&page=1&size=5'
},
comment : {
type: 'collection',
url:'/comments?target_type=3&target_id='+item_id
},
});

var view = window.app.initView({
playHeaderView : {
tpl : playHeaderItem,
model: data.items
},
descriptionView : {
tpl : descriptionItem,
model: data.itemDetail
},
productItemView : {
tpl : productItem,
},
teamView : {
tpl : teamItem,
model: data.member
},
unionView : {
tpl : unionInvestItem,
model: data.unionuser
},
commentView : {
tpl : commentList,
collection: data.comment
},
});


window.app.showLayout(view);


view.teamView.on('show',function(){
$('#teamintroduction_href').hide();
})


view.descriptionView.on('show',function(){
var detailhref = $('.movie-details-more').attr('href').replace('#movie/detail','#app/moviedetail')
$('.movie-details-more').attr('href',detailhref)
})

view.unionView.on('show',function(){
$('#investor_href').addClass('hide')
$('#teamintroduction_href').addClass('hide')

})


view.commentView.on('show',function(){
$('.us-ask').addClass('hide')
var pullhandle = new pullHandle({
container: '#content-section',
view: this,
size: 5,
page: 1,
url: '/comments?target_type=3&target_id='+item_id,
pullUp: true,
//pullDown: true,
})
})
$('#footer-section').addClass('hide')

却将万字平戎策,换得东家种树书。。。咳咳。。分割线之后,我总结一下,拿着过时的技术栈晒一晒,就不会生菇,这篇博客就是为了提醒我:不忘初心,砥砺前行