标签: gulp

  • 使用 Pug 和 Stylus 开发小程序的 watch 脚本

    使用 Pug 和 Stylus 开发小程序的 watch 脚本

    首先,我试用了 Wepy,丑的一逼,遂放弃。

    小程序开发有两点比较蛋痛:

    1. 每个页面必须有3个文件,wxml,js,wxss
    2. 使用 wxml 替代 html,使用 wxss 替代 css,使得默认的编译失效

    Webpack 在这里不太适用,因为 1,我们并非要把所有代码打包到一起。WebStorm 的 File Watcher 也不适用,因为它输出的文件扩展名是固定的(跟 pug 和 stylus 源程序有关)。于是我经过摸索了,使用 gulp 脚本解决了这个问题,代码如下:

    import gulp from 'gulp';
    import pug from 'gulp-pug';
    import rename from 'gulp-rename';
    
    const pugFiles = 'pages/**/*.pug';
    
    // 通用的 pug 处理,可以把 pug 转译并改名为 .wxml 文件
    async function doPUG(path) {
      gulp.src(path)
        .pipe(pug())
        .pipe(rename({
          extname: '.wxml',
        }))
        .pipe(gulp.dest('./pages'));
    }
    
    // 将所有 pug 进行转译
    gulp.task('pug', async () => {
      return doPUG(pugFiles);
    });
    
    // 侦听 .pug 文件的变化,并转译被修改的
    gulp.task('watch', ['pug'], () => {
      gulp.watch(pugFiles, ({path}) => {
        doPUG(path);
      });
    });
    

    接下来,开发的时候,只要运行 gulp watch 即可。

    用类似的方式,我们还能处理 stylus -> css,这里就不详述了,大家可以自己试一试。

    完整的 gulpfile 在 GitHub 仓库里,请自行取用。

  • Gulp 中顺序执行任务

    Gulp 中顺序执行任务

    书接上文,Chrome 插件中无法直接使用 Handlebars 处理模板。两种方案,一是利用沙箱,将 .eval() 放在独立的环境中执行,好处是其它跨域的操作也能这样处理,坏处是写起来麻烦。另一种则是利用 Handlebars 的“预编译”功能,将模板提前编译好,直接在代码中引用。好处是写起来更顺畅,并且从发布插件的角度来看,早晚都要这样做。

    我决定选用后者,于是我需要把模板提取出来进行预编译,然后我准备写个 Gulp 任务来搞定这个。

    从页面中提取模板不算太难,写个正则就好,这里提前约定,模板使用 <script type="x-handlebars-template"> 标签包裹。

    gulp.task('template', function () {
      let promise = new Promise((resolve, reject) => {
        fs.readFile('popup.html', (err, content) => {
          if (err) reject(err);
          resolve(content);
        }
      });
      promise.then((content) => {
        content.replace(/<script([^>]*)>([\S\s]+?)<\/script>/g, (match, attr, template) {
          // 具体处理模板,略掉了
        });
      })
    });
    

    模板编译之后,还需要用 Webpack 打包才能使用,于是要增加 Webpack 的任务。这个比较简单,参考它的 文档 即可。不过很明显,必须等全部模板预编译完成才能打包。之前我已经试过用 run sequence 顺序执行任务,不过这里我用到 Promise,情况似乎有变。

    稍微 Google 一下,得知要能顺序执行任务有三种选择:

    使用 callback

    gulp.task('task', function (callback) {
      setTimeout(function () {
        // 任务执行完成后,调用 callback
        callback();
      }, 5000);
    });
    

    返回 stream

    这个好像是标准做法,也是我之前做的。

    gulp.task('task', function (callback) {
       returen gulp.src('*.js')
         .pipe(uglify())
         .pipe(gulp.desc('dist/');
    });
    

    返回 Promise 对象

    gulp.task('task', function () {
      return new Promise(resolve, reject) => {
        resolve();
      });
    });
    

    既然支持 Promise 那就好办了,在 .then() 前面加一个 return 就好。


    完整代码

    参考文章

    Handling Sync Tasks with Gulp JS

  • 初尝Gulp

    初尝Gulp

    Gulp自出世起,热度就很高。它利用了Node的Stream机制,速度很快;函数式的写法也很便于阅读。这两大优势让它一跃成为最受欢迎的批处理工具,几乎占据了半壁江山(2015前端工具普查)。

    我之前一直用Grunt,为了不落后于时代,前几天在一个业余项目中试用了一下Gulp,以下是我的感受。

    确实好读

    虽然无法得到证实,不过我相信Grunt的设计中有很多都是借鉴Ant得来的——在没有Grunt之前,我曾经用Ant脚本 + Google Closer Compiler + Google Closer Stylesheets 压缩代码——比如,它的配置是JSON格式的,跟XML非常相像。Grunt的问题也在这里:声明任务需要写JSON配置文件,不同的任务需要写在一起,然后通过registerTask('task', ['task1', 'task2:js', 'task3', ....])来组织。这样前后脱节,确实既不好写,也不好读。个把月回来完全看不懂也不算意外……

    而Gulp的设计则更加自由,它充分利用JavaScript的函数式写法,一个任务就处理一批文件,从上往下看,结构非常清晰:

        gulp.task('js', function () {
          gulp.src(['js/'])
            .pipe(concat())
            .pipe(replace('@version@', version))
            .pipe(uglify())
            .pipe(gulp.dest('dist/js/app.js'));
        });
    

    胜者:Gulp

    速度快,然无卵

    Gulp受推崇的另一大原因就是速度快,一般的任务都是毫秒级。

    不过,这对于我来说意义不大。作为一名人民币玩家,哥的惯用IDE是WebStorm和PHPStorm,均支持文件实时编译和自动刷新等常用功能。所以我只需要批处理工具帮我压缩文件和打包即可。

    这个回合:打平。

    Stream VS Native,异步 VS 同步

    前面提到,Gulp利用了Node的Stream机制,它的内部是处理文档流。这方面Grunt比较保守,仍然是把文件读进内存,然后进行字符串操作。二者的机制不同不好对比,不过作为从页面仔成长起来的前端工程师,不得不承认我对的理解并不深刻,对文件读取和二进制操作也不甚了了,所以在理解二者和开发业务插件的时候,我宁可选择Grunt。

    另外,Gulp的任务是异步的,所以在我的使用场景中——先clean目录,然后各种压缩,最后打包成zip——就很难搞(所以我觉得很多人用Gulp只是为了实时编译预处理文件)。后来用了sequence插件才搞定。

    这方面我觉得Grunt虽然保守,但是更接近前端开发者的知识结构,学习成本更低。

    胜者:Grunt

    杂项

    Gulp的团队应该是有代码洁癖的,比如,他们有一个官方插件仓库,这很正常;但是他们竟然还有一个Gulp插件黑名单……简直匪夷所思……

    所以Gulp团队显然不愿意重复发明轮子,比如简单的clean目录,他们就不愿意做,而且也不让别人做,因为已经有很多工具可以实现这个功能了……但是对于初学者比如我来说,就会在插件引擎中找半天,最后还是Google到相关指引才得到正确的做法。

    这方面Grunt团队做的很好。Grunt插件中有一组是官方提供的,以grunt-contrib为命名空间,基本上,使用这套组件就可以完成我所有的日常工作了。

    胜者:Grunt


    总结

    大趋势上,Gulp的确势头迅猛。但是从实际体验中,我觉得Grunt目前更成熟,也能满足工作所需。

    我并不想说Gulp不好,只是现在的我用起来不太顺手。如果哪天我有时间好好搞搞后端,搞搞Node开发,把Stream概念搞清楚,也许我也会转投Gulp。不过目前,还是继续用Grunt吧。

  • 近期要学习实践的新技术

    近期要学习实践的新技术

    众所周知,程序员是一个必须随时更新知识技能的职业。这其中,前端程序员尤甚。虽然我自称全栈,多半也要依赖前端技术作为小无相功驱使内力,方能打出少林寺七十二绝技写出其它平台的产品。所以,主动学习,更新知识技能是我必须坚持的。

    同时,在前端这个充满变革的领域,我不能把各种新奇的东西都放到实际生产中去。所以,不定期的集中学习就不可避免。

    那么,近期要学习实践的新技术有哪些呢?

    1. Bootstrap 4
    2. gulp
    3. Angular 2 直接从2开始吧,计划做个Todo
    4. React + React Native 要不做鸡血君?
    5. Polymer
    6. Material Design Lite
    7. Phonegap 5 自然是迁移游戏泡泡
    8. Eletron 结合别的技术做个写博客的工具。
    9. socket.io
    10. browserify

    希望能在年底前搞定。