return to table of content

Show HN: Jampack – Optimizes static websites as a post-processing step

chambored
10 replies
1d1h

This is exactly what I've been looking for. I had been using my own scripts with Sharp for image optimizations like this, but this eliminates the need for the that entirely and works much better!

I ran Jampack after building my Quarto static site and got a 32% smaller folder with no noticeable drawbacks yet. Here are my metrics before Jampack and after using PageSpeed Insights:

before Jampack:

- mobile: - 52 Performance - 73 Accessibility - 100 Best Practices - 85 SEO

- desktop: - 90 Performance - 75 Accessibility - 100 Best Practices - 82 SEO

after Jampack:

- mobile: - 49 Performance - 80 Accessibility - 100 Best Practices - 92 SEO

- desktop: - 85 Performance - 82 Accessibility - 100 Best Practices - 91 SEO

georges_gomes
7 replies
1d1h

Hi! Happy you enjoyed it! I would have expected better results for Performance metrics! If you don't mind sharing your static site output pre-jampack I would enjoy checking out. georges [at] divriots [dot] com

samstave
5 replies
1d

Just want to say this two comment interaction is a perfect distilled example of value of posting to HN for such things.

nolok
4 replies
23h45m

I would say it's exactly why I miss the network of forums of old internet, where this interaction was common on pretty much any subject matter from video game saves to tooling to whatever.

Facebook groups, discord rooms, reddit subs and the likes just aren't the same, they all feel so impersonal and detached, in some people compete for internet points, in others everything is ephemeral and closed off ... Maybe it's just nostalgia / me being old.

samstave
2 replies
23h32m

Sam's Law:

"As an idea or subject gains wider popularity and interest, the level of passion and laser focus on the _outcomes_ of the idea or subject gets diluted to the average level of understanding of the interested audience for the core subject"

(my weak attempt at describing this issue)

rrr_oh_man
1 replies
22h8m

The Peter Principle of communities: They grow until they become useless.

samstave
0 replies
21h38m

Petering out, as it were :-)

joemi
0 replies
23h19m

Facebook groups, discord rooms, reddit subs and the likes just aren't the same

I think it depends on which ones you're using. There are some facebook groups and subreddits I use that still feel very much like a small-forum, where people are generally good and helpful and many of the users are regulars. I haven't seen any discord rooms like that except for some ones that are direct spinoffs of the facebook groups and subreddits I mentioned, so that seems more like a credit to the users than the medium.

I think they have to be pretty niche, though. But to be fair, forums of the old internet also had similar issues where once they reached a certain size the experience was different/worse than when they were smaller.

chambored
0 replies
1d

I've zipped it up and sent a link.

lelandfe
1 replies
1d

Remember that Lighthouse (and therefore PageSpeed Insights) scores fluctuate. Consider running multiple times and taking median scores when doing comparisons of performance like this. "The median Lighthouse score of 5 runs is twice as stable as 1 run" https://developers.google.com/web/tools/lighthouse/variabili...

chambored
0 replies
22h40m

That's a fair point. There were certainly small discrepancies when I ran it multiple times, but I'll use the median metric moving forward.

microflash
5 replies
1d3h

Would love to see a way to subset fonts based on unicode range of SSG output and freeze opentype axes based on font-feature-settings defined in the CSS.

georges_gomes
2 replies
1d3h

Yes, lots of cool things to do around fonts! I have in TODO to add automatic system font fallback with the right metrics in order to improve CLS automatically. Is it what you call "freeze opentype axes based on font-feature-settings" or is it something else?

I would like to do the subset font optimization. I'm just not sure how much of an improvement it's going to be. Have you done it manually before?

microflash
1 replies
1d2h

Is it what you call "freeze opentype axes based on font-feature-settings" or is it something else?

I was talking in context of variable fonts which come with lots of features mapped to opentype tags and axes. font-feature-settings property selects (or activates) those features. Usually this is done at few CSS selector levels. The variable fonts can be trimmed by freezing those features. I did something like this with Fira Code a few years ago. [1]

