前端部署之CDN的那些事情

现在的前端开发主流是 PWA,简而言之就是像 App 一样使用。基于 PWA 技术可以离线访问,并且可以添加程序到菜单里。离线技术使用的是比较成熟的 Service Workers。但是配合 CDN 就有很多不得不注意的事情。

# CDN 部署静态资源

现代化前端开发主要是把 CSS,JS,图片等静态资源放在 CDN 上有效提高载入速度。把静态 HTML 文件放在服务器上,有利于更新网站最新状态,例如进入维护状态,直接把静态 HTML 文件替换为维护页面即可。

# 同源策略问题

正常情况下,资源文件和主网站不在同一个域名下,例如主网站是icehoney.me,资源网站是static.icehoney.me。当然了,资源文件使用 GET 方法浏览器自动载入,没有任何问题。但是注册 Service Worker 的 JS 文件是不能放在 CDN 上的,因为这是官方的规定。个人理解是出于安全因素的考虑。所以我们在主服务器上不仅要放静态的 HTML 文件,还要放一个 serive-worker.js 文件。

# SVG symbol 的使用问题

现在前端的开发针对很多小图标,都是采用 SVG 的方式来引用。其中 SVG symbol 特别好用,可以在页面里嵌入一个 inline 的 SVG,然后在其他对方使用<use>标签来引用。但是对于放在 CDN 上的 SVG 文件,不能直接使用下面的形式:

<use xlink:href="https://static.icehoney.me/icon.svg#china" />
1

如果引用 CDN 的 SVG 浏览器会报错,解决方案是使用svg-inline-loader,手动在文档里面注入 SVG 文件。document.body.insertAdjacentHTML 方法可以注入 inline 的 SVG。

# Workbox 配置

首先,PWA 项目的路由都是由前端来处理,所以我们需要使用navigateFallback保证不管导航到哪个路由都能映射到缓存的 HTML 文件。然后是使用runtimeCaching配置缓存服务器请求。

# 总结

由于 Service Workers 的导入使得 CDN 部署变得有些麻烦,不过这些问题好在都能找到解决方案。还有一点是 Chrome 的 Network 面板里的 offline 模式不能测试 Service Workers 的离线。需要自己手动拔网线才能测试。

# 引用

Is it possible to serve service workers from CDN/remote origin? (opens new window)

Workbox webpack Plugins (opens new window)

iOS12下Safari浏览器的BUG

新时代的前端开发遇上新时代的 IE6, 没错我说的就是苹果的 Safari 浏览器,当年谷歌抛弃 WebKit 内核自立门户真是正确的选择。Chrome 有很好的 bug 反馈机制,而 Safari 要想反馈 bug 首先得成为苹果的付费开发者。

# 事件穿透

当我们遇到一个特殊需求,有两个绝对定位的 DIV(position:absolute)。如果指定了z-index必然会有上下的层级关系,值大的在上面,值小的在下面。但是我们需要上面的 DIV 不接受任何的事件,由下层的 DIV 捕获事件并处理。这时候可以使用一个神奇的 CSSpointer-events: none;来解决。只要给上层 DIV 指定了这个 CSS 属性,上层 DIV 就不会接收任何事件,相对的下层就可以收到所有事件的响应。

# 测试用 Demo

为此,我专门在codepen (opens new window)写了一个 demo。当然,这个 CSS 属性主流浏览器都已经支持了。但是当上层 DIV 里包含了一个 iframe 的时候,iOS12 下的 Safari 表现就变得奇怪了,demo 中,我在 Back DIV 里监听了touchstartclick事件,正常情况下两个事件都会触发,但是在有 iframe 的时候,safari 只会触发touchstart事件。

# 解决方案

既然少触发了一个事件,那我们的解决方案就是模拟点击事件,不过代码中必须通过 User-Agent 限制执行的范围,否则造成其他浏览器双击就不好了。模拟事件很简单,自己新建一个事件,然后在指定的 DOM 上dispatchEvent就好了。但是针对 input 输入框,即使模拟了click事件也不能出发 iOS 打开键盘激活输入,解决办法就是如果在input元素触发的touchstart事件,就执行input.focus()。 这样就可以激活输入的键盘了,不过要注意的是只有touchstart可以触发,测试发现touchend并不能触发。

# 总结

iOS 下的 Safari 浏览器有很多 BUG,经常找 BUG 的我也算是有点经验。最重要的方法就是排除法,删除多余的 DOM。缩小影响因子,最后确定原因。

# 引用

The stacking context (opens new window)

Creating and triggering events (opens new window)

计算贝塞尔曲线的长度

贝塞尔曲线是工业上经常用的一种曲线,经常用用来汽车的外观设计。贝塞尔曲线根据控制点的不同可以分为:

  1. 一阶贝塞尔曲线(2 个控制点)
  2. 二阶贝塞尔曲线(3 个控制点)
  3. 三阶贝塞尔曲线(4 个控制点)
  4. n 阶贝塞尔曲线(n+1 个控制点)

# 二阶贝塞尔曲线

这次讲述的是二阶贝塞尔曲线的长度计算。首先计算曲线的长度之前,我们需要知道曲线的数学方程表达式,由于目前博客还未支持数学表达式的显示,所以我只能帖出wiki 链接 (opens new window)。求曲线的长度,本质上是很难计算出精确值的,但只要近似值的误差绝对小,在实际使用中也是足够的。求曲线的长度本质上是进行定积分的计算。

# 高斯求积

在定积分的数值计算中,高斯求积 (opens new window)可以说是一个精度非常高的公式。

我们只需要把二阶贝塞尔曲线代入高斯求积公式中便可以计算出结果,求积公式的节点个数 n 越大,精度就越高。

不过高斯求积公式中节点个数对应的位置和权重表的计算,我还是没弄明白。

# 代码实现

已经有人给出了代码实现,所以大家可以直接去 Github 上查看bezier.js (opens new window)

并且有详细的解释:Arc length (opens new window)

# 总结

曲线的计算都可以归纳成对定积分的计算,只要知道曲线的数学方程式,就可以使用定积分的数值计算来计算出结果。

# 引用

A Primer on Bézier Curves (opens new window)