Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: legacy avoid insert the entry module css #9761

Merged
merged 2 commits into from Aug 19, 2022

Conversation

poyoho
Copy link
Member

@poyoho poyoho commented Aug 19, 2022

Description

simple build will collect all entry module css into chunk.viteMetadata.importedCss and inject into the index.html same with legacy.

legacy build should avoid insert the entry module css again

the test would same with #9507.

Sync chunk no generate the css but also had the style.
Async chunk should generate the css and had the style.

Additional context


What is the purpose of this pull request?

  • Bug fix
  • New Feature
  • Documentation update
  • Other

Before submitting the PR, please make sure you do the following

  • Read the Contributing Guidelines.
  • Read the Pull Request Guidelines and follow the Commit Convention.
  • Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
  • Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123).
  • Ideally, include relevant tests that fail without this PR but pass with it.

patak-dev
patak-dev previously approved these changes Aug 19, 2022
Comment on lines +560 to +567
// legacy build and inline css

// the legacy build should avoid inserting entry CSS modules here, they
// will be collected into `chunk.viteMetadata.importedCss` and injected
// later by the `'vite:build-html'` plugin into the `index.html`
if (chunk.isEntry) {
return null
}
Copy link
Member

Choose a reason for hiding this comment

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

I haven't quite caught up with the recent legacy changes, but are we now moving legacy-specific code into core? (just curious 😬)

Copy link
Member

Choose a reason for hiding this comment

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

This branch has always been in the css plugin. It would be great to move it plugin-legacy but there are some details where we are cheating from the inception of the plugin.

Copy link
Member Author

Choose a reason for hiding this comment

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

maybe no. The previous PR #9507 fix the legacy build css (this if branch) no replace the asset flag(__VITE_ASSET) because the css-post later than asset. This PR optimized legacy build css generate logic, and this if branch will trigger by legcy build. 😊

@patak-dev patak-dev merged commit 0765ab8 into vitejs:main Aug 19, 2022
@poyoho poyoho deleted the perf/legacy-css branch August 19, 2022 15:38
@Tal500
Copy link
Contributor

Tal500 commented Sep 24, 2022

@patak-dev @sapphi-red, can you please explain me how after this logic, the JS navigation between entry pages, say in Nuxt.js, should work under Vite on legacy mode?

This PR should have canceled the ability to emulate in JS the navigation between one entry page to the other. In modern, the navigation performs preloading that loads the CSS, but in legacy, no preloading will happen.

Indeed, when I worked on SvelteKit legacy support as I mentioned in #9902, the CSS where not inlined because of this PR that were merged.

This was the main motivation for me to work on PR #9920, that clearly (relatively simply) solves all the compatibility issues, by preloading CSS both on modern and legacy.

@sapphi-red
Copy link
Member

IIUC this PR is fixing #2062 (comment) by removing the inlined one.
So I guess preload for CSS in entry chunk won't work after this PR.

@Tal500
Copy link
Contributor

Tal500 commented Sep 25, 2022

IIUC this PR is fixing #2062 (comment) by removing the inlined one. So I guess preload for CSS in entry chunk won't work after this PR.

So am I right in my observation that this PR breaks some good behavior, and now the CSS loading on navigation for entry files is breaking on legacy, not only on SvelteKit(on legacy, by my external proposal on SvelteKit)?

@poyoho
Copy link
Member Author

poyoho commented Sep 25, 2022

do you mean some preload link <link rel="modulepreload" href="..."> can worker on legacy mode and the legacy js also no load the css?

@Tal500
Copy link
Contributor

Tal500 commented Sep 25, 2022

do you mean some preload link <link rel="modulepreload" href="..."> can worker on legacy mode and the legacy js also no load the css?

No. What I mean is this:
This PR remove CSS inlining on legacy, for all the chunks that is considered to be entry points.

If you serve static SSR, and the navigation between pages isn't handled by JS(such in Next.js, Nuxt and SvelteKit), nothing is wrong in this because the CSS files were already loaded on initial SSR in the <link> tag(also on legacy).

For example, if you're using Nuxt and you on page "/"(homepage), and the user navigates to the "/about" page, the page wouldn't be loaded again by SSR, rather the navigation will be dynamic by JS code.
If you're on modern, than on Vite preload, the CSS files needed for the "/about" page will be injected dynamically in link tags to the head.
However, if you're on legacy, than the styles should be injected via inline styling while dynamically navigating to the "/about" page, but because of this PR no inline styling will be on legacy, since the chunk correlated to the "/about" page is considered to be an entry chunk.

@poyoho
Copy link
Member Author

poyoho commented Sep 26, 2022

and the user navigates to the "/about" page, the page wouldn't be loaded again by SSR rather the navigation will be dynamic by JS code.

It mean the navigation by client js don't deps on SSR again. But I don't know why the /about page will considered to be an entry chunk.

