放弃友言

告别友言,回归 WordPress 评论框。

WordPress 内嵌评论,不过不算太好用;当时也有其它用第三方评论的需求,所以就分别注册了友言和多说,游戏泡泡用多说,博客用友言。一直到现在。

多说前阵子关了,搜了一下发现网易云跟帖也要关了。国内硕果仅存的可能就是搜狐畅言了,不过搜狐嘛,老态龙钟,也不让人放心。最后决定,还是上外国的吧。

友言从我用开始就半死不活的样子,竟然坚持到现在,也挺难得。不过估计他们团队已经放弃这块业务了,Bug 多,功能少,各种服务失效。其实我早就想换,不过一直犯懒。现在 https 已经上了,友言也废了,提前切吧。

然后发现友言不支持评论导出……好吧,谢谢友言,有缘再见。

上 HTTPS

现在工具链如此成熟,上 https 简直容易到死。

为啥

  1. 更安全。现在经常在公共场合工作,如果登录博客走 http,太不安全。
  2. 更稳定。国内运营商劫持简直丧心病狂,只能 https 解燃眉之急。
  3. 更有逼格。好歹是个工作十几年的老油条,自己博客连个 https 都没,浏览器一直报告“不安全”,看着太低端。

怎么上

简直容易到死。我之所以选在这个时间上 https,就是想等工具链成熟。现在何止成熟,简直傻瓜。

  1. 免费证书有好几家,我选择 Let’s Encrypt,无他,他们家名字好记。
  2. 进入官网,选择 “Get Started” 进入下一页
  3. 简单阅读一下,他们建议使用命令行工具 Certbot
  4. 听人劝吃饱饭,那就用,进入官网,选择 Software -> Nginx,System -> Ubuntu 17.04,自动跳转到使用步骤。
  5. 然后安装 Certbot
  6. certbot --nginx(其实不带参数也行,它会自动检查),启动配置向导,跟着一步一步来。它会自动配置证书、自动修改 nginx、还可以更新证书,基本上一路回车就行。
  7. 修改 /etc/crontab,配置自动更新。按理说证书有效期为90天,差不多3个月更新就行。然而 crontab 只能按月配置,这样算起来一年有好几天会出问题,所以我干脆配置奇数月的第一天更新。

问题

  1. 七牛云需要独立的证书,申请中。
  2. 友言也挂了,看来要用回 WordPress 自己的评论,或者干脆 Disqus。

组件化的度

最近快被贵司的后台架构搞崩溃了,吐槽吐槽发泄一下。

加入贵司后,接手前端开发,主做后台产品。按理说,我在前司做了5年后台产品,轻车熟路,熟的不能再熟,这项工作对我来说应该再合适不过。结果进展非常不顺,甚至老板来敲打我,说工作效率太低,需求做的太慢。

我也不得不承认,就目前来看,自己确实没有达到很高的效率。不过我也得吐槽一下,这是有原因的!不是我不努力,而是现在的架构实在太太太……(我得选个好词,以免伤害到球哥的感情),太僵硬吧。

(目前的后台架构是球哥基于 Vue 设计开发的组件化框架。球哥是个码力十足,有追求有实力的人,我非常欣赏他,然则这套框架我实在不敢苟同。)

Vue 最大的优势,就在于它用很低的成本赋予了 Web MVVM 的能力。于是我们这些前端开发者可以用很低的软件复杂度,完成非常优秀的产品。而且,其作者还尽可能的把 Vue 解耦,降低入门门槛和使用门槛,我们不需要上来就面对一大批陌生的名词和概念,几乎可以直接上手实操。

可惜,与之同期到来的,还有“组件化”这把双刃剑。组件化当然有好处,它方便我们复用代码,提升效率。但也有很多开发者走上歪路——写组件库,用组件库。写组件库当然有好处,比如,是个扬名立万的好机会。用组件库也有好处,可以提升效率,省去很多开发量。

