Skip to content

Lazy Loading Component Based CSS#1095

Open
Gnyblast wants to merge 3 commits intomaxence-charriere:masterfrom
Gnyblast:master
Open

Lazy Loading Component Based CSS#1095
Gnyblast wants to merge 3 commits intomaxence-charriere:masterfrom
Gnyblast:master

Conversation

@Gnyblast
Copy link

@Gnyblast Gnyblast commented Nov 1, 2025

I was looking for a way to lazy load/unload component based CSS on navigation.
This is an important and good future for various reasons:

  • Most of the modern UI frameworks support components base styling
  • It reduces the chance of style conflict, having everything in a single file vs partial
  • It gives your better initial load performance
  • It makes code readability better because instead of having 1 gigantic CSS file, you can create a small dedicated CSS files for each of your components

I made it work on client-side and server-side initial rendering too and tested on my local.

  • Basically for http.go it goes over the Composer type of components deep down and checks if it has dedicated style file set, then on the initial creation of head tag, it adds them there (only once)
  • For Client-Side, OnMountComponent and OnDismountComponent (because only Composer type can have dedicated CSS) checks if dedicated CSS file is set and then adds it to head. Also there's a small implementation that waits css to be loaded to mount the component, otherwise it's again quite bad user experience happens, like component mount and css then applied to bare HTML. Also it removes them when you are navigating to another page which does not have anything to do with that CSS.

Quick example:

type MatInput struct {
	app.Compo
	hint       string
	input_type string
	label      string
}

func NewMatInput(hint string, input_type string, label string) *MatInput {
	m := &MatInput{
		hint:       hint,
		input_type: input_type,
		label:      label,
	}
	m.SetLazyCSSPath("/web/test.css")
	return m
}
func (m *MatInput) Render() app.UI {
	return app.Label().Class("mdc-text-field mdc-text-field--filled").Body(
		app.Span().Class("mdc-text-field__ripple"),
		app.Span().Class("mdc-floating-label").Text(m.hint).ID(m.label),
		app.Input().Class("mdc-text-field__input").Type(m.input_type).Aria("labelby", m.label),
		app.Span().Class("mdc-line-rippl"),
	)
}

So this is a bit forcing you to have constructor which I don't think it's bad, so that you can set your path for css dedicated to that components.

I believe same can be done for JS but I'm not sure about it since the users of this framework tries to avoid JS on their project. Regardless usage of such external libraries that are component based (such as material library) might require you to inject JS to your component with some lazy strategy.

I might for sure missed something or some of my implementation might be handled better because I'm not very familiar with code base, I'm open to suggestions.

Guney Saramali added 2 commits November 1, 2025 13:51
- Created 2 new method for Composer so that LazyCSS file can be set and get
- Created implementation for initial load done by server-side to load the component CSS into the head because when applied later it creates a bad UI experience like components are bareand then being styled after page load which is quite bad
- Created client-side wasm implementation for Mount and Dismount so that components CSS on navigation can get lazy loaded or unloaded on exit
- I reduced down the work to a single iteration for checking If LazyCSS exists while going over childrens
@Gnyblast
Copy link
Author

Gnyblast commented Nov 1, 2025

I also want to propose some improvements for your feature versions:

image

If you looks at above image, some conventional structural design implementation would make things far more easier for people coming from modern web frameworks and also would make things thightly stick on each other.

2 new directories:

  1. Components: These are, you can call them widgets maybe, small reusable dynamic elements that are imported to the main pages of the app
  2. Views: These are actual pages that you pass them into you app.Route() wrapped with a Compose which we can say that, they are actual root body of the app.

it would be making much sense if components are created under package components and pages are under package views. Then default serveHTTP of the http.go could be configured to serve any css file under subsequent packages of these two packages like it does for web and then my above implementation would be made to handle lazy-loading the component and page specific css into the app.

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.

1 participant