All Posts

在JavaScript项目中锁定npm依赖包版本

问题 最近在项目中遇到这样一个问题,webpack生成的vender包的哈希值在我和同事的电脑上不一致。由于之前已经配置过了CommonsChunkPlugin(配置如下),所以我们期望的结果是在不同环境下构建出的文件哈希值应该是一致的。 注:只给出了和本文内容相关的配置项 module.exports = { entry: { app: './src/js/app.jsx', vender: [ 'classnames', 'react', 'react-dom', 'redux', 'react-redux', 'redux-promise-middleware', 'updeep', 'axios', 'jdc-rc-list', 'react-router', 'react-router-redux' ] }, output: { path: path.resolve(__dirname, './build/js/'), filename: (isDevelopmentEnvironment ? '[name].bundle.js' : '[name].[chunkhash].js'), chunkFilename: (isDevelopmentEnvironment ? '[name].bundle.js' : '[name].[chunkhash].js') }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: ['vender', 'manifest'], minChunks: Infinity, }) ] }; 调查 经过多次验证发现,我们在各自的电脑上多次构建出来的哈希值可以保持一致,只是在两台电脑上不一致。考虑到vender中打包的都是第三方依赖,于是猜测是两台电脑上安装的依赖包不同。接着对比了两人的package.json中的dependencies,完全一致。 考虑到package.json文件中包版本中的^符号匹配的范围比较大。参考npm官方给出的解释: ^1.2.3 := >=1.2.3 <2.0.0 ^0.2.3 := >=0.2.3 <0.3.0 ^0.0.3 := >=0.

React Conf 2017视频 百度网盘地址

React Conf 2017的全部视频已经在YouTube上放出来了。为了方便在家里的电视上播放,就全部下载了一套。顺便上传了百度网盘一份。感兴趣的可以看看哦。全部720p。 下载地址: http://pan.baidu.com/s/1gfl5FzX

园博园一日游

来北京快3年了,之前每次坐高铁回家都会路过园博园。每次透过车窗看到园里漂亮的风景,总会和老婆商量着什么时候来。可惜我住在大东边,园博园在帝都西南角,每次想到坐地铁要2个多小时就放弃了。现在有车了,出行方便了,却又总也想不起来了。昨天还是老婆提议:『我们明天去园博园啊?!』于是俩人一拍即合,来一场说走就走的春游。 订票 确定要去,马上在携程上定了两张门票。原价20,携程上18。(点此订票)注意:携程上买的电子票只能在园区三号门的售票处换票。这点千万注意。 出发 今天早起看天气,格外给力。天很蓝,云很白。吃过早饭,8:40从家出发。一路畅通,只用1个小时就把五环跑了半圈,到达目的地。 到达导航终点遇到了第一个问题,百度地图上搜到位于长顺一路上的停车场都是临时停车场,现在已经关闭了。于是掉头往园区正门开去,一路上有不少车在掉头。看来是不少人都中招了。不过好消息是园区正门有保安在指挥,正门再往西一点点就是正式停车场了。 蓝色圈圈就是停车场的位置。 停好车,背上包往园区正门走。换票很方便,把携程发来的取票码出示给工作人员就好了,购买特价票(包括电子票)必须要出示相关证件哦。排在我前面的一个大姐买了老人票但是没带证件,只好退票重新买。另外一个要注意的就是,园区不允许携带宠物进入。 入园 正门门口 入园后,园区内部是由许多馆/园组成的。比如一进门看到的鄂尔多斯馆、合肥园、荆门园等等。都是以省市或古地名命名的。或大或小,各有特色。随便放几张照片感受下: 晋中园 晋中园内的戏台 合肥园门口的牌楼 粤秀 各种园实在太多,我们自己走的也只是很小一部分,就不一一列举了。有兴趣还是亲自去看一看。下面说三个重点推荐的景观吧。 附一个园区地图(可以右键新窗口打开查看大图) 北京园 北京园应该是园博园里最大的一个园了,毕竟是首都嘛。建筑风格也保持了皇家建筑的大气,威严。 北京园内的主要建筑:聚景阁 古都北京山川形胜写意 忆江南 这里可以说是今天行程最大的收获了。出乎意外的美。置身其中,仿佛一下子去到了江南某个小城的私家园里之中。 永定塔 永定塔位于园内西北部的半山腰上,是园区的最高点,也是我今天走到的最远的位置。老婆在逛完忆江南后就走不动了,找了个长凳休息。于是我开启了暴走模式,直奔永定塔。 终于来到山下,拾阶而上,一路没什么人。 离塔越来越近 途径文源亭 文源亭后是两条铁道,时不时还会有货运列车经过。 在文源亭远眺北京城,可以看到中央电视塔,国贸。这天气,视野真的很不错。 继续上山,偶然发现的隧道。从文字上也看的出很有历史啦。前面提到的两条铁轨就穿过这里从永定塔下穿行而过。 终于来到塔下,可惜并不对外开放。只能在外边看看啦。 餐饮 从永定塔下来已经是下午1点了,还没吃午饭。于是一边往大门走一边找吃的。然而并没有什么收获,要么是路边小亭子里吃泡面,要么是去少数几个餐厅里吃。看到一个吉祥馄炖,走进去看了看就出来了。环境很一般,很多人在打扑克牌,比较吵。上一个菜价单供参考: 最后午饭在石景山华联的呷哺呷哺解决的。从园博园开车过去大约20分钟左右。可选择的的餐馆也很多。比园区里的那些餐饮靠谱多了。 费用小计 最后附一个今天的费用小计,供参考: 园博园停车:20(5元/小时) 园博园门票:36(18元/人) 华联停车:6元 呷哺呷哺:74元

