bower小技巧一则

在项目根目录下创建.bowerrc文件,可以改变bower安装组件的默认目录。

早先看到过一个用socket服务在线调试PHP的工具,后来怎么也找不到,于是决定自己造轮子。socket.io提供WebSocket服务,nodejs(今天竟然发布了5.0stable,简直丧心病狂) + express.js做服务器端。以前没有正经用过express.js,不过感觉上把Web所需的内容和nodejs所需的内容混在一起应该不是什么最佳实践,还是分开比较好。

使用express.static('public')可以把public目录映射为web根目录。但是用bower管理依赖的话,默认安装目录在项目的根目录,虽然也可以映射出去,不过实际路径和项目路径有异,Webstorm里的黄色波浪线看起来也很不舒服。

Google一下果然bower可以解决这个问题。在项目根目录下创建.bowerrc文件,按照JSON的写法,写入:

    {
      "directory": "public/components"
    }

就可以指定别的目录作为安装依赖的位置。然后可以移动原来的依赖文件夹,也可以重新执行bower install

Chrome表单验证和keyup导致的灵异问题

chrome的表单验证在keydown之后触发,可能会导致依赖keyup事件的一些东西出问题。

先说下环境,Mac OS El Capitan + Chrome 46,框架是Backbone + Boostrap。

我做了一个自动搜索组件,独立测试时一切正常,放到产品中,别的都没问题,只有回车会出问题。代码在这里

不用说,这个问题很诡异,调试了半天没有头绪,只能通过观察现象去推测:

  1. 没有报错
  2. 除了回车,其它功能正常
  3. 除了回车,keyUpHandler都能被正确触发
  4. 回车后,光标跳到其它元素

看来看去,第4条最可疑——我按的是回车,它会什么会跳到别的单元格呢?

这次运气比较好,表单中的接下来的几个元素刚好是日期,用到Bootstrap Datetimepicker这个插件,focus之后会自动填充日期。于是我发现,每次跳到的“其它元素”,都是原先空白的,而且是required的;不会跳到固定的,或者紧挨着的那个文本框。

于是我便想,会不会是:

  1. 表单submitkeydown之后触发
  2. 触发之后进行表单验证,发现有未填的required元素,于是跳到该元素并提示
  3. Bootstrap Datetimepicker响应focus时间,填入日期,提示消失
  4. 我的Typeahead响应blur事件,隐藏列表
  5. keyup事件触发,但是输入框已没有焦点,就没有触发

这个推测看起来有点道理,于是我把侦听的事件改成keydown,问题果然解决。

再访富国岛

希望孩子慢慢长大,慢慢将我们的世界分享给他。

2011年,我参加工作的第五个年头,201二进宫的第二个年头,我和老婆去越南富国岛度蜜月。这趟旅程给我带来的远不止美好的回忆:第一次出国,各种新奇的经历,让我禁不住重新思考过去五年在201的种种经历,最终决定立刻离开。

所以我现在经常建议年轻人出国转转,修正修正三观。

言归正传。这次国庆本来计划去甲米或者别的什么没去过的敌方,后来订票订晚了,到处都很贵,于是想起来这个性价比极高的地方:上次曾经订下一个5年之约,虽然这还差半年,也算是还愿了。

越南,富国岛,似乎没有太大的变化,Mango Bay有好吃的食物和开放的房间,Bai Sao依然美丽动人,Le Verenda的服务和环境也仍然让人心旷神怡。不过对于我们而言,最大的变化是这次带了姆二。亲子游最大的变化就是一切日程以孩子为准:早上起来吃早饭,然后找个地方玩一下;然后吃午饭,睡午觉;醒了再找个地方玩一会儿,接着就吃晚饭;然后回去洗澡准备睡觉。第二天重演这个过程。

原本想躺在沙滩上发呆,或者坐在露台上看书,或者两个人一起做马杀鸡,结果全成了陪小朋友挖沙土或者游泳。而且感觉时间过得飞快,一睁一闭,就回来上班了!有了孩子就是这样,带了他要后悔,不带的话,可能更后悔。

Anyway,仍然希望孩子慢慢长大,慢慢将我们的世界分享给他。

初尝Gulp

本文从4个方面对比了Grunt和Gulp的优劣,根据我个人的状态,最终还是选择Grunt。不过将来,说不定我也会转投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吧。

Handlebars 4

Handlebars升级到4.0后,{{#if}}不再作为一层影响查找,以前的`../../`可以改成`../`了。

图文……好像有关。

Handlebars自从升到2.0之后,就放开了,版本号蹭蹭涨,如今已经升到4.0版。

这个版本最显著的变化在于层级结构,以往的版本中,所有的Block Helper都可以形成一个层级。对于{{#each}}{{#with}}这种还好说,层级关系比较明确,很好理解;但是{{#if}},也有可能形成一个层级,这就很奇怪了。尤其像我前文所述,它只是可能形成一个层级,就更诡异了。

所以这个修改其实是件好事儿。

接下来,代码时间。

Before

    {{#each list}}
      {{#if is_true}}
        <p>这里需要向上两层才能找到值。{{../../value}}注意,这里是两层。</p>
      {{/if}}
    {{/each}}
    var data = {
        list: [
          // items..
        ],
        value: 'value'
      }
      , template = Handlebars.compile(hbs);
    template(data);

After

    {{#each list}}
      {{#if is_true}}
        <p>这里需要向上两层才能找到值。{{../value}}那,这里只有一层了</p>
      {{/if}}
    {{/each}}

JavaScript是一样的。

总结

为了写这篇文章又去看了一遍Handlebars的文档,发现新增了不少特性,尤其开始支持子表达式,看来有必要再好好看一遍。

近期要学习实践的新技术

接下来的一段时间里主动学习,更新一下知识。

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

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

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

  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

希望能在年底前搞定。

大招募!2016年春节北海道滑雪之旅

计划明年年初去日本滑雪。

这个人啊,真的跑不了的。有了孩子后,啥都想给他。今年去清迈耍了泼水节,回来后突然特别想带他去滑雪,当然也有吃货俱乐部北海道特辑的原因。加上以前就特别想跟老婆去日本,于是便开始各种YY。

现在准备把YY落地,同时也向各位兄弟姐妹同学同事发出邀请(是的,我不仅好了伤疤忘了痛而且忘得厉害),明年我们一起去北海道打雪仗吧!

继续阅读“大招募!2016年春节北海道滑雪之旅”

招募!2016清迈泼水节

2016年清迈泼水节开团了!快来加入我们吧!

今年,我们全家一起去了清迈,并且参加了泼水节,非常好玩。所以我准备明年多组织点人,一起去玩!(是的,我已经从上次比较失败的岘港会安之行中好了伤疤忘了痛了)

以下是一些照片:

(直接把照片贴了,懒得写游记了)

怎么样,很好玩吧!快来加入我吧!!


接下来是详情。

泰国 清迈 泼水节

泰国是旅游圣地,就不多说了。清迈位于泰国北部,是泰北的政治经济文化中心。它历史悠久,兴建于七百多年前,号称兰纳(Lanna)泰王国。以前是泰国的附属国,后来被并入泰国。所以清迈的气质和泰南的大城市比如曼谷相差很大(其实我没去过,这段属于道听途说),清迈更加小清新,甚至我们连人妖都没见到。清迈被华人所熟知的另外一大因素便是邓丽君,据说她最喜欢清迈,经常来此疗养,最后不幸发生时也香消于此。至今梅坪酒店仍然保留着那个套房,供后人瞻仰。

泼水节当地人称宋干节,起源于沐浴礼佛,尤其是用净水清洗佛像,后来演变成水枪大战。据我目测有以下玩法:

  1. 塔佩门广场是最大的一处战场,乱战
  2. 沿护城河一圈,大家各自守着各自的门口,对战路上的行人和车辆
  3. 当地人或外地人可以租皮卡,绕着护城河的道路转,与守路的人对战
  4. 城里的小路上也有很多人(以小孩子居多)各自为战
  5. 商家自然不会错过这个机会,会在各种路边搭起各种站台,请妹子在台上跳舞,和台下泼水互动

参与的有当地人,有外国人,年女老少都有,随便泼,有些人很坏,用冰水,超刺激。一般来说,穿着花枝招展的美女,与扎眼的各种人,都是吸引炮火的对象。

其它娱乐项目

除了泼水和窝在酒店里,清迈作为著名旅游城市,其它娱乐项目也很多。比如照片中我们参加的大象营。还有各种丛林探险、速降、自行车越野等。对于女生来说,马杀鸡和SPA必不可少,这边各种档位的都有。有兴趣的还可以报名厨艺班,学习一下当地菜肴的做法。

作为泰国丽江,就算再咖啡馆泡着也是可以的嘛!

开销

清迈的消费还是蛮低的,普通小店一顿饭10~15块就能搞定,大一点的店也就30、50块。当然,大餐也有,我们为给老妈过生日,定的Le Crystal,车接车送,大概一个人不到400吧。

清迈水果丰富,到处都是冷饮店咖啡馆,一杯smoothie 10+,果汁3、5块。

泼水节期间晚上都有夜市,基本上都是2、3块、5、6块,二十块可以吃很多东西了,还有30块/小时的大街马杀鸡。

唯一贵的可能就是酒店。泼水节期间,古城(水战中心)的酒店都会涨价,平时200随便住,这时候大概要400~600。我们住的Rich Lanna,标间一晚(含早餐)要将近600,不过地段相当好。

总之,做好“穷家富路上”准备的我们,无时无刻不觉得,好便宜啊……

其它注意事项

咳咳,丑话放到最后说。

我觉得很好玩,所以力邀各位朋友一起来玩。但是我不是专业搞旅游的,而且我也属于生活半不能自理+选择性障碍+懒的人,所以我觉得我还是不带队好。如果大家一起来玩,我能提供的:

  1. 资讯,包括日程,购物等
  2. 机票酒店推荐
  3. 提醒大家必需物品

我不能提供的:

  1. 管吃管喝管玩
  2. 订机票酒店

我希望的,就是大家商量好,来年一块儿去,到清迈碰头一起玩,想一起玩就一起玩,想自己SPA就自己SPA,各自分享好吃的好玩的好看的,就OK了。

报名啊报名

  1. 小囧表示了兴趣,所以蛋东也可能回来。如果大家都是201的,团名就叫“中X村不在线”好了,哦也

Mac OS上各种开发环境的配置(未完成)

Mac OS下各环境的配置。

很多开发人员喜欢 Mac OS,因为它基于FreeBSD,有原生的命令行工具,配置各种开发环境都很方便。我个人偏爱Windows,我觉得各种可视化用起来更爽。

这篇文章介绍如何在Mac OS 10.10 Yosemite上配置各种开发环境,范围以前端所需为主。

Xcode

无论你是否准备开发iOS或者Mac OS上的应用,Xcode最新版都是必须的。因为里面包含了系统必须的命令行工具和编译工具,没有它们支持,我们就无法安装后面那些东西。

好在Xcode是免费的,虽然体积巨大(而且早年不支持断点续传,我第一遍Xcode装了半个月),但只要你有恒心有毅力,智商正常,就都能装上。

方法:

  1. 打开App Store
  2. 搜索Xcode
  3. 安装
  4. 安装完成后,在命令行里运行xcode-select -p,如果显示/Applications/Xcode.app/Contents/Developer则表明Xcode 命令行工具已经安装成功,否则的话,执行xcode-select --install安装

homebrew

工欲善其事,必先利其器。在*nix环境下装东西,一个好的包管理工具是必须的。我使用的是Homebrew,它的安装非常简单:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

因为Mac OS默认包含并启动了Ruby环境,所以此时系统就开始执行homebrew的安装。关于brew的用法,可以看它的官网,或者运行brew help阅读帮助。

nodejs

有了homebrew,一切都好办了。

brew install nodejs
node -v

不过我更喜欢标准版,在nodejs的官网下载dmg安装包,直接安装即可。

ruby

Mac OS默认包含ruby,不过我喜欢最新版,所以还是拜托给homebrew好了。

brew install ruby

homebrew会把包安装在/usr/local/Cellar目录下,然后通过软链接链接到/usr/local。有些系统默认包含的组件已经注册在/usr/local或者/usr/bin,创建链接可能会失败。不用担心,homebrew提供了详细的帮助信息,仔细阅读,按照提示一步一步做,就OK了。

Python & httpie

python我用的很少,耳闻3和2差别巨大,也就不敢追新。所以我用系统自带的Python,只是安装了 httpie 这个工具来调试远程数据。安装一样是通过homebrew:

brew install httpie
http httpie.org

apache httpd

Apache httpd是Mac OS的默认组件,直接运行sudo apachectl start即可开启apache服务器,然后访问 http://localhost/ 就能看到默认页面了。

系统默认的文档地址为 /Library/WebServer/Documents,把静态的页面放进去,就能正常浏览,用来测试还是蛮方便的。不过我觉得不算太实用。因为一来埋得很深,通过Finder无法直接到达;二来作为公司配的开发机,一般来说我不建议在公共目录里做东西。

不过配置起来也不复杂。打开 /etc/apache2/extra/httpd-vhost.conf,里面应该有两个没有真正起作用的范例配置。基本上按照那里即可。

先放出去,回头再补充好了……

漏装php55w-mbstring导致中文邮件乱码

yum安装新版本php需要手动安装各种依赖。

朋友的WordPress发中文邮件总是乱码,喊我帮忙看看。很奇怪,后台、文章里的中文都能正常显示,看起来一切正常;我在我电脑上搭了一套,同样的代码,发邮件也没问题。

后来打开phpmailer的debug模式,发现什么都对,就是中文内容都是问号。

继续往上找到发邮件的函数,运气不错插件留了filter,遂修改模板,add_filter强制转换内容。

转换前先检查,不是UTF-8再转:

    if (!mb_detect_encoding($content)) {
      $content = iconv('ASCII', 'UTF-8', $content);
    }
    return $content;

结果代码传上去报错,说没有mb_detect_encoding,然后想起来yum安装php时确实默认不包含很多扩展,于是手动安装yum install php55w-mbstring。然后重启apache,发邮件测试,正常了。

我又想是不是缺少多字节文本模块(Multibyte String)导致原先无法发送中文呢?去掉filter,仍然正常,确实如此。

总结

yum安装新版php需要增加源,而新版的源默认不包含很多常用的库,使用的时候最好都装上。WordPress的翻译机制面对多字节文本时,编码不对不会报错,也需要小心。