但是,所有组件库都有一个避不开的槛——颗粒度。颗粒度太细,用起来跟原生 HTML 差不多,意义不大;颗粒度太粗,一旦不合业务逻辑,就会很蛋疼(对,我就很蛋疼,简直每隔几天蛋就要碎一次……)。怎么样来确定颗粒度的粗细呢?只能看业务了。

2B 开发的特点

回到2B业务上。2B开发有几个明显不同于2C开发的地方:

  1. 业务流程又长又复杂
    • 2C 业务,比如微博、微信,用户操作简单直接,效果反馈很快
    • 2B 业务,如果某个操作要填10个表单,经过5个环节审批,那就一个都少不了
  2. 客户多付费,必须尊重他们的需求

这两点之下,会产生一些要求:

  1. 表单复杂,校验项多,灵活性要求高。此时,表单生成器就不再适用;只要,要把可以生成的简化版,和需要人工的复杂版分开。
  2. 表格多,列多,单元格多变。此时,表格组件也不宜复杂,处理好简单的分页筛选即可,剩下的还是交给业务相关的组件。
  3. 表格表单复用性差,很多表格表单都只出现一次,或者有自己独特的需求。此时,组件的优势不复存在,工作量怎么做都是接近的,反倒是原始的做法更清晰直接。

2B 开发的组件化

所以,我认为,2B 的产品,不适宜上来就用组件库搭建复杂的框架。相反,用最简单直接的 HTML、JS 元素,加上 MVVM 特性,效果会更好。

初期

最合适的组件化方案就是“不要过早组件化”。组件化的颗粒度以增强原始 HTML 元素为主,比如 Typeahead(输入搜索下拉选择)、给 Input 增加通用的校验工具,等等。用几乎最原始的方式开发,完成需求。这样看起来土,但带来的两个非常重要的好处:

  1. 思路直接,符合直觉,开发者不用投入大量精力学习新框架可以凭直觉完成
  2. 颗粒细,方便实现各种业务逻辑。比如表单想哪几个字段一起校验就一起校验,想怎么显示数据就怎么显示数据。

中期

这个时候我们应该完成很多需求了,哪些组件使用频繁值得抽象,哪些组件很复杂但是只用一次,大家心理都有数了,就可以开始着手进行组件化的工作。

不过,这个时候,仍然不需要做什么表单生成器、表格生成器之类的东西。我们要做的,是强业务相关组件。比如,某个表单在多处被重复使用,我们就要想办法把它抽象成组件(一般用到第3次,就要考虑做组件,用到第4次就一定要做成组件)。做出来的组件,只包含这个表单;抽象的目的:统一管理这个表单,方便别人复用。

抽象成组件的目的,是让今后的开发更成熟快捷,不是为了提炼出一套通用工具集,放到市场上扬名立万。

晚期

这个时候我们应该积累了不少组件,足以应付日常需求,可以快速响应快速开发。此时,组件化以重构为主。

最终,很遗憾,我们并未收获一套普适的通用组。但是,我们得到一套和业务深度绑定的组件库,和建筑于底层,弹性好鲁棒佳的架构。


这才是我眼中的组件化之道。

尬聊会:第四期实录

尬聊会第二期实录。聊了学习、半路出家、去哪里找工作等问题。

视频地址 Bilibili

时间:2017-09-17 22:00
地点:douyu.tv/meathill
回看视频:http://blog.meathill.com/tech/galiao-4.html

0. 试讲 PPT

https://github.com/orgs/meathill-lecture/

1. 从学校到工作必须习惯的转变

有人问:觉得现在的工作比较难完成,怎么办?是不是要换工作。

职场当中,普通员工和领导之间,基层领导和中层领导,中层领导和高层领导,大多数处于一种荣辱与共的状态,是多和博弈。所以,尽早与领导沟通,重新安排分配工作,对大家都有好处。换工作这里并不合适。

