ソースを参照

@uppy/thumbnail-generator: refactor to ESM (#3734)

Antoine du Hamel 2 年 前
コミット
5a2dd50d6c

+ 1 - 0
.eslintrc.js

@@ -219,6 +219,7 @@ module.exports = {
         'packages/@uppy/status-bar/src/**/*.js',
         'packages/@uppy/svelte/src/**/*.js',
         'packages/@uppy/svelte/rollup.config.js',
+        'packages/@uppy/thumbnail-generator/src/**/*.js',
         'packages/@uppy/tus/src/**/*.js',
         'packages/@uppy/unsplash/src/**/*.js',
         'packages/@uppy/url/src/**/*.js',

+ 2 - 0
packages/@uppy/thumbnail-generator/package.json

@@ -5,6 +5,7 @@
   "license": "MIT",
   "main": "lib/index.js",
   "types": "types/index.d.ts",
+  "type": "module",
   "keywords": [
     "file uploader",
     "uppy",
@@ -26,6 +27,7 @@
     "exifr": "^7.0.0"
   },
   "devDependencies": {
+    "@jest/globals": "^27.4.2",
     "namespace-emitter": "2.0.1"
   },
   "peerDependencies": {

+ 114 - 107
packages/@uppy/thumbnail-generator/src/index.js

@@ -1,17 +1,110 @@
-const { UIPlugin } = require('@uppy/core')
-const dataURItoBlob = require('@uppy/utils/lib/dataURItoBlob')
-const isObjectURL = require('@uppy/utils/lib/isObjectURL')
-const isPreviewSupported = require('@uppy/utils/lib/isPreviewSupported')
-const { rotation } = require('exifr/dist/mini.umd.js')
+import { UIPlugin } from '@uppy/core'
+import dataURItoBlob from '@uppy/utils/lib/dataURItoBlob'
+import isObjectURL from '@uppy/utils/lib/isObjectURL'
+import isPreviewSupported from '@uppy/utils/lib/isPreviewSupported'
+import { rotation } from 'exifr/dist/mini.umd.js'
 
-const locale = require('./locale')
+import locale from './locale.js'
+import packageJson from '../package.json'
+
+/**
+ * Save a <canvas> element's content to a Blob object.
+ *
+ * @param {HTMLCanvasElement} canvas
+ * @returns {Promise}
+ */
+function canvasToBlob (canvas, type, quality) {
+  try {
+    canvas.getContext('2d').getImageData(0, 0, 1, 1)
+  } catch (err) {
+    if (err.code === 18) {
+      return Promise.reject(new Error('cannot read image, probably an svg with external resources'))
+    }
+  }
+
+  if (canvas.toBlob) {
+    return new Promise(resolve => {
+      canvas.toBlob(resolve, type, quality)
+    }).then((blob) => {
+      if (blob === null) {
+        throw new Error('cannot read image, probably an svg with external resources')
+      }
+      return blob
+    })
+  }
+  return Promise.resolve().then(() => {
+    return dataURItoBlob(canvas.toDataURL(type, quality), {})
+  }).then((blob) => {
+    if (blob === null) {
+      throw new Error('could not extract blob, probably an old browser')
+    }
+    return blob
+  })
+}
+
+function rotateImage (image, translate) {
+  let w = image.width
+  let h = image.height
+
+  if (translate.deg === 90 || translate.deg === 270) {
+    w = image.height
+    h = image.width
+  }
+
+  const canvas = document.createElement('canvas')
+  canvas.width = w
+  canvas.height = h
+
+  const context = canvas.getContext('2d')
+  context.translate(w / 2, h / 2)
+  if (translate.canvas) {
+    context.rotate(translate.rad)
+    context.scale(translate.scaleX, translate.scaleY)
+  }
+  context.drawImage(image, -image.width / 2, -image.height / 2, image.width, image.height)
+
+  return canvas
+}
+
+/**
+ * Make sure the image doesn’t exceed browser/device canvas limits.
+ * For ios with 256 RAM and ie
+ */
+function protect (image) {
+  // https://stackoverflow.com/questions/6081483/maximum-size-of-a-canvas-element
+
+  const ratio = image.width / image.height
+
+  const maxSquare = 5000000 // ios max canvas square
+  const maxSize = 4096 // ie max canvas dimensions
+
+  let maxW = Math.floor(Math.sqrt(maxSquare * ratio))
+  let maxH = Math.floor(maxSquare / Math.sqrt(maxSquare * ratio))
+  if (maxW > maxSize) {
+    maxW = maxSize
+    maxH = Math.round(maxW / ratio)
+  }
+  if (maxH > maxSize) {
+    maxH = maxSize
+    maxW = Math.round(ratio * maxH)
+  }
+  if (image.width > maxW) {
+    const canvas = document.createElement('canvas')
+    canvas.width = maxW
+    canvas.height = maxH
+    canvas.getContext('2d').drawImage(image, 0, 0, maxW, maxH)
+    return canvas
+  }
+
+  return image
+}
 
 /**
  * The Thumbnail Generator plugin
  */
 
-module.exports = class ThumbnailGenerator extends UIPlugin {
-  static VERSION = require('../package.json').version
+export default class ThumbnailGenerator extends UIPlugin {
+  static VERSION = packageJson.version
 
   constructor (uppy, opts) {
     super(uppy, opts)
@@ -84,7 +177,7 @@ module.exports = class ThumbnailGenerator extends UIPlugin {
    * account. If neither width nor height are given, the default dimension
    * is used.
    */
-  getProportionalDimensions (img, width, height, rotation) {
+  getProportionalDimensions (img, width, height, rotation) { // eslint-disable-line no-shadow
     let aspect = img.width / img.height
     if (rotation === 90 || rotation === 270) {
       aspect = img.height / img.width
@@ -110,39 +203,6 @@ module.exports = class ThumbnailGenerator extends UIPlugin {
     }
   }
 
-  /**
-   * Make sure the image doesn’t exceed browser/device canvas limits.
-   * For ios with 256 RAM and ie
-   */
-  protect (image) {
-    // https://stackoverflow.com/questions/6081483/maximum-size-of-a-canvas-element
-
-    const ratio = image.width / image.height
-
-    const maxSquare = 5000000 // ios max canvas square
-    const maxSize = 4096 // ie max canvas dimensions
-
-    let maxW = Math.floor(Math.sqrt(maxSquare * ratio))
-    let maxH = Math.floor(maxSquare / Math.sqrt(maxSquare * ratio))
-    if (maxW > maxSize) {
-      maxW = maxSize
-      maxH = Math.round(maxW / ratio)
-    }
-    if (maxH > maxSize) {
-      maxH = maxSize
-      maxW = Math.round(ratio * maxH)
-    }
-    if (image.width > maxW) {
-      const canvas = document.createElement('canvas')
-      canvas.width = maxW
-      canvas.height = maxH
-      canvas.getContext('2d').drawImage(image, 0, 0, maxW, maxH)
-      image = canvas
-    }
-
-    return image
-  }
-
   /**
    * Resize an image to the target `width` and `height`.
    *
@@ -152,9 +212,9 @@ module.exports = class ThumbnailGenerator extends UIPlugin {
     // Resizing in steps refactored to use a solution from
     // https://blog.uploadcare.com/image-resize-in-browsers-is-broken-e38eed08df01
 
-    image = this.protect(image)
+    let img = this.protect(image)
 
-    let steps = Math.ceil(Math.log2(image.width / targetWidth))
+    let steps = Math.ceil(Math.log2(img.width / targetWidth))
     if (steps < 1) {
       steps = 1
     }
@@ -166,73 +226,14 @@ module.exports = class ThumbnailGenerator extends UIPlugin {
       const canvas = document.createElement('canvas')
       canvas.width = sW
       canvas.height = sH
-      canvas.getContext('2d').drawImage(image, 0, 0, sW, sH)
-      image = canvas
+      canvas.getContext('2d').drawImage(img, 0, 0, sW, sH)
+      img = canvas
 
       sW = Math.round(sW / x)
       sH = Math.round(sH / x)
     }
 
-    return image
-  }
-
-  rotateImage (image, translate) {
-    let w = image.width
-    let h = image.height
-
-    if (translate.deg === 90 || translate.deg === 270) {
-      w = image.height
-      h = image.width
-    }
-
-    const canvas = document.createElement('canvas')
-    canvas.width = w
-    canvas.height = h
-
-    const context = canvas.getContext('2d')
-    context.translate(w / 2, h / 2)
-    if (translate.canvas) {
-      context.rotate(translate.rad)
-      context.scale(translate.scaleX, translate.scaleY)
-    }
-    context.drawImage(image, -image.width / 2, -image.height / 2, image.width, image.height)
-
-    return canvas
-  }
-
-  /**
-   * Save a <canvas> element's content to a Blob object.
-   *
-   * @param {HTMLCanvasElement} canvas
-   * @returns {Promise}
-   */
-  canvasToBlob (canvas, type, quality) {
-    try {
-      canvas.getContext('2d').getImageData(0, 0, 1, 1)
-    } catch (err) {
-      if (err.code === 18) {
-        return Promise.reject(new Error('cannot read image, probably an svg with external resources'))
-      }
-    }
-
-    if (canvas.toBlob) {
-      return new Promise(resolve => {
-        canvas.toBlob(resolve, type, quality)
-      }).then((blob) => {
-        if (blob === null) {
-          throw new Error('cannot read image, probably an svg with external resources')
-        }
-        return blob
-      })
-    }
-    return Promise.resolve().then(() => {
-      return dataURItoBlob(canvas.toDataURL(type, quality), {})
-    }).then((blob) => {
-      if (blob === null) {
-        throw new Error('could not extract blob, probably an old browser')
-      }
-      return blob
-    })
+    return img
   }
 
   /**
@@ -255,7 +256,7 @@ module.exports = class ThumbnailGenerator extends UIPlugin {
       const current = this.uppy.getFile(this.queue.shift())
       if (!current) {
         this.uppy.log('[ThumbnailGenerator] file was removed before a thumbnail could be generated, but not removed from the queue. This is probably a bug', 'error')
-        return
+        return Promise.resolve()
       }
       return this.requestThumbnail(current)
         .catch(() => {}) // eslint-disable-line node/handle-callback-err
@@ -264,6 +265,7 @@ module.exports = class ThumbnailGenerator extends UIPlugin {
     this.queueProcessing = false
     this.uppy.log('[ThumbnailGenerator] Emptied thumbnail queue')
     this.uppy.emit('thumbnail:all-generated')
+    return Promise.resolve()
   }
 
   requestThumbnail (file) {
@@ -396,3 +398,8 @@ module.exports = class ThumbnailGenerator extends UIPlugin {
     }
   }
 }
+
+// TODO: remove these methods from the prototype in the next major.
+ThumbnailGenerator.prototype.canvasToBlob = canvasToBlob
+ThumbnailGenerator.prototype.protect = protect
+ThumbnailGenerator.prototype.rotateImage = rotateImage

+ 9 - 6
packages/@uppy/thumbnail-generator/src/index.test.js

@@ -1,6 +1,7 @@
-const { UIPlugin } = require('@uppy/core')
-const emitter = require('namespace-emitter')
-const ThumbnailGeneratorPlugin = require('./index')
+import { describe, it, expect, jest } from '@jest/globals'
+import { UIPlugin } from '@uppy/core'
+import emitter from 'namespace-emitter'
+import ThumbnailGeneratorPlugin from './index.js'
 
 const delay = duration => new Promise(resolve => setTimeout(resolve, duration))
 
@@ -139,6 +140,9 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
       URL.revokeObjectURL = jest.fn(() => null)
 
       try {
+        const file1 = { id: 1, name: 'bar.jpg', type: 'image/jpeg', data: new Blob() }
+        const file2 = { id: 2, name: 'bar2.jpg', type: 'image/jpeg', data: new Blob() }
+
         plugin.createThumbnail = jest.fn(async () => {
           await delay(50)
           return 'blob:http://uppy.io/fake-thumbnail'
@@ -148,8 +152,6 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
           if (id === 2) file2.preview = preview
         })
 
-        const file1 = { id: 1, name: 'bar.jpg', type: 'image/jpeg', data: new Blob() }
-        const file2 = { id: 2, name: 'bar2.jpg', type: 'image/jpeg', data: new Blob() }
         core.mockFile(file1.id, file1)
         core.emit('file-added', file1)
         core.mockFile(file2.id, file2)
@@ -191,7 +193,8 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
           expect(file.id).toBe(expected.shift())
           expect(preview).toBe(`blob:${file.id}.png`)
         } catch (err) {
-          return reject(err)
+          reject(err)
+          return
         }
         if (expected.length === 0) resolve()
       })

+ 1 - 1
packages/@uppy/thumbnail-generator/src/locale.js

@@ -1,4 +1,4 @@
-module.exports = {
+export default {
   strings: {
     generatingThumbnails: 'Generating thumbnails...',
   },

+ 13 - 0
website/src/docs/thumbnail-generator.md

@@ -58,6 +58,19 @@ uppy.use(ThumbnailGenerator, {
 
 A unique identifier for this plugin. It defaults to `'ThumbnailGenerator'`.
 
+### `locale: {}`
+
+<!-- eslint-disable no-restricted-globals, no-multiple-empty-lines -->
+
+```js
+export default {
+  strings: {
+    generatingThumbnails: 'Generating thumbnails...',
+  },
+}
+
+```
+
 ### `thumbnailWidth: 200`
 
 Width of the resulting thumbnail. Default thumbnail dimension is 200px. Thumbnails are always proportional and not cropped. If width is provided, height is calculated automatically to match ratio.

+ 1 - 0
yarn.lock

@@ -10149,6 +10149,7 @@ __metadata:
   version: 0.0.0-use.local
   resolution: "@uppy/thumbnail-generator@workspace:packages/@uppy/thumbnail-generator"
   dependencies:
+    "@jest/globals": ^27.4.2
     "@uppy/utils": "workspace:^"
     exifr: ^7.0.0
     namespace-emitter: 2.0.1