为了账号安全,请及时绑定邮箱和手机立即绑定

【前端骚操作】PWA落地!Express与HTTPS支持

title

PWA

Progressive Web App 渐进式网络应用程序,简单来说,就是你可以通过一些浏览器接口,保存对应的资源,然后浏览器如果断网了,依然可以获取到保存的资源。跟上古的缓存差不多,但是这是已经被各大浏览器支持的特性,目前 Google 大力推进中。

本文项目

我们的项目就是我之前说的自己那个网站:only-u.site,这个是我自己用着玩的,然后挂在 Coding 上。这几天,貌似 Coding 抽风了,老是来回的抽风,我实在是受不了了,干脆挂在自己服务器用吧,不然我日常都没法用了,所以便有了如下的流程。

  1. 申请证书
  2. Express 部署网站
  3. 挂上 https 证书
  4. 补充 PWA 对应的资源

申请证书

由于本人域名买自阿里云,site 后缀的也便宜,就在阿里找 https 证书,放心,我穷,必然是免费版(有需求就上付费版,我是个人的,所以免费省点钱)。

阿里也是脏,免费的藏得很深。

证书首页

这里是找不到免费证书的。

找免费1

按图点击,否则还是看不到免费。

找免费2

OK,露脸了。

免费

购买,然后补全资料等审核,大概几分钟就好了。

PS:遇到选项就默认可以。

下载

最后下载解压,你会得到两个文件,我们下面用到。

Express 部署 https 服务

Express 部署不多说,网上一大堆详细介绍,https 相关已经加上注释,代码如下(省略私密):

const path = require('path')
const express = require("express")
const https = require('https') // 没错,不是 http
const fs = require('fs')
const app = express()
const port = 443 // https 端口
const host = '110.110.110.110'
// 根据你具体项目结构设置路径,我路径是 index.html 在上层,所以这样设置
app.use(express.static(path.resolve(__dirname, '..')))
// 证书配置,这里就是那两个文件了
const privateKey = fs.readFileSync(__dirname + '/*.key')
const certificate = fs.readFileSync(__dirname + '/*.pem')
const credentials = { key: privateKey, cert: certificate }

// 根路径
app.get('/', (req, res) => {
  const fileName = 'index.html'
  fs.readFile(filePath, function (err, data) {
    if (err) res.end("<h1>500</h1>服务器内部错误!")
    else {
      res.writeHead(200, { 'content-type': contentType })
      res.end(data.toString())
    }
  })
})

// 启动服务
// 这个是 http
app.listen(80, host, err => {
  if (err) console.log(err)
  else console.log(`run in https://${host}:${port}`)
})
// 这个是 https
https.createServer(credentials, app).listen(port, host, err => {
  if (err) console.log(err)
  else console.log(`run in https://${host}:${port}`)
})

这样我们的页面就可以访问到了。如下:

https 页面


设置 PWA

这里一样,关键步骤看注释,主要就是两段代码:

<script>
  if (navigator.serviceWorker != null) {
    navigator.serviceWorker.register('sw.js')
      .then(function () {
        console.log('Service Worker Registered');
      })
  }
</script>

html 这段用来检测浏览器是否支持 serviceWorker,支持就访问 sw.js 来注册,没有支持就 pass。

然后是 sw.js:

const cacheName = 'only-001'

const cacheList = [
  "/",
  "index.html",
  "js/app.js",
  "js/engines.js",
  "css/app.css",
  "css/app.min.css",
  "static/img/icon_0.png",
  "static/img/icon_1.png",
  "static/img/icon_2.png",
  "static/img/icon_3.png",
  "static/img/icon_4.png",
  "static/img/icon_5.png",
  "static/img/icon_6.png",
  "static/img/icon_7.png",
  "static/img/logo_48.png",
  "static/img/logo_96.png",
  "static/img/logo_144.png"
]

// Service Worker 注册完成事件,写入缓存
self.addEventListener('install', e => {
  e.waitUntil(
    caches.open(cacheName)
      .then(cache => cache.addAll(cacheList))
      .then(() => self.skipWaiting())
  )
})

// Service Worker 启动事件,处理更新缓存
self.addEventListener('activate', function(e) {
  e.waitUntil(
    Promise.all(
      caches.keys().then(keyList => {
        return keyList.map(key => {
          // 遍历已有缓存,保留与当前一样的缓存,即更新
          if (key !== cacheName) return caches.delete(key)
          else return null
        })
      })
    ).then(() => {
      return self.clients.claim()
    })
  )
})

// 请求接口事件,处理相关逻辑
self.addEventListener('fetch', function(e) {
  e.respondWith(
    // 如果缓存内容存在,则提供缓存内容,否则继续 fetch
    caches.match(e.request).then(function(response) {
      return response || fetch(e.request.url)
    })
  )
})

这里内容是 serviceWorker 的生命周期相关事件,这里不涉及通知。

注意两点:

  1. 最上面的 cacheName 需要在下次更新 sw.js 的时候手动修改,否则浏览器认为你没有更新这个文件,没错,这个是前端控制的,有没有瞬间能装逼的感觉?
  2. cacheList 我得手动一个一个加上,通配符没用,如果有小伙伴有方法的话,告知一下……

补充

PWA 还有个配套的东西可选,就是手机浏览的时候可以保存在本地,“当做”APP 使用。

配置文件 manifest.json,代码如下:

{
  "name": "only u",
  "short_name": "only u",
  "display": "standalone",
  "start_url": "/",
  "theme_color": "#1f243e",
  "background_color": "#1f243e",
  "icons": [
    {
      "src": "static/img/logo_48.png",
      "sizes": "48x48",
      "type": "image/png"
    },
    {
      "src": "static/img/logo_96.png",
      "sizes": "96x96",
      "type": "image/png"
    },
    {
      "src": "static/img/logo_144.png",
      "sizes": "144x144",
      "type": "image/png"
    }
  ]
}

各自功能如下:

标题 功能
name 用于显示在推荐横幅上与启动画面
short_name 显示在桌面
display 是否显示 Chrome UI,可选 browser
orientation 可选横向 landscape,可不填
start_url 启动进入的页面
theme_color 主题色,用于调整工具栏与 Chrome UI 颜色
background_color 启动时的背景色
icons 48dp 倍数,48x48, 96x96, 14x144, 192x192 自动选取桌面(48 乘以显示倍数)与启动页图标(最接近 128)

效果如下:

安卓保存

这个是手机 Chrome 保存效果。

保存效果

在右边,跟 APP 显示一样的。

欢迎屏幕

这个欢迎屏幕显示在 manifest.json 文件里面配置了。

使用效果

注意,没有浏览器的搜索框(地址栏)了,跟 APP 效果一致!

粪叉

附一张“粪叉”效果,除了缩略图有问题,貌似其他都一样支持的(没做 Safari 的细节样式兼容)。


小结

  1. 阿里提供免费的 https 证书,比较难找,建议域名跟 https 在一个平台处理,避免不必要的麻烦。
  2. Express 是个好东西,谁用谁知道。
  3. PWA 是近几年可能的大势,早了解早好。
  4. Safari 也是支持 PWA,但是标准可能跟 Chrome 不同。

欢迎关注,如有需要 Web,App,小程序,请留言联系。

点击查看更多内容
9人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
软件工程师
手记
粉丝
1.6万
获赞与收藏
893

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消