-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TypeError: g is not a constructor #62
Comments
I had this same issue, but solved it by making sure my imports looked like this:
I had some auto-import issues screw me up |
@JClackett I am aware of the issue and have been looking into a solution. The cause of this issue is the DiskCache option. (In the meantime, I suggest replacing this with MemoryCache) Cause: Fix: Related:
|
I had exactly the same issue and in the meantime used your suggestion @Josh-McFarlin . |
Any updates or should I just focus on creating my own custom cache? |
Could use an update on this as well |
For anyone interested I kind of just made my own based on this package that saves to a local folder (fly volumes in my case). // image.server.ts
import { Response as NodeResponse } from "@remix-run/node"
import type { LoaderArgs } from "@vercel/remix"
import axios from "axios"
import { createHash } from "crypto"
import fs from "fs"
import fsp from "fs/promises"
import path from "path"
import sharp from "sharp"
import { IS_PRODUCTION } from "~/lib/config.server"
const badImageBase64 = "R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
function badImageResponse() {
const buffer = Buffer.from(badImageBase64, "base64")
return new Response(buffer, {
status: 500,
headers: {
"Cache-Control": "max-age=0",
"Content-Type": "image/gif;base64",
"Content-Length": buffer.length.toFixed(0),
},
})
}
function getIntOrNull(value: string | null) {
if (!value) return null
return Number.parseInt(value)
}
export async function generateImage({ request }: LoaderArgs) {
try {
const url = new URL(request.url)
const src = url.searchParams.get("src")
if (!src) return badImageResponse()
const width = getIntOrNull(url.searchParams.get("width"))
const height = getIntOrNull(url.searchParams.get("height"))
const quality = getIntOrNull(url.searchParams.get("quality")) || 90
const fit = (url.searchParams.get("fit") as keyof sharp.FitEnum) || "cover"
// Create hash of the url for unique cache key
const hash = createHash("sha256")
.update("v1")
.update(request.method)
.update(request.url)
.update(width?.toString() || "0")
.update(height?.toString() || "0")
.update(quality?.toString() || "80")
.update(fit)
const key = hash.digest("hex")
const cachedFile = path.resolve(path.join(IS_PRODUCTION ? "data/cache/images" : ".data/cache/images", key + ".webp"))
const exists = await fsp
.stat(cachedFile)
.then((s) => s.isFile())
.catch(() => false)
// if image key is in cache return it
if (exists) {
console.log({ Cache: "HIT", src })
const fileStream = fs.createReadStream(cachedFile)
return new NodeResponse(fileStream, {
status: 200,
headers: { "Content-Type": "image/webp", "Cache-Control": "public, max-age=31536000, immutable" },
})
} else {
console.log({ Cache: "MISS", src })
}
// fetch from original source
const res = await axios.get(src, { responseType: "stream" })
if (!res) return badImageResponse()
// transform image
const sharpInstance = sharp()
sharpInstance.on("error", (error) => {
console.error(error)
})
if (width || height) sharpInstance.resize(width, height, { fit })
sharpInstance.webp({ quality })
// save to cache
await fsp.mkdir(path.dirname(cachedFile), { recursive: true }).catch(() => {
// dont need to throw here, just isnt cached in file system
})
const cacheFileStream = fs.createWriteStream(cachedFile)
const imageTransformStream = res.data.pipe(sharpInstance)
await new Promise<void>((resolve) => {
imageTransformStream.pipe(cacheFileStream)
imageTransformStream.on("end", () => {
resolve()
})
imageTransformStream.on("error", async () => {
// remove file if transform fails
await fsp.rm(cachedFile).catch(() => {
// dont need to throw here, just isnt removed from file system
})
})
})
// return transformed image
const fileStream = fs.createReadStream(cachedFile)
return new NodeResponse(fileStream, {
status: 200,
headers: { "Content-Type": "image/webp", "Cache-Control": "public, max-age=31536000, immutable" },
})
} catch (e) {
console.log(e)
return badImageResponse()
}
} // api.image.ts
import { generateImage } from "~/services/image.server"
export const loader = generateImage |
for what its worth, I've created a pure fs disk cache implementation: import crypto from 'node:crypto'
import { access, writeFile, rmdir, readFile } from 'node:fs/promises'
import { mkdirSync } from 'node:fs'
import type { CacheConfig, CacheStatus } from 'remix-image/server'
import { Cache } from 'remix-image/server'
type DiskCacheConfig = CacheConfig & {
path: string
}
function createHash(input: string) {
const hash = crypto.createHash('sha256')
hash.update(input)
return hash.digest('hex')
}
export class DiskCache extends Cache {
config: DiskCacheConfig
constructor(config: Partial<DiskCacheConfig> | undefined = {}) {
super()
this.config = {
path: config.path ?? '.cache/remix-image',
ttl: config.ttl ?? 24 * 60 * 60,
tbd: config.tbd ?? 365 * 24 * 60 * 60,
}
mkdirSync(this.config.path, { recursive: true })
}
has(key: string): Promise<boolean> {
return access(`${this.config.path}/${createHash(key)}`)
.then(() => true)
.catch(() => false)
}
status(key: string): Promise<CacheStatus> {
// this code never gets called, not sure why.
throw new Error('Method not implemented.')
}
get(key: string): Promise<Uint8Array | null> {
return readFile(`${this.config.path}/${createHash(key)}`).catch(() => null)
}
set(key: string, resultImg: Uint8Array): Promise<void> {
return writeFile(`${this.config.path}/${createHash(key)}`, resultImg)
}
clear(): Promise<void> {
return rmdir(this.config.path, { recursive: true })
}
} |
Add `interop: "auto"` to rollup config and remove terser transformation for remix-image/server Terser is not useful for nodejs' only package and make debug harder BaseCache is not a constructor is better than g is not a constructor Closes Josh-McFarlin#62
Add `interop: "auto"` to rollup config and remove terser transformation for remix-image/server Terser is not useful for nodejs' only package and make debug harder BaseCache is not a constructor is better than g is not a constructor Closes Josh-McFarlin#62
Add `interop: "auto"` to rollup config and remove terser transformation for remix-image/server Terser is not useful for nodejs' only package and make debug harder BaseCache is not a constructor is better than g is not a constructor Closes Josh-McFarlin#62
Any updates on this? |
Describe the bug
When following the docs and getting setup, when I run the dev server I get:
Your Example Website or App
No response
Steps to Reproduce the Bug or Issue
Just follow the installation docs
Expected behavior
No errors when starting server
Screenshots or Videos
No response
Platform
Additional context
No response
The text was updated successfully, but these errors were encountered: