Skip to content

Ensuring that masonry will only be initialized on the client side (SSR fix) - #1121

Open
cliqqz wants to merge 1 commit into
desandro:masterfrom
cliqqz:patch-1
Open

Ensuring that masonry will only be initialized on the client side (SSR fix)#1121
cliqqz wants to merge 1 commit into
desandro:masterfrom
cliqqz:patch-1

Conversation

@cliqqz

@cliqqz cliqqz commented Jan 14, 2020

Copy link
Copy Markdown

Since JS frameworks / libraries + SSR (Server-Server-Rendering) got pretty popular it would be great to make this plugin work with SSR projects. This condition ensures that the masonry plugin will only load within the browser and not on the server and eventually crash it by resulting in a ReferenceError for the window object.

an older reference issue I found where other people experienced this: #966

…n using it within SSR projects

Since JS frameworks / libraries + SSR (Server-Server-Rendering) got pretty popular it would be great to make this plugin work with SSR projects. This condition ensures that the masonry plugin will only load within the browser and not on the server and eventually crash it then.
@desandro

Copy link
Copy Markdown
Owner

Thanks for this contribution. I think there is a better solution to load import masory-layout when you're in a SSR environment.

@drewbaker

Copy link
Copy Markdown

I would Masonry to have not throw window not defined errors when used with import. Yes you can work around this with a require() but now with the popularity of Vite that doesn't work out of the box either. So this PR would have been a nice solution I think.

@Xyaren

Xyaren commented Oct 24, 2023

Copy link
Copy Markdown

This is also blocking me from using SSR. Please consider this PR.

@jvyden

jvyden commented Oct 24, 2023

Copy link
Copy Markdown

For those looking for a workaround for Angular SSR while this PR becomes official, you can tell NPM to pull this version directly from git if you specify the repository and commit hash in your package.json:

    "masonry-layout": "github:cliqqz/masonry#ffd2b614237176fd184b70b90a4559f9716dd29c",

I believe you also need to modify your package-lock as well for changes to take effect. You can view my implementation here: https://github.com/LittleBigRefresh/refresh-web/blob/master/package.json

@jvyden jvyden left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving as I've had this working in production for a couple months now. Pretty sure this repository is just unmaintained, though.

Our best bet is native support for masonry grids in CSS to stop being experimental: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout

@Xyaren

Xyaren commented Oct 24, 2023

Copy link
Copy Markdown

For those looking for a workaround for Angular SSR while this PR becomes official, you can tell NPM to pull this version directly from git if you specify the repository and commit hash in your package.json:

    "masonry-layout": "github:cliqqz/masonry#ffd2b614237176fd184b70b90a4559f9716dd29c",

I believe you also need to modify your package-lock as well for changes to take effect. You can view my implementation here: https://github.com/LittleBigRefresh/refresh-web/blob/master/package.json

As I am using it as a peerDependency of ngx-masonry I was able to define an overwrite like this:

...
  "dependencies": {...},
  "devDependencies": {...},
  "overrides": {
    "ngx-masonry": {
      "masonry-layout": "github:cliqqz/masonry#ffd2b614237176fd184b70b90a4559f9716dd29c"
    },
...

https://docs.npmjs.com/cli/v8/configuring-npm/package-json#overrides

This requires a non-ancient npm version though.

erickgcastro

This comment was marked as duplicate.

@leblancmeneses

Copy link
Copy Markdown

alternative solution given this is a 1 line fix is to use npx patch-package masonry-layout after you update node_modules/masonry-layout with what this pr has.

oriolj added a commit to oriolj/masonry-pretext that referenced this pull request Apr 8, 2026
…dev.5, § L.2b)

`import Masonry from 'masonry-pretext'` no longer crashes during
Next.js / Nuxt / SvelteKit / Vite SSR build passes. The fix wraps
every UMD wrapper's `window` reference with
  `typeof window !== 'undefined' ? window : {}`
so the bundle can be loaded in a Node `vm` context with empty
globals. The factory bodies' `window.console` / `window.jQuery`
reads then become `undefined` instead of throwing — and the
existing falsy checks already handle that.

Verified by test/visual/ssr-smoke.mjs which loads
dist/masonry.pkgd.min.js in a `node:vm` context with empty
globals and asserts the IIFE doesn't throw. **The test was added
in desandro#4 as a diagnostic that always failed; this commit flips it
to passing and promotes it into `make test` as a permanent gate.**

Patches:

  - masonry.js (line 33): direct source edit. UMD call site
    wrapped. First source edit in the fork — every previous
    improvement went through a build-time plugin.
  - scripts/build.mjs:
      - new ssrDomGuardPlugin with one entry per dep file:
          - outlayer/outlayer.js     (UMD call site)
          - outlayer/item.js         (UMD call site, via the
                                      existing patch plugin's
                                      transform desandro#7 to avoid an
                                      onLoad-filter conflict)
          - get-size/get-size.js     (UMD call site)
          - fizzy-ui-utils/utils.js  (UMD call site + a typeof
                                      document guard inside the
                                      docReady function body)
          - jquery-bridget/jquery-bridget.js  (UMD call site)
  - Makefile + package.json: `make test` and `npm test` now run
    visual + ssr-smoke. New `npm run test:ssr` for ssr-only.

Closes upstream desandro/masonry:
  - desandro#1194  "Fix for window undefined issue with SSR"
  - desandro#1121  "Ensuring that masonry will only be initialized on the client side (SSR fix)"
  - desandro#1201  "vite build fails"
All three open for 1-2 years with no upstream movement.

Numbers (vs pre-005):

  masonry.js source raw     7473 →  7510  (+37 B)
  dist/masonry.pkgd.min.js raw  23296 → 23450  (+154 B,  +0.66%)
  dist/masonry.pkgd.min.js gz    7616 →  7629  ( +13 B,  +0.17%)
  dist/masonry.pkgd.min.js br    6851 →  6898  ( +47 B,  +0.69%)
  visual regression tests    4/4  →  4/4
  SSR smoke test              ✗  →   ✓    ← first pass

vs upstream-frozen v4.2.2:
  dist/masonry.pkgd.min.js raw  24103 → 23450  (−653 B)
  dist/masonry.pkgd.min.js gz    7367 →  7629  (+262 B, of which
                                                +13 B is the SSR
                                                fix; the rest is
                                                the residual desandro#2
                                                esbuild cost)
  SSR import works            ✗  →   ✓    ← first time

The SSR fix took 3 iterations of build-and-test to converge.
Iteration 1 missed the docReady chain (Outlayer.create runs
htmlInit at module load → docReady → document.readyState).
Iteration 2 missed jquery-bridget (forgot it gets bundled via
the entry file's require). Each missing patch was surfaced in
<30 seconds by ssr-smoke.mjs and fixed in another minute. The
methodology converged to a working SSR fix because the gate was
already in place.

Predicted vs actual: all six predictions inside their bands.

Full record: improvements/005-ssr-import-fix.md
Roadmap progress: FORK_ROADMAP.md § Progress (row 4b')

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants