-
Notifications
You must be signed in to change notification settings - Fork 29.9k
docs: cacheHandlers use object instead of class #86022
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
base: canary
Are you sure you want to change the base?
Conversation
|
Allow CI Workflow Run
Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer |
| module.exports = { | ||
| constructor() { | ||
| this.client = createClient({ url: process.env.REDIS_URL }) | ||
| this.client.connect() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The object literal syntax doesn't support constructor methods like classes do. When converting from a class to an object, the Redis client initialization needs to be moved outside the exported object. Consider restructuring like this:
const { createClient } = require('redis')
const client = createClient({ url: process.env.REDIS_URL })
client.connect()
module.exports = {
// Methods that use client
async get(cacheKey, softTags) {
// Implementation using client
},
// Other methods...
}This ensures the Redis client is properly initialized before the module is exported and can be used by the handler methods.
| module.exports = { | |
| constructor() { | |
| this.client = createClient({ url: process.env.REDIS_URL }) | |
| this.client.connect() | |
| const { createClient } = require('redis') | |
| const client = createClient({ url: process.env.REDIS_URL }) | |
| client.connect() | |
| module.exports = { | |
Spotted by Graphite Agent
Is this helpful? React 👍 or 👎 to let us know.
| const { createClient } = require('redis') | ||
|
|
||
| module.exports = class RedisCacheHandler { | ||
| module.exports = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Redis cache handler example has broken initialization code. When exporting an object literal with a constructor() method, that method won't be called automatically, so this.client will never be initialized.
View Details
📝 Patch Details
diff --git a/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.mdx b/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.mdx
index 06612b22f4..174aafe116 100644
--- a/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.mdx
+++ b/docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.mdx
@@ -333,15 +333,13 @@ For durable storage like Redis or a database, you'll need to serialize the cache
```js filename="cache-handlers/redis-handler.js"
const { createClient } = require('redis')
-module.exports = {
- constructor() {
- this.client = createClient({ url: process.env.REDIS_URL })
- this.client.connect()
- }
+const client = createClient({ url: process.env.REDIS_URL })
+client.connect()
+module.exports = {
async get(cacheKey, softTags) {
// Retrieve from Redis
- const stored = await this.client.get(cacheKey)
+ const stored = await client.get(cacheKey)
if (!stored) return undefined
// Deserialize the entry
@@ -383,7 +381,7 @@ module.exports = {
// Combine chunks and serialize for Redis storage
const data = Buffer.concat(chunks.map((chunk) => Buffer.from(chunk)))
- await this.client.set(
+ await client.set(
cacheKey,
JSON.stringify({
value: data.toString('base64'),
@@ -411,7 +409,7 @@ module.exports = {
async updateTags(tags, durations) {
// Implement tag-based invalidation if needed
// Could iterate over keys with matching tags and delete them
- }
+ },
}
```
Analysis
Redis cache handler example has non-functional constructor method
What fails: The Redis cache handler example at lines 336-340 in docs/01-app/03-api-reference/05-config/01-next-config-js/cacheHandlers.mdx exports an object literal with a constructor() method. When Next.js loads this handler and calls get() or set() methods, this.client is undefined because the constructor() method is never automatically invoked on object literals.
How to reproduce: Export the exact Redis handler code from the documentation as cache-handlers/redis-handler.js, configure it in next.config.js under cacheHandlers.remote, and attempt to use 'use cache: remote' in a Server Component. The get() and set() methods will fail when trying to access this.client.get() or this.client.set().
What happens: At runtime, this.client evaluates to undefined in the get(), set(), and other methods, causing errors like "Cannot read property 'get' of undefined" when methods attempt to call this.client.get() or this.client.set().
Expected: The cache handler should properly initialize its Redis client so that get() and set() methods can access it successfully.
Why this is a bug: In JavaScript, when you export an object literal like module.exports = { constructor() { ... }, get() { ... } }, the constructor() is just a regular method property - it does NOT automatically execute during object creation (unlike ES6 classes). Next.js loads cache handlers via dynamic import and uses them directly without calling new, so constructor() never runs, leaving instance state uninitialized.
Fix applied: Changed from initializing this.client in a constructor() method to initializing client as a module-level constant that's shared across all handler method calls.
This PR fixes the docs' example where it used class (like cacheHandler (no s)), but cacheHandlers expect an object.