private void SaveTestResources() { var settings = new CombinatorSettings { ResourceBaseUri = new Uri("http://localhost") }; var resource1 = _resourceRepository.NewResource(ResourceType.Style); resource1.Content = "test"; _cacheFileService.Save(_cssResourcesFingerprint, resource1, settings); _cacheFileService.Save(_jsResourceFingerprint, _resourceRepository.NewResource(ResourceType.JavaScript), settings); _cacheFileService.Save(_jsResourceFingerprint, _resourceRepository.NewResource(ResourceType.JavaScript), settings); ClearSession(); }
public void MinificationExclusionWorks() { _resourceRepository.FillWithTestStyles(); var settings = new CombinatorSettings { MinificationExcludeFilter = new Regex("test\\.css"), MinifyResources = true }; var resource = _resourceRepository.GetResource("~/Modules/Piedone.Combinator/Styles/test.css"); _resourceProcessingService.ProcessResource(resource, new StringBuilder(), settings); Assert.That(resource.Content.StartsWith("minified:") && resource.Content.Contains("/Modules/Piedone.Combinator/Styles/test.css"), Is.False); resource = _resourceRepository.GetResource("~/Modules/Piedone.Combinator/Styles/test2.css"); _resourceProcessingService.ProcessResource(resource, new StringBuilder(), settings); Assert.That(resource.Content.StartsWith("minified:") && resource.Content.Contains("/Modules/Piedone.Combinator/Styles/test2.css"), Is.True); }
public void SpriteGenerationRuns() { _resourceRepository.Clear(); CombinatorResource resource; var type = ResourceType.Style; resource = _resourceRepository.SaveResource("~/Modules/Piedone.Combinator/Styles/1.css", type); var settings = new CombinatorSettings { GenerateImageSprites = true }; var combinedResources = _combinatorService.CombineStylesheets(_resourceRepository.GetResources(type), settings); resource = _resourceRepository.GetResource(combinedResources.First()); Assert.That(resource.Content.Contains("ImageSprite"), Is.True); }
public void SetsAreSplit() { _resourceRepository.Clear(); CombinatorResource resource; var type = ResourceType.Style; resource = _resourceRepository.SaveResource("~/Modules/Piedone.Combinator/Styles/1.css", type); resource = _resourceRepository.SaveResource("~/Modules/Piedone.Combinator/Styles/2.css", type); resource = _resourceRepository.SaveResource("~/Modules/Piedone.Combinator/Styles/3.css", type); resource = _resourceRepository.SaveResource("~/Modules/Piedone.Combinator/Styles/4.css", type); resource = _resourceRepository.SaveResource("~/Modules/Piedone.Combinator/Styles/5.css", type); resource = _resourceRepository.SaveResource("~/Modules/Piedone.Combinator/Styles/6.css", type); var settings = new CombinatorSettings { ResourceSetFilters = new Regex[] { new Regex("1"), new Regex("4|5") } }; var combinedResources = _combinatorService.CombineStylesheets(_resourceRepository.GetResources(type), settings); Assert.That(combinedResources.Count, Is.EqualTo(4)); }
/// <summary> /// Combines (and minifies) the content of resources and saves the combinations. /// </summary> /// <param name="resources">Resources to combine.</param> /// <param name="fingerprint">Just so it shouldn't be recalculated.</param> /// <param name="resourceType">Type of the resources.</param> /// <param name="settings">Combination setting.s</param> /// <exception cref="ApplicationException">Thrown if there was a problem with a resource file (e.g. it was missing or could not be opened).</exception> private void Combine(IList <ResourceRequiredContext> resources, string fingerprint, ResourceType resourceType, ICombinatorSettings settings) { if (resources.Count == 0) { return; } var combinatorResources = new List <CombinatorResource>(resources.Count); foreach (var resource in resources) { var combinatorResource = _combinatorResourceManager.ResourceFactory(resourceType); // Copying the context so the original one won't be touched. combinatorResource.FillRequiredContext( resource.Resource.Name, resource.Resource.GetFullPath(), resource.Settings.Culture, resource.Settings.Condition, resource.Settings.Attributes, resource.Resource.TagBuilder.Attributes); combinatorResource.IsRemoteStorageResource = settings.RemoteStorageUrlPattern != null && settings.RemoteStorageUrlPattern.IsMatch(combinatorResource.AbsoluteUrl.ToString()); combinatorResources.Add(combinatorResource); } var combinedContent = new StringBuilder(1000); var resourceBaseUri = settings.ResourceBaseUri != null ? settings.ResourceBaseUri : new Uri(_hca.Current().Request.Url, "/"); Action <CombinatorResource, List <CombinatorResource> > saveCombination = (combinedResource, containedResources) => { if (combinedResource == null) { return; } // Don't save emtpy resources. if (combinedContent.Length == 0 && !combinedResource.IsOriginal) { return; } if (!containedResources.Any()) { containedResources = new List <CombinatorResource> { combinedResource } } ; var bundleFingerprint = containedResources.GetCombinatorResourceListFingerprint(settings); var localSettings = new CombinatorSettings(settings); if (localSettings.EnableResourceSharing && settings.ResourceSharingExcludeFilter != null) { foreach (var resource in containedResources) { if (localSettings.EnableResourceSharing) { localSettings.EnableResourceSharing = !settings.ResourceSharingExcludeFilter.IsMatch(resource.AbsoluteUrl.ToString()); } } } if (!combinedResource.IsOriginal) { combinedResource.Content = combinedContent.ToString(); if (combinedResource.Type == ResourceType.Style && !string.IsNullOrEmpty(combinedResource.Content) && settings.GenerateImageSprites) { _resourceProcessingService.ReplaceCssImagesWithSprite(combinedResource); } combinedResource.Content = "/*" + Environment.NewLine + "Resource bundle created by Combinator (http://combinator.codeplex.com/)" + Environment.NewLine + Environment.NewLine + "Resources in this bundle:" + Environment.NewLine + string.Join(Environment.NewLine, containedResources.Select(resource => { var url = resource.AbsoluteUrl.ToString(); if (localSettings.EnableResourceSharing && !resource.IsCdnResource && !resource.IsRemoteStorageResource) { var uriBuilder = new UriBuilder(url); uriBuilder.Host = "DefaultTenant"; url = uriBuilder.Uri.ToStringWithoutScheme(); } return("- " + url); })) + Environment.NewLine + "*/" + Environment.NewLine + Environment.NewLine + Environment.NewLine + combinedResource.Content; } // We save a bundle now. First the bundle should be saved separately under its unique name, then for this resource list. if (bundleFingerprint != fingerprint && containedResources.Count > 1) { if (!_cacheFileService.Exists(bundleFingerprint, localSettings)) { _cacheFileService.Save(bundleFingerprint, combinedResource, localSettings); } // Overriding the url for the resource in this resource list with the url of the set. combinedResource.IsOriginal = true; // The following should fetch one result theoretically but can more if the above Exists()-Save() happens // in multiple requests at the same time. var set = _cacheFileService.GetCombinedResources(bundleFingerprint, localSettings).First(); combinedResource.LastUpdatedUtc = set.LastUpdatedUtc; if (IsOwnedResource(set)) { if (settings.ResourceBaseUri != null && !set.IsRemoteStorageResource) { combinedResource.RequiredContext.Resource.SetUrl(UriHelper.Combine(resourceBaseUri.ToStringWithoutScheme(), set.AbsoluteUrl.PathAndQuery)); } else if (set.IsRemoteStorageResource) { combinedResource.IsRemoteStorageResource = true; combinedResource.RequiredContext.Resource.SetUrl(set.AbsoluteUrl.ToStringWithoutScheme()); } else { combinedResource.RequiredContext.Resource.SetUrl(set.RelativeUrl.ToString()); } AddTimestampToUrlIfNecessary(combinedResource); } else { combinedResource.RequiredContext.Resource.SetUrl(set.AbsoluteUrl.ToStringWithoutScheme()); } } _cacheFileService.Save(fingerprint, combinedResource, localSettings); combinedContent.Clear(); containedResources.Clear(); }; Regex currentSetRegex = null; var resourcesInCombination = new List <CombinatorResource>(); for (int i = 0; i < combinatorResources.Count; i++) { var resource = combinatorResources[i]; var previousResource = (i != 0) ? combinatorResources[i - 1] : null; var absoluteUrlString = ""; var saveOriginalResource = false; try { absoluteUrlString = resource.AbsoluteUrl.ToString(); if (settings.CombinationExcludeFilter == null || !settings.CombinationExcludeFilter.IsMatch(absoluteUrlString)) { // If this resource differs from the previous one in terms of settings or CDN they can't be combined if (previousResource != null && (!previousResource.SettingsEqual(resource) || (previousResource.IsCdnResource != resource.IsCdnResource && !settings.CombineCdnResources))) { saveCombination(previousResource, resourcesInCombination); previousResource = null; // So it doesn't get combined again in if (saveOriginalResource) below. } // If this resource is in a different set than the previous, they can't be combined if (currentSetRegex != null && !currentSetRegex.IsMatch(absoluteUrlString)) { currentSetRegex = null; saveCombination(previousResource, resourcesInCombination); } // Calculate if this resource is in a set if (currentSetRegex == null && settings.ResourceSetFilters != null && settings.ResourceSetFilters.Length > 0) { int r = 0; while (currentSetRegex == null && r < settings.ResourceSetFilters.Length) { if (settings.ResourceSetFilters[r].IsMatch(absoluteUrlString)) { currentSetRegex = settings.ResourceSetFilters[r]; } r++; } // The previous resource is in a different set or in no set so it can't be combined with this resource if (currentSetRegex != null && previousResource != null && resourcesInCombination.Any()) { saveCombination(previousResource, resourcesInCombination); } } // Nesting resources in such blocks is needed because some syntax is valid if in its own file but not anymore // when bundled. if (resourceType == ResourceType.JavaScript) { combinedContent.Append("{"); } combinedContent.Append(Environment.NewLine); _resourceProcessingService.ProcessResource(resource, combinedContent, settings); // This can be because e.g. it's a CDN resource and CDN combination is disabled. if (resource.IsOriginal) { saveOriginalResource = true; } combinedContent.Append(Environment.NewLine); if (resourceType == ResourceType.JavaScript) { combinedContent.Append("}"); } combinedContent.Append(Environment.NewLine); resourcesInCombination.Add(resource); } else { saveOriginalResource = true; } if (saveOriginalResource) { // This is a fully excluded resource if (previousResource != null) { saveCombination(previousResource, resourcesInCombination); } resource.IsOriginal = true; saveCombination(resource, resourcesInCombination); combinatorResources[i] = null; // So previous resource detection works correctly } } catch (Exception ex) { if (ex.IsFatal()) { throw; } throw new OrchardException(T("Processing of resource {0} failed.", absoluteUrlString), ex); } } saveCombination(combinatorResources[combinatorResources.Count - 1], resourcesInCombination); }
public override IList <ResourceRequiredContext> BuildRequiredResources(string stringResourceType) { // It's necessary to make a copy since making a change to the local variable also changes the private one. var resources = new List <ResourceRequiredContext>(base.BuildRequiredResources(stringResourceType)); var settingsPart = _cacheManager.Get("Piedone.Combinator.CombinatorSettingsPart", ctx => { _combinatorEventMonitor.MonitorConfigurationChanged(ctx); return(_siteService.GetSiteSettings().As <CombinatorSettingsPart>()); }); if (resources.Count == 0 || Orchard.UI.Admin.AdminFilter.IsApplied(_httpContextAccessor.Current().Request.RequestContext) && !settingsPart.EnableForAdmin) { return(resources); } var resourceType = ResourceTypeHelper.StringTypeToEnum(stringResourceType); try { var settings = new CombinatorSettings { CombineCDNResources = settingsPart.CombineCDNResources, EmbedCssImages = settingsPart.EmbedCssImages, EmbeddedImagesMaxSizeKB = settingsPart.EmbeddedImagesMaxSizeKB, MinifyResources = settingsPart.MinifyResources }; if (!String.IsNullOrEmpty(settingsPart.CombinationExcludeRegex)) { settings.CombinationExcludeFilter = new Regex(settingsPart.CombinationExcludeRegex); } if (!String.IsNullOrEmpty(settingsPart.EmbedCssImagesStylesheetExcludeRegex)) { settings.EmbedCssImagesStylesheetExcludeFilter = new Regex(settingsPart.EmbedCssImagesStylesheetExcludeRegex); } if (!String.IsNullOrEmpty(settingsPart.MinificationExcludeRegex)) { settings.MinificationExcludeFilter = new Regex(settingsPart.MinificationExcludeRegex); } if (!String.IsNullOrEmpty(settingsPart.ResourceSetRegexes)) { var setRegexes = new List <Regex>(); foreach (var regex in settingsPart.ResourceSetRegexes.Trim().Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) { if (!String.IsNullOrEmpty(regex)) { setRegexes.Add(new Regex(regex)); } } settings.ResourceSetFilters = setRegexes.ToArray(); } if (resourceType == ResourceType.Style) { // Checking for overridden stylesheets var currentTheme = _themeManager.GetRequestTheme(_httpContextAccessor.Current().Request.RequestContext); var shapeTable = _shapeTableLocator.Lookup(currentTheme.Id); foreach (var resource in resources) { var shapeName = StylesheetBindingStrategy.GetAlternateShapeNameFromFileName(resource.Resource.GetFullPath()); // Simply included CDN stylesheets are not in the ShapeTable, so we have to check if (shapeTable.Bindings.ContainsKey("Style__" + shapeName)) { var binding = shapeTable.Bindings["Style__" + shapeName].BindingSource; resource.Resource.SetUrl(binding, null); } } return(_combinatorService.CombineStylesheets(resources, settings)); } else if (resourceType == ResourceType.JavaScript) { return(_combinatorService.CombineScripts(resources, settings)); } return(base.BuildRequiredResources(stringResourceType)); } catch (Exception ex) { if (ex.IsFatal()) { throw; } Logger.Error(ex, "Error when combining " + resourceType + " files"); return(base.BuildRequiredResources(stringResourceType)); } }
public override IList <ResourceRequiredContext> BuildRequiredResources(string stringResourceType) { // It's necessary to make a copy since making a change to the local variable also changes the private one. var resources = new List <ResourceRequiredContext>(base.BuildRequiredResources(stringResourceType)); var settingsPart = _siteService.GetSiteSettings().As <CombinatorSettingsPart>(); if (resources.Count == 0 || Orchard.UI.Admin.AdminFilter.IsApplied(_httpContextAccessor.Current().Request.RequestContext) && !settingsPart.EnableForAdmin) { return(resources); } var resourceType = ResourceTypeHelper.StringTypeToEnum(stringResourceType); try { Uri resourceBaseUri = null; if (!string.IsNullOrEmpty(settingsPart.ResourceBaseUrl)) { resourceBaseUri = UriHelper.CreateUri(settingsPart.ResourceBaseUrl); } var settings = new CombinatorSettings { CombineCdnResources = settingsPart.CombineCdnResources, ResourceBaseUri = resourceBaseUri, EmbedCssImages = settingsPart.EmbedCssImages, EmbeddedImagesMaxSizeKB = settingsPart.EmbeddedImagesMaxSizeKB, GenerateImageSprites = settingsPart.GenerateImageSprites, MinifyResources = settingsPart.MinifyResources, EnableResourceSharing = settingsPart.EnableResourceSharing }; if (!string.IsNullOrEmpty(settingsPart.CombinationExcludeRegex)) { settings.CombinationExcludeFilter = new Regex(settingsPart.CombinationExcludeRegex); } if (!string.IsNullOrEmpty(settingsPart.RemoteStorageUrlRegex)) { settings.RemoteStorageUrlPattern = new Regex(settingsPart.RemoteStorageUrlRegex); } if (!string.IsNullOrEmpty(settingsPart.EmbedCssImagesStylesheetExcludeRegex)) { settings.EmbedCssImagesStylesheetExcludeFilter = new Regex(settingsPart.EmbedCssImagesStylesheetExcludeRegex); } if (!string.IsNullOrEmpty(settingsPart.MinificationExcludeRegex)) { settings.MinificationExcludeFilter = new Regex(settingsPart.MinificationExcludeRegex); } if (!string.IsNullOrEmpty(settingsPart.ResourceSharingExcludeRegex)) { settings.ResourceSharingExcludeFilter = new Regex(settingsPart.ResourceSharingExcludeRegex); } if (!string.IsNullOrEmpty(settingsPart.ResourceSetRegexes)) { var setRegexes = new List <Regex>(); foreach (var regex in settingsPart.ResourceSetRegexesEnumerable) { if (!string.IsNullOrEmpty(regex)) { setRegexes.Add(new Regex(regex)); } } settings.ResourceSetFilters = setRegexes.ToArray(); } DiscoverResourceOverrides(resources, resourceType); IList <ResourceRequiredContext> result; if (resourceType == ResourceType.Style) { result = _combinatorService.CombineStylesheets(resources, settings); } else if (resourceType == ResourceType.JavaScript) { result = _combinatorService.CombineScripts(resources, settings); } else { return(base.BuildRequiredResources(stringResourceType)); } RemoveOriginalResourceShapes(result, resourceType); return(result); } catch (Exception ex) { if (ex.IsFatal()) { throw; } Logger.Error(ex, "Error when combining " + resourceType + " files"); return(base.BuildRequiredResources(stringResourceType)); } }