Performance: Middleman 4 vs. Middleman 3

I have a blog site that contains around 400 posts, plus about 2500 supporting pages (i.e. pages outside the ‘posts’ directory), and probably 12,000 image assets.

When I do a full site build using Middleman 3.4.1, it takes about 4 minutes on my machine to generate the full site.

If I do the same build using Middleman 4.1.0.rc.2, it takes around 15 minutes.

The major slowdown appears to occur as it reads the config file. Here are the lines from the verbose output:

== Change (#<Set: {:source}>): robots.txt
== Change (#<Set: {:source}>): sitemap/index.html.markdown
== Reading: Local config: config.rb
== Activating: blog
== Requesting resource list rebuilding: first_run_change_page
== Requesting resource list rebuilding: first_run_change_page
== Requesting resource list rebuilding: first_run_change_page
== Requesting resource list rebuilding: first_run_change_page
== Requesting resource list rebuilding: first_run_change_page

After displaying the line:

== Change (#<Set: {:source}>): sitemap/index.html.markdown

Middleman 4 seems to hang for a long time.

Is there anything that I can do to speed up Middleman 4? Would it help to ‘ignore’ the directories containing the image assets? I don’t know if these are being pulled into the sitemap (in the Middleman sense) and slowing the process somehow.

Thanks in advance for any suggestions.

Hi @angusm, I’ve spent a lot of the last week targeting these regressions. Hoping to have something out in v4.1.0 very soon. The biggest issue involves Sass and Sprockets. Basically, Ruby Sass takes a very long time to compile. In v4, I added the ability to use SassC (by adding the sassc gem to your project) which makes Sass compiles lightning fast. Sprockets does not support SassC, so it remains slow. In v4, the time at which Sprockets compiles Sass is easily, resulting in that early hang.

There were also a bunch of smaller tweaks. The blog extension had a bunch of bad regressions as well.

Finally, I’ve enabled parallel builds in v4.1.0 which is adding a nice 50% speed boost. Hoping to have this all out soon.

2 Likes

Thank you.

I did some fairly informal testing and came up with some timings for a complete rebuild of the site that I’m working on. For the record, the site has around 3200 HTML pages.

Middleman 3.4.1: ~4 minutes
Middleman 4.1.0rc2: ~17 minutes
Middleman 4.1.4: ~10 minutes

Enabling ‘sassc’ didn’t seem to make a huge difference in my case; the build was about 20 seconds faster with it enabled, but that’s within the margin of error for my very sloppy testing procedures.

Your recent changes have definitely sped up the build process – v4.1.4 is a big improvement over v4.1.0rc2 – but v3.4.1 is still faster by a large margin. Do you think there are still potential optimizations to be made, or is this the new normal?

Starting Middleman in ‘server’ mode is also still noticeably slower in v4 than in v3.

One other thing I just noticed is that something seems to have changed in v4 with respect to page metadata. For example, the following code fragment:

	<% countries = blog.articles.group_by {|a| a.metadata[:page]['country'] } 
	   filtered_countries = countries.select { |key,value| !key.nil? }
	%>
	<ul class="archivelinks">
		<% filtered_countries.keys.sort.each do |country| %>
		  <li><%= link_to normalize_country_name(country), country_path(country) %></a></li>
		<% end %>
	</ul>

produces a menu based on the value of the ‘country’ item in each page’s frontmatter under v3.4.1; in v4.x, however, it just comes up blank. I didn’t see anything in the release notes that obviously related to this, so I’m unsure whether this is a bug or whether v4 demands a new way of doing this. I’d be interested in any suggestions that you had for making it work again.

Thanks.

1 Like

Frontmatter is stored under data. Try a.data.country.

W.R.T. performance. It would be very helpful to have a reproducible performance test case on our end. Would you be able to help with that? Let’s move this to Github if so.

Last time I was profiling stuff, the 3 slow items were sprockets, blog and Contracts. You can run without contracts by adding NO_CONTRACTS=true before the MM command.

Are you using either blog or sprockets?

Thanks for the information about data; that solved that problem.

I am using blog (but not sprockets). The blog site I’m building contains around 450 blog posts, and there are about 2600 other pages to build outside the posts directory. Around 400 of those other pages also contain information that is read in during the process of building the blog pages; so the process of building a blog page ‘post-A’ will also do a YAML::load of the corresponding page file ‘other-file-A’. Turning off that feature doesn’t appear to impact build times significantly.

I’d be very happy to try to provide a test case. What do you need?

Repo access would be enough. If that’s not possible, maybe you could anonymize your project and send me a zip?

I realize I never gave you the test project that you asked for.

However, I’m pleased to say that Middleman 4.2.0 is much faster than previous versions; a complete build of my rather huge site is now 4 or 5 times faster than previously, and ‘exec server’ is also usable again.

I think you fixed that problem quite conclusively. Thank you.

Hiya

What does NO_CONTRACTS=true imply - would be nice to know what happens underneath with this option.

I assume using as:

NO_CONTRACTS=true bundle exec middleman build

Im always trying to improve my speed of building.