-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Dramatically improving the build time of web-sys #2012
Conversation
@alexcrichton I can't figure out how to fix the webidl-tests. When I run |
Nice wins! I'm definitely eager to get this landed since these are pretty massive wins and are huge boons for beginners first trying out all this! Before we dive too much into tests though I'd like to get some more information about this if we can. Correct me if I'm wrong, but it looks like this is pre-generating source code so when you download web-sys from crates.io you don't need to parse any WebIDL, is that right? If so then we originally explicitly actually chose to not do this for the one reason that the generated code from wasm-bindgen is actually unstable with respect to the wasm-bindgen crate itself. The generated code from wasm-bindgen 0.2.0, for example, is not guaranteed to compile against wasm-bindgen 0.2.1 and beyond. At an API level everything is stable, but the internals necessary to get everything working over time have been tweaked. I think this may be solvable, though, by using an Additionally you've posted some timings, but could you break them down a bit? For example in these timings:
what is Also what's the other time in this measurement? The two sub-components don't add up to the total so I'm curious where the total came from? It sounds like you're updating dependencies between features I think? I don't think we really intentionally avoided that from before, but I thought it was the case that if you enabled Finally, when going the code generation route, can you add a CI check that |
That is correct. The code is fully and completely generated, so all rustc needs to do is load the appropriate
That's a good point. So rather than generating fully expanded code, it should instead generate code like this: #[wasm_bindgen]
extern "C" {
#[wasm_bindgen(extends = EventTarget)]
pub type Window;
// generate methods for Window...
} I like that a lot better anyways, it's a lot cleaner, and it fixes some of the issues/messiness I ran into. So I'll make that change.
I don't know. I simply watched the Cargo build output in the terminal, and when it said I assume it includes the time spent compiling the
I saw it compiling
The total time is the total time spent to compile the project. So that means compiling all of the dependencies, and compiling the project itself. So that includes Of course the times are with a clean project (no
Release mode. I never compile my projects in debug mode, because the runtime performance hit is really huge, and the build times for debug mode aren't that much faster.
I wasn't surprised that the
My understanding is that the old code should simply have pruned out all of the non-
I'll need to do some checking on that. I think it's possible to use some
That's a good idea, I'll look into that. |
Oh so that was actually another idea we had early on, emitting But hey if it can be done it'd be pretty slick :) Ok thanks for explaining the build timings! My intuition is definitely that for wasm release mode is almost always the same in terms of build time as debug mode, but the proc macros required to build wasm are often significantly more costly in release mode than debug mode in terms of compile time. Cargo's recently stabilize profile overrides feature may help here as well, but I think it's probably best to fix it at the source, it's really hard to beat a 7s compile time with |
I've been making good progress on having it generate Also, after running some tests, if you enable the |
Very nice! That all sounds great to me 👍 |
6741e53
to
eb301b8
Compare
@alexcrichton I got everything ported to use And it actually involved removing large chunks of complex code from Now compiling Now I just need to get the unit tests and CI working. I had to add a new I cleaned up the bin script too, so now you can go into the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! This looks great to me, I'm also pretty happy with how this worked out :)
I'd be fine renaming attributes as appropriate, and adding new attributes is fine by me too. Mind making sure there's docs on them in the guide though?
Also the cleanups look great for the web-sys build script and such, and agreed that this is a great step forward to custom-webidl crates!
@alexcrichton As a side effect of generating
These features already existed, but they were private to I've also added in docs for Also, the web-sys unit tests are failing with a strange error, and I can't figure out what's causing it. |
Those new features sound good to me, thanks! I'll see if I can try to help and dig into the failures here. |
Ok I think that's just a preexisting bug where if you define the same thing within a crate's tests and main crate it causes issues. This didn't previously happen becaue the hash generation for web-sys was "special", but now that it's no longer special it ran afoul of this issue. I just went ahead and removed the |
Ok I can reproduce that failure locally. It looks like |
Ok I think everything might be working now, we'll see with CI. I've switch away from custom rustfmt settings to stable rustfmt for everything because I would prefer to keep a simple workflow of |
Oh boy and now it's all green, yay! @Pauan wanna take a look at the changes I made? Or do you otherwise have anything else that this needs to do before landing? |
Instead refactor things so webidl-tests can use the Rust-code-generation as a library in a build script. Also fixes `cargo fmt` in the repository.
@alexcrichton Thanks! I rebased and touched up a few things. I think this is ready for review/merge. I'm curious why named constructors worked in the past, I thought I had very carefully ported all of the functionality over, so I'm not sure how I missed that. |
Ok great! Let's land then. Thanks so much again for doing all the work here! |
Sweet! |
Certainly! It appears I've waited far too long for a release, this is a huge release! |
Woo!! |
Sadly, this PR broke analysis and completion for I feel bad for saying this after reading the discussion here, but the original version of this PR that generated the expanded code directly would be much more prefearable for IDEs like IntelliJ because it would just work out of the box. On the other hand, the final version generates For this reason, lot of users of I'm not sure what to do about it, but I felt like it's at least worth pointing that out. You might consider generating some more "ide-friendly" code, but I can see that this approach has some major advantages so leaving it as is definitely understandable (and proc-macro support in IDEs will need to happen at some point anyway). If you want to see specifically what is problematic, I wrote it in the comment on releveant intellij-rust issue - intellij-rust/intellij-rust#5104 (comment) . |
@panstromek Increasing the build time from 10 seconds to 4:17 minutes just to get IDE support is not worth it. The build times are a much bigger showstopper. Proc macros are extremely common in Rust, they are used constantly and pervasively. Many libraries (including wasm-bindgen) require proc macros. Asking libraries to not use proc macros is not going to work, instead the IDEs need to work on adding support for proc macros. Also, even if we did revert this PR, that would only fix web-sys: IDE support would still be broken with every other crate (including js-sys), because they all use the Your link doesn't seem to have anything to do with web-sys, that seems like a more general problem with IDEs + wasm-bindgen, so you should file a new issue about that. |
I follow intellij-rust releases closely and write a good bit of Rust + wasm and I’ve never had auto complete work neither before nor after this PR landed. @panstromek are you positive that this ever worked in the first place? I noticed that in the linked issue you expressed that you weren’t certain. Just asking because I distinctly remember being excited about out dir support and it not working with web_sys (as well as most other libraries). I had the setting for it enabled. It could’ve just been something that I faced though and maybe it was working for others. |
That's definitely not what I had in mind. I wouldn't want to revert this PR, because the win is huge. If anything, I would only advocate for using the first version of it that generated the expanded code directly without Apart from that, it is not universaly true, because you pay this compile time cost only once for initial build, while IDE support is something you use all the time, so there's a clear tradeoff that some people are willing to make.
Yes, but proper IDE support is still years away (and some of it is even impossible). Until then, I don't see anything wrong with being "IDE-friendly", especially in cases like this, where proc macro is more a convenience then necessity. But as I said, it's totally understandable to leave it as is. Also, there is a difference - some proc-macros are much more IDE-friendly than others, especially ones that just generate internal code or glue, so in practice most commonly used proc macro crates work just fine.
This is true, the problem is more general than just @chinedufn It worked for me once, even though I had to do little bit of tuning that I described here: intellij-rust/intellij-rust#3066 (comment) It could autocomplete and resolve to the generated file. Note that I had older version of |
That doesn't work, because it will cause version conflicts (which is why I changed it to use So the only two choices are the 4:17 minute build time version or the
It is not a convenience, it is a necessity. The
Like I said, that is a more general problem than web-sys, so you should file a new issue about that. |
I wrote these comments under assumption that this is not the case, because it didn't follow from the discussion above. Quoting Alex:
I specifically meant
There is already an issue about general proc macro support, this is no different. Overall, I don't understand why you have such a dismissive attitude about it. I don't think I wrote anything controversial and I think that IDE support is reasonable concern to have, especially considering such a hard feature to support like proc macros. I commented here because it seemed like something that could be enabled on the wasm-bindgen side with way less effort than on the editor side, where it requires big part of proc macro support and that just won't happen anytime soon, like maybe for few another years ( and full If this is not feasible, then fine - but that wasn't immediately obvious from the thread and I don't think there is a reason to be so negative about it. |
@panstromek What you are asking for is unreasonable. You are asking for very large changes which will hurt maintainability, lock the version of wasm-bindgen, make the docs far worse, and undo all of the major work which was done to move to I'm not being "dismissive" or "negative", I am explaining to you in a straightforward and matter of fact way why the changes you are asking for won't work. Yes IDE support is important, but not if it significantly hurts other areas. There are trade-offs here, this isn't just a simple "oh we can easily support IDE" situation. If there is something about the |
@panstromek To put it into perspective, you are essentially asking for a complete rewrite of the web-sys code generation, and it also requires changes to the wasm-bindgen internal ABI. It is not some small change where we can just revert a couple things. There's a reason this (very large) PR required 9 days of hard non-stop work to implement. |
Well, if you put it like that, then ok. From what I can tell, it seemed like just reviving back something you already had implemented before (that's how it looks like from the first few comments, along with PR description). And I beg to differ, you didn't actually explain anything, you just said hard "no" and gave information that contradicts other comments at the begining of this thread, which didn't help at all in understanding why this would be a problem. It's clearer now after your last comments. |
This is a pretty big change which touches on a bunch of things, but it shouldn't be a breaking change.
The reason for this PR is that web-sys takes an absurdly long time to build:
As you can see, web-sys alone is taking up 3:19 minutes out of the 4:17 minutes build time. A big chunk of that is running the
build.rs
script, but even the compilation afterwards takes way too long.This is in a project which is about as close to "hello world" as it gets:
So it really should not be taking that long. And even worse, it has to do a full recompilation every time you add a new feature to the
features
list, which happens often during development.This PR completely fixes that, so now it looks like this:
The
build.rs
script is completely gone, and now it takes a mere 7 seconds to compile web-sys, which means the project now only takes 1:03 minutes to build rather than 4:17 minutes.This PR accomplishes that by doing the following:
Rather than using a
build.rs
script to re-parse and re-generate from WebIDL every single time, instead it uses abin/build-web-sys
script to generate the WebIDL once. This script only needs to be re-run when changing the WebIDL.This new script creates a separate file for each feature, so the
"Window"
feature corresponds to theweb-sys/src/bindings/gen_Window.rs
file.It creates a
web-sys/src/bindings/mod.rs
file which re-exports all of thegen_
files, and it usescfg
so each file will be behind a feature flag. That means Rust doesn't even need to parse the files which aren't enabled, so everything is much faster.It adds new
cfg
flags inside of thegen_
files to accommodate things likeWindow::navigator
which should only be enabled ifNavigator
is enabled.This also means it needed to add some
cfg
flags to thedescriptor
glue code generated by#[wasm_bindgen]
. I don't particularly like this, but I don't see a better way.In
Cargo.toml
it generates the[features]
list with appropriate dependencies already specified (so"Window"
depends on"EventTarget"
, etc.)This is a bit of a rough PR, so there might be some mistakes or a better way to accomplish this, but I think it's a solid start.
This has the following benefits:
Obviously this is far faster, saving 3:12 minutes on build time for web-sys.
The
wasm-bindgen-webidl
crate is no longer a dependency ofweb-sys
, further improving the build times.It's no longer necessary to do hacky things like setting the
__WASM_BINDGEN_DUMP_FEATURES
env var.Because the generated files are checked into git, that means we get git diffs when changing the WebIDL.
The generated code is properly formatted, so rustdocs will actually be usable now.
I think this moves us a little bit closer to allowing users to generate their own crates based on WebIDL.
To actually run the script, just
cd bin/build-web-sys
and then docargo run --release
. All of the code will be auto-generated in the right folders. The features list will be in theweb-sys/features
file, which can then be copied over to theweb-sys/Cargo.toml
file.