I would like to do the subset font optimization. I'm just not sure how much of an improvement it's going to be. Have you done it manually before?

It can be quite an improvement for fonts like Inter which ship with massive number of glyphs to support different languages.[2] Doing this manually is a huge pain. Zach Leatherman created a tool called Glyphhanger to automate some of the usecases [3]

[1]: https://github.com/naiyerasif/FiraSourceMono

[2]: https://paulcalvano.com/2024-02-16-identifying-font-subsetti...

[3]: https://github.com/zachleat/glyphhanger

georges_gomes
0 replies
1d1h

Thanks for all the links! It's definitely bumping my excitement towards subset fonts!

account42
1 replies
4h5m

Why bother when you can optimize your font size to 0 by using browser/system fonts.

lobsterthief
0 replies
41m

Because sometimes custom fonts are a design/product requirement. Using a system font stack is not a solution for everyone.

KingOfCoders
5 replies
1d1h

After trying this (JS always amazing, 47 vulnerabilities (19 moderate, 24 high, 4 critical)), my web vitals went down from 84 to 77.

So not sure about that one.

Also some svg images went missing.

georges_gomes
3 replies
1d1h

Needs a little bit of updates :) will do. If you can share your static website on GitHub repo or something I would love to have a look. georges [at] divriots [dot] com

KingOfCoders
2 replies
1d1h

Rolled back, https://www.amazingcto.com/

There where many errors, I'll try again later and send you the vitals + errors.

[Edit] Generally I would love this.

mousetree
1 replies
1d

Heads up, you've got an h3 tag now on your website that says "Articlesnpm install -D @divriots/jampack from Stephan".

KingOfCoders
0 replies
1d

Lol, thank you. Fixed.

KingOfCoders
0 replies
12h0m

[Update] Played with the settings (it seems to problems with above the fold loading of external images (svgs)), I'm now at 93, bravo! (Also there were problems with svg fonts, I removed them)

[Edit] A little bit more tuning, 93/92/100/100

rkagerer
4 replies
1d

This looks great! Although personally I hate it when I scroll a page beyond the 'fold' and have to wait for images to load. By default, does this load the remaining below-the-fold content in the background once the above-the-fold stuff is complete?

lelandfe
2 replies
23h29m

It does not. It leverages native lazy loading. All major browsers treat a `loading="lazy"` attribute as meaning "do not load this image/iframe until it is nearly in view." https://developer.mozilla.org/en-US/docs/Web/HTML/Element/im...

However, this does inline aspect ratios, so the layout won't change after they're done loading - the cardinal sin of lazy loading.

rkagerer
1 replies
21h36m

Thanks.

