CesiumGS / cesium

An open-source JavaScript library for world-class 3D globes and maps :earth_americas:
https://cesium.com/cesiumjs/
Apache License 2.0
12.73k stars 3.45k forks source link

Next.js & webpack: first entity rendering slow #12068

Open Fedec96 opened 2 months ago

Fedec96 commented 2 months ago

What happened?

My Next.js application correctly loads and renders Cesium, but when I draw an entity for the first time, a bunch of JS files are downloaded, and the time it takes to download them results in a delay in rendering. After that, the rendering is faster.

Here's what I see in my network tab when I draw a rectangle for the first time:

network

Is there a way to load these files right away with the application to avoid these kinds of delays?

Here's my next.config.mjs file:

import path from "path";
import CopyPlugin from "copy-webpack-plugin";

/** @param {string} subpath */
const makePath = (subpath) => path.join(process.cwd(), subpath);

/** @type {import("next").NextConfig} */
const nextConfig = {
  webpack: (config, { webpack }) => {
    config.plugins.push(
      new CopyPlugin({
        patterns: [
          {
            from: makePath("node_modules/cesium/Build/Cesium/Workers"),
            to: "../public/cesium/Workers",
            info: { minimized: true },
          },
        ],
      }),

      new CopyPlugin({
        patterns: [
          {
            from: makePath("node_modules/cesium/Build/Cesium/ThirdParty"),
            to: "../public/cesium/ThirdParty",
            info: { minimized: true },
          },
        ],
      }),

      new CopyPlugin({
        patterns: [
          {
            from: makePath("node_modules/cesium/Build/Cesium/Assets"),
            to: "../public/cesium/Assets",
            info: { minimized: true },
          },
        ],
      }),

      new CopyPlugin({
        patterns: [
          {
            from: makePath("node_modules/cesium/Build/Cesium/Widgets"),
            to: "../public/cesium/Widgets",
            info: { minimized: true },
          },
        ],
      }),

      new webpack.DefinePlugin({ CESIUM_BASE_URL: JSON.stringify("/cesium") })
    );

    return config;
  },
};

export default nextConfig;

I wonder if this is by design or I am missing something on the configuration part. Thanks in advance!

Reproduction steps

No response

Sandcastle example

No response

Environment

Browser: Microsoft Edge 126.0.2592.87 (64 bit) CesiumJS Version: 1.119.0 Operating System: Microsoft Windows 11 23H2 22631.3810 (64 bit)

jjspace commented 2 months ago

Hey @Fedec96, this looks like the expected behavior for right now. The files you're seeing loaded in the network tab are required for the web workers to render geometry which aren't needed until there's actually a rectangle required to render.

Just as a sanity check can you make sure this happens in a project that's not using Next.js? I think the problem will be the same if you're using the es6 imports regardless but good to confirm if it's related to next or a standard issue.

The iife that's provided in the build directories has the workers inline but using that is less preferred if you're in a project with a build step like webpack that can tree-shake. (See #10619)

If this is a more general issue about speeding up the Workers and load time that's a larger topic we would have to discuss more in depth. I think it could make sense to have some sort of "pre-load" option but I don't know what form that would take or how easy it would be to implement in the current systems.

Fedec96 commented 2 months ago

Thank you @jjspace for the in-depth response! The behavior is indeed the same for a non-Next.js application (i.e. React only). At this point I wonder why don't I see this happening on the sandcastle? What's different in there?

jjspace commented 2 months ago

Thanks for confirming this isn't just a next issue @Fedec96

At this point I wonder why don't I see this happening on the sandcastle?

Sandcastle loads Cesium with the single file, iife function version of the build that's oriented more to be included in static pages and projects that aren't built using es6 and module imports. As I mentioned in my last comment the iife includes all the workers code inline with the rest of the cesium library so it loads the whole thing at once and doesn't request all the worker files later when they're actually used.

Right now we don't have a way to preload the worker files themselves which is why this would be a slightly larger change to tackle.

Fedec96 commented 2 months ago

Right, thanks again @jjspace. I think this is what c137.js (formerly webpack-cesium) was designed for -- unfortunately the author removed it from everywhere. But having an all-in-one option would be great.