前端PWA:让你的网站变成App

前端PWA:让你的网站变成App

毒舌时刻

前端PWA?这不是噱头吗?

"PWA有什么用,用户直接用浏览器不就好了"——结果用户体验差,无法离线访问,
"我有原生App,不需要PWA"——结果开发成本高,维护困难,
"PWA就是加个manifest和service worker,多简单"——结果功能不完整,用户体验差。

醒醒吧,PWA不是简单的技术组合,而是一种现代化的Web应用模式!

为什么你需要这个?

  • 离线访问:即使没有网络也能访问应用
  • 安装到主屏幕:像原生App一样方便使用
  • 推送通知:及时向用户发送重要信息
  • 性能提升:缓存静态资源,加快加载速度
  • 跨平台:一次开发,多平台运行

反面教材

<!-- 反面教材:不完整的PWA配置 --> <!DOCTYPE html> <html> <head> <title>我的PWA应用</title> <!-- 缺少manifest.json --> <!-- 缺少service worker --> </head> <body> <h1>我的PWA应用</h1> <p>这是一个PWA应用</p> </body> </html> 
// 反面教材:简单的service worker // service-worker.js self.addEventListener('install', event => { console.log('Service Worker 安装'); }); self.addEventListener('activate', event => { console.log('Service Worker 激活'); }); self.addEventListener('fetch', event => { console.log('Service Worker 拦截请求'); }); 

正确的做法

<!-- 正确的做法:完整的PWA配置 --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>我的PWA应用</title> <!-- 添加manifest.json --> <link rel="manifest" href="/manifest.json"> <!-- 添加主题颜色 --> <meta name="theme-color" content="#317EFB"> <!-- 添加Apple Touch Icon --> <link rel="apple-touch-icon" href="/icons/icon-192x192.png"> <!-- 添加预加载 --> <link rel="preload" href="/style.css" as="style"> <link rel="preload" href="/script.js" as="script"> <link rel="stylesheet" href="/style.css"> </head> <body> <h1>我的PWA应用</h1> <p>这是一个完整的PWA应用</p> <button>发送通知</button> <script src="/script.js"></script> <script> // 注册service worker if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/service-worker.js') .then(registration => { console.log('Service Worker 注册成功:', registration.scope); }) .catch(error => { console.log('Service Worker 注册失败:', error); }); }); } </script> </body> </html> 
// 正确的做法:manifest.json { "name": "我的PWA应用", "short_name": "PWA应用", "description": "一个完整的PWA应用示例", "start_url": "/", "display": "standalone", "background_color": "#ffffff", "theme_color": "#317EFB", "icons": [ { "src": "/icons/icon-72x72.png", "sizes": "72x72", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-96x96.png", "sizes": "96x96", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-128x128.png", "sizes": "128x128", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-144x144.png", "sizes": "144x144", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-152x152.png", "sizes": "152x152", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-192x192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-384x384.png", "sizes": "384x384", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-512x512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" } ] } 
// 正确的做法:完整的service worker // service-worker.js const CACHE_NAME = 'pwa-app-cache-v1'; const ASSETS_TO_CACHE = [ '/', '/index.html', '/style.css', '/script.js', '/manifest.json', '/icons/icon-72x72.png', '/icons/icon-96x96.png', '/icons/icon-128x128.png', '/icons/icon-144x144.png', '/icons/icon-152x152.png', '/icons/icon-192x192.png', '/icons/icon-384x384.png', '/icons/icon-512x512.png' ]; // 安装Service Worker self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME) .then(cache => { console.log('Cache opened'); return cache.addAll(ASSETS_TO_CACHE); }) .then(() => self.skipWaiting()) ); }); // 激活Service Worker self.addEventListener('activate', event => { const cacheWhitelist = [CACHE_NAME]; event.waitUntil( caches.keys().then(cacheNames => { return Promise.all( cacheNames.map(cacheName => { if (cacheWhitelist.indexOf(cacheName) === -1) { return caches.delete(cacheName); } }) ); }) .then(() => self.clients.claim()) ); }); // 拦截网络请求 self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request) .then(response => { // 如果缓存中有响应,直接返回 if (response) { return response; } // 否则发起网络请求 return fetch(event.request) .then(response => { // 如果响应有效,缓存一份 if (response && response.status === 200 && response.type === 'basic') { const responseToCache = response.clone(); caches.open(CACHE_NAME) .then(cache => { cache.put(event.request, responseToCache); }); } return response; }) .catch(error => { // 网络错误时返回离线页面 if (event.request.mode === 'navigate') { return caches.match('/offline.html'); } }); }) ); }); // 处理推送通知 self.addEventListener('push', event => { const data = event.data.json(); const options = { body: data.body, icon: '/icons/icon-192x192.png', badge: '/icons/icon-72x72.png', data: { url: data.url } }; event.waitUntil( self.registration.showNotification(data.title, options) ); }); // 处理通知点击 self.addEventListener('notificationclick', event => { event.notification.close(); event.waitUntil( clients.openWindow(event.notification.data.url) ); }); 
// 正确的做法:使用推送通知 // script.js // 请求通知权限 function requestNotificationPermission() { if ('Notification' in window) { Notification.requestPermission().then(permission => { if (permission === 'granted') { console.log('通知权限已授予'); } else { console.log('通知权限被拒绝'); } }); } } // 发送通知 function sendNotification() { if ('serviceWorker' in navigator && 'PushManager' in window) { navigator.serviceWorker.ready.then(registration => { registration.showNotification('测试通知', { body: '这是一条测试通知', icon: '/icons/icon-192x192.png', badge: '/icons/icon-72x72.png', data: { url: '/' } }); }); } } // 页面加载时请求通知权限 window.addEventListener('load', () => { requestNotificationPermission(); // 绑定按钮点击事件 const notificationBtn = document.getElementById('notification-btn'); if (notificationBtn) { notificationBtn.addEventListener('click', sendNotification); } }); // 检查是否是PWA模式 function checkPwaMode() { const isPwa = window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone || document.referrer.includes('android-app://'); if (isPwa) { console.log('应用以PWA模式运行'); } else { console.log('应用以浏览器模式运行'); } } checkPwaMode(); 

毒舌点评

看看,这才叫前端PWA!不是简单地添加manifest和service worker,而是构建一个完整的PWA应用,包括离线访问、推送通知、安装到主屏幕等功能。

记住,PWA不是替代原生App,而是一种补充。它可以让你的Web应用获得类似原生App的体验,同时保持Web的跨平台优势。

所以,别再觉得PWA是噱头了,它是现代Web开发的重要方向!

总结

  • manifest.json:配置应用名称、图标、显示模式等
  • Service Worker:实现离线缓存、推送通知等功能
  • 离线访问:缓存静态资源,确保无网络时也能访问
  • 安装到主屏幕:提供类似原生App的入口
  • 推送通知:及时向用户发送重要信息
  • 性能优化:缓存策略、预加载等
  • 可访问性:确保PWA对所有用户都友好
  • 跨平台:一次开发,多平台运行

PWA,让你的网站变成真正的应用!

Read more

低代码革命:ModelEngine可视化编排,解锁大模型应用工作流开发新范式

当大模型技术从实验室走向产业落地,企业对大模型应用的需求已从“可用”转向“高效、可定制、可复用”。传统代码式开发模式下,大模型应用构建需投入大量专业开发人力,开发周期长、迭代效率低,且难以适配业务的快速变化,成为制约大模型规模化落地的核心瓶颈。 在此背景下,ModelEngine平台的可视化编排技术应运而生,以“低代码、高灵活、强拓展”的核心优势,打破技术与业务之间的壁垒,重构大模型应用工作流的开发逻辑,让开发者乃至业务人员都能快速构建符合需求的大模型应用,开启大模型应用开发的全新范式。 本文结合一线实战经验,从基础节点应用、工作流全流程开发与调试、自定义插件创新拓展、智能表单交互优化四大核心维度,深度拆解ModelEngine可视化编排的技术逻辑与实践路径,融入前瞻性观点与前沿实践,提出可复制的落地方法论,为AI应用开发者、企业技术管理者提供有价值的参考,助力行业实现大模型应用的低成本、规模化落地。 一、基础节点深耕:可视化编排的底层逻辑与高效应用技巧 可视化编排的核心价值,在于将复杂的技术逻辑拆解为可拖拽、可配置的基础节点,让“技术小白”也能快速上手。但要实现工作流的高效