10+ years ago I wrote a GreaseMonkey userscript for a dating site that collected all your results into one scrollable table. It exercised very explicit control over the image loading sequence. If I recall (and my memory might be spotty), it grabbed 1 thumbnail image per match initially, in the order they were displayed, to populate the table. Once all the thumbnails were pulled (which didn't take very long), it would start downloading full sized images, in the background. Hovering a match to view more details would immediately prioritize that matches photos, and if you hovered over one of said match's photo thumbnails (as if to click) that specific image would be placed at the top of the queue.

It was all done using Javascript (no frameworks) and XmlHttpRequest, and worked pretty well. This was back when servers only allowed you a couple (or handful) of connections at a time. I wrote a "TaskQueue" class in Javascript implementing a very simple form of cooperative multitasking (jobs designed to do their work in chunks). Tasks could "preempt" others, and you could define simple relationships so a group of tasks could block on one they were dependent on.

Funny story, I actually sent a link to the tool to a girl on the site who I eventually wound up in a long-term relationship with ("here, let me help you make it more efficient to browse for other guys...").

Anyway, at the time I felt like it was table stakes that a page like this should be able to exert some sensible control over the sequencing and prioritization of its image assets, in a fashion that has the user's best interests at heart. I'm glad browsers have finally evolved out-of-the-box attributes like "loading=lazy", but I kind of wish there were an option between "eager" and "lazy" that simply deferred the lazy content until all the other content is done. So I can still walk away to get a coffee (or switch to another tab) and come back to a fully, instantly-responsive page.

lelandfe
0 replies
21h25m

Great story.

Once all the thumbnails were pulled... it would start downloading full sized images

LQIP, Low-Quality Image Placeholder – that was pretty new stuff circa 2014. Facebook also popularized fetching a tiny version, and blurring it: https://engineering.fb.com/2015/08/06/android/the-technology...

georges_gomes
0 replies
21h51m

As user @lelandfe pointed out here, Jampack is using browser native loading="lazy".

There is currently no way to change this behavior but I could add an option that would preload the below-the-fold images in the background when all the page is loaded. It's actually a pretty nice idea.

I'm just afraid it will load unnecessary images at the bottom of the page but if it's an option, anybody can choose to have it or not!

codetrotter
0 replies
21h11m

That repository links to a site https://www.modpagespeed.com/ which in turn links to a different repository https://github.com/we-amp/ngx_pagespeed

It only has one extra commit, which deletes RETIRED.txt which was added in the repo you linked.

So at the moment it seems someone is intending to continue development. And might even be working on it, but haven’t pushed any work to the main branch.

Solvency
3 replies
23h28m

If my website is an image-heavy portfolio that I wrote myself in pure HTML/CSS/JS with zero dependencies whatsoever... does a tool like this offer me any value? What could it do here?

My site consists of a project grid (large thumbnails) and project page with hi-rez (3200x2000) images in a JS slideshow I wrote.

georges_gomes
2 replies
21h11m

Do you have a link you can share? I think the project grid with thumbnails could benefit greatly from Jampack but I would need to see the page to confirm.

Solvency
1 replies
20h44m

https://tinonyman.com/archive

Not my site, but mine (in progress) is almost exactly the same UX/UI but with zero dependencies or libraries/frameworks.

georges_gomes
0 replies
13h10m

Yes, this is a perfect use case for Jampack. You have simple large images in HTML <img>. Jampack would make them responsive with multiple sizes so mobile phone get small images and desktop larger images. And images would be made lazy when outside the screen. Mobile phone would download 1/10th of the data I guess.

pdimitar
2 replies
1d2h

Ohhh, I like this is a lot! Will use it!

Any unimpressed commenters willing to point any defects? To me this looks like the equivalent of compiling C to super-optimized assembly and is definitely doing things that I wouldn't want to do myself.

rthnbgrredf
1 replies
1d

I don't know if we are on the right track if we have to ship "super optimized assembly" for HTML and CSS. I think we should be able to write the most simple and straightforward HTML and CSS and the Browser on all devices should just render it fine.

If we really have to ship super optimized assembly, then I would completely skip HTML and CSS altogether and just ship highly optimized web assembly and let developers use whatever language they want.

pdimitar
0 replies
5h31m

I don't know if we are on the right track if we have to ship "super optimized assembly" for HTML and CSS

You know, I don't disagree. In fact I am 100% with you, it's just that we have to work with the realities presented in front of us. I'd think that nowadays we (as in, the general bigger tech community) know how would we do HTML+CSS much better from scratch but this is not ever happening -- I think we all know it.

So the next best thing in my view is (when it comes to generating static pages, that is, not sure about how viable this tool would be if you put it in the pipeline to improve all your dynamically-generated HTML -- it has to be hyper-optimized in order for it to not get in the way; having an nginx/Caddy plugin could also work):

1. Write Markdown or something else that's easier on the eyes and fingers;

2. Write your own CSS or use a theme from your SSG software;

3. Generate the HTML with your SSG software;

4. (NEW STEP) Run it through JamPack;

5. Deploy.

Personally as a techie I want my pages to have 100/100 lightweight / speedy / small score. That includes things like not loading images until they enter the viewport, that includes using all sorts of OS- / browser-specific hackery for faster loading, it includes the fastest time to first contentful paint... that includes everything that can be used in terms of tricks, in fact.

So again, I get your point and I really wish we lived in that reality but at one point I stopped believing that we ever will so I am trying to settle for the second best thing.

kibwen
2 replies
1d1h

I'm interested in the notion of identifying "critical" CSS that should be inlined rather than live in its own stylesheet.

I was hoping there was some principled way of identifying critical and non-critical CSS (e.g. user interaction effects like :hover would always be considered non-critical), but it looks like the library it's using just tries to render your page and do a best-effort detection on which rules are considered critical, which IMO is a little unsatisfying: https://github.com/GoogleChromeLabs/critters

chrismorgan
1 replies
22h47m

If you have less than 50KB of CSS, inline it. (And if you have more than 50KB of CSS, you’re probably doing it wrong. Well, OK, maybe you’re inlining fonts too, that’s understandable. But if you have more than 50KB of other styles, you’re probably doing it wrong.)

Seriously, inlining is absurdly good for performance, even compared with a warm cache, and the threshold where external stylesheets or scripts perform better is surprisingly high, into the hundreds of kilobytes for some common markets.

The notion of critical CSS… it’s a defeatist attitude, trying to grasp back some squandered performance, rather than fixing the underlying problem.

I regret to say this is just based on casual experience and observation, not any methodical technique. I would really like someone to run with this concept and measure it more fully. I just doubt it’s going to be me.

spxneo
1 replies
23h56m

what are some static site generators people are using in production? I think this could be used to further optimize the output.

( Case in point, yesterday I spent all day trying to follow examples to turn Divjoy react website into a simple html to serve from S3 bucket. I can't believe how hard that was and I am still struggling. Ideally something that can just auto-deploy to S3 bucket and point domains to it. It hurts that I paid money for it and the developer is gone, discord is abandoned. This is why I always prefer FOSS )

nine_k
0 replies
23h50m

Well, Hugo, Zola, Jekyll. They sort if have parts of this.

sodality2
1 replies
1d1h

Hm, this didn't change anything hugely on one of my projects - for example, it reduced the total bundle size, but it increased the gzip'd size, so it's actually a net negative for me. But it looks like the CSS improvements actually did help.

It looks like a great idea and would probably help if I had any images in my project.

georges_gomes
0 replies
1d1h

Hi! It's true that it you don't have images, the benefits are limited. Also, your CSS may become bigger at the end because we automatically improve compatibility with browser. You can disable this by setting browserlist to empty string. https://jampack.divriots.com/features/browser-compatibility/

riddley
1 replies
19h24m

This is super cool. Any chance you'd make a Docker container for it to simplify usage for people who are scared of node?

turtlebits
0 replies
13h19m

You don't need a prebuilt docker container, just run the command from within a node image.

    docker run -v ${PWD}:/dist node npx @divriots/jampack /dist

celicoo
1 replies
1d1h

Thanks for the project!

Can I expect it to run out of the box for Next.js static-generated files? If so, any recommendations on how to set it up in a Next.js project?

georges_gomes
0 replies
1d

Hi! If the static output of your Next.js project is `./build` then add `&& jampack ./build` to your build command.

If the site is 100% static then it should play nice. If it's hydrated with JS: results may vary. Let me know!

account42
1 replies
5h30m

First example already shows a complete disregard for quality and backwards comaptibility.

Lazy-load assets below-the-fold ⬇.

Ok so that seals it - this chases scores over actual user experience.

notahacker
0 replies
1d

This looks like it covers several use cases people are picking the SSG and its plugins to handle in the first place, especially if they're picking Astro or Eleventy.

Is there a reason for preferring them as a separate post-build step? I guess the tradeoff is faster rebuilds when you're developing vs the possibility that you miss subtle bugs resulting from introducing stuff like width declarations for images?

lispisok
0 replies
23h56m

As somebody who loathes doing webpage layout, refuses to learn it, but has to still do it sometimes this looks great

jdthedisciple
0 replies
21h58m

Highly needed - thanks!

georges_gomes
0 replies
22h17m

I'm receiving lots of static websites by email from people who want to help me with real world examples :heart: you guys are awesome! Thank you so much!

dan_can_code
0 replies
1d2h

This is great! Having to handle these tasks manually can be very tedious, so this tool is a breath of fresh air.

Alifatisk
0 replies
1d2h

This is very cool