Could not load the “sharp” module using the linux-x64 runtime

I am working on a nest js project and I am using sharp library, suddenly I am starting to get error when trying to run the docker container
here is my dockerfile

FROM node:20-alpine AS builder
WORKDIR /app
COPY . .
RUN yarn
RUN npx nx build api --production=true

FROM node:20-alpine AS runner
WORKDIR /app

COPY --from=builder /app/package.json ./
COPY --from=builder /app/yarn.lock ./

RUN yarn install --production
RUN yarn add sharp --ignore-engines

COPY --from=builder /app/dist/apps/api ./
ARG PORT=3333
ENV PORT=${PORT}

EXPOSE ${PORT}

CMD [ "node", "main" ]

I tried upgrading and downgrading sharp version, and still didn’t work

Allowed propertyName for Javascript setProperty

I’m using javaScript setProperty(propertyName, value) a lot and it works perfectly until I want to set properties like justifyContent when using flexboxes.

It does work with the propertyName ‘flexDirection’ – I can change from row to column or vice verse.

Now when I want to set the ‘justifyContent’ propertyName to ‘flex-start’, ‘center’, ‘left’ it looks like it just doesn’t execute it (or ignores it). It works of course when specifically use something like object.style.justifyContent = “flex-end”

I have a feeling that there is a restricted list of propertyNames for which one can use the setProperty. I tried to look for a list of allowed propertyNames but couldn’t find it anywhere which makes me doubt that this is the problem (it can’t be that I’m the first one to question this).

Also possible that the naming convention flexDirection or justifyContent is different.

Biggest chance is that I’m overseeing something stupid because of my lack of experience:D.

Can anyone point me in the right direction on where to find answer to this mystery?

How to dynamically compile a directory of mdx files before each vite build?

I’m using React and Vite for a project I’m working on.

What I currently need to do is compile and render all of the MDX files in a directory but I don’t want to do the actual compilation on the client side and I want to exclude some of the files so that they aren’t even in the final build.

I already tried using Vite’s glob importing but I don’t think that can be used to filter out files based on metadata.

My current plan is to:

  1. Read all of my mdx files into an array
  2. Parse the frontmatter and decide which ones I want to keep accordingly
  3. Run the remaining files through the mdx compiler
  4. Be able to import the array into my app

I have all of it figured out except the last step, but I keep encountering errors.

From my research it appears vite offers both virtual modules and build hooks for executing code before the build.

I currently have tried using virtual modules and it seems like the right solution but I’m just not sure how to get my mdx data exported from a virtual module.

import fs from "fs"
import fm from "front-matter"
import { evaluate } from "@mdx-js/mdx"
import * as runtime from "react/jsx-runtime"
import remarkFrontmatter from "remark-frontmatter"
import remarkMdxFrontmatter from "remark-mdx-frontmatter"
import toSource from "tosource"
const path = "./src/posts"
const rawPosts = fs.readdirSync(path).map(fileName => {
  const file = fs.readFileSync(`${path}/${fileName}`)
  return String(file)
})
const filteredPosts = rawPosts.filter(async file => {
  const frontmatter = fm(file)
  // use frontmatter to decide which files to keep
  return true
})
const finalPosts = await Promise.all(
  filteredPosts.map(async file => {
    const parsed = await evaluate(file, {
      ...runtime,
      remarkPlugins: [
        remarkFrontmatter,
        remarkMdxFrontmatter,
      ],
    })
    return parsed
  })
)
export default function posts() {
  const moduleId = "virtual:posts"
  const resolvedModuleId = "" + moduleId

  return {
    name: "my-plugin",
    resolveId(id) {
      if (id === moduleId) {
        return resolvedModuleId
      }
    },
    load(id) {
      if (id === resolvedModuleId) {
        // not sure what to do here
        return ?
      }
    },
  }
}

I already tried JSON.stringifying the array but the function disappears when doing that, so what is a better approach? Should I just be compiling the mdx and not evaluating it yet? In that case I don’t know how I would dynamically create multiple virtual modules to import. I realize I could probably use the buildStart hook to run a separate script but I feel like it could be achieved with virtual modules similar to how I have tried so far.

Blogger homepage sections are empty after adding VideoObject JSON-LD schema to some posts

I’m facing an issue with my Blogger website where the sections on the homepage are not displaying any posts. I suspect this started happening after I edited some of my posts to add a VideoObject JSON-LD schema