I guess the /about page will bunlded by SSG. so all the page will be an entry point, and the / -> /about, client also use the SSG output js chunk(as entry point bundled and no preload css). So /about mistakenly considered as main entry.

IIUC, your PR #9920 maybe can resolve this, make the css as chunk and dynamic load is also can reduce the legacy mode size. 👍

@sapphi-red
Copy link
Member

My this comment (#9761 (comment)) was talking about <link rel="preload" href="...">.

However, if you're on legacy, than the styles should be injected via inline styling while dynamically navigating to the "/about" page, but because of this PR no inline styling will be on legacy, since the chunk correlated to the "/about" page is considered to be an entry chunk.

If build.rollupOptions.input is ['index.html', 'about.html'], the chunk loaded by about.html will be an entry chunk. But when you are using client-side routing, I guess build.rollupOptions.input is ['index.html'] and will be code-splitted at dynamic import. In that case, the first chunk loaded by html is an entry chunk, but other's won't be an entry chunk (e.g. chunk that loaded depending on path).

@poyoho
Copy link
Member Author

poyoho commented Sep 26, 2022

yes, It may be two case to replay.

  1. such as in Next.js, Nuxt and SvelteKit downstream, they need to SSG for each page.
  2. build.rollupOptions.input is ['index.html', 'about.html']

@Tal500
Copy link
Contributor

Tal500 commented Sep 27, 2022

If build.rollupOptions.input is ['index.html', 'about.html'], the chunk loaded by about.html will be an entry chunk. But when you are using client-side routing, I guess build.rollupOptions.input is ['index.html'] and will be code-splitted at dynamic import. In that case, the first chunk loaded by html is an entry chunk, but other's won't be an entry chunk (e.g. chunk that loaded depending on path).

But now what will happen on legacy mode when the user first load the "/about" page(which is serve by SSR with the CSS content in <link> tag), and then decide to navigate to the homepage ("/")? My point is that you can't predict, nor should you, which page will be loaded first, and therefore you treat all of the site pages by default as SSR-abled(here it means as entries).

This is a consensus in all the SSR/SSG methodology, to treat every page (by default) as entry.

@sapphi-red
Copy link
Member

sapphi-red commented Sep 28, 2022

If it works like that, I guess it's a server-side routing. Or it has a custom handing that isn't handled by Vite.

@Tal500
Copy link
Contributor

Tal500 commented Sep 28, 2022

If it works like that, I guess it's a server-side routing. Or it has a custom handing that isn't handled by Vite.

Are you suggesting that Vite shouldn't care at all (even not even via some configuration varaible?) a client side routing between two entry points? It just seems a crucial part of Vite preloading.

Can someone test the scenario I described earlier in Vue&Nuxt when the mode is legacy? It might have the same critical bug there I were facing with SvelteKit legacy. I just don't Vue enough to do so by myself.

If we don't want to merge #9920 (hope it will be merged finally though), here is an alternative solution that reduces the double loading of entry points CSS(i.e. loading both ".css" and the inlined CSS in JS) for legacy mode:
If the file isn't entry, perform the same as today, just inline the CSS in the JS code. If the file is entry, then have two JS files:

  1. A JS file that contain the original page JS code.
  2. A JS file containing a function that returns a string of the inlined CSS.

On initial page load, i.e. SSR, just serve 1, like happens today.
On Vite preloading function, on legacy mode, load additionally the corresponding JS files of 2, if the file is entry (i.e. the additional JS files of 2 should be passed in the parameter).

@sapphi-red
Copy link
Member

Are you suggesting that Vite shouldn't care at all (even not even via some configuration varaible?) a client side routing between two entry points? It just seems a crucial part of Vite preloading.

No, I'm not suggesting that. I'm just saying that I guess that behavior is not handled by Vite.
AFAIK Vite injects entry chunk references to HTML and entry chunks won't be loaded from non-entry chunks.

For a client side routing app that is chunk splitted at dynamic imports, Vite will preload CSS before loading that chunk.
But IIUC what you are saying is not this case, because splitted chunks won't be an entry chunk.

@Tal500
Copy link
Contributor

Tal500 commented Sep 28, 2022

For a client side routing app that is chunk splitted at dynamic imports, Vite will preload CSS before loading that chunk. But IIUC what you are saying is not this case, because splitted chunks won't be an entry chunk.

What happen today is that preloading CSS, together with preloading the JS in general, isn't happaning at all on legacy mode (and PR #9920 changes this behaviour).
This is why on modern mode, everything works great no matter if the CSS is part of entry or not. However, on legacy mode, since there is no preloading, rather just inlined CSS in JS (and this will be empty for entry points), the case is different here.

TD'LR: In modern mode everything just works, in legacy mode not everything works. This seems to be a wrong behavior overall as far as I understand.

@Tal500
Copy link
Contributor

Tal500 commented Sep 29, 2022

I formed a suitable issue for out latest discussion in #10285. The continuation of this conversation can be moved there.

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.

None yet

5 participants