blog icon indicating copy to clipboard operation
blog copied to clipboard

个人技术博客,博文写在 Issues 里。

Results 121 blog issues
Sort by recently updated
recently updated
newest added

当我们开发一个单页应用时,常见的优化做法是生成两个文件: - vendor.js:包含一些第三方依赖,例如 `jQuery`、`Vue` 等 - app.js:包含项目代码 然后给这两个文件根据文件内容计算出一个 hash 加在文件名中,并配置一个长达一年的 Cache Control,这样能大大加快应用的访问速度。 因为 vendor.js 的内容基本上很少更新,所以下一次我们更改了 app.js 的内容时,vendor.js 仍然在浏览器的缓存中,那么用户就只需要重新下载 app.js 了。 但为了在 [Webpack](http://webpack.github.io/) 中做到这一点,真是费了不少功夫。 为了将项目中的第三方依赖代码抽离出来,官方文档上推荐使用 [CommonsChunkPlugin](http://webpack.github.io/docs/list-of-plugins.html#2-explicit-vendor-chunk)。 当我们在项目里实际使用之后,发现一旦更改了 app.js 内的代码,vendor.js 的 hash...

Webpack

最近在做一个 Chrome App ,用来读取电子秤的读数。目前市面上大部分电子秤都是串行接口,在 Chrome App 里读取串行接口设备的数据很容易(见[文档](https://developer.chrome.com/apps/app_serial)),但今天公司给了我一个 USB 接口的设备。 看了下 [Chrome App 里连接 USB 设备的文档](https://developer.chrome.com/apps/app_usb),上面说如果我要读取一个 USB 设备的数据,我首先得将它的 Vendor ID 与 Product ID 列在 manifest.json 里。但其实不必去找说明书(说明书里也不一定有),Chrome 本身就提供了接口来获取连接到设备的信息。 这个接口就是 [chrome.use.getUserSelectedDevices](https://developer.chrome.com/apps/usb#method-getUserSelectedDevices)。 这个方法很特殊,就像 HTML5...

Chrome 应用

今天在开发一个扩展程序的时候发现了一个很有意思的现象。 [官方文档](https://developer.chrome.com/extensions/content_scripts#execution-environment)里是这样描述内容脚本的执行环境的: > Content scripts execute in a special environment called an _isolated world_. They have access to the DOM of the page they are injected into, but not to...

Chrome 扩展

最近迷上了 [TypeScript](https://www.typescriptlang.org/),于是用它重写了 [Selection-Translator/translation.js](https://github.com/Selection-Translator/translation.js) 算是练手。 开发时,我使用了 Rollup + [rollup-plugin-typescript2 插件](https://github.com/ezolenko/rollup-plugin-typescript2)打包模块。 因为 Rollup 是基于 ES2015 的模块语法打包模块的,所以 tsconfig.json 里的 `module` 会被插件强制设置为 `es2015`。translation.js 引用了一个 CommonJS 模块 [blueimp-md5](https://www.npmjs.com/package/blueimp-md5),当 `module` 被设置为 `es2015` 的时候,我没法用 `import md5 =...

Rollup
TypeScript

在新的项目里,我已经开始全面使用 [Babel](https://babeljs.io/) 与 [SASS](http://sass-lang.com/) 了。本来 [WebStorm](https://www.jetbrains.com/webstorm/) 里自带 File Watcher 功能,但我认为项目本身应该尽可能的脱离编辑器环境,这样每个人都可以使用通用的方法进行开发,所以自己写了一个 gulp 任务:[lmk123/gulp-es6-sass](https://github.com/lmk123/gulp-es6-sass)。 然而,我现在决定使用 WebStorm 里的 File Watcher 了,原因如下: - 每次开始开发之前,都要启动一个 gulp watcher 任务太繁琐了 - 编译之后的文件不能立刻同步进 WebStorm,这导致刷新网页后,加载的仍然是旧文件 - 将编译步骤加入 gulp 流程会使得...

Sass
ES2015
WebStorm

手头有一个需求,要求当手机从竖屏旋转到横屏的时候需要做些处理。设备旋转时可以使用 `resize` 或是 `orientationchange` 事件得到通知,但判断当前设备是否是水平状态就有一些麻烦了。 一开始我使用的是 `window.innerWidth` 与 `window.innerHeight` 来判断,但在 Android 手机里,当输入法弹出来的时候,会导致 `window.innerHeight` 变小并触发 `resize` 事件,此时 `window.innerWidth` 就会大于 `window.innerHeight`,但这并不是我想要的。 后来,我开始使用 `window.outerWidth` 与 `window.outerHeight`,但在 iOS 下,这两个属性的值始终是 0。 谷歌一番之后,看到有人说使用 `window.matchMedia("(orientation: landscape)").matches` 来判断,但从...

> 本文首发于[饿了么大前端知乎专栏](https://zhuanlan.zhihu.com/ElemeFE):[使用缓动函数制作更自然的动画](https://zhuanlan.zhihu.com/p/26535740),这里在我的博客再发一遍 :stuck_out_tongue_closed_eyes: 自然界中的物体从起点移动到终点时,速度从来不是一成不变的。汽车启动时速度会由慢变快,停止时则由快变慢;篮球落地时会在地上来回反弹,并逐渐停止运动。大家都期待事物的呈现遵循一定的运动规律,所以,在网页中适当的使用动画能让用户得到更舒适的体验。 要制作出更加自然的动画,就需要理解什么是**缓动函数**。简单来说,缓动函数用于控制动画从初始值运动到最终值的速率。幸运的是,业界已经整理出了一些[常用的缓动函数曲线](http://easings.net/),本文将向读者介绍如何在 CSS 与 JavaScript 里使用这些缓动函数。 ## 在 CSS 中使用缓动函数 CSS 提供了四种基础的缓动函数: - `linear` 表示线性动画,动画从开始到结束一直是同样的速度,看起来不是很自然。 - `ease-in` 表示缓入动画,动画的速度先慢后快,就好像汽车启动时一样。缓入动画会在速度最快时停止,这会让动画结束得很突然,因为自然界中的运动总是慢慢减速后才停止的。 - `ease-out` 表示缓出动画,与缓入动画正好相反,缓出动画的速度先快后慢,就好像汽车慢慢停止一样。 - `ease-in-out` 表示缓入缓出动画,它的速度由慢变快,最后再变慢,就好像汽车启动、加速、然后停下来一样。 总的来说,线性动画与缓入动画不太符合自然运动规律;缓出动画初始速度很快,能给人一种快速反应的感觉;缓入缓出动画更符合自然界的运动规律,但是动画开始时速度很慢,会显得很迟钝,所以运行时间不宜过长,一般最好控制在 300 至...

用过 NPM 的朋友可能都有过下面的经历: 你创建了一个项目,用 npm 安装了一些第三方模块。一个月过去了,另外一个人想跟你一起开发这个项目,但他却无法在他的电脑上正常运行你的项目,尽管在你自己的电脑上一切如常。 你可能已经猜到了,这是因为你自己电脑上的第三方模块和他电脑上的第三方模块的版本不一致导致的。 出现这个问题的过程是这样的:当你第一次安装一个模块的时候,假设它的版本号是 `1.0.0`,但在 `package.json` 里 npm 会自动帮你设置一个版本范围:`^1.0.0`。一个月过去了,这个模块已经更新到了 `1.1.0`,但是你从来没有更新过,可是当别人在安装你的项目的时候,npm 会在他的电脑上安装这个版本范围内的最新版本,也就是 `1.1.0`,这里面可能会包含一些 「Breaking Changes」,所以就导致了在你电脑上好好的项目,在别人的电脑上却跑不起来。 即使这个项目只有你一个人开发,你也不应该依赖 npm 自动帮你设置的“版本范围”——一旦你一不小心运行了 `npm update` 来升级你的第三方依赖,你仍然会遇到上面的问题,更糟糕的是,你根本不知道你升级前用的是哪个版本的第三方模块,你可能不得不去挨个翻看你依赖的模块们有哪些 「Breaking Changes」并逐个更改,等你差不多改完的时候也该下班了,然而跟别人说好今天要完成的功能你还一点都没有开始做。 所以,聪明的开发者都会在 package.json 里锁定模块的版本号,以保证在任何情况下大家安装的模块都是一致的。 即使你的项目是用...

NPM

写 JavaScript 的应该都知道,我们应该避免修改内置对象(例如 `Object`、`Function`)的原型链,但今天一个同事问我:为什么要避免这样做? 于是我给他讲了我自己经历过的一件事。 当时我在开发一个工具库的时候,写了如下这段代码: ```js function Watching (config) { // config.watch 是一个可选项,所以没有的时候就给一个默认值 var watchingNode = document.querySelector(config.watch || '.watch-node') watchingNode.addEventListener(...) // ... } ``` 代码上线之后,有用户反馈在 Firefox 浏览器下点了某个按钮没有反应,然后我就用 Firefox 打开那个网页去调试,发现在执行到上面代码的第三行的时候报了个奇怪的错误,调试了一下,发现...

今天项目上线之后,有人反馈部分页面出现了问题,但一刷新就好了。我检查了一下,直接从地址栏进入的时候,html 上加载的是 app.hash-a.js,但一旦刷新,html 加载的就是 app.hash-b.js 了。 简而言之,浏览器将 `index.html` 这个文件缓存下来了,随后在开发者工具的 Network 面板里也看到,直接在浏览器地址栏进入 index.html 时,HTTP 响应是 `200(from cache)`,但一旦刷新,就变成 `200(ok)` 了。 于是我打开 chrome://cache/,果然在里面找到了我们项目的网址,点进去看到 HTTP 响应头是: ``` HTTP/1.1 200 OK Server: Tengine/2.1.2 Date: Thu,...

HTTP