专栏首页.NET开发那点事ASP.NET Core Blazor Webassembly 之 渐进式应用(PWA)

ASP.NET Core Blazor Webassembly 之 渐进式应用(PWA)

Blazor支持渐进式应用开发也就是PWA。使用PWA模式可以使得web应用有原生应用般的体验。

什么是PWA

PWA应用是指那些使用指定技术和标准模式来开发的web应用,这将同时赋予它们web应用和原生应用的特性。 例如,web应用更加易于发现——相比于安装应用,访问一个网站显然更加容易和迅速,并且你可以通过一个链接来分享web应用。 在另一方面,原生应用与操作系统可以更加完美的整合,也因此为用户提供了无缝的用户体验。你可以通过安装应用使得它在离线的状态下也可以运行,并且相较于使用浏览器访问,用户也更喜欢通过点击主页上的图标来访问它们喜爱的应用。 PWA赋予了我们创建同时拥有以上两种优势的应用的能力。 这并不是一个新概念——这样的想法在过去已经在web平台上通过许多方法出现了多次。渐进式增强和响应式设计已经可以让我们构建对移动端友好的网站。在多年以前的Firefox OS的生态系统中离线运行和安装web应用已经成为了可能。 PWAs, 不但如此,更是提供了所有的甚至是更多的特性,来让web更加优秀。

引用自MDN

说人话就是PWA可以让你的web程序跟一般应用一样运行,有桌面图标,能离线,没有浏览器地址栏,一切看起来想个普通的程序/APP。

新建Blazor PWA程序

使用VS新建一个Blazor程序,选择Webassembly模式,勾选支持PWA。

支持PWA的Blazor程序主要是多了几个东西:

  1. manifest.json
  2. service-worker.js

manifest.json

manifest.json是个清单文件,当程序被安装到设备上的时候会读取里面的信息,名称是什么,图标是什么,什么语言等等。