配置Fiddler拦截iOS/Andorid的https请求

Fiddler可以配置用来拦截https请求。但默认配置下仅支持拦截PC上的请求。在移动端上的https请求会因为证书问题而失败。如下图所示: 要解决这个问题,只需要在iOS/Android系统上安装一个安全证书即可。具体步骤如下: 访问http://www.telerik.com/fiddler/add-ons,下载并安装CertMaker for iOS and Android插件。 安装完成后重启Fiddler。 重启后浏览器访问http://ipv4.fiddler:8888,如果看到如下内容,表示安装成功。 在手机浏览器(iOS建议Safari)里打开前边提到的链接,点击页面中最后一个链接FiddlerRoot certificate。下载完后会提示如下页面: 点击安装,弹出安全认证,要求输入密码。输入后出现以下页面: 继续点击安装。安装成功提示如下: 到这里,所有的配置工作就全部做完了。现在再次访问https页面,已经可以正常打开了。

键盘鼠标共享神器 Mouse without Borders

如果你像我一样办公桌上有2台或以上的电脑(比如一个台式机,一个笔记本),那么有个问题一定在困扰着你。那就是两台电脑有各自的一套键鼠设备。来回切换使用两台电脑的时候要在两套键鼠设备之前切换,非常不方便。同时,两套设备还会占据办工作上很大的空间。 今天要分享一个神器帮你解决这个问题,那就是微软出品的Mouse without Borders。通过它,你可以利用一套键鼠设备在若干台(最多4台)电脑之前无缝切换。就好像是在两个连接在同一个电脑的两个显示器之间切换一样方便。 使用方法 下载并安装Mouse without Borders,需要连接的两台电脑上都要安装。 下载地址 在两台电脑上都启动程序。会看到如下的欢迎界面 在第一台电脑上点击NO,看到如下页面。记下这里的SECURITY CODE。 在第二台电脑上点击YES,输入之前记下的SECURITY CODE和主机名。点击LINK。 连接成功后会出现以下提示界面: 按需修改配置。配置界面如下。通常默认配置已经够用了。如果确有需要按需调整即可。 功能,特色 Mouse without Borders的主要特色有: 一套键鼠控制多台设备 各台设备间完全平等,可以使用任意一台主机的键鼠控制任意其他主机 各台主机间共享剪切板内的内容,随意复制粘贴(支持复制文件) 支持在主机间拖拽复制文件 可以截取任意一台设备上屏幕的内容(Ctrl+Shift+S进入截屏模式,鼠标拖拽选择截屏区域,在本地打开画图工具,Ctrl+V即可看到截图内容) 缺点 我的能想到的唯一缺点就是不支持跨平台,仅支持Windows操作系统。毕竟是Microsoft出品。。。 类似产品 Synergy 功能与Mouse without Borders类似。主要区别在于,与Mouse without Borders相比: 优点: 跨平台 支持Windows Linux Mac 缺点: 有服务器,客户端的概念。只能使用服务器的键鼠控制其他主机 不支持在主机间复制粘贴文件或拖拽复制文件(官方宣传支持该功能,但始终复制不成功) 不支持截取其它主机的屏幕 综上,如果你需要跨平台,那么没得选,只能Synergy。否则果断选择Mouse without Borders。

