{"version":3,"file":"index.mjs","sources":["../../src/vite/utils.ts","../../src/vite/index.ts"],"sourcesContent":["// thumbhash/examples/browser/index.html at main · evanw/thumbhash\n\nimport { subtle } from 'uncrypto'\n\n// https://github.com/evanw/thumbhash/blob/main/examples/browser/index.html\nexport function binaryToBase64(binary: Uint8Array) {\n  return btoa(String.fromCharCode(...binary))\n}\n\n/**\n * Hashes the given data using SHA-256 algorithm.\n *\n * Official example by MDN: https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest\n * @param {Uint8Array} data - The data to be hashed\n * @returns {Promise<string>} - The SHA-256 hash of the message\n */\nasync function digestUint8ArrayDataSha256(data: Uint8Array) {\n  const hashBuffer = await subtle.digest('SHA-256', data) // hash the message\n  return Array.from(new Uint8Array(hashBuffer)) // convert buffer to byte array\n}\n\n/**\n * Simulate hash function of rollup.\n *\n * About hashing, please read the documentation of rollup:\n * https://rollupjs.org/configuration-options/#output-hashcharacters\n * https://github.com/rollup/rollup/blob/1b85663fde96d84fceaa2360dba246d3cb92789b/docs/configuration-options/index.md?plain=1#L628\n *\n * For implementation details, please read the source code of rollup:\n * https://github.com/rollup/rollup/blob/1b85663fde96d84fceaa2360dba246d3cb92789b/src/utils/FileEmitter.ts#L259\n * https://github.com/rollup/rollup/blob/1b85663fde96d84fceaa2360dba246d3cb92789b/src/utils/crypto.ts#L12\n *\n * @param {Uint8Array} data - The data to be hashed\n * @param {number} length - The length of the hash\n * @returns {Promise<string>} - The first 10 characters of the SHA-256 hash of the message\n */\nexport async function hash(data: Uint8Array, length = 10) {\n  const hashResult = await digestUint8ArrayDataSha256(data)\n  const hashBase64 = binaryToBase64(new Uint8Array(hashResult)) // convert bytes to base64 encoded string\n  if (length > 0)\n    return hashBase64.substring(0, length)\n\n  return hashBase64\n}\n\n/**\n * Normalize the base64 string to be used in the URL.\n *\n * @param {string} base64 - The base64 string to be normalized\n * @returns {string} - The normalized base64 string\n */\nexport function normalizeBase64(base64: string) {\n  return base64.replace('/', '_').replace('+', '-').replace('=', '-')\n}\n","import type { Plugin } from 'vite'\nimport type { SiteConfig } from 'vitepress'\n\nimport type { ThumbHash, ThumbHashCalculated } from '../types'\nimport { mkdir, readFile, stat, writeFile } from 'node:fs/promises'\n\nimport { join, relative } from 'node:path'\nimport CanvasKitInit from 'canvaskit-wasm'\nimport { cyan, gray } from 'colorette'\nimport ora from 'ora'\nimport { rgbaToThumbHash, thumbHashToDataURL } from 'thumbhash'\n\nimport { glob } from 'tinyglobby'\nimport { normalizePath } from 'vite'\nimport { binaryToBase64, hash, normalizeBase64 } from './utils'\n\ninterface VitePressConfig {\n  vitepress: SiteConfig\n}\n\n/**\n * Calculate the thumbhash data for the image.\n *\n * Referenced the following implementations:\n * thumbhash/examples/browser/index.html at main · evanw/thumbhash\n * https://github.com/evanw/thumbhash/blob/main/examples/browser/index.html\n *\n * And the following implementations:\n * vite-plugin-thumbhash/packages/core/index.ts at main · cijiugechu/vite-plugin-thumbhash\n * https://github.com/cijiugechu/vite-plugin-thumbhash/blob/main/packages/core/index.ts\n *\n * @param {Uint8Array} imageData - The image data to be calculated\n * @returns {Promise<Omit<ThumbHash, 'fileName' | 'assetUrl' | 'assetUrlWithBase'>>} - The thumbhash data of the image\n */\nasync function calculateThumbHashForFile(imageData: Uint8Array): Promise<ThumbHashCalculated> {\n  const canvasKit = await CanvasKitInit()\n  const image = canvasKit.MakeImageFromEncoded(imageData)\n  if (!image)\n    throw new Error('Failed to make image from encoded data.')\n\n  const width = image.width()\n  const height = image.height()\n\n  const scale = 100 / Math.max(width, height)\n  const resizedWidth = Math.round(width * scale)\n  const resizedHeight = Math.round(height * scale)\n\n  // Paint the image to the canvas.\n  const canvas = canvasKit.MakeCanvas(resizedWidth, resizedHeight)\n  const context = canvas.getContext('2d')!\n  context.drawImage(image as unknown as CanvasImageSource, 0, 0, resizedWidth, resizedHeight)\n  // Retrieve back the image data for thumbhash calculation as the\n  // form of RGBA matrix.\n  const pixels = context.getImageData(0, 0, resizedWidth, resizedHeight)\n\n  // Easy calculation of thumbhash data.\n  const thumbHashBinary = rgbaToThumbHash(pixels.width, pixels.height, pixels.data)\n  // Encode the thumbhash data to base64 and data URL.\n  const thumbHashBase64 = binaryToBase64(thumbHashBinary)\n  const thumbHashDataURL = await thumbHashToDataURL(thumbHashBinary)\n\n  return {\n    dataBase64: thumbHashBase64,\n    dataUrl: thumbHashDataURL,\n    width: resizedWidth,\n    height: resizedHeight,\n    originalWidth: width,\n    originalHeight: height,\n  }\n}\n\nfunction createThumbHashDataFromThumbHash(\n  rootDir: string,\n  assetDir: string,\n  baseUrl: string,\n  imageFileName: string,\n  imageFullFileName: string,\n  imageFullHash: string,\n  imageFileHash: string,\n  thumbHash: ThumbHashCalculated,\n): ThumbHash {\n  const fileName = relative(rootDir, imageFileName)\n\n  const thumbhashData: ThumbHash = {\n    ...thumbHash,\n    assetFileName: normalizePath(relative(rootDir, imageFullFileName)),\n    assetFullFileName: normalizePath(imageFullFileName),\n    assetFullHash: imageFullHash,\n    assetFileHash: imageFileHash,\n    assetUrl: normalizePath(join(assetDir, fileName)),\n    assetUrlWithBase: normalizePath(join(baseUrl, assetDir, fileName)),\n  }\n\n  // Since assets url is used to refer to the image when rendered\n  // in the HTML, we need to ensure that the asset URL starts with a slash\n  // where base is not included.\n  if (!thumbhashData.assetUrlWithBase.startsWith('/'))\n    thumbhashData.assetUrlWithBase = `/${thumbhashData.assetUrlWithBase}`\n\n  return thumbhashData\n}\n\nfunction getCacheDir(vitePressCacheDir: string) {\n  return join(vitePressCacheDir, '@nolebase', 'vitepress-plugin-thumbnail-hash', 'thumbhashes')\n}\n\nfunction getMapFilename(cacheDir: string) {\n  return join(cacheDir, 'map.json')\n}\n\nasync function exists(path: string) {\n  try {\n    await stat(path)\n    return true\n  }\n  catch (error) {\n    if (!(error instanceof Error))\n      throw error\n    if (!('code' in error))\n      throw error\n    if (error.code !== 'ENOENT')\n      throw error\n\n    return false\n  }\n}\n\nasync function mkdirIfNotExist(dir: string) {\n  const targetDirExists = await exists(dir)\n  if (targetDirExists)\n    return\n\n  await mkdir(dir, { recursive: true })\n}\n\nasync function readCachedMapFile(path: string): Promise<Record<string, ThumbHash>> {\n  const targetPathExists = await exists(path)\n  if (!targetPathExists)\n    return {}\n\n  const content = await readFile(path)\n  return JSON.parse(content.toString('utf-8'))\n}\n\n/**\n * The Vite plugin to pre-process images and generate thumbhash data for them.\n *\n * @returns {Plugin} - The Vite plugin instance\n */\nexport function ThumbnailHashImages(): Plugin {\n  return {\n    name: '@nolebase/vitepress-plugin-thumbnail-hash/images',\n    enforce: 'pre',\n    config() {\n      return {\n        optimizeDeps: {\n          exclude: [\n            '@nolebase/vitepress-plugin-thumbnail-hash/client',\n          ],\n        },\n        ssr: {\n          noExternal: [\n            '@nolebase/vitepress-plugin-thumbnail-hash',\n          ],\n        },\n      }\n    },\n    async configResolved(config) {\n      const root = config.root\n      const vitepressConfig = (config as unknown as VitePressConfig).vitepress\n\n      const startsAt = Date.now()\n\n      const moduleNamePrefix = cyan('@nolebase/vitepress-plugin-thumbnail-hash/images')\n      const grayPrefix = gray(':')\n      const spinnerPrefix = `${moduleNamePrefix}${grayPrefix}`\n\n      const spinner = ora({ discardStdin: false, isEnabled: config.command === 'serve' })\n\n      spinner.start(`${spinnerPrefix} Prepare to generate hashes for images...`)\n\n      const cacheDir = getCacheDir(vitepressConfig.cacheDir)\n      await mkdirIfNotExist(cacheDir)\n      const thumbhashMap = await readCachedMapFile(getMapFilename(cacheDir))\n\n      spinner.text = `${spinnerPrefix} Searching for images...`\n\n      const files = await glob(`${root}/**/*.+(jpg|jpeg|png)`, { onlyFiles: true })\n\n      spinner.text = `${spinnerPrefix} Calculating thumbhashes for images...`\n\n      const thumbhashes = await Promise.all(files.map(async (file) => {\n        const cacheHit: ThumbHash | undefined = thumbhashMap[normalizePath(relative(root, file))]\n        if (cacheHit)\n          return cacheHit\n\n        const readImageRawData = await readFile(file)\n\n        // The hash implementation is mirrored and simulated from the rollup.\n        // But it's never guaranteed to be the same as the rollup's hash.\n        const imageFullHash = await hash(readImageRawData, -1)\n        const imageFileHash = normalizeBase64(imageFullHash.substring(0, 10))\n\n        // Calculate the thumbhash data for the image as thumbhash demonstrates.\n        const calculatedThumbhashData = await calculateThumbHashForFile(readImageRawData)\n\n        // Construct the thumbhash data for the image.\n        return createThumbHashDataFromThumbHash(\n          root,\n          vitepressConfig.assetsDir,\n          vitepressConfig.site.base,\n          file,\n          file,\n          imageFullHash,\n          imageFileHash,\n          calculatedThumbhashData,\n        )\n      }))\n\n      spinner.text = `${spinnerPrefix} Aggregating calculated thumbhash data...`\n\n      for (const thumbhash of thumbhashes)\n        thumbhashMap[thumbhash.assetFileName] = thumbhash\n\n      spinner.text = `${spinnerPrefix} Writing thumbhash data to cache...`\n\n      await writeFile(getMapFilename(cacheDir), JSON.stringify(thumbhashMap, null, 2))\n\n      const elapsed = Date.now() - startsAt\n      spinner.succeed(`${spinnerPrefix} Done. ${gray(`(${elapsed}ms)`)}`)\n    },\n  }\n}\n"],"names":[],"mappings":"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"}