The Problem:

The sections for “مقالات متنوعة” (Miscellaneous Posts), “ويندوز” (Windows), and “لينكس” (Linux) on my homepage are empty. They only show the section title, but no posts appear underneath, even though they have the correct labels.

enter image description here

Recent Changes:

I believe the issue started after I tried to fix a video indexing problem reported in Google Search Console. I edited several posts that have embaded youtube viedo’s, and added the following snippet to the post body using the HTML view in the editor

enter image description here

example:


<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "VideoObject",
  "name": "how to share files in the Linux system",
  "description": "Some description.",
  "thumbnailUrl": "https://i.ytimg.com/vi/zNxLmpk0lgM/maxresdefault.jpg",
  "uploadDate": "2017-08-04T14:29:00+03:00",
  "embedUrl": "https://www.youtube.com/embed/zNxLmpk0lgM",
  "contentUrl": "https://www.pro-cs-is.com/2017/08/linux-file-sharing.html"
}
</script>

and this

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "VideoObject",
  "name": "how to make a backup copy of Windows without programs and restore it",
  "description": "Some descrption.",
  "thumbnailUrl": "https://i.ytimg.com/vi/C7BM3rrPg0o/maxresdefault.jpg",
  "uploadDate": "2018-01-24T04:38:00+03:00",
  "embedUrl": "https://www.youtube.com/embed/C7BM3rrPg0o",
  "contentUrl": "https://www.pro-cs-is.com/2018/01/windows-backup-restore.html"
}
</script>

I removed this code from posts and the problem is still present

Asking for an opinion on a specifc JavaScript book

I have tried several books on JavaScript programming and have been dissatisfied with them all. I would like some advice on a specific book I have found but I don’t know if it would still be relavant today with modern JavaScript.
Is the book “Secrets of the JavaScript Ninja Second Edition” still relavant? If not, what book would you suggest in its place?

Intersection Observer for two elements

I started off with a situation where I wanted to observe an element on my page, let’s call it “trigger”. It is usually always visible upon page load (above the fold).

As we scroll down, if “trigger” is no longer visible, I want to apply a CSS class to another element.

Here is my code for doing so and it works:

const trigger = document.getElementById('trigger')
const otherElement = document.getElementById('some-other-element')

const intersectionObserver = new IntersectionObserver(
    ([entry]) => {
        if (entry.intersectionRatio === 0) {
            otherElement.classList.add('special-class')
        } else if (entry.intersectionRatio === 1) {
            otherElement.classList.remove('special-class')
        }
    },
    {
        threshold: [0, 1],
    },
)

intersectionObserver.observe(trigger)

Upon testing this, I realized that users can have smaller devices in which case the bottom edge of the device is actually above where the “trigger” sits so on page load, the “trigger” is actually not visible. Therefore, my “special-class” is automatically applied which is not what I want to have happen.

I thought of a solution to this issue which would be to observe two elements: my trigger and another element like a nav bar or a header which will always be at the top of the page and only if both elements have been scrolled past do I apply my “special-class”. However, I could not figure out how to get IntersectionObserver to observe both elements and how my code would change accordingly.

How to fix Post validation failed: title: Cast to string failed – formidable (Node)

I’m making a POST request to create a blog post and I’m using formidable to upload an img for each post but I’m receiving a 400 error.

UPDATE: I’m now receiving an actual error:

Post validation failed: title: Cast to string failed for value "[ 'njk' ]" (type Array) at path "title", body: Cast to string failed for value "[ 'ugyjhvbhujb' ]" (type Array) at path "body", slug: Path `slug` is required.

console.log(formData) returns an object of strings in the frontend like:

{ title: "suyghb", body: "cguyasjbhxz"...}

but in the backend the values in fields aka formData are now arrays like:

{ body: [ 'ihubj' ], title: [ '87tugyh' ] }

why is this?

​​I tried setting

'Content-Type': 'application/json

but then I receive the error request entity too large.

posts.js (controllers)

