QwikDev / qwik

Instant-loading web apps, without effort
https://qwik.dev
MIT License
20.64k stars 1.28k forks source link

[🐞] SSG works even without intending so #5912

Open hosseinitabar opened 6 months ago

hosseinitabar commented 6 months ago

Which component is affected?

Qwik Rollup / Vite plugin

Describe the bug

I don't want SSG at all. I have not configured it. I do not have ssg in my codebase anywhere. Yet when I run npm run build or npm run build.server I see this green message:

Starting Qwik City SSG...

And it breaks my build at CI/CD, because it wants to connect to many API URLs and they might have problems.

The culprit is this that does not have an if statement to check for SSG.

Why do you force SSG upon the community?

Reproduction

No need for MRE

Steps to reproduce

No response

System Info

System:
    OS: Linux 6.5 Debian GNU/Linux 12 (bookworm) 12 (bookworm)
    CPU: (12) x64 Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz
    Memory: 24.58 GB / 31.12 GB
    Container: Yes
    Shell: 5.2.15 - /bin/bash
  Binaries:
    Node: 20.11.1 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 10.4.0 - /usr/local/bin/npm
  Browsers:
    Chromium: 122.0.6261.57
  npmPackages:
    @builder.io/partytown: ^0.9.2 => 0.9.2 
    @builder.io/qwik: ^1.4.5 => 1.4.5 
    @builder.io/qwik-auth: ^0.1.3 => 0.1.3 
    @builder.io/qwik-city: ^1.4.5 => 1.4.5 
    undici: ^6.6.2 => 6.6.2 
    vite: ^5.1.4 => 5.1.4

Additional Information

No response

hosseinitabar commented 6 months ago

I found out that the existence of a custom 404.tsx file in the src/routes/404.tsx causes the SSG to run automatically. If I remove that file, then the SSG won't run and I won't encounter errors. This is very bad. Why do you automatically assume that somebody who has added custom 404 wants SSG?

hosseinitabar commented 6 months ago

I realized that in your docs it's said:

It's worth noting that custom 404 pages are statically generated at build time, resulting in a static 404.html file, rather than individually server-side rendered pages. This strategy reduces the load on your HTTP server, avoiding server-side rendering of 404 pages, and thus preserving resources.

My 404.tsx page is a static page. Why do you run a lot of other parts of my codebase to turn this into a static page? Many of my routeLoaders are run, and they cause my build to break. This is my 404.tsx page:

const NotFound = () => {
    return <div
        dir="ltr"
        class="flex h-[75vh] items-center justify-center p-5 bg-white w-full"
    >
        <div class="text-center">
            <div class="inline-flex rounded-full bg-yellow-100 p-4">
                <div class="rounded-full stroke-yellow-600 bg-yellow-200 p-4">
                    <svg class="w-16 h-16" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M14.0002 9.33337V14M14.0002 18.6667H14.0118M25.6668 14C25.6668 20.4434 20.4435 25.6667 14.0002 25.6667C7.55684 25.6667 2.3335 20.4434 2.3335 14C2.3335 7.55672 7.55684 2.33337 14.0002 2.33337C20.4435 2.33337 25.6668 7.55672 25.6668 14Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg>
                </div>
            </div>
            <h1 class="mt-5 text-[30px] font-bold text-slate-800 lg:text-[50px]">404 - Page not found</h1>
            <p class="text-slate-600 mt-5 lg:text-lg">The page you are looking for does not exist or <br />has been removed.</p>
        </div>
    </div>
}

export default NotFound
wmertens commented 6 months ago

Qwik's philosophy is to make things easy for the dev and to provide great defaults.

Defaulting to SSG for the static 404 helps the server a little bit at runtime.

You're in a bit of a special case because your app doesn't work in the build enviroment. You can disable ssg by setting ssg: null.

It loads all the routes to render the 404 because it initializes all layouts. The server doesn't load routes on-demand so they are ready by the time a request comes in.

If your layouts don't have side effects, they shouldn't call APIs at startup.

octet-stream commented 6 months ago

You can disable ssg by setting ssg: null.

When ssg is disabled, custom 404 page does show up only under /404.html route, even in production. Why?

wmertens commented 6 months ago

Ah - so without SSG, custom 404 handlers don't work?

I'm going to call this "works as intended" and would be happy to guide you to make a PR that changes this.

octet-stream commented 6 months ago

Just try this reproduction repo: https://github.com/octet-stream/qwik-ssg-custom-not-found-page-issue

  1. Clone this repository
  2. Install dependencies via bun i
  3. Build the project bun run build
  4. Start the app bun run serve
  5. Open http://localhost:3000/404 and you'll see the default Qwik route error
  6. Navigate to http://localhost:3000/404.html and you'll see custom 404 error page, just like in developmen
  7. Stop the app
  8. Comment out the 18th line in adapters/bun/vite.config.ts
  9. Build project again
  10. Start the app again and repeat steps 5 and 6. You'll see that 404 page is served for any unmatched route, as expected
octet-stream commented 6 months ago

I'm going to call this "works as intended" and would be happy to guide you to make a PR that changes this.

I don't think this is how custom 404 should work. At least other frameworks would serve custom error page as you expect, under any route. Again, I am talking about production, I've read the documentation before bringing this up to your attention and I know this is intended behaviour during the development.

octet-stream commented 6 months ago

@hosseinitabar in your case you can place your routes under named group like on my screenshot, this will help because it won't run the code within this group, but I doubt it won't break if you have another custom 404 page somewhere deep at your router.

Like this:

image

It will still run SSG to generate static 404 page, but the code inside (main) won't run.

Still, it would be great to be able to serve custom 404 for unmatched routes with disabled SSG.

octet-stream commented 6 months ago

I think I figured how it works: When you build your project for production, Qwik generates @qwik-city-not-found-paths.js file with an array of [path: string, html: string] tuples (this code generates the module). Normally when the html string contains the whole html code of a custom 404 page that matches the path, when both router and staticFile fuction return null, but when ssg option is set to null, the html contains the code of the default 404 page, and also /404.html address is served by the router.