@uppy/compressor: migrate to TS (#4907)

* refactor compressor to ts

* rename Options

* export opts
This commit is contained in:
Mikael Finstad 2024-02-12 23:10:49 +08:00 committed by GitHub
parent 2e93ba8b48
commit 6b4f5b68f7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 112 additions and 21 deletions

View file

@ -3,10 +3,11 @@ import Core from '@uppy/core'
import getFileNameAndExtension from '@uppy/utils/lib/getFileNameAndExtension'
import fs from 'node:fs'
import path from 'node:path'
import CompressorPlugin from './index.js'
import CompressorPlugin from './index.ts'
// Compressor uses browser canvas API, so need to mock compress()
CompressorPlugin.prototype.compress = (blob) => {
// @ts-expect-error mocked
CompressorPlugin.prototype.compress = async (blob: Blob) => {
return {
name: `${getFileNameAndExtension(blob.name).name}.webp`,
type: 'image/webp',
@ -16,11 +17,28 @@ CompressorPlugin.prototype.compress = (blob) => {
}
// eslint-disable-next-line no-restricted-globals
const sampleImage = fs.readFileSync(path.join(__dirname, '../../../../e2e/cypress/fixtures/images/image.jpg'))
const sampleImage = fs.readFileSync(
path.join(__dirname, '../../../../e2e/cypress/fixtures/images/image.jpg'),
)
const file1 = { source: 'jest', name: 'image-1.jpeg', type: 'image/jpeg', data: new File([sampleImage], 'image-1.jpeg', { type: 'image/jpeg' }) }
const file2 = { source: 'jest', name: 'yolo', type: 'image/jpeg', data: new File([sampleImage], 'yolo', { type: 'image/jpeg' }) }
const file3 = { source: 'jest', name: 'my.file.is.weird.png', type: 'image/png', data: new File([sampleImage], 'my.file.is.weird.png', { type: 'image/png' }) }
const file1 = {
source: 'jest',
name: 'image-1.jpeg',
type: 'image/jpeg',
data: new File([sampleImage], 'image-1.jpeg', { type: 'image/jpeg' }),
}
const file2 = {
source: 'jest',
name: 'yolo',
type: 'image/jpeg',
data: new File([sampleImage], 'yolo', { type: 'image/jpeg' }),
}
const file3 = {
source: 'jest',
name: 'my.file.is.weird.png',
type: 'image/png',
data: new File([sampleImage], 'my.file.is.weird.png', { type: 'image/png' }),
}
describe('CompressorPlugin', () => {
it('should change update extension in file.name and file.meta.name', () => {

View file

@ -1,14 +1,34 @@
import { BasePlugin } from '@uppy/core'
import { BasePlugin, Uppy } from '@uppy/core'
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import { RateLimitedQueue } from '@uppy/utils/lib/RateLimitedQueue'
import getFileNameAndExtension from '@uppy/utils/lib/getFileNameAndExtension'
import prettierBytes from '@transloadit/prettier-bytes'
import CompressorJS from 'compressorjs'
import locale from './locale.js'
export default class Compressor extends BasePlugin {
import type { Body, Meta, UppyFile } from '@uppy/utils/lib/UppyFile'
import type { PluginOpts } from '@uppy/core/lib/BasePlugin.ts'
import locale from './locale.ts'
declare module '@uppy/core' {
export interface UppyEventMap<M extends Meta, B extends Body> {
'compressor:complete': (file: UppyFile<M, B>[]) => void
}
}
export interface CompressorOpts extends PluginOpts, CompressorJS.Options {
quality: number
limit?: number
}
export default class Compressor<
M extends Meta,
B extends Body,
> extends BasePlugin<CompressorOpts, M, B> {
#RateLimitedQueue
constructor (uppy, opts) {
constructor(uppy: Uppy<M, B>, opts: CompressorOpts) {
super(uppy, opts)
this.id = this.opts.id || 'Compressor'
this.type = 'modifier'
@ -30,7 +50,7 @@ export default class Compressor extends BasePlugin {
this.compress = this.compress.bind(this)
}
compress (blob) {
compress(blob: Blob): Promise<Blob | File> {
return new Promise((resolve, reject) => {
/* eslint-disable no-new */
new CompressorJS(blob, {
@ -41,15 +61,17 @@ export default class Compressor extends BasePlugin {
})
}
async prepareUpload (fileIDs) {
async prepareUpload(fileIDs: string[]): Promise<void> {
let totalCompressedSize = 0
const compressedFiles = []
const compressedFiles: UppyFile<M, B>[] = []
const compressAndApplyResult = this.#RateLimitedQueue.wrapPromiseFunction(
async (file) => {
async (file: UppyFile<M, B>) => {
try {
const compressedBlob = await this.compress(file.data)
const compressedSavingsSize = file.data.size - compressedBlob.size
this.uppy.log(`[Image Compressor] Image ${file.id} compressed by ${prettierBytes(compressedSavingsSize)}`)
this.uppy.log(
`[Image Compressor] Image ${file.id} compressed by ${prettierBytes(compressedSavingsSize)}`,
)
totalCompressedSize += compressedSavingsSize
const { name, type, size } = compressedBlob
@ -61,7 +83,9 @@ export default class Compressor extends BasePlugin {
this.uppy.setFileState(file.id, {
...(name && { name }),
...(compressedFileName.extension && { extension: compressedFileName.extension }),
...(compressedFileName.extension && {
extension: compressedFileName.extension,
}),
...(type && { type }),
...(size && { size }),
data: compressedBlob,
@ -73,7 +97,10 @@ export default class Compressor extends BasePlugin {
})
compressedFiles.push(file)
} catch (err) {
this.uppy.log(`[Image Compressor] Failed to compress ${file.id}:`, 'warning')
this.uppy.log(
`[Image Compressor] Failed to compress ${file.id}:`,
'warning',
)
this.uppy.log(err, 'warning')
}
},
@ -97,7 +124,7 @@ export default class Compressor extends BasePlugin {
file.data = file.data.slice(0, file.data.size, file.type)
}
if (!file.type.startsWith('image/')) {
if (!file.type?.startsWith('image/')) {
return Promise.resolve()
}
@ -128,11 +155,11 @@ export default class Compressor extends BasePlugin {
}
}
install () {
install(): void {
this.uppy.addPreProcessor(this.prepareUpload)
}
uninstall () {
uninstall(): void {
this.uppy.removePreProcessor(this.prepareUpload)
}
}

View file

@ -0,0 +1,25 @@
{
"extends": "../../../tsconfig.shared",
"compilerOptions": {
"noImplicitAny": false,
"outDir": "./lib",
"paths": {
"@uppy/utils/lib/*": ["../utils/src/*"],
"@uppy/core": ["../core/src/index.js"],
"@uppy/core/lib/*": ["../core/src/*"]
},
"resolveJsonModule": false,
"rootDir": "./src",
"skipLibCheck": true
},
"include": ["./src/**/*.*"],
"exclude": ["./src/**/*.test.ts"],
"references": [
{
"path": "../utils/tsconfig.build.json"
},
{
"path": "../core/tsconfig.build.json"
}
]
}

View file

@ -0,0 +1,21 @@
{
"extends": "../../../tsconfig.shared",
"compilerOptions": {
"emitDeclarationOnly": false,
"noEmit": true,
"paths": {
"@uppy/utils/lib/*": ["../utils/src/*"],
"@uppy/core": ["../core/src/index.js"],
"@uppy/core/lib/*": ["../core/src/*"],
},
},
"include": ["./package.json", "./src/**/*.*"],
"references": [
{
"path": "../utils/tsconfig.build.json",
},
{
"path": "../core/tsconfig.build.json",
},
],
}

View file

@ -5,7 +5,7 @@ export interface DeterminateFileProcessing {
}
export interface IndeterminateFileProcessing {
mode: 'indeterminate'
message?: undefined
message?: string
value?: 0
}
export type FileProcessingInfo =