Did you checked this https://help.salesforce.com/articleView?id=000212807&type=1
Background: In Spring'15, as part of the Flexible Managed Packages initiative, we enabled the removal of Visualforce (page, global component and static resource) from published managed packages. This should help you owner of managed packages in getting rid of obsolete VF.
(Flexible Managed Packages is an initiative that enables the removal of components from published managed packages. So far, the supported component types are custom tab, field,object, validation rule, record type, field set, button, link, VF page, global VF component, staticresource.)
Close to Spring'15 release date, we discovered a scenario that we had not previously addressed. Before describing the scenario, it is helpful to discuss the behavior of apex w.r.t. packaging.
Apex and Packaging: Ever since Apex and VF were made packageable, public apex classes and public VF components are deleteable from published managed packages. If you go to your packaging org and delete any public apex class / VF component, the result is the deletion of the same in the subscriber org upon upgrade to that version of the package. The subscriber has no role in the process.
When we built the Flexible Managed Packages initiative, we did not want to delete any metadata in the subscriber org. For E.g.: if you delete a custom field or validation rule in the packaging org, upon upgrade, these "deleted" components have the "Delete" button/link in the subscriber org, but the upgrade process does not delete anything in the subscriber org. This way, the subscriber sys admin has the flexibility to analyze the impact and then delete things as needed. We have remained consistent with this model and even when you delete VF (page, global component and static resource) in the subscriber org, we do not delete
metadata; we just enable the delete button.
Inconsistency: As a result of the above, there is an inconsistency. Public apex classes and public VF components are deleted in subscriber org upon upgrade, whereas the same is not done for VF pages and global VF components. (This is all subscriber side behavior; in packaging org, when you delete any of these, they are gone for good). After a lot of deliberations, we decided to live with this inconsistency as we wanted to err on the side of caution (don't delete metadata in subscriber org as part of flexible managed packages initiative).
Scenario: Now coming back to the scenario .. One example of the simple scenario goes like this: you have VF page p1 referencing public VF component pc1. So in 1.0 of the package, it is p1 => pc1. In ver 1.1, you decide to get rid of p1. Let's suppose we enable you to upgrade your customer from 1.0 to 1.1. The issue with supporting this is, the
subscriber may not delete p1 after the upgrade even though they have the ability to do so. In your packaging org, since p1 is gone, there is nothing preventing you from deleting pc1 from your package. Let's suppose you delete pc1 and release 1.2 of your package. Now if the subscriber upgrades to 1.2, the VF page p1 will fail to load as it depends on pc1 that was deleted upon upgrade. Now this p1 may be a business critical VF page and the customer ends up experiencing a serious disruption of functionality.
Resolution
Fix: To fix this proactively so that we don't get to a situation where a VF page or global VF component in the subscriber org is broken, we came up with the following solution: during upgrade (in the example above, upgrade from 1.0 to 1.1), we will check to see if there is any VF page or global VF component that is in DELETED state AND is referencing some public apex or vf component. If the answer is yes, we block the upgrade so that we don't put the customer's VF in bad state.
Action from your side: So, you may be wondering, what should we do to ensure package upgrades are not broken? Taking the above example, create a patch version 1.0.1 off of 1.0.In 1.0.1, edit the VF page p1 and remove reference to pc1. Upgrade your v1.0 customers (using push functionality) to first 1.0.1 and then to 1.1. By doing this, you are breaking the reference that p1 has on pc1 at 1.0.1. Then the upgrade to 1.1 will go smoothly. We understand that the 2step process is cumbersome, but by imposing this constraint, we are ensuring that your customers will never end up in a state where any part of your app is nonfunctional. (Also, when you try to delete a VF page or component in the packaging org, we describe aspects of this in a warning message so that you are aware of the 2step process.)