Day 26: 载入图片

这系列的程序码在 https://github.com/DanSnow/ironman-2020/tree/master/static-site-generator

这篇用到的图片来源,授权是 CC0 ,作者是 Snapwire

图片是网页上一个很重要的元素, Gatsby 也提供了个跟它的 GraphQL 查询搭配的图片最佳化,不过老实说那个有点复杂,我并没有打算要做一个完全一样的,这边就来做一个比较简单的实做,我们提供图片的最佳化与 lazy loading 就好

图片最佳化

这部份会使用到 imagemin 这个 Node.js 下常用的图片最佳化的套件,不过是以 webpack loader 的形式来使用的,所以就安装:

$ yarn add --dev image-webpack-loader

然後我们要把它再包装成自己的 webpack loader ,这样我们比较好加自己额外的资讯进去,不过这边其实只有网址而已

这边写一个很简单的 webpack loader

module.exports = function () {
  return `
  import url from '!!${require.resolve('file-loader')}!${require.resolve('image-webpack-loader')}!${this.resource}'

  export default { url }`
}

module.exports.raw = true

再来我们要解决在 Server 端载入图片的问题,我们写个程序去 hook Node.js 的 require

import Module from 'module'

export function patchRequire() {
  // 保存原本的 require
  const originalRequire = Module.prototype.require

  // 覆写 require
  Module.prototype.require = function (id) {
    // 图片的地方我是用 webpack alias 来载入的,所以判断是不是 ~ 开头,不过正常应该是要判断副档名
    if (id.startsWith('~')) {
      return {}
    }
    return originalRequire.call(this, id)
  }
}

这样在 Server 端载入使用者的程序才不会出错

lazy loading

这边用的是很简单的实作:

import React, { useEffect, useState } from 'react'

export function Image({ img }) {
  // server 端就直接回传
  if (!img.url) {
    return <div>Loading...</div>
  }

  const { url } = img
  const [ready, setReady] = useState(false)

  useEffect(() => {
    // 等待图片载完
    const img = document.createElement('img')
    img.addEventListener('load', () => setReady(true))
    img.src = url
  }, [url])

  // 图片还没好也显示 Loading ,这样才跟 Server Render 的内容一样
  if (!ready) {
    return <div>Loading...</div>
  }

  // 显示图片
  return <img src={img.url} />
}

其实这篇原本还想用 sharp 提供图片缩放的,只是我在安装上出了点问题,另外范例程序中还有被我注解掉的用 blurhash 当 placeholder 的实作,因为 Node.js 的图片处理速度实在是太慢了,导致重 build 非常的花时间

下一篇我想来讲 incremental build


<<:  [Day27] AWS Data Pipeline

>>:  Day 26 介绍 vite

【网页制作证书】点止学嘢

【[网页制作证书] 】 Certificate in Website Development 全面学...

[Day 28] - Gatsby feat. EC ( 下 )

昨天我们完成了一个基本的购物流程,但程序码内有着不安全的问题,今天我们要用 .env 的形式来规避这...

Day18 javascript 阵列

今天咱们先来简单的稍为介绍一下JavaScript Array(阵列) 物件,JavaScript ...

[无广告]自动封锁,诈骗电话,骚扰电话,行销,广告,推销,来电未显示,不明的电话,响一声就挂,一接就挂,一接秒挂

安桌手机适用 Android 无广告 自动封锁,诈骗电话,骚扰电话,行销,广告,推销,来电未显示,不...

[Day24] Scrum失败经验谈 – 壁垒分明的职务配置

不足的丰富资源 未依团队性质配置的资源,会制造资源不足的假象 在IT团队最大的时候,有11人,分别是...