之前写的一篇文章 开发新人要适应的变化

2. 学习方法,我学了东西很快忘

  1. 尽量多的做东西
  2. 尽量的关注这方面的内容
  3. 做一些自己的小产品/工具

3. 编程思维

有时候需要一个需求,明明不难,却无从下手

—— 写得少

把数字转成中文大写,比如 1024 => 壹仟零贰拾肆

方法同上。

走出舒适领域。

4. 老师, 我是半路出家, 非计算机方向。在编程道路上常常会有力不从心。

  1. 可以解决,比如通过阅读、看视频、练习等
  2. 可以忽略,需要我们学会区分知识的边界

5. SEO 分页还是ssr好

如果服务器很好,那无所谓;不然的话,静态分页好。

6. 找工作去哪个网站比较好

建议大家常泡社区:

  1. https://segmentfault.com/questions
  2. https://www.v2ex.com/

7. 找工作技术和人力都过了还是没要我,怎么回事?

  1. 有更合适的人选
  2. 这个岗位不招人了
  3. 这个岗位出现了变化
  4. 你感觉错了……

尬聊会:第三期实录

尬聊会第二期实录。聊了跳槽、工作选择、加班等问题。

视频地址 Bilibili

时间:2017-08-06 22:00
地点:douyu.tv/meathill
回看视频:http://blog.meathill.com/tech/galiao-3.html

  1. 我的第一份工作,兼谈如何跳槽
    1. http://blog.meathill.com/internet/days-in-a-company-first-leave.html
    2. http://blog.meathill.com/internet/days-in-a-company-quit-relax-and-back.html
  2. 为什么尽量避开外包公司?
    1. 对技术要求很低
    2. 对产品的标准很低
    3. 没有办法在一个产品做持续的投入
    4. (大外包公司)很难和采购外包的企业共同发展
  3. 李文星事件的启示:
    1. 天上不会掉馅饼
    2. 了解这个社会的运行机制
    3. 学会算账
  4. 加班好不好
    1. 拒绝制度性加班
    2. 拒绝崇拜加班的领导
    3. 如果总加班,很可能是管理能力太差
    4. 不要盲目拒绝加班
  5. 从小公司跳到上市公司 有可能吗

  6. 大佬前端学习路线大概是什么样

解决 [Vue warn]: You may have an infinite update loop in a component render function

在 `v-for` 循环当中,如果用方法或者计算属性对 vm.$data 的属性进行操作,理论上,可能因为修改到循环对象,诱发无限循环。此时 Vue 就会发出警告(并不是真的已经无限循环了)。

今天写着写着,突然发现控制台里有错误:

[Vue warn]: You may have an infinite update loop in a component render function

这个问题很奇怪,之前从来没有遇到过。如果是我自己主导的项目,倒也好办,慢慢 debug 就是;偏偏在公司的项目里遇到这个问题,而公司项目的体系结构很复杂,我还没完全掌握。更恼火的是,因为体系复杂,debug 也非常困难,再加上尚无测试框架,这个难搞啊……

好死不死的,当时是下午3、4点钟,正好到了肚饿的时刻,结果又落入低血糖状态,真是屋漏偏逢连阴雨,船小又碰顶头风,饿得我脑仁生疼……

不过终于还是被我 Google + debug 出来。事实上是这样的,在 v-for 循环当中,如果用方法或者计算属性对 vm.$data 的属性进行操作,理论上,可能因为修改到循环对象,诱发无限循环。此时 Vue 就会发出警告(并不是真的已经无限循环了)。

例如这样一个组件,它里面是用 :checked + <label> 实现的一组按钮。它有以下功能:

  1. 为了能够分组,需要设置它们的 name 属性
  2. 为了能够用 <label> 控制 <input>,需要给 <input> 设置 id
  3. 按钮可以被删除

于是我选择这样做:

