Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: Jampack – Optimizes static websites as a post-processing step (github.com/divriots)
328 points by georges_gomes 8 months ago | hide | past | favorite | 58 comments
Hi!

Jampack is a post-processing tool that takes the output of your Static Site Generator (aka SSG) and optimizes it for best user experience and best Core Web Vitals scores.

As of today it can:

- Optimize local images, CDN images or external images

- Optimize above-the-fold vs below-the-fold

- Limit images max width

- Inline critical CSS

- Prefetch links on scroll

- Improve browser compatibility

- Auto-fixes HTML issues

- Warn for HTML accessibility issues

- Compress all assets in the end

It processes directly the static output so it's compatible with any SSG or framework. We are intensively using it as a post-processing step to our Astro websites for example.

With Jampack, we end-up focusing more on how simple, readable and maintainable our code is, throw images of any size, and let it optimize for maximum performance.

We hope this can be helpful to lot of people! Cheers, Georges and the ‹div›RIOTS team!




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


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...


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.


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


I've zipped it up and sent a link.


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


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.


> 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.


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)


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


Petering out, as it were :-)


This reminds me of the PageSpeed modules for Apache and Nginx https://developers.google.com/speed/pagespeed/module


I believe the project is not maintained anymore.

Github repository is archived: https://github.com/apache/incubator-pagespeed-ngx.

Or has it perhaps moved to some other location?


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.


I haven’t seen a clear answer. https://news.ycombinator.com/item?id=37578513


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.


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.


> 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.


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.


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?


> 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


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


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


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


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


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.


To back this up I would point to https://news.ycombinator.com/item?id=32587740


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?


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


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?


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.


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.


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...


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!


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 )


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


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.


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/


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.


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.


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.


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.


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


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.


[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


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


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.


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


Lol, thank you. Fixed.


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.



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!


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?


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!


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


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


Highly needed - thanks!


This is very cool




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: