Better

Ethan的博客,欢迎访问交流

gulp自动化构建工具

今天在给代码压缩丑化中,出现一个迟迟无法解决的错误,主要原因是因为团队协作开发中,成员粗心针对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',funcion(){
      //Stuff here
      });
      
      这是gulp设置task的大概模版,'task-name'是你给任务起的名字,稍后在命令行执行gulp task-name,将任务执行。
  • 基础语法
    • */.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');
    })
    })
    

常用插件

问题解决

问题最终通过一个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);
    });
    

代码压缩与混淆

  1. (cordova hook)检查javascript:这一步需要在代码压缩和代码混淆之前进行以保证javascript代码无错误
  2. (gulp task)将html页面代码转换为angular的JS代码:这一步起到了混淆html页面代码的作用
  3. (gulp task)启用angular严格依赖注入:这一步需要在代码混淆之前进行以保证angular的依赖注入没有问题
  4. (gulp task) 组合js代码以及组合css代码:这一步起到了混淆js代码以及css代码的作用
  5. (cordova hook)代码丑化、压缩、混淆

为完成上述任务,我们需要同时使用gulp tasks以及cordova hooks。当执行ionic serve时,gulp tasks会被执行。当执行ionic build Android/iOS或ionic run android/ios时,cordova hooks会被执行。

更多gulp工具



留言