Web3钱包开发的最佳实践:从架构设计到安全实现

Web3钱包开发的最佳实践:从架构设计到安全实现

一、引言 在2026年的Web3生态中,钱包早已不是简单的密钥管理器。它正在演变为集交易、质押、治理参与和社交功能于一体的Web3综合中心。随着Web3的普及不再局限于开发者和爱好者,主流用户、机构投资者和企业应用都在寻求兼顾安全性与易用性的钱包解决方案。 本文旨在为开发者提供一份系统性的Web3钱包开发指南,涵盖架构选择、安全设计、技术栈选型、账户抽象集成、多链支持、嵌入式钱包实现以及前沿趋势等多个维度。 二、钱包架构的核心选择 2.1 托管钱包与非托管钱包:关键架构决策 开发钱包面临的最重要早期决策是选择托管还是非托管架构,每一个后续功能、合规要求和盈利模式都源自此选择。 托管钱包:公司作为中介控制用户的私钥,类似于传统银行持有账户。托管钱包需要大量安全投入、跨地区的合规操作和保险考虑,责任风险更高,但它们为受监管的金融服务和机构合作打开了大门。 非托管钱包:用户自己掌控私钥,MetaMask推广了这种模式。用户负责自己的安全和恢复,责任由用户承担,但学习曲线陡峭,一旦操作失误可能导致资金永久丢失。这种方式在许多地区的监管负担较低,责任风险也较小,但限制了某些盈利路径

第十章:HIL-SERL算法真实机器人训练实战

第十章:HIL-SERL算法真实机器人训练实战

引言 在机器人学习领域,如何让机器人在真实环境中快速、安全地学习复杂任务一直是一个重要挑战。传统的强化学习方法往往需要大量的试错过程,这在真实机器人上既耗时又存在安全风险。而纯粹的模仿学习虽然安全,但往往难以处理训练数据中未见过的情况。 HIL-SERL(Human-in-the-Loop Sample-Efficient Reinforcement Learning,人在环路样本高效强化学习)为这一问题提供了一个优雅的解决方案。这种方法巧妙地结合了人类演示、在线学习和人工干预,能够在短短几个小时内训练出高性能的机器人策略。 本章将详细介绍如何使用 LeRobot 框架实践 HIL-SERL ,帮助读者掌握在真实机器人上进行强化学习训练的完整流程。 10.1 HIL-SERL 方法概述 HIL-SERL 是一种样本高效的强化学习算法,它将人类演示与在线学习和人工干预相结合。该方法从少量人类演示开始,使用这些演示训练奖励分类器(reward classifier),然后采用演员-学习者( actor-learner)架构,在策略执行过程中允许人类干预,以指导探索并纠正不安全的

低代码AI平台:Coze与Dify深度对比

低代码 AI 平台(如 Coze 和 Dify)旨在降低 AI 应用开发门槛,使开发者甚至非技术人员也能快速构建基于大模型(LLM)的智能应用。它们通常提供可视化编排、插件集成、知识库管理、对话流程设计等功能。在实际项目中,常常需要将这些平台与现有系统集成,或进行二次开发以满足特定业务需求。 以下从 集成方式 与 二次开发能力 两个维度,分别介绍 Coze 和 Dify 的特点及实践建议: 一、Coze(字节跳动) 1. 集成方式 * Webhook / API 调用 Coze 支持通过 Bot ID 和 API Token 调用其提供的 RESTful API,可将 Bot