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

--incremental Build, only process files that have changed. #108

Closed
zachleat opened this issue Apr 17, 2018 · 33 comments
Closed

--incremental Build, only process files that have changed. #108

zachleat opened this issue Apr 17, 2018 · 33 comments
Labels
enhancement: favorite Vanity label! The maintainer likes this enhancement request a lot. enhancement feature: 🥝 incremental builds large-task

Comments

@zachleat
Copy link
Member

zachleat commented Apr 17, 2018

This is the step that requires knowledge of each template’s dependencies:

  • What collections the changed template is a part of and what other templates consume those collections.
  • Keep in mind JavaScript dependencies (for 11ty.js)
  • If the file is a layout, rebuild other templates use the layout.
  • If the file is a data file, rebuild what templates use the data (global data will require some extra work but directory and template data are straightforward)
  • Passthrough copy files filed separately as Incremental passthrough copy #977

Punt into separate issues, later:

  • If the file is a config file, package.json, rebuild everything for now.
  • If the file is an include or an extend or an import or other internal-to-template-language specific feature, how do we discover what other files consume this? Maybe no way to tell for relative includes that don’t live in the includes folder?
@zachleat
Copy link
Member Author

The really difficult part about this task is that doing it correctly would require a detailed dependency map of the content, specifically around what uses what collections.

@dillonbheadley
Copy link

I believe the pug cli watch option does this. Even if included css file changes it only rebuilds templates that reference it.
It’s very smart. Not sure how it’s done tho.

@zachleat zachleat added the needs-votes A feature request on the backlog that needs upvotes or downvotes. Remove this label when resolved. label May 3, 2018
@zachleat
Copy link
Member Author

zachleat commented May 3, 2018

This repository is now using lodash style issue management for enhancements (see https://twitter.com/samselikoff/status/991395669016436736)

This means enhancement issues will now be closed instead of leaving them open. The enhancement backlog can be found here: https://github.com/11ty/eleventy/issues?utf8=%E2%9C%93&q=label%3Aneeds-votes+sort%3Areactions-%2B1-desc+

@zachleat zachleat closed this as completed May 3, 2018
@zachleat
Copy link
Member Author

Use Object.defineProperties to add getters to track dependencies between templates and data.

@zachleat
Copy link
Member Author

Proxies and Sorted Directed Acyclic Graphs, y’all.

https://www.npmjs.com/package/toposort
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

@zellwk
Copy link

zellwk commented Dec 7, 2018

Just adding another thought: I wonder how would incremental watch mode work with a task runner like Gulp and browser sync?

@jakearchibald
Copy link

If/when this happens, it'd be great if the optimisations were available outside of watch mode.

TypeScript does this via .tsbuildinfo files.

This means that users that are using different watchers would benefit from the incremental build too.

@Ryuno-Ki
Copy link
Contributor

Hm, some people referred different existing implementations. Could we gather their source code here so to lay out a plan?
(If we get lucky, we find shared libraries among them!)

@zachleat
Copy link
Member Author

zachleat commented Sep 7, 2019

Did a really dumb/rough start of this here 6e294bd

@zachleat zachleat changed the title --incremental Watch Mode --incremental Build Sep 7, 2019
@zachleat
Copy link
Member Author

After working on https://www.zachleat.com/web/own-my-tweets/ I’m also thinking a nice feature might be some smarts about pagination data too, specifically adding entries into a huge paginated array would only write files for the new/changed entries.

@zachleat zachleat added the enhancement: favorite Vanity label! The maintainer likes this enhancement request a lot. label Sep 17, 2019
@zachleat
Copy link
Member Author

@matthewp had an interesting idea about reading files in the output directory to compare contents to avoid re-writing and save on rsync tasks https://twitter.com/matthewcp/status/1174013502215852032

zachleat added a commit that referenced this issue Sep 20, 2019
…output content for the file is the same but it doesn’t seem any faster yet so 🤷‍♂️ #108
@zachleat
Copy link
Member Author

I did a fair bit of work to experiment playing around with @matthewp’s idea to compare output before writing is in the incremental-file-hash-cache branch but it wasn’t quite good enough. Will require more work but might get scrapped. https://github.com/11ty/eleventy/tree/incremental-file-hash-cache

Hashing the content seemed to be fast enough (using farmhash https://www.npmjs.com/package/farmhash) but writing an extra file for the cache seemed to negate the gains here.

Some super quick numbers (farmhash versus node’s built-in crypto module)

image

Yeah, not writing any files did provide a small performance improvement for large projects (but at the cost of up-front hashing for the first run to create the cache file)

I dunno, just not quite sold here on this yet.

@matthewp
Copy link

@zachleat Thanks for giving it a try! For clarity, I wasn't expecting the comparison to speed up builds, I was expecting it to speed up rsync.

Out of curiosity, was this hashing implementation a separate hash file for every page, or did you concat these some how into 1 hashed file so you only need to do 1 read.

From an implementation simplicity perspective you could skip the hashing and just read in the current version of the file. This would indeed be slower, but how much slower?

@piperhaywood
Copy link

Another thought about this:
If --incremental or something similar is too difficult, a different approach that might help is to exclude files via the config file instead of .eleventyignore. This way, we can use the preexisting --config flag to swap configs when developing locally.

My specific use case:
We’re pulling in data from an API on each build. Right now there are only 20 pages on the whole site, but the build time is taking anywhere from 9 to 50 seconds each time due to the API. Ideally we wouldn’t hit that API every time, it’s only really necessary when the site is deployed to Netlify. If I could exclude that particular file within an Eleventy config file such as eleventy.dev.js, then I could run npx @11ty/eleventy --serve --config=eleventy.dev.js for much faster development.

@dceddia
Copy link
Contributor

dceddia commented Nov 22, 2019

This feature would be awesome to have. I was thinking about how to do the dependency mapping and how it seems like each template language would need to be able to do its own map.

Poking around Nunjucks docs I found the load event (here). It sounds potentially useful! They say:

The 'load' event gets emitted whenever a Loader retrieves the source of a template. It can be listened to in order to determine template dependencies at runtime.

Still gotta build up that DAG I guess, but this might be a step in the right direction, for Nunjucks anyway.

@AleksandrHovhannisyan
Copy link
Contributor

AleksandrHovhannisyan commented Mar 3, 2021

@Ryuno-Ki Not necessarily. Jekyll does this very intelligently by only rebuilding a file under one of two conditions:

  1. If the file itself was modified. For example, if you modify a blog post or a page, it will get rebuilt.
  2. If the file is included by other files/pages, or if it's a layout for other pages, then all those dependencies will get rebuilt.

Right now, I'm seeing build times of only 4-5 seconds with Jekyll 4 whenever a single file changes. With 11ty, that increases to 20 seconds because everything is getting rebuilt every single time. Eventually, if I save a file frequently enough, it just runs out of memory and crashes. I'm dumb, ignore. I wasn't using the incremental flag, lol. It actually does work and is faster than Jekyll from what I can tell.

@uxdiscovery
Copy link

Really looking forward to this epic feature. I'm working with an i18n project which eventually generates 5000+ pages. That takes 15 mins to finish a build

@Takazudo
Copy link

Isn't eleventy interested in incremental build?
The fact that eleventy does not have this feature is the huge disadvantage against other SSG solutions, I guess.

@Ryuno-Ki
Copy link
Contributor

https://github.com/orgs/11ty/projects/3 lists the feature as in-progress.

@Takazudo
Copy link

@Ryuno-Ki Oh I understood. Thank you for the guidance!

As a person who develops web sites and web applications for client works, I want you to know that we can't choose eleventy for the big projects because of this.

@Ryuno-Ki
Copy link
Contributor

What a bummer!
Perhaps you can find another great tool at https://jamstack.org/generators/ that suits your requirements better.

@AleksandrHovhannisyan
Copy link
Contributor

Actually, now that I've revisited working on migrating my site to 11ty, I'm curious: Isn't this how the --incremental flag already behaves? I've noticed that it doesn't actually rebuild the entire site, which is a good thing. I must've not been using it before.

@pbuzdin
Copy link

pbuzdin commented Nov 18, 2021

@j-f1
Copy link
Contributor

j-f1 commented Dec 31, 2021

A neat addition to this would be to have --serve mode only build/copy files that are requested. This would mean that changing a file would immediately tell Browsersync to reload, which would then tell Eleventy to trigger a build of everything needed by that file (optionally skipping if none of the dependencies have changed).

@zachleat
Copy link
Member Author

@j-f1 related to #108 (comment) #2456

@rr923
Copy link

rr923 commented Dec 19, 2022

@zachleat Can I use this feature for production build? I noticed that the document says:
Incremental builds perform a partial build operating only on files that have changed to improve build times when doing local development.

@zachleat
Copy link
Member Author

@rr923 Work on higher fidelity incremental builds is happening and I will likely add more issues to reflect more of the nuances but for this to offer improvements to production builds on your CI server we’ll need cold start incremental first:

https://www.11ty.dev/docs/usage/incremental/#cold-start

zachleat added a commit to 11ty/11ty-website that referenced this issue Dec 21, 2022
@zachleat
Copy link
Member Author

Docs updated: https://www.11ty.dev/docs/usage/incremental/

As of 2.0.0-canary.21 we’re now shipping:

Further issues have been filed for future improvements:

This is finally in good enough shape that I’m ready to say that Eleventy now has incremental builds support. I’m going to milestone --incremental as complete in 2.0 🏆

@zachleat zachleat removed the needs-votes A feature request on the backlog that needs upvotes or downvotes. Remove this label when resolved. label Dec 21, 2022
@zachleat zachleat moved this from In Progress to Closed in Incremental Builds Dec 21, 2022
@zachleat zachleat added this to the Eleventy 2.0.0 milestone Dec 21, 2022
@zachleat zachleat unpinned this issue Jan 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement: favorite Vanity label! The maintainer likes this enhancement request a lot. enhancement feature: 🥝 incremental builds large-task
Projects
No open projects
Development

No branches or pull requests