Best way to monkey patch Ember internals?


#1

Every so often I find myself in a situation where I’m tracking down a bug and I want to monkey patch some internal Ember function, usually as a temporary or debug fix.

Today I’m in a situation where I need to change this function: https://github.com/emberjs/data/blob/ced0cdfe9c410575adb0034ea06bf4f51fd9e4ab/addon/-private/utils/parse-response-headers.js - There’s a bug that causes it to not work correctly in fastboot.

I’ve been able to fix this with running fastboot + node debugger, but now I want to monkey patch it so I can deploy my application.

In the past, I would fork the Ember Data version tag my app is using and then point my package.json at that fork. However that’s cumbersome and hard to understand.

Earlier I noticed that the parseResponseHeaders is available in as a module in require.entries['ember-data/-private'].module.exports.parseResponseHeaders. This got me thinking… is it possible to monkey patch this function without needing an ED fork?


#2

I can’t really relate to this. Forking a dependency seems much cleaner and clearer to me than monkey patching.


#3

Agree with @ef4 here.

Generally (to me) the best path would probably be:

  • to fork
  • throw extra tests here to show what is broken
  • make the test pass (and confirm that it hasn’t broken other things)
  • send a PR to open up discussion
  • update your app’s package.json to use your fork (which is pretty simple these days via "ember-data": "github:rwjblue/ember-data#branch-name", syntax)

This does a few things:

  • it gets you up and running
  • puts the general problem space out to the maintainers
  • makes it super clear that you have some “special” sauce if/when you go to upgrade the dependency

#4

Absolutely, I’ve already opened PR fix for this issue.

The thing I’m confused about is I’m running an older version of Ember Data. When the PR gets merged I won’t be able to use the version of ED it gets merged into (since it will likely be 3.3, which is way ahead of my application).

What I ended up doing was branching off the older ED version tag, cherry picking the PR commits into that new branch, and pushing it to GH. Then referencing that branched tag in my package.json.

It’s certainly not awful, but I think my general confusion is now my application is dependent on a branched version, which means I’ll have to keep cherry picking that PR back to branched tags as I upgrade ED, until I hit version 3.3.

I still feel like a monkey patch is easier to manage here.


Edit: This is a really good point:

makes it super clear that you have some “special” sauce if/when you go to upgrade the dependency


#5

Yep, this is absolutely a positive, not a negative!

  1. It incentivizes you to stay current (which should generally be the goal anyways)
  2. helps ensure that you always control what customizations you need
  3. helps make it super clear exactly what changes to the library you have made (in the patching world, it is often unclear where these patches live, how they interact with the libs code itself, what is actually required by your app any longer, etc)

The issue here with patching is that you completely loose the ability to know when your patch breaks some other functionality.


#6

@ryanto if it is an identified bug I think that it would be worth notifying the Data team and trying to release a fix release for previous versions (at least to matching LTS or popular release versions even though Data did not previously have an LTS policy?)


#7

@rwjblue Ok I think I’m convinced. Thanks for explaining :smiley:


#8

I would also add that git is quite excellent at maintaining a long lived branch with your own patch even as you pull subsequent changes from upstream. It’s basically what it was designed for. The only trick is: do everything with merges. No rebases, no cherry-picks.