{
  "name": "BlazorPWA",
  "short_name": "BlazorPWA",
  "start_url": "./",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#03173d",
  "icons": [
    {
      "src": "icon-512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ]
}

service-worker.js

service-worker用来跑一些后台任务。它跟浏览器主进程是隔离的,也就是说跟原来的JavaScript运行时是分开,当然了它不会阻塞页面。我们可以用它来完成一些功能,比如对所有的fetch/xhr请求进行过滤,哪些请求走缓存,哪些不走缓存;比如在后台偷偷给你拉一些数据缓存起来。

// Caution! Be sure you understand the caveats before publishing an application with
// offline support. See https://aka.ms/blazor-offline-considerations

self.importScripts('./service-worker-assets.js');
self.addEventListener('install', event => event.waitUntil(onInstall(event)));
self.addEventListener('activate', event => event.waitUntil(onActivate(event)));
self.addEventListener('fetch', event => event.respondWith(onFetch(event)));

const cacheNamePrefix = 'offline-cache-';
const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`;
const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/ ];
const offlineAssetsExclude = [ /^service-worker\.js$/ ];

async function onInstall(event) {
    console.info('Service worker: Install');

    // Fetch and cache all matching items from the assets manifest
    const assetsRequests = self.assetsManifest.assets
        .filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url)))
        .filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url)))
        .map(asset => new Request(asset.url, { integrity: asset.hash }));
    await caches.open(cacheName).then(cache => cache.addAll(assetsRequests));
}

async function onActivate(event) {
    console.info('Service worker: Activate');

    // Delete unused caches
    const cacheKeys = await caches.keys();
    await Promise.all(cacheKeys
        .filter(key => key.startsWith(cacheNamePrefix) && key !== cacheName)
        .map(key => caches.delete(key)));
}

async function onFetch(event) {
    let cachedResponse = null;
    if (event.request.method === 'GET') {
        // For all navigation requests, try to serve index.html from cache
        // If you need some URLs to be server-rendered, edit the following check to exclude those URLs
        const shouldServeIndexHtml = event.request.mode === 'navigate';

        const request = shouldServeIndexHtml ? 'index.html' : event.request;
        const cache = await caches.open(cacheName);
        cachedResponse = await cache.match(request);
    }

    return cachedResponse || fetch(event.request);
}

项目里有2个service-worker.js文件,一个是开发时候的没逻辑,还有一个是发布时候的有一些缓存的逻辑。

运行一下

如果是PWA程序,在浏览器地址栏有个+号一样的图标,点击可以把程序安装到本地。

安装完了会在桌面生成一个图标,打开会是一个没有浏览器地址栏的界面。

这样一个PWA程序已经可以运行了。

离线运行

如果只是这样,仅仅是没有浏览器地址栏,那PWA也太没什么吸引力了。个人觉得PWA最大的魅力就是可以离线运行,在没有网络的情况下依然可以运行,这样才像一个原生编写的程序。

修改service-worker

离线的原理也很简单,就是请求的数据都缓存起来,一般是缓存Get请求,比如各种页面图片等。

// In development, always fetch from the network and do not enable offline support.
// This is because caching would make development more difficult (changes would not
// be reflected on the first load after each change).

self.addEventListener('fetch', event => event.respondWith(onFetch(event)));
self.addEventListener('install', event => event.waitUntil(onInstall(event)));

async function onInstall(event) {
    console.info('Service worker: Install');
}


async function onFetch(event) {
    let cachedResponse = null;
    const cache = await caches.open('blazor_pwa');
    if (event.request.method === 'GET') {
        const request = event.request;
        cachedResponse = await caches.match(request);
        if (cachedResponse) {
            return cachedResponse;
        }
        var resp = await fetch(event.request)
        cache.put(event.request, resp.clone());
        return resp;
    }

    return fetch(event.request);
}

修改一下sevice-worker.js,把GET请求全部缓存起来。这里为了演示图方便,其实情况显然不会这么简单粗暴。为了能缓存页面,显然必须先在线运行成功一次。

模拟离线

当我们修改完上面的js,然后在线正常一次后,可以看到所有GET请求的资源都被缓存起来了。

我们可以用chrome来模拟离线情况:

选择offline模式,然后刷新我们的页面,如果依然可以正常运行则表示可以离线运行。

总结

使用Blazor可以快速的开发PWA应用。利用PWA跟Blazor Webassembly的特性,可以开发出类似桌面的应用程序。或许这是跨平台桌面应用开发除了electron的又一种方案吧。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 在Mac上使用Visual Studio Code开发/调试.NET Core代码

      .Net Core 1.0终于发布了,Core的一大卖点就是跨平台。这个跨平台不只是跨平台运行,而且可以跨平台开发。今天抽空研究了下在Mac下如何使用VS ...

    kklldog
  • nodejs+express+jade+mongodb给我baby做个小相册(2)-留言板

    上一篇简单的实现了下照片的展现跟浏览功能,这一篇我将给这个程序添加一个留言的功能。那么留言的话肯定要涉及到数据持久了,其实对于这个小功能的话,用个xml就可以,...

    kklldog
  • .Net Core 自定义配置源从配置中心读取配置

    配置,几乎所有的应用程序都离不开它。.Net Framework时代我们使用App.config、Web.config,到了.Net Core的时代我们使用ap...

    kklldog
  • PHP网络编程之抽象一个event-loop(十八节)

    一部分格局比较大的泥腿子估计内心早就已经预见到了这种「风口」,虽然可能没有做好迎接这种「风口」的物理准备,但也至少做好了心理准备,没关系迟早还会?回来的。

    老李秀
  • 浅谈JavaScript的事件(事件对象)

      在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含这所有与事件有关的信息。包括导致事件的元素、事件的类型和事件的相关信息。例如鼠标操作...

    水击三千
  • 前端学习(53)~键盘事件

    onmousewheel:鼠标滚轮滚动的事件,会在滚轮滚动时触发。但是火狐不支持该属性。

    Vincent-yuan
  • javascript当中 document onkeydown的用法

    例 2.2(documentKeypressIEFF.html) 马克-to-win:当系统看见这句话:document.onkeydown = handleK...

    马克java社区
  • 【tkinter】辨识键盘输入

    在使用tkinter的时候经常会不知道某个键盘具体对应的 event.char和event.keycode是什么,上网去查找又很麻烦。

    JNingWei
  • 巧用 Serverless,轻松搭建微信公众号的智能后台服务

    一般来说,想给微信公众号增加更多的功能,需要有一台服务器,来进行公众号后台服务的搭建。那么在 Serverless 架构下,是否有更简便的方法来实现这么一个公...

    腾讯云serverless团队
  • 深圳Java培训:游戏中寻找学习JAVA的乐趣

    本篇主要介绍RobocodeAPI中的各种事件函数的说明,便于使用函数时有更清晰的思路。

    深圳java培训技术

扫码关注云+社区

领取腾讯云代金券