Redux 3.6.0 源码阅读 之 src/createStore.js

嗯,就是学习一下,读读源码。顺便把源码里的文档翻译了一下并添加了一些简单的注释。 本文对应的文件是src/createStore.js import isPlainObject from 'lodash/isPlainObject' import $$observable from 'symbol-observable' /** * ActionTypes里定义的是Redux保留的私有action。 * 对于任何未知的action,你必须返回store的当前状态。 * 如果传入的当前状态是undefined,你必须返回store的初始状态。 * 不要在应用代码中直接引用这些action。 */ export var ActionTypes = { INIT: '@@redux/INIT' } /** * createStore方法用于创建一个保存程序状态的store。 * 改变store中数据的唯一方法是调用store的`dispatch()`方法。 * * 你的应用中应该只有一个store。为了将程序状态中不同部分的变更逻辑 * 组合在一起,你可以通过`combineReducers`方法将多个reducer组合成一个reducer。 * * @param {Function} reducer 一个返回应用下一状态的函数,入参是程序的当前状态以及 * 要发送的action。 * * @param {any} [preloadedState] store的初始状态。你可以选择性的为store指定一个 * 初始状态。 * 如果你使用了`combineReducers`方法来生成最终的reducer。那么这个初始状态对象的 * 结构必须与调用`combineReducers`方法时传入的参数的结构保持对应关系。 * * @param {Function} enhancer store增强器。你可以选择性的传入一个增强函数来扩展 * store的功能,例如中间件,时间旅行,持久化等。Redux自带的唯一一个增强器是 * `applyMiddleware()`方法。 * * @returns {Store} 返回一个可以读取状态,发送action以及订阅变更通知的Redux store。 */ export default function createStore(reducer, preloadedState, enhancer) { // 如果只传入reducer和enhancer,则store的初始状态为undefined if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { enhancer = preloadedState preloadedState = undefined } // enhancer必须是一个函数 if (typeof enhancer !

[译]什么是Promise.try

原文地址 http://cryto.net/~joepie91/blog/2016/05/11/what-is-promise-try-and-why-does-it-matter/ 在#Node.js#频道里经常困扰大家的一个话题是Bluebird提供的Promise.try方法。大家并不清楚该方法的功能也不知道为何要使用它。同时,几乎所有的关于Promsie的指南中针对该方法错误的演示使得这种情况没有任何改善。 在本文中,我会尝试解释究竟什么是Promise.try以及为何你应该使用它。我假设你已经对Promise有所了解并且知道.then在Promise中的作用。 即使你在使用一个不同的Promsie实现(例如ES6 Promise),本文还是可以帮到你。文章末尾我会解释如何在非Bluebird环境中实现相同的功能。 究竟什么是Promise.try呢? 简单来说,除了不需要跟在一个前置Promise之后以外,Promise.try很像.then。这么说还是有一些含糊不清,所以让我们先看一个示例。 以下是一段典型的Promise使用场景: function getUsername(userId) { return database.users.get({id: userId}) .then(function(user) { return user.name; }); } 到目前为止,一切顺利。我们假设database.users.get会返回一个Promise,并且该Promise最终会返回一个带有name属性的对象。 以下是同样的代码,但是引入了Promise.try: var Promise = require("bluebird"); function getUsername(userId) { return Promise.try(function() { return database.users.get({id: userID}); }).then(function(user) { return user.name; }); } 可以看到,我们的调用链以Promise.try而不是database.users.get开始。像使用.then一样,我们执行Promise.try方法并传递给它一个直接返回database.users.get调用的函数。 这样做有什么意义呢? 以上的代码看起来似乎是多余的。但实际上它有以下几个优点: 更好的错误处理 同步代码中的异常不论出现在何处都会以rejection的形式向Promise链后端传递。 更好的兼容性 你可以始终使用你自己喜欢的Promise实现,而不用担心第三方代码在使用哪个。 更好的代码阅读体验 所有的代码在水平方向上将处于同一个缩进层级,这将使你阅读代码变得更容易。 接下来我会逐一介绍这些优点: 1. 更好的错误处理 Promise的一个被大力宣扬的优点就是用户可以用同一种方式同时处理同步异常和异步异常 —— 同步异常会被捕获并且会作为一个rejected Promise向后传递。但事实真的是这样吗?让我们看看以下这个上文示例的小变种: function getUsername(userId) { return database.users.get({id: userId}) .then(function(user) { return uesr.

[译] 寻找时间成为一名更优秀的程序员

原文链接 https://medium.freecodecamp.com/finding-time-to-become-a-better-developer-eebc154881b2#.t1uuonhtf 没有时间做任何事。这就是你感受,不是吗?没有时间学习你觉得你需要学会以跟上潮流的知识。没有时间回过头去重构那些丑陋的代码。它至少能工作,何况截止日期马上就要到了。没有时间编写单元测试。没有时间为今后要维护你代码的伙计编写文档或注释。没有时间思考。没有时间呼吸。没时间! 好吧…如果你能花时间阅读本文,我保证你自己会为那些重要的事找到更多时间。 我曾经以为成为一名伟大程序员的唯一途径就拼命工作。我的健康,友谊,家庭都因此受到影响。理解以下5个关于时间管理的真相拯救了我。 1. 你不需要为了赶潮流而学习每一个新事物 你不需要 毫无疑问一个优秀的程序员应该保持不断的学习,但是你把学习的焦点放在哪儿能在很大程度上影响你需要花费的时间。 “老的事物已经死去,(终归老去的)新事物万岁!” 首先,不要被出现在那些每37秒就宣布一个新标准的博客上的头条所愚弄。这些新技术,新框架,新特性中的大多数永远都不会被认可与采纳,因此你根本不需要了解它们。那些真正能够脱颖而出的也会经历比博客圈和发明厂商宣传的长的多的时间才会被采用。公司投资于他们的技术栈 —— 和那些小创业公司不一样,他们不可能说变就变。所以,放松一下,你的职业生涯很安全。 把你的学习聚焦在三方面,以下面列出的顺序为优先级: 1. 基础 —— 当你有了非常扎实的基础知识之后,学习新技能会变得非常容易。举个例子,如果你对JavaScript有着深入的了解,你就可以飞速的掌握任何新的JavaScript框架。如果你深入学习了面向对象编程,你也能快速掌握任何新的面向对象语言。深入学习基础知识会极大的提高你的学习效率。始终把提高对基础知识的掌握放在第一位。 2. 你最常使用的技术栈的最新版本/特性 —— 存在一套你每天都会使用的技术栈。这些是可以帮你养活你及你家人的工具。当这些工具的新版本发布时,投入时间学习是很值得的。 3. 由市场领导者主导的流行技术 —— 如果一个颇具规模的公司,比如Google,Facebook或是Microsoft提出某项新技术并已经开始小有名气,这也值得你的关注。市面上曾经有许多JavaScript框架争夺人们的注意力,然后Angular和React出现了并将那些框架彻底消灭。我不是说今后不会有搅局者出现成为下一个焦点,但实际情况往往是杂牌技术只不过是一些噪音。 学习时间应该是你日程安排的一部分。每天抽出一点时间来学习。这不需要很长的时间,即使是每天花25分钟阅读和练习也可以快速积累。 2. 编写优秀的代码比编写糟糕的代码需要更少的时间,但感觉上并不是这样 时间是一个扁圆 你很可能喜欢开发完几个新功能后当你试着运行并且发现似乎可以正常工作时那一刻的感受。但那只是你时间投入的开始。在一个功能上投入的时间包括了后期调试的时间,重构花费的时间以及解决由于开发时的不良设计导致的其它问题的时间。当你开始以这种方式认识你的时间投入时,你会发现,从长远来看,更少的错误和更好的设计是值得投资的。 你可以做两件事来减少代码中的错误并实现更好的设计。 1. 使用测试驱动开发 首先编写测试,然后编写代码以使测试通过。这不仅会减少bug还会导致更好的设计,因为当你按照可测试的方式组织代码时,你最终会得到更小,更简单的,依赖更少的函数。 2. 使用迭代的设计方式 在你的代码能真正工作之前,不要花时间试图让你的代码变完美。你永远不可能在脑子里把它设计的完全正确。你必须敲击键盘来生成实现预期功能的代码。问题是程序员尝尝犯两个常见的错误:要么时花了太多时间思考而没有足够的时间动手,要么就是不去优化他们最初的方案。遵循最初由Kent Beck提出的口头禅:“make it work, make it right, make it fast” —— 按照话中的顺序。 3. 7x24的工作不会让你成为英雄,管理预期才会 下班到家,开始工作! 这一条几乎杀了我。我曾经同意并承诺过我老板或客户提出的任何疯狂的时间表。我害怕说“不”。我害怕让任何人失望。为了交付我可以做任何事。我曾经睡在办公桌下,有过多次长达40+小时的马拉松式的编程经历。 起初我是一颗耀眼的明星。别人对我大加赞赏,我感觉自己像是个英雄。但是我设置了一个不可能实现的预期。不可能长久的像那样工作。最终我开始疲惫不堪,生病并错过截止日期。我开始得到不可靠的名声。这是个坏消息。 最后我终于明白真正的英雄是那些持续可靠的人。他们说到做到。要成为那样的英雄的唯一途径就是管理预期。 你需要控制时间表以便总是可以按时交付高质量的工作。起初这会非常困难。这意味着必须说“不”并把需求打回。 在最开始,你的老板和客户不会被你的拒绝刺激到。但一旦你证明自己是值得信赖的,一切都将开始改变。 随着时间的推移,其它程序员会迟到,交付马虎的工作或是筋疲力竭变得不可靠。这时你就会成为团队中真正的英雄。事实上,学会这一点让我成为我的领域里最受欢迎的咨询顾问。由于狠抓预期管理,我在质量和时效性方面建立了良好的声誉。 4. 不是所有花在“改善”代码上的时间都会得到相同的回报 花费时间是一种投资。和所有投资一样,投资回报率是一个合理的期望。你的所得至少应该和投入一样多,希望是越多越好。 我们已经谈论过“make it work, make it right, make it fast”。这个是不错的口头禅但这里有一个陷阱:“right”并不意味着完美,“fast”也不是说越快越好。

koa框架源码阅读笔记 之 lib/application.js

最近在学习ES6 Generator特性时发现了koa这个基于Generator的Web框架,它可以让开发者以一种“同步的方式”编写包含各种异步请求的Web应用。下面是关于它的一段中文介绍: 由 Express 原班人马打造的 koa,致力于成为一个更小、更健壮、更富有表现力的 Web 框架。使用 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的回调函数嵌套,并极大地提升常用错误处理效率。Koa 不在内核方法中绑定任何中间件,它仅仅提供了一个轻量优雅的函数库,使得编写 Web 应用变得得心应手。 从介绍中可以看出这又是一个小而美的框架。到GitHub项目页面上看了一下发现源码里只有4个JS文件,总代码量只有1571行(以2015年12月26日最新稳定版1.1.2为准)。于是决定把代码clone下来学习一下,本篇会先从整个框架的入口文件lib/application.js说起。 总体说明 lib/application.js文件export出的是一个构造函数,用来创建一个koa应用。一个koa应用最常用的方法有2个: - listen(port) 执行listen后会通过http.createServer启动一个服务器并监听指定端口 - use(middleware) 注册一个中间件,一个koa应用可以注册多个中间件, 处理请求时会按照中间件注册的顺序执行这些中间件。 更多详细信息可以参考GitHub文档页面。 代码注释 function Application() { if (!(this instanceof Application)) return new Application; this.env = process.env.NODE_ENV || 'development'; this.subdomainOffset = 2; this.middleware = []; this.proxy = false; this.context = Object.create(context); this.request = Object.create(request); this.response = Object.create(response); } 以上就是Application构造函数的定义,很简洁,主要做了以下几件事情: - 通过instanceof判断来支持不带new关键字的调用。 - 设置应用运行环境,会从环境变量NODE_ENV读取,默认值为development - 声明this.

在JDF项目中使用ES6新特性

Note: 目前虽然JDF已经支持使用ES6开发脚本,但线上使用还在前期摸索阶段,请大家根据自己项目实际情况评估使用情况 最近利用业余时间给JDF增加了ES6代码的支持。背后的原理是在项目构建阶段利用Babel将.babel文件转译成ES5代码。关于Babel的更多使用方法可以参考其官网的配置文档。 下面开始正式介绍在利用ES6特性开发前的准备工作: - 升级JDF到最新版本(>= 1.8.2) - 进入JDF项目目录,安装基本的Babel preset和plugin。关于preset和plugin的更多说明请参考文档 npm install babel-preset-es2015 npm install babel-plugin-transform-es3-member-expression-literals npm install babel-plugin-transform-es3-property-literals 配置项目的.gitignore文件,忽略node_modules目录。在文件中添加以下内容: **/node_modules/ 引入es6-base.js(包含 es5-shim和babel-polyfill) 至此,所有的准备工作就完成了。接下来就可以利用ES6的各种新特性开发了。需要注意的是所有包含了ES6特性的脚本文件扩展名必须是.babel,否则JDF是不会对其进行编译的。 最后是一份简单的FAQ: Q: ES6都有哪些新特性,有没有推荐的学习资料? 当然有,中文版的有阮一峰出品的ECMAScript 6入门。 英文的有: - ES6 In Depth来自Mozilla团队博客的一系列文章,每篇讲解一个新特性。建议按时间顺序阅读。 - Understanding ECMAScript 6来自Nicholas C. Zakas大神的一本ES6小书。 Q: 我想使用额外的Babel plugin或preset该怎样配置? 只需在package.json中指定需要额外引入的plugin或preset,例如: "babel": { "plugins": ["syntax-async-functions","transform-regenerator"], "presets": ["stage-0"] } 并在JDF项目的目录中安装相关npm package即可。 Q: .babel文件编译出来的代码我看不懂,出了问题如何调试呢? 我们看到的经过Babel转译后的JS是这样的: 这里包含了大量的Babel生成的代码,非常不利于调试。不过不用担心,JDF在本地开发模式中启用了sourceMap,你只需在Chrome开发者工具中的Sources Tab中在你要调试的JS文件目录下找到同名的.babel文件即可。相关JS中的报错信息,都会被映射到转译前的.babel文件的对应位置。 关于sourceMap的更多信息请参考这里。