export const create = (req, res) => {
    let form = new formidable.IncomingForm()
    form.keepExtensions = true
    form.parse(req, (err, fields, files) => {
        if (err) {
            return res.status(400).json({
                error: "Image could not be uploaded."
            })
        }
      
        let post = new Post(fields)
        if (files.photo) {
            const photoFilePath = files.photo.map((file) => {
                return file.filepath
            })
            }
            const photoStr = photoFilePath.toString()
            post.photo.data = fs.readFileSync(photoStr, 'utf-8')
            post.photo.contentType = files.photo.type
        }
        post.save()
           /• .then & .catch •/

Form Validation

const { body, validationResult } = require('express-validator');

exports.userSignupValidator = (req, res, next) => {
    validationBodyRules = [
        body('email', 'email is required').exists(),
        body('password', 'password is required').exists(),
        body('email', 'email is required').notEmpty(),
        body('password', 'password is required').notEmpty()
    ]

    checkRules = (req, res, next) => {
        const errors = validationResult(req);
        if (!errors.isEmpty()) {
            return res.status(400).json({ errors: errors.array() });
        }
        next();
    };
}

API request (client side)

export const createPost = (token, formData) => {
    console.log(formData)
    return fetch('http://localhost:8000/posts/new-post', {
        method: 'POST',
        headers: {
            Authorization: `Bearer ${token}`,
        },
        body: formData
    })
        .then(response => {
            return response.json();
        })
        .catch(err => {
            console.error(err);
        });
};

Strange behaviour of NumberInput and Select component in ChakraUI

I am facing a strange situation with ChakraUI components. I am trying to use ChakraUI’s NumberInput component and Select component.

Scenario 1:
If the NumberInput component is written before the Select component and I try to enter any value in it, I am able to enter the value but
if I try to select any value in the Select component, the error below is thrown:

TypeError: selectEl.options is not iterable
    at syncSelectElement (http://localhost:5173/node_modules/.vite/deps/@chakra-ui_react.js?v=5690b4d1:37436:39)
    at action (http://localhost:5173/node_modules/.vite/deps/@chakra-ui_react.js?v=5690b4d1:5214:29)
    at http://localhost:5173/node_modules/.vite/deps/@chakra-ui_react.js?v=5690b4d1:36885:7
    at http://localhost:5173/node_modules/.vite/deps/@chakra-ui_react.js?v=5690b4d1:5109:21
    at react-stack-bottom-frame (http://localhost:5173/node_modules/.vite/deps/react-dom_client.js?v=5690b4d1:17478:20)
    at runWithFiberInDEV (http://localhost:5173/node_modules/.vite/deps/react-dom_client.js?v=5690b4d1:1485:72)
    at commitHookEffectListMount (http://localhost:5173/node_modules/.vite/deps/@chakra-ui_react.js?v=5690b4d1:8460:122)
    at commitHookPassiveMountEffects (http://localhost:5173/node_modules/.vite/deps/@chakra-ui_react.js?v=5690b4d1:8518:60)
    at commitPassiveMountOnFiber (http://localhost:5173/node_modules/.vite/deps/@chakra-ui_react.js?v=5690b4d1:9887:29)
    at recursivelyTraversePassiveMountEffects (http://localhost:5173/node_modules/.vite/deps/@chakra-ui_react.js?v=5690b4d1:9868:13)

Scenario 2:
When the Select component is used before the NumberInput component, it works fine, but I am unable to enter any value in the NumberInput component. In this case also, no errors are thrown.

I inspected the HTML and found that both components have the same id attribute, which is most likely the source of the issue. However, I tried giving them different ids, but the id attribute is not updating and is being rendered as some ChakraUI-generated id value.

Versions:

  • ChakraUI: ^3.21.0
  • tailwindcss: ^4.1.10
  • vite: ^6.3.5
  • react: ^19.1.0

I have encountered this situation for the first time while using ChakraUI. Kindly help me in resolving the issue.

Please let me know if additional information is required.

How to delete Firestore document when a user closes the web page

I have a web application utilising React and Firestore where users can create “rooms” which when active allow users to interact with the host. There is an option to both activate and deactivate the room to disallow interaction.

I am considering what is the best way to automatically “deactivate the room” – either when the user closes the web app (either on desktop or mobile), or if the room has been inactive for a while; something around an hour.

I have researched this and found two possibilities:

  1. Firestore – TTL – it seems like this is the most reliable way, where I could set a field to have the room’s expiry an hour in the future each time it is updated. I wanted to ask if there are any costs/limits to using TTL, as it seems the only cost is that the document delete will count against your quota.
  2. To use visibilityState / unload of which they seem to have their caveats on mobile, e.g.
const onVisibilityChange = () => {
  if (document.visibilityState === 'hidden') {
    delDoc();
  }
};

useLayoutEffect(() => {
  document.addEventListener("unload", onVisibilityChange);
  return () => document.removeEventListener("unload", onVisibilityChange);
});

For desktop: I am interested to know if the user has closed the tab or navigated away from the room hosting page.
For mobile: I am interested to know if the user has closed the tab via the browser, or if the user has force closed the browser via the app switcher.

Any help would be much appreciated.

Bootstrap 5 mega menu not displaying properly on dekstop

I have been bashing my head against a brick wall all afternoon and I am stumped.

I want to create a Bootstrap 5 mega menu and I’m not using jQuery so have all the JavaScript as Vanilla JavaScript.

On mobile, everything is working as it should but on desktop, when I click on the Services menu option, the mega menu only displays to the width of the parent width so all the text is shrunk.

What am I doing wrong or missing?

Screenshot showing the expanded mega menu on desktop view

Here is my complete code

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Mega Menu with Slide-in Mobile Nav</title>
  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
  <style>
    body {
      margin: 0;
      font-family: Arial, sans-serif;
    }

    .site-menu {
      list-style: none;
      padding-left: 0;
      margin: 0;
    }

    .site-menu > li {
      display: inline-block;
      position: relative;
      margin-right: 20px;
    }

    .site-menu > li > a {
      color: white;
      text-decoration: none;
      padding: 8px 12px;
      display: inline-block;
    }

    .site-menu > li > a:hover {
      color: #ffc107;
    }

    .site-navigation {
  position: relative;
  background: #333;
  padding: 1rem;
  max-width: 1200px;   /* Set this to your navbar max width */
  margin: 0 auto;      /* center navbar */
}

.site-navigation .container-fluid {
  display: none;
  position: absolute;
  background: #fff;
  top: 100%;           /* just below navbar */
  left: 0;             /* align left edge of navbar */
  width: 100%;         /* full width of navbar */
  z-index: 999;
  padding: 20px 0;
  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  box-sizing: border-box;
  transform: none !important;  /* cancel any shifts */
}

.site-navigation li.show > .container-fluid {
  display: block;
}


    /* Mobile Menu */
    .site-mobile-menu {
      width: 300px;
      position: fixed;
      top: 0;
      right: 0;
      height: 100vh;
      background: white;
      transform: translateX(110%);
      transition: transform 0.3s ease-in-out;
      z-index: 1050;
      overflow-y: auto;
      box-shadow: -2px 0 8px rgba(0, 0, 0, 0.15);
      display: flex;
      flex-direction: column;
    }

    .site-mobile-menu.open {
      transform: translateX(0);
    }

    .site-menu-toggle {
      cursor: pointer;
      display: inline-block;
    }

    /* Mobile submenu */
    .mobile-mega-menu {
      overflow: hidden;
      max-height: 0;
      transition: max-height 0.4s ease;
    }

    .mobile-mega-menu.show {
      max-height: 800px;
    }

    .mobile-mega-content {
      padding: 1rem;
      background: #f8f9fa;
    }

    .mobile-mega-content .list-group-item {
      font-size: 0.95rem;
    }

    /* Click-blocker for closing menu */
    .menu-overlay {
      display: none;
      position: fixed;
      inset: 0;
      z-index: 1040;
      background: rgba(0, 0, 0, 0.3);
    }

    .menu-overlay.active {
      display: block;
    }

    /* Close icon styling */
    #js-menu-close {
      font-size: 2rem;
      font-weight: bold;
      line-height: 1;
      cursor: pointer;
      user-select: none;
    }

    /* Mobile menu list styling */
    .site-mobile-menu .site-menu {
      padding-left: 0;
      margin: 0;
      list-style: none;
      flex-grow: 1;
    }

    .site-mobile-menu .site-menu > li {
      border-bottom: 1px solid #ddd;
      width: 100%;
    }

    .site-mobile-menu .site-menu > li > a {
      display: block;
      padding: 12px 20px;
      color: #333;
      text-decoration: none;
      font-weight: 600;
    }

    .site-mobile-menu .site-menu > li > a:hover {
      background: #f0f0f0;
    }
  </style>
</head>
<body>

  <div class="menu-overlay" id="menuOverlay"></div>

  <div class="container">
    <nav class="site-navigation text-end" role="navigation">
      <div class="d-inline-block d-lg-none py-3">
        <a href="#" id="js-menu-toggle" class="site-menu-toggle text-white">
          <span class="icon-menu h3">☰</span>
        </a>
      </div>
      <ul class="site-menu js-clone-nav d-none d-lg-block">
        <li class="nav-item"><a class="nav-link" href="#">Home</a></li>
        <li class="nav-item" id="desktopServices">
          <a href="#" class="nav-link">Services ▾</a>
          <div class="container-fluid">
            <div class="row my-4">
              <div class="col-md-6 col-lg-4 mb-3">
                <div class="list-group list-group-flush">
                  <p class="mb-0 list-group-item text-uppercase fw-bold">Celebrations of Love</p>
                  <a href="#" class="list-group-item">Wedding & Civil Ceremonies</a>
                  <a href="#" class="list-group-item">Engagement Parties</a>
                  <a href="#" class="list-group-item">Anniversaries</a>
                </div>
              </div>
              <div class="col-md-6 col-lg-4 mb-3">
                <div class="list-group list-group-flush">
                  <p class="mb-0 list-group-item text-uppercase fw-bold">Birthday Celebrations</p>
                  <a href="#" class="list-group-item">Adult Birthday Celebrations</a>
                  <a href="#" class="list-group-item">Teen Birthday Parties</a>
                  <a href="#" class="list-group-item">Child Birthday Parties</a>
                </div>
              </div>
              <div class="col-md-6 col-lg-4 mb-3">
                <div class="list-group list-group-flush">
                  <p class="mb-0 list-group-item text-uppercase fw-bold">Special Occasions</p>
                  <a href="#" class="list-group-item">Themed Parties (e.g. Halloween)</a>
                  <a href="#" class="list-group-item">School/College Discos</a>
                  <a href="#" class="list-group-item">Proms</a>
                  <a href="#" class="list-group-item">Corporate Events</a>
                </div>
              </div>
            </div>
          </div>
        </li>
        <li class="nav-item"><a class="nav-link" href="#">Contact</a></li>
        <li class="nav-item"><a class="nav-link" href="#">Hire</a></li>
        <li class="nav-item"><a class="nav-link" href="#">Blog</a></li>
        <li class="nav-item"><a class="nav-link" href="#">About</a></li>
      </ul>
    </nav>

    <div class="site-mobile-menu" id="mobileMenu" aria-hidden="true">
      <div class="p-3 border-bottom text-end">
        <span id="js-menu-close" aria-label="Close menu" role="button" tabindex="0">&times;</span>
      </div>
      <ul class="site-menu">
        <li><a href="#">HOME</a></li>
        <li>
          <a href="#" id="mobileServicesToggle" aria-expanded="false" aria-controls="mobileMegaMenu">SERVICES ▾</a>
          <div class="mobile-mega-menu" id="mobileMegaMenu" aria-hidden="true">
            <div class="mobile-mega-content">
              <div class="list-group mb-3">
                <p class="fw-bold text-uppercase mb-0">Celebrations of Love</p>
                <a href="#" class="list-group-item">Wedding & Civil Ceremonies</a>
                <a href="#" class="list-group-item">Engagement Parties</a>
                <a href="#" class="list-group-item">Anniversaries</a>
              </div>
              <div class="list-group mb-3">
                <p class="fw-bold text-uppercase mb-0">Birthday Celebrations</p>
                <a href="#" class="list-group-item">Adult Birthday Celebrations</a>
                <a href="#" class="list-group-item">Teen Birthday Parties</a>
                <a href="#" class="list-group-item">Child Birthday Parties</a>
              </div>
              <div class="list-group">
                <p class="fw-bold text-uppercase mb-0">Special Occasions</p>
                <a href="#" class="list-group-item">Themed Parties</a>
                <a href="#" class="list-group-item">School/College Discos</a>
                <a href="#" class="list-group-item">Proms</a>
                <a href="#" class="list-group-item">Corporate Events</a>
              </div>
            </div>
          </div>
        </li>
        <li><a href="#">BLOG</a></li>
        <li><a href="#">ABOUT</a></li>
        <li><a href="#">CONTACT</a></li>
      </ul>
    </div>
  </div>
  <script>
    document.addEventListener('DOMContentLoaded', () => {
  const menuToggle = document.getElementById('js-menu-toggle');
  const mobileMenu = document.getElementById('mobileMenu');
  const menuClose = document.getElementById('js-menu-close');
  const menuOverlay = document.getElementById('menuOverlay');
  const mobileServicesToggle = document.getElementById('mobileServicesToggle');
  const mobileMegaMenu = document.getElementById('mobileMegaMenu');
  const desktopServices = document.getElementById('desktopServices');

  // Open mobile menu
  menuToggle.addEventListener('click', e => {
    e.preventDefault();
    mobileMenu.classList.add('open');
    menuOverlay.classList.add('active');
    mobileMenu.setAttribute('aria-hidden', 'false');
  });

  // Close mobile menu (close icon)
  menuClose.addEventListener('click', () => {
    closeMobileMenu();
  });

  // Close mobile menu (overlay click)
  menuOverlay.addEventListener('click', () => {
    closeMobileMenu();
  });

  // Close mobile menu helper
  function closeMobileMenu() {
    mobileMenu.classList.remove('open');
    menuOverlay.classList.remove('active');
    mobileMenu.setAttribute('aria-hidden', 'true');

    // Also close the Services submenu if open
    mobileMegaMenu.classList.remove('show');
    mobileServicesToggle.setAttribute('aria-expanded', 'false');
    mobileMegaMenu.setAttribute('aria-hidden', 'true');
  }

  // Toggle Services submenu on mobile
  mobileServicesToggle.addEventListener('click', e => {
    e.preventDefault();
    const isExpanded = mobileServicesToggle.getAttribute('aria-expanded') === 'true';
    if (isExpanded) {
      mobileMegaMenu.classList.remove('show');
      mobileServicesToggle.setAttribute('aria-expanded', 'false');
      mobileMegaMenu.setAttribute('aria-hidden', 'true');
    } else {
      mobileMegaMenu.classList.add('show');
      mobileServicesToggle.setAttribute('aria-expanded', 'true');
      mobileMegaMenu.setAttribute('aria-hidden', 'false');
    }
  });

  // Close mobile menu when clicking on any mobile link except Services toggle
  mobileMenu.querySelectorAll('a').forEach(link => {
    link.addEventListener('click', e => {
      // Don't close if clicking the Services toggle link itself
      if (link === mobileServicesToggle) return;
      closeMobileMenu();
    });
  });

  // Desktop Services menu toggle on click
const desktopServicesLink = desktopServices.querySelector('a');

desktopServicesLink.addEventListener('click', (e) => {
  e.preventDefault();
  desktopServices.classList.toggle('show');
});

// Optional: close mega menu if clicking outside
document.addEventListener('click', (e) => {
  if (!desktopServices.contains(e.target)) {
    desktopServices.classList.remove('show');
  }
});
});

  </script>
  </body>
  </html>

How to Prevent Suspense Waterfall in React 18 with Dynamic, Server-Driven Components?

I’m building a React 18.3 (TypeScript) app where components are dynamically rendered based on a server-provided JSON structure. I’m using React.Suspense and React.lazy for code-splitting to load components dynamically. Here’s a simplified example:

import React, { Suspense, lazy } from 'react';

// Server response
const serverConfig = {
  type: 'Layout',
  children: [
    { type: 'WidgetA', dataUrl: '/api/widgetA' },
    { type: 'WidgetB', dataUrl: '/api/widgetB' },
  ],
};

// Component map
const componentMap = {
  Layout: lazy(() => import('./components/Layout')),
  WidgetA: lazy(() => import('./components/WidgetA')),
  WidgetB: lazy(() => import('./components/WidgetB')),
};

const renderTree = (config) => {
  const Component = componentMap[config.type];
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Component {...config}>
        {config.children?.map(renderTree)}
      </Component>
    </Suspense>
  );
};

function App() {
  return renderTree(serverConfig);
}

Each component fetches its own data using a custom hook with fetch. My issue is that nested Suspense boundaries cause a waterfall effect, where components load sequentially, slowing down the UI. I’ve tried useTransition, but it doesn’t fully resolve the issue for dynamic trees.

How can I parallelize data fetching for all components to avoid the Suspense waterfall?
Are there best practices or libraries (e.g., React Query) for optimizing dynamic component loading with server-driven configs?

I’ve read the React docs on Suspense and Concurrent Rendering but couldn’t find guidance on dynamic, server-driven setups. Any code examples or patterns would be helpful!

Firebase cloud message gettoken not work on Edge newest version

I using firebase cloud message.
It just work perfect on Chrome but not work on Edge with same code.

Here is the code:

import {
    initializeApp
} from 'https://www.gstatic.com/firebasejs/11.10.0/firebase-app.js';
import {
    isSupported,
    getMessaging,
    getToken,
    onMessage,
    deleteToken
} from 'https://www.gstatic.com/firebasejs/11.10.0/firebase-messaging.js';
const firebaseConfig = {
    apiKey: 'apiKey',
    authDomain: 'authDomain',
    projectId: 'projectId',
    storageBucket: 'storageBucket',
    messagingSenderId: 'messagingSenderId',
    appId: 'appId'
};
const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);
var registration = null;
navigator.serviceWorker.register('/mydomain/service-worker-sw.js').then((reg) => {
    registration = reg;
    console.log('Service Worker registered with scope:', reg.scope);
    return navigator.serviceWorker.ready;
}).then((registration) => {
    if (registration.active) {
        registration.active.postMessage({
            type: 'SET_GLOBAL_VARIABLE',
            value: firebaseConfig
        });
    } else if (navigator.serviceWorker.controller) {
        navigator.serviceWorker.controller.postMessage({
            type: 'SET_GLOBAL_VARIABLE',
            value: firebaseConfig
        });
    }
    return getToken(messaging, {
        vapidKey: 'vapidKey',
        serviceWorkerRegistration: registration
    });
}).then((currentToken) => {
    if (currentToken) {
        console.log('Token - ' + currentToken);
        myFireBaseToken = currentToken;
    } else {
        console.log('No registration token available. Request permission to generate one.');
        requestPermission();
    }
}).catch((err) => {
    console.log('An error occurred while retrieving token. ', err);
});
onMessage(messaging, (payload) => {
    myFireBase = JSON.stringify(payload);
});

function requestPermission() {
    console.log('Requesting permission...');
    Notification.requestPermission().then((permission) => {
        if (permission === 'granted') {
            console.log('Notification permission granted.');
        }
    });
}

Error message:

An error occurred while retrieving token. AbortError: Registration failed – push service error

  • Browser: Edge version 138.0.3351.95
  • Windows 10: 22H2

How can I solve this issue on Edge?

How do i bundle a full stack Next js app with API routes in an electron JS?

for several days I’ve been trying to use my full stack next js app with app route, API route and typescript and bundle it in an Electron JS app. but all my attempts have failed, some only work as dev but not in production. so Here i wanna give you my next js tree and some basic code.

next-app/
├── src/
│   ├── app/
│   │   ├── api/
│   │   │   └── hello/route.ts      # Simple API route (GET)
│   │   ├── layout.tsx              # Root layout (mandatory)
│   │   └── page.tsx                # Home page
│   ├── styles/
│   │   └── globals.css             # Optional global styles
│   └── lib/                        # (Optional) helper functions, utils
├── public/                         # Static files (images, etc.)
├── next.config.js                  # Next.js config
├── tsconfig.json                   # TypeScript config
├── package.json                    # Scripts and dependencies
├── .gitignore
└── README.md

so the page.ts

"use client";

import { useEffect, useState } from "react";

export default function HomePage() {
  const [data, setData] = useState<any>(null);

  useEffect(() => {
    fetch("/api/hello")
      .then((res) => res.json())
      .then(setData)
      .catch(console.error);
  }, []);

  return (
    <main style={{ padding: 40 }}>
      <h1>Welcome to Electron + Next.js</h1>
      <p>This is a fullstack app running inside Electron.</p>

      <h2>API response:</h2>
      {data ? <pre>{JSON.stringify(data, null, 2)}</pre> : <p>Loading...</p>}
    </main>
  );
}

and the route.ts

import { NextResponse } from 'next/server';

export function GET() {
  return NextResponse.json({
    message: 'Hello from API route!',
    time: new Date().toISOString(),
  });
}

so this is a simple next js app. Now Please help me integrate electron to it. I would want to build an installable from it and be able to install on my computer and the full app to work. if you include the steps of what to install and configure it would be amazing.

Is moving inline JavaScript to an external file a valid way to avoid using nonces in CSP for a static site?

I’m building a static site (using Vite + React, hosted on Netlify) and I want to set a strict Content Security Policy (CSP) without using unsafe-inline or nonces.

Since my site is static, managing nonces dynamically via backend is not ideal.

Question:
If I move all my inline JavaScript into external .js files, can I completely avoid using CSP nonces?
In other words, is the following approach valid and secure for modern browsers?

Set CSP to:

Content-Security-Policy: default-src ‘self’; script-src ‘self’; object-src ‘none’; base-uri ‘self’;

Load all scripts only via <script src="..."></script> (no inline JavaScript in HTML).

Optionally add Subresource Integrity (integrity) attributes for extra protection.

Does this fully eliminate the need for nonces, or is there something I’m missing?
Any security implications or browser compatibility issues?

Thanks in advance!

I removed all inline JavaScript from my index.html file and moved it into external .js files.

I then updated my CSP header to only allow script-src ‘self’ without ‘unsafe-inline’ or nonces, expecting everything to work securely.

However, I want to confirm if this setup is valid and secure according to CSP best practices, especially on static sites where managing nonces dynamically is not possible.

Pyppeteer returns None or empty content when scraping Digikala product page

I’m trying to scrape a product page from Digikala using Pyppeteer because the site is heavily JavaScript-rendered.

Here is my render class:

import asyncio
from pyppeteer import launch
from pyppeteer.errors import TimeoutError

class JsRender:
    def __init__(self, chromium_path):
        self.chromium_path = chromium_path

    async def fetch_content(self, url, headers=None):
        try:
            browser = await launch(executablePath=self.chromium_path, headless=True)
            page = await browser.newPage()

            if headers:
                await page.setExtraHTTPHeaders(headers)

            await page.goto(url, {'waitUntil': 'networkidle2', 'timeout': 60000})
            await asyncio.sleep(2)  # Added sleep just in case
            content = await page.content()
            await browser.close()
            return content
        except TimeoutError:
            print(f'Timeout while loading {url}')
            return None

    def get_page_content(self, url, headers=None):
        return asyncio.get_event_loop().run_until_complete(self.fetch_content(url, headers))

And here’s how I call it:

from browser_configure import JsRender
from bs4 import BeautifulSoup
from utility import covert_price

browser = JsRender(r'C:UserssamaAppDataLocalChromiumApplicationchrome.exe')

url = 'https://www.digikala.com/product/dkp-17986495/%DA%AF%D9%88%D8%B4%DB%8C-%D9%85%D9%88%D8%A8%D8%A7%DB%8C%D9%84-%D8%A7%D9%BE%D9%84-%D9%85%D8%AF%D9%84-iphone-16-ch-%D8%AF%D9%88-%D8%B3%DB%8C%D9%85-%DA%A9%D8%A7%D8%B1%D8%AA-%D8%B8%D8%B1%D9%81%DB%8C%D8%AA-128-%DA%AF%DB%8C%DA%AF%D8%A7%D8%A8%D8%A7%DB%8C%D8%AA-%D9%88-%D8%B1%D9%85-8-%DA%AF%DB%8C%DA%AF%D8%A7%D8%A8%D8%A7%DB%8C%D8%AA/'
content = browser.get_page_content(url)

soup = BeautifulSoup(content,'html.parser')

#-------------------------------------------------------------
tilel = soup.select_one('h1.text-h5-180').text
star = soup.select_one('p.text-body1-strong')
star = float(star.text) if star else 0
price = soup.select_one('div.w-full.flex.gap-1.item-center').text
price = covert_price(price)
colors = soup.select('span.text-body-1-180.whitespace-nowrap.text-neutral-650')
colors = [color.text for color in colors if color ]
#-------------------------------------------------------------

detail = soup.select_one('table.border-collapse')
print(detail)

No matter what I try, content is always None.

I’ve tried:

Adding await asyncio.sleep(2)

Using waitUntil: ‘networkidle2’

Making sure Chromium path is valid

Changing selectors

Still, page.content() returns nothing or fails.

The Digikala page works in the browser, but not with Pyppeteer.

How can I properly render and scrape content from Digikala with Pyppeteer?

I tried several approaches to make sure the page content is fully loaded before extracting it:

Added await asyncio.sleep(2) after page.goto to wait extra time for rendering.

Used waitUntil: ‘networkidle2’ in page.goto to wait until network activity calms down.

Tried await page.waitForSelector(‘div#ProductTopFeatures’) to wait for a specific element on the page.

Verified the Chromium executable path is correct.

Checked if the URL is accessible and not blocked.

Used BeautifulSoup to parse the returned HTML content.

I expected to get the full HTML content of the product page with all dynamic elements rendered, so I could scrape the product details successfully.
But instead, the content is always None or empty.