<template>
<div>
  <template v-for="(item, index) in items">
    <input type="checkbox" :name="'my-component-' + selfIndex" :id="getID">
    <label :for="getID(false)">
    <button type="button" @click="remove(index)">&times;</button>
  </template>
</div>
</template>

<script>
let count = 0;

export default {
  data() {
    return {
      selfIndex: 0,
      itemIndex: 0,
    }
  },
  methods: {
    getID(increase = true) { // 注意,问题就出在这里
      if (increase) {
        this.itemIndex++;
      }
      return `my-component-${this.selfIndex}-${this.itemIndex}`;
    },
  },
  beforeMount() {
    this.selfIndex = count;
    count++;
  }
}
</script>

这里,为了能生成唯一 ID,我选择每次循环都对 vm.itemIndex++,这就会出现前面说的问题,存在隐患。

解决的方案有两种,一种是把 itemIndex 也放在局部变量里,使它不直接关联在组件上;另一种则是写一个全局的唯一 ID 生成函数,然后引用进来。原理都是一样的。


这两天听评书《乱世枭雄》,学到一句话“拉屎脸朝外”,形容讲义气,不知道咋联系的……

MediaElement 笔记

贵司官网需要放视频,于是需要用播放器,最后选定 MediaElement。然后就开始踩坑之旅。当然,有些是我的问题,不过也有不少是文档没说清楚。这里记录一下。

贵司官网需要放视频,于是需要用播放器。然后就产生如下需求:

  1. 协议好,支持免费商用,最好 MIT
  2. 支持 SRT 字幕
  3. 支持尽可能多的平台

经过筛选,最后选定 MediaElement,一看 WordPress 在用基本就放心了。然后就开始踩坑之旅。当然,有些是我的问题,不过也有不少是文档没说清楚。这里记录一下。


全屏和弹性宽度

当前版本 4.2.5 有个 Bug,如果设置宽度为 100%,那么从全屏恢复到内嵌状态时,会留着全屏的宽度,撑开页面。如果设定一个特定的宽度就不会。但我们的页面是响应式的,需要允许它随页面变化而变化。

这个时候只好手工来做,我的选择是让它 100%,然后侦听从全屏返回的事件,发生后就把宽度恢复。另外,因为 fullscreenchange 事件还没有统一标准,所以不同浏览器里的事件名称也不一样,更不爽的是,IE 下是驼峰,其它浏览器是全小写,我也懒得再写函数转化了,反正就3种情况,全写一遍好了。

// fix MediaElement's issue
  let fitVideo = function() {
    setTimeout(() => {
    $('.mejs__container').width('100%')
      .find('video').width('100%')
      .end().find('.mejs__layers')
      .children().width('100%');
  }, 50);
};
if ('onwebkitfullscreenchange' in document) {
  document.onwebkitfullscreenchange = function() {
    if (!document.webkitFullscreenElement) {
       fitVideo();
    }
  };
} else if ('onmozfullscreenchange' in document) {
  document.onmozfullscreenchange = function() {
    if (!document.mozFullScreenElement) {
      fitVideo();
    }
  };
} else if ('MSFullscreenChange' in document) {
  document.MSFullscreenChange = function() {
    if (!document.msFullscreenElement) {
      fitVideo();
    }
  };
}

默认字幕

Web 标准是有默认字幕的,<track defualt> 即可。但是 MediaElement 没有,最后在 StackOverflow 上找到答案,原来有个未记录在文档里的初始化属性可以控制:

let player = new MediaElementPlayer('intro-video', {
  startLanguage: 'cn', // 这里的名字应该和 <track> 种的 srclang 属性一致
});

插件与生态

MediaElement 把一些有用但不太常用的功能抽出来做成了插件,放在 MediaElement Plugins。不过看起来这个项目有些属于维护,使用的时候很多问题。比如,直接在 features 里开启特定功能,即使对应的插件没有加载,也不会报错,就是没反应,很令人迷茫。

避免发起又取消请求

网站上线后,老板发现一个问题:从 Chrome 的 Network 面板可以看到,网页打开后,对视频文件发起了一到多个不等的请求,并且都取消了。

经过研究,我认为这个请求是 <video> 发起的,因为 preload 的默认值是 auto(参见:MDN),也即打开页面就预加载。而此时 MediaElement 被初始化,为了正确显示 UI,它会把 <video> 标签挪到自己创建的 <div> 里,这个过程就会导致“预加载 -> 取消”。因为视频默认不播放,所以我给 <video> 加上了 preload="none",问题解决。


其它大体上文档都能找到,就不多说了。

Vue 里 $mount 方法的作用

关于 Vue 的 $mount 方法,一问一答。

今天由同学问道:“vue文档里说如果 Vue 实例在实例化时没有收到 el 选项,则它处于“未挂载”状态,没有关联的 DOM 元素。可以使用 vm.$mount() 手动地挂载一个未挂载的实例。这个方法在项目中有什么用呢,是一个组件可以挂载到多个dom上就这一个作用吗?”

我的答案如下:

有些时候你创建 vm 的时候 DOM 可能还没准备好,或者写 vm 的时候不确定它要挂在哪个 DOM 上,这个时候就有用了。

当项目大的时候,很多情况是开发的时候估计不到的。比如 A 类里面想使用一个 B 类,但是 B 类有 10 个子类,对应不同场景,你写 A 类的时候根本不知道产品中会使用哪个 B 的子类,所以就要想办法把控制权交出去,这就叫“控制反转”——即控制权从开发者的手上,交到使用者的手上。

我觉得 $mount 这里也是类似的,就是你写了一个 Vue 类,但是不能控制使用场景。所以就要有一个 $mount 方法,由使用者控制,绑到目标 DOM 上。

他又问:“懂了,还有一个问题是一个组件能不能利用$mount属性挂载到多个dom上,我刚刚试了一下是可以渲染,这种用法常见吗??”

我答:

我没这么做过,不过我认为是合理的。

我觉得这个跟 Vue 的定位有关。Vue 和 React、Angular 不一样,后者是大公司企业级产品。Vue 其实很想取代 jQuery,所以这方面其实跟 jq 的插件是很相似的。

Webpack 笔记

记录一些 webpack 的使用经验。我是渐进式使用 webpack 的,一开始只用它打包 js。但是现在开始会把越来越多的依赖交给它管理,所以记一篇笔记。这里不会教怎么使用,而是结合开发经验,总结一些特定需求的解决方案。

我使用的版本:3.5.1

我是渐进式使用 webpack 的,一开始只用它打包 js。但是现在开始会把越来越多的依赖交给它管理,所以记一篇笔记。这篇不是教程,而是结合开发经验,总结一些特定需求的解决方案。

继续阅读“Webpack 笔记”

关于“大漠”的一点不好的记忆

关于大漠的一点不好的记忆。不过当年没搞清楚到底是哪个。发生了最近的事情,我觉得可能是这个……

我这个人不爱交际,在行业里一直是个小透明。

不过我当年也曾想试着改变一下自己,所以找了个前端交流群加了进去。具体的群名字忘记了,总之是“大漠”创建的群。

然后发现这个群真TM恶心。群主大漠有几个小弟,一副高高在上颐指气使的样子,对群里成员吆五喝六随意攻击,不仅对发问者提出各种限制,对回答者也提出各种限制。群主也是一副老子对你们这些废柴施恩,还不快快对我歌功颂德的气势。(具体做法记不清了,好多年了。)

然后我就受不了啦。如果前端圈子都这个吊样子,那我不交际也不要紧。于是吐槽两句自己退群了。

退了之后,想说这个大漠是谁啊,怎么这么差劲,然后搜了一下,发现叫这个名字的好多,无法确定是哪个,我也懒得跑回去确认。


发生了最近的事情后,我举得按人品和气度,有可能是这个……