Redundant References Remover VSX





5.00/5 (1 vote)
A Visual Studio Extension that locates and removes duplicate script references in a web project.


Introduction
A Visual Studio Extension that locates and removes duplicate script references in a web project.
Problem Statement
Whilst developing a web project, you will add some script references (JavaScript\CSS) to your page (well, duh).
But then you forget which scripts you added, and add them again.
(happens a lot with MVC 3 where you don't have a visual designer and the page can become quite big)
so basically you end up with something like this:
Referencing a script twice will not only slow down the website, it may also lead to an unexpected behavior as a JavaScript function calling a controller can be executed twice.
Sometimes the scenario gets more complicated, when a reference to the same script is included in both the layout/master page-file as well as a partial view.
Solution
Redundant References Remover Extension solves these problems, it scans the views in the web-project looking for duplicated references and removes them.
Downloads
Download Extension
Source Code
After the installation, the tool appears under Other Windows
Code Anatomy
There are 3 services that do the workIVisualStudioService
handles Visual Studio Interaction public interface IVisualStudioService { WebProject GetWebProject(); IList<Page> GetPages(ProjectItems item); vsSaveStatus RemoveReference(ProjectItem projectItem, string reference, int offset); }
IPagesService
handles processing of pages and scanning for repeated referencespublic interface IPagesService { void ProcessPages(IEnumerable<Page> pagesList); IEnumerable<Page> GetDuplicatesInSameFile(IEnumerable<Page> pages); IEnumerable<ParentChildDuplicates> GetDuplicatesInLayoutAndFile(IEnumerable<Page> pages); }
IRegexService
Extracts different parts of info from the Page's htmlpublic interface IRegexService { IEnumerable<string> GetReferences(string pageContent); string GetDefaultLayoutPageName(string content); IEnumerable<string> GetMultipleLayouts(string content); IEnumerable<string> GetPartialViews(string content); IEnumerable<string> GetWebControls(string content); bool CheckPageHasNullLayout(string content); string GetMasterPageName(string content); }There are 3 types of web projects, mvc2, mvc3 and web forms, each handle the master\child layout differently.
So we make the parent class
WebFormPagesService
with virtual functions.namespace Services.Implementation { using System; using System.Collections.Generic; using System.Linq; using Entities; using Services.Contracts; using EnvDTE; public class WebFormPagesService : IPagesService { #region Member Variables protected readonly IRegexService _regexService; #endregion Member Variables #region Constructor public WebFormPagesService(IRegexService regexService) { this._regexService = regexService; } #endregion Constructor #region IPagesService void IPagesService.ProcessPages(IEnumerable<Page> pagesList) { foreach (Page page in pagesList) { page.References = GetReferences(page); var parents = GetParents(page.Name, page.Content, pagesList); if (page.Parents != null) { page.Parents.Concat(parents); } else { page.Parents = parents; } var children = GetChildren(page.Content, pagesList); foreach (var child in children) { if (child.Parents == null) { child.Parents = new List<Page>(); } child.Parents.Add(page); } } LinkParents(pagesList); } IEnumerable<Page> IPagesService.GetDuplicatesInSameFile(IEnumerable<Page> pages) { foreach (var page in pages) { var duplicates = page.References.Where(p => p.Value != 1).ToDictionary(p => p.Key, p => p.Value); if (duplicates.Count != 0) { yield return new Page { Content = page.Content, Item = page.Item, Name = page.Name, Parents = page.Parents, References = duplicates }; } } } IEnumerable<ParentChildDuplicates> IPagesService.GetDuplicatesInLayoutAndFile(IEnumerable<Page> pages) { var duplicatesList = new List<ParentChildDuplicates>(); foreach (var child in pages) { var childReferences = child.References.Keys; foreach (var parent in child.Parents) { var parentsReferences = parent.References.Keys; var commonReferences = parentsReferences.Intersect(childReferences); if (commonReferences.Count() > 0) { var parentChildDuplicate = new ParentChildDuplicates { Parent = parent, Child = child, Duplicates = commonReferences }; duplicatesList.Add(parentChildDuplicate); } } } return duplicatesList; } #endregion . . . } }
Conclusion
That's it, the code is pretty much straight forward.
If you have any comment\suggestion\question about the implementation\code topology drop me a line ;)
Improvement\Future Work
Currently the code doesn't support detecting the Inclusion of both a minified and unminified version of a script.
... src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"> ... src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js">But I'll get to it, when I have time.
Useful Resources
YSlow rule #13 – Remove Duplicate Scripts
Introduction to Visual Studio 2010 Extensibility
Manipulating Project Files in VS
Customizing Visual Studio Extension Icon in Visual Studio 2010