3. 动态生成图标

动态生成图标 学习卡片

任务说明

本案例需要完成一个完整的PWA图标动态生成方案:通过Canvas在运行时绘制应用图标,并输出为不同尺寸的PNG文件,最终将这些图标引用到Web App Manifest中。这样即使没有设计资源,也能快速生成一套适配不同设备的图标。

实现方案

核心思路是编写一个独立的Node.js脚本,使用纯Canvas API(通过canvas包)绘制一个带渐变背景和文字标识的图标,然后按PWA规范输出192px和512px两种必需尺寸,同时生成favicon.ico所需的源图。脚本执行后会在icons/目录下生成图标文件,随后我们创建一个引用这些图标的manifest.webmanifest文件。

代码实现

// generate-icons.js
const fs = require('fs');
const path = require('path');
const { createCanvas } = require('canvas');

// 图标绘制函数:绘制渐变背景 + 中心文字
function drawIcon(size) {
  const canvas = createCanvas(size, size);
  const ctx = canvas.getContext('2d');

  // 背景渐变(从左上到右下)
  const gradient = ctx.createLinearGradient(0, 0, size, size);
  gradient.addColorStop(0, '#4facfe');
  gradient.addColorStop(1, '#00f2fe');
  ctx.fillStyle = gradient;
  ctx.fillRect(0, 0, size, size);

  // 绘制白色圆角边框(模拟应用图标风格)
  ctx.strokeStyle = 'rgba(255,255,255,0.6)';
  ctx.lineWidth = Math.max(2, size * 0.02);
  const margin = size * 0.08;
  ctx.beginPath();
  ctx.roundRect(margin, margin, size - 2 * margin, size - 2 * margin, size * 0.15);
  ctx.stroke();

  // 绘制中心文字 "PWA"
  ctx.fillStyle = '#ffffff';
  ctx.font = `bold ${Math.floor(size * 0.28)}px "Arial", sans-serif`;
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';
  ctx.fillText('PWA', size / 2, size / 2);

  return canvas.toBuffer('image/png');
}

// 确保输出目录存在
const outDir = path.join(__dirname, 'icons');
if (!fs.existsSync(outDir)) {
  fs.mkdirSync(outDir);
}

// 生成PWA所需尺寸
const sizes = [192, 512];
sizes.forEach(size => {
  const buffer = drawIcon(size);
  fs.writeFileSync(path.join(outDir, `icon-${size}x${size}.png`), buffer);
  console.log(`已生成 icon-${size}x${size}.png`);
});

// 额外生成一个180px用于苹果touch-icon(可选)
const appleBuffer = drawIcon(180);
fs.writeFileSync(path.join(outDir, 'apple-touch-icon.png'), appleBuffer);
console.log('已生成 apple-touch-icon.png');

console.log('所有图标生成完毕!');

Manifest配置

// manifest.webmanifest
{
  "name": "Canvas图标演示应用",
  "short_name": "图标演示",
  "start_url": "./index.html",
  "display": "standalone",
  "background_color": "#4facfe",
  "theme_color": "#00f2fe",
  "icons": [
    {
      "src": "icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "any"
    },
    {
      "src": "icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "any"
    },
    {
      "src": "icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ]
}

落地与运行

首先安装依赖:

npm install canvas

然后执行脚本生成图标:

node generate-icons.js

执行后会在当前目录下生成icons/文件夹,其中包含icon-192x192.png、icon-512x512.png和apple-touch-icon.png三个文件。将manifest.webmanifest与icons/目录放在Web应用的根目录下,并在HTML中通过<link rel="manifest" href="#" aria-disabled="true" data-keke-missing-local-link="1" onclick="return false">引用即可。

验证方法

1. 运行node generate-icons.js后,检查icons/目录下是否生成三个PNG文件,且文件大小不为0。
2. 用图片查看器打开任意图标,确认尺寸分别为192×192、512×512和180×180像素,背景为蓝白渐变,中央有白色"PWA"文字。
3. 在Chrome浏览器中启动本地HTTP服务器(如npx serve)访问页面,打开DevTools → Application → Manifest面板,确认图标列表正确加载且无404错误。
4. 在Lighthouse面板运行PWA审计,确认"安装提示"相关检查项中图标配置通过。

判定标准:脚本无报错执行完毕;生成的图标尺寸与manifest声明完全一致;浏览器能正确识别并显示manifest中的图标资源。
动态图标生成流程 generate-icons.js Canvas绘制 + 导出PNG icons/ 目录 icon-192x192.png icon-512x512.png apple-touch-icon.png manifest.webmanifest icons 数组引用 192 + 512 + maskable 浏览器验证 DevTools → Application → Manifest 执行 node generate-icons.js → 生成PNG → manifest引用 → 浏览器加载验证 依赖: npm install canvas