Skip to content

Patch for "Maximum recursive updates..." on Methods like flipRight() and flipLeft() #122

@piets3n

Description

@piets3n

Hi! 👋

Firstly, thanks for your work on this project! 🙂

Today I used patch-package to patch flipbook-vue@1.0.0-beta.4 for the project I'm working on.

Thanks @jeffreykthomas for pointing out the issues with minX and maxX, so i could dirty patch this issue quick and dirty

Problem Description

When using flipbook-vue v1.0.0-beta.4 with Vue.js in Node.js 22.18.0+ environments (particularly with Nuxt 4.1.0+), you may encounter this error on flipbook-vue methods like flipRight() or flipLeft():

[Vue warn]: Maximum recursive updates exceeded in component. This means you have a reactive effect that is mutating its own dependencies, either directly or indirectly...

Root Cause

The issue occurs in Node.js 22+ due to enhanced Vue reactivity detection. The makePolygonArray function updates reactive properties minX and maxX repeatedly within a loop, causing Vue's reactivity system to detect recursive updates and throw the error.

Problematic code pattern:

// Inside a loop - triggers Vue reactivity on every iteration
this.maxX = Math.max(Math.max(x0, x1), this.maxX);
this.minX = Math.min(Math.min(x0, x1), this.minX);

Environment Details

  • Node.js: 22.18.0+
  • Nuxt: 4.1.0+
  • flipbook-vue: v1.0.0-beta.4
  • Issue: Appears specifically in newer Node.js versions with enhanced Vue reactivity

Solution

The fix uses local variables during calculations and updates reactive properties only once at the end:

Installation

  1. Install patch-package if you haven't already:
npm install patch-package --save-dev
# or
yarn add patch-package --dev
  1. Add to your package.json scripts:
{
  "scripts": {
    "postinstall": "patch-package"
  }
}
  1. Apply the patch:
    • Create the patch file: flipbook-vue+1.0.0-beta.4.patch
    • Copy the content below in it
    • Place it in your project's patches/ directory
    • Run npm install or yarn install

Manual Fix (Alternative)

If you prefer to apply the fix manually, locate the makePolygonArray function in:

  • node_modules/flipbook-vue/dist/flipbook.mjs
  • node_modules/flipbook-vue/dist/flipbook.cjs.js

Replace this pattern:

this.minX = 2e308;
this.maxX = -2e308;
// ... inside loop:
this.maxX = Math.max(Math.max(x0, x1), this.maxX);
this.minX = Math.min(Math.min(x0, x1), this.minX);

With:

// Use local variables to avoid Vue reactivity issues
var localMinX = 2e308;
var localMaxX = -2e308;
// ... inside loop:
localMaxX = Math.max(Math.max(x0, x1), localMaxX);
localMinX = Math.min(Math.min(x0, x1), localMinX);

// Update reactive properties only once at the end
this.minX = localMinX;
this.maxX = localMaxX;

Why This Works

  • Local variables (localMinX, localMaxX) are not reactive
  • Calculations happen without triggering Vue's reactivity system
  • Single update at the end prevents recursive update detection
  • Preserves functionality while eliminating the error

Verification

After applying the fix:

  1. The flipbook component should work without console errors
  2. Page animations should function normally
  3. No "Maximum recursive updates exceeded" warnings

Additional Notes

  • This fix is minimal and only addresses the root cause
  • No experimental code or workarounds included
  • Safe for production use
  • Compatible with both ESM and CommonJS builds

For Package Maintainers

This issue affects developers upgrading to Node.js 22+ with Vue.js applications. Consider incorporating this fix into the next release of flipbook-vue to prevent widespread issues for users upgrading their Node.js environments.

Here is the diff that solved my problem:

diff --git a/node_modules/flipbook-vue/dist/flipbook.cjs.js b/node_modules/flipbook-vue/dist/flipbook.cjs.js
index 10f806e..fa4dc11 100644
--- a/node_modules/flipbook-vue/dist/flipbook.cjs.js
+++ b/node_modules/flipbook-vue/dist/flipbook.cjs.js
@@ -571,8 +571,10 @@ var script = {
         rotate = -rotate;
         dRotate = -dRotate;
       }
-      this.minX = 2e308;
-      this.maxX = -2e308;
+      
+      // Use local variables to avoid Vue reactivity issues with minX/maxX
+      var localMinX = 2e308;
+      var localMaxX = -2e308;
       results = [];
       for (i = j = 0, ref = this.nPolygons; (0 <= ref ? j < ref : j > ref); i = 0 <= ref ? ++j : --j) {
         bgPos = (i / (this.nPolygons - 1) * 100) + "% 0px";
@@ -590,13 +592,18 @@ var script = {
         m.rotateY(-rotate);
         x0 = m.transformX(0);
         x1 = m.transformX(polygonWidth);
-        this.maxX = Math.max(Math.max(x0, x1), this.maxX);
-        this.minX = Math.min(Math.min(x0, x1), this.minX);
+        localMaxX = Math.max(Math.max(x0, x1), localMaxX);
+        localMinX = Math.min(Math.min(x0, x1), localMinX);
         lighting = this.computeLighting(pageRotation - rotate, dRotate);
         radian += dRadian;
         rotate += dRotate;
         results.push([face + i, image, lighting, bgPos, m.toString(), Math.abs(Math.round(z))]);
       }
+      
+      // Update the reactive properties only once at the end
+      this.minX = localMinX;
+      this.maxX = localMaxX;
+      
       return results;
     },
     computeLighting: function(rot, dRotate) {
diff --git a/node_modules/flipbook-vue/dist/flipbook.mjs b/node_modules/flipbook-vue/dist/flipbook.mjs
index 7d9674c..0b37df8 100644
--- a/node_modules/flipbook-vue/dist/flipbook.mjs
+++ b/node_modules/flipbook-vue/dist/flipbook.mjs
@@ -569,8 +569,10 @@ var script = {
         rotate = -rotate;
         dRotate = -dRotate;
       }
-      this.minX = 2e308;
-      this.maxX = -2e308;
+      
+      // Use local variables to avoid Vue reactivity issues with minX/maxX
+      var localMinX = 2e308;
+      var localMaxX = -2e308;
       results = [];
       for (i = j = 0, ref = this.nPolygons; (0 <= ref ? j < ref : j > ref); i = 0 <= ref ? ++j : --j) {
         bgPos = (i / (this.nPolygons - 1) * 100) + "% 0px";
@@ -588,13 +590,18 @@ var script = {
         m.rotateY(-rotate);
         x0 = m.transformX(0);
         x1 = m.transformX(polygonWidth);
-        this.maxX = Math.max(Math.max(x0, x1), this.maxX);
-        this.minX = Math.min(Math.min(x0, x1), this.minX);
+        localMaxX = Math.max(Math.max(x0, x1), localMaxX);
+        localMinX = Math.min(Math.min(x0, x1), localMinX);
         lighting = this.computeLighting(pageRotation - rotate, dRotate);
         radian += dRadian;
         rotate += dRotate;
         results.push([face + i, image, lighting, bgPos, m.toString(), Math.abs(Math.round(z))]);
       }
+      
+      // Update the reactive properties only once at the end
+      this.minX = localMinX;
+      this.maxX = localMaxX;
+      
       return results;
     },
     computeLighting: function(rot, dRotate) {

This issue body was partially generated by patch-package.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions