I think two aspects have played a significant part in the migration pain:
1. The amount of breaking changes. If it was possible to do a little at a time, over a series of releases, it's a bit more manageable.
2. Being an interpreted language makes it difficult/painful to break compatibility over a series of releases, as all applications and libraries have to be kept source compatible. Source compatibility also makes it a pain for library maintainers, as you can't just cross-compile the library to a older ABI.
Maybe support for consuming libraries based on an intermediate, compiled representation, would make it easier for the library eco-system to follow breaking changes over a series of releases, and in turn make it more feasible for applications to handle a small amount of breaking changes over a longer release timeline.