今天在给代码压缩丑化中,出现一个迟迟无法解决的错误,主要原因是因为团队协作开发中,成员粗心针对angular代码的服务注入没有按照规范来,导致代码一压缩,服务名称就变成了不可识别字符,因此报错服务找不到,在项目代码量起来之后,问题实在是难以发现。
gulp简介
什么是gulp
是一个前端自动化的构建工具,直白点说,如果没有这个工具,我们利用人工依旧可以做到以下优点,但是在项目逐渐庞大的时候,采用这个工具,可以提升性能和效率。
为什么用gulp
- js和css属于静态文件,很多时候浏览器存在缓存机制,为了避免缓存带来的误会,可以利用构建工具,给每一个静态文件添加一个版本号,这样浏览器就会认为是新的文件,就不存在缓存机制
- 性能优化:文件合并,减少http请求;文件压缩,减少文件体积,加快下载速度
- 效率提升:自动添加CSS3的
vendor
前缀;代码分析检查改正;在使用MVC和MVVM的框架后,可在提交之前,使用gulp自动跑一遍单元测试 - 个人总结:编译 less-sass,打包 css-js,压缩 图片
什么是vendor前缀
前缀并非所有都是需要的,但通常你加上这些前缀不会有任何害处——只要记住一条,把不带前缀的版本放到最后一行。
主要的需要添加浏览器引擎前缀(vendor-prefix)的属性包括:
- @keyframes
- 移动和变换属性(transition-property, transition-duration, transition-timing-function, transition-delay)
- 动画属性 (animation-name, animation-duration, animation-timing-function, animation-delay)
- border-radius
- box-shadow
- backface-visibility
- column属性
- flex属性
- perspective属性 完整的列表不只这些,而且还会增加。
前缀格式:
- -moz- / 火狐等使用Mozilla浏览器引擎的浏览器 /
- -webkit- / Safari, 谷歌浏览器等使用Webkit引擎的浏览器 /
- -o- / Opera浏览器(早期) /
- -ms- / Internet Explorer (不一定) /
基本用法
- 安装nodejs
- 全局安装gulp
npm install --global gulp
- 项目安装gulp以及gulp插件
npm install --save-dev gulp
- 创建并配置gulpfile.js
- 任务模板
这是gulp设置task的大概模版,'task-name'是你给任务起的名字,稍后在命令行执行gulp task-name,将任务执行。gulp.task('task-name',funcion(){ //Stuff here });
- 任务模板
- 基础语法
- */.scss:匹配当前目录及其子目录的所有scss文件
- .scss :号匹配当前目录任意文件,所以这里的*scss匹配当前目录下所有scss文件
- !not-me.scss:!号移除匹配的文件,这里将移除not-me.scss
- *.+(scss|sass):+号后面会跟着圆括号,里面的元素用|分割,匹配多个选项,这里将匹配scss和sass文件
- 运行任务
- webstorm中使用:选择gulpfile.js文件,右键选择Show Gulp Tasks,若出现”No task found”,选择右键”Reload tasks”,双击运行即可。
常用Gulp工具
- gulp-concat 文件连接
- gulp-sass:sass转css
- gulp-less:less转css
- gulp-minify-css:压缩css
- gulp-rename:重命名
- gulp-uglify:JS代码丑化
- gulp-watch:代码监测
- gulp-ng-annotate:angular代码依赖注入维护
- gulp-ng-html2js:angular中html转js
- gulp-minify-html:html压缩
- gulp-autoprefixer:css自动添加前缀,提高兼容性
- gulp-sourcemaps:映射文件
gulp-sourcemaps
重点讲讲这个吧,在实际工作中,我们将代码合并压缩之后,在网站开发时,调试就会是一个很大的问题,因为代码已经不能看了,这个工具的作用是在代码压缩合并前后,维护一个映射关系,最后通过这个maps文件可以反解析到最初的源代码,目前chrome是支持自动转换的。
有一个问题需要注意,sourcemaps写map文件是支持定义路径的,如果不传路径参数,那么会默认写在合并压缩文件的末尾,这样一来,其实压缩就只起到了代码丑化的效果,文件基本没有减少,我们可以指定路径的方式,将代码和映射文件分开存放。
映射文件是分开存放了,可是性能有优化吗?逆向解析需要map文件,会不会同样请求呢?答应是不会的,普通用户浏览的时候,并不会加载.map文件所以,并不需要担心产生多余的http请求,只有在开启了控制台(F12)的时候,才会加载.map文件,不过在控制台的network面板中是找不到这个请求记录的。
代码示例
- css常用
gulp.task('allCss', ['px2rem'], function (done) { gulp.src(['./www/src/**/*.css', '!./www/src/**/*.rem.css']) .pipe(concat('all.css')) .pipe(rename({suffix: '.min'})) //rename压缩后的文件 .pipe(autoprefixer({ browsers: ['IOS >= 8', 'Android >= 4.2'], cascade: true, remove: true })) .pipe(minifyCss({ keepSpecialComments: 0 })) .pipe(gulp.dest('./www/dist/')) .on('end', done); });
- JS常用
gulp.task('allJs', function (done) { // 如果文件合并顺序有要求的,可以先后写 gulp.src(['./www/src/app/app.js', './www/src/app/services.js', './www/src/*/**/*.js', './www/config.js']) .pipe(sourcemaps.init()) //ngAnnotate这是使用是错误的,下面有修正 .pipe(ngAnnotate({ add: true })) .pipe(concat('all.js')) .pipe(uglify()) .pipe(sourcemaps.write('./')) .pipe(gulp.dest('./www/dist/')) .on('end', done); });
- html常用
gulp.task('allHtml', function (done) { gulp.src("./www/src/**/*.html") .pipe(minifyHtml({ empty: true, spare: true, quotes: true })) .pipe(ngHtml2Js({ moduleName: "templates", prefix: "src/" })) .pipe(concat("templates.js")) .pipe(uglify()) .pipe(gulp.dest("./www/dist/")) .on('end', done); });
- 监测文件,自动开始任务
gulp.task('watch', ['sass'], function () { gulp.start('allJs'); gulp.start('allCss'); gulp.start('allHtml'); watch('./www/src/*/**/*.js', function () { gulp.start('allJs'); }); watch('./www/src/**/*.css', function () { gulp.start('allCss'); }); watch('./www/src/**/*.html', function () { gulp.start('allHtml'); }) })
常用插件
- run-sequence
- Links: https://www.npmjs.com/package/run-sequence
- 作用:让gulp任务,可以相互独立,解除任务间的依赖,增强task复用
- browser-sync
- Links: http://www.browsersync.io/
- 作用:静态文件服务器,同时也支持浏览器自动刷新
- del
- Links:https://www.npmjs.com/package/del
- 作用:删除文件/文件夹
- gulp-coffee
- Links: https://github.com/wearefractal/gulp-coffee
- 作用:编译coffee代码为Js代码,使用coffeescript必备
- coffee-script
- Links: https://www.npmjs.com/package/coffee-script
- 作用:gulpfile默认采用js后缀,如果要使用gulpfile.coffee来编写,那么需要此模块
- gulp-nodemon
- Links: https://www.npmjs.com/package/gulp-nodemon
- 作用:自动启动/重启你的node程序,开发node服务端程序必备
- yargs
- Links: https://www.npmjs.com/package/yargs
- 作用:用于获取启动参数,针对不同参数,切换任务执行过程时需要
- gulp-util
- Links: https://www.npmjs.com/package/gulp-util
- 作用:gulp常用的工具库
- gulp-uglify
- Links: https://www.npmjs.com/package/gulp-uglify
- 作用:通过UglifyJS来压缩JS文件
- gulp-concat
- Links: https://www.npmjs.com/package/gulp-concat
- 作用:合并JS
- gulp-sourcemaps
- Links: https://www.npmjs.com/package/gulp-sourcemaps
- 作用:处理JS时,生成SourceMap
- gulp-less
- Links:https://www.npmjs.com/package/gulp-less
- 作用:将less预处理为css
- gulp-sass
- Links:https://www.npmjs.com/package/gulp-sass
- 作用:将sass预处理为css
- gulp-autoprefixer
- Links:https://www.npmjs.com/package/gulp-autoprefixer
- 作用:使用Autoprefixer来补全浏览器兼容的css。
- gulp-minify-css
- Links:https://www.npmjs.com/package/gulp-minify-css
- 作用:压缩css。
- connect-history-api-fallback
- Links:https://www.npmjs.com/package/connect-history-api-fallback
- 作用:开发angular应用必须,用于支持HTML5 history API.
问题解决
问题最终通过一个gulp工具解决,gulp-ng-annotate
就是专门处理这种问题的,因为压缩js会破坏AngularJS文件所需的依赖注入,以至于无法工作。这个插件会自动帮您维护好依赖,因此不用担心依赖注入会被破坏。
记住:凡是你觉得繁琐的事情,社区里十有八九有大神帮你填坑了!
调试出现异常
本以为大功搞成了,开开心心,结果同事开发发现调试出现一些奇怪的问题,在这里记录,一个一个解决或解释原因。
- 打断点时,断点那一行出现空格,同时选中方法或表达式时不能自动计算结果,
貌似不影响功能,影响开发。 - 考虑到会不会是sourcemaps不支持ng-annotate,注释ng-annotate,问题确实不存在了,但是不能不使用这么好的工具吧,因此将ng-annotate在sourcemaps.init()之前使用,同样不会出现空格的原因,但是出现调试时不能直接在控制台打印当前环境的变量,会得到undefined报错,同时选中方法或表达式时不能自动计算结果,因为变量已经是undefined,方法或表达式其实也已经报错,貌似不影响功能,影响开发。
- 今日发现,sourcemaps的确不支持ng-annotate,会影响功能的运行!
gulp.task('allJs', function (done) { // 如果文件合并顺序有要求的,可以先后写 gulp.src(['./www/src/app/app.js', './www/src/app/services.js', './www/src/*/**/*.js', './www/config.js']) //ngAnnotate必须放在sourcemaps外面 .pipe(ngAnnotate({ add: true })) .pipe(sourcemaps.init()) .pipe(concat('all.js')) .pipe(uglify()) .pipe(sourcemaps.write('./')) .pipe(gulp.dest('./www/dist/')) .on('end', done); });
代码压缩与混淆
- (cordova hook)检查javascript:这一步需要在代码压缩和代码混淆之前进行以保证javascript代码无错误
- (gulp task)将html页面代码转换为angular的JS代码:这一步起到了混淆html页面代码的作用
- (gulp task)启用angular严格依赖注入:这一步需要在代码混淆之前进行以保证angular的依赖注入没有问题
- (gulp task) 组合js代码以及组合css代码:这一步起到了混淆js代码以及css代码的作用
- (cordova hook)代码丑化、压缩、混淆
为完成上述任务,我们需要同时使用gulp tasks以及cordova hooks。当执行ionic serve时,gulp tasks会被执行。当执行ionic build Android/iOS或ionic run android/ios时,cordova hooks会被执行。