public void AddLink(string type, string path, string url = null) { if (type == null) { throw new ArgumentNullException(nameof(type)); } if (path == null) { throw new ArgumentNullException(nameof(path)); } if (!UPath.TryParse(path, out _)) { throw new ArgumentException($"Invalid path [{path}]", nameof(path)); } if (url != null) { if (!UPath.TryParse(url, out _)) { throw new ArgumentException($"Invalid url [{url}]", nameof(url)); } } if (path.Contains("*") && (url == null || !url.EndsWith("/"))) { throw new ArgumentException($"Invalid url [{path}]. Must end with a `/` if the path contains a wildcard.", nameof(url)); } var link = new BundleLink(this, type, path, url); Links.Add(link); }
private static void RemoveSourceMaps(BundleLink link) { var content = link.Content; if (content == null) { return; } content = RegexSourceMapSimple.Replace(content, string.Empty); content = RegexSourceMapMulti.Replace(content, string.Empty); link.Content = content; link.ContentObject.Content = content; }
private static void Minify(IContentMinifier minifier, BundleLink link, string minifyExtension) { var contentObject = link.ContentObject; // Don't try to minify content that is already minified if (contentObject != null && !link.Path.EndsWith($".min.{link.Type}")) { var minifiedResult = minifier.Minify(link.Type, link.Content, link.Path); contentObject.Content = minifiedResult; link.Content = minifiedResult; var minExtension = (minifyExtension ?? string.Empty) + "." + link.Type; if (!contentObject.Url.EndsWith(minExtension)) { var url = Path.ChangeExtension(contentObject.Url, minExtension); contentObject.Url = url; } } }
private void ProcessBundleLinks(BundleObject bundle, Dictionary <UPath, ContentObject> staticFiles) { Dictionary <string, ConcatGroup> concatBuilders = null; if (bundle.Concat) { concatBuilders = new Dictionary <string, ConcatGroup>(); foreach (var type in bundle.UrlDestination) { if (!concatBuilders.ContainsKey(type.Key)) { concatBuilders[type.Key] = new ConcatGroup(); } } } // Expand wildcard * links for (int i = 0; i < bundle.Links.Count; i++) { var link = bundle.Links[i]; var path = link.Path; var url = link.Url; if (!path.Contains("*")) { continue; } // Always remove the link bundle.Links.RemoveAt(i); var upath = (UPath)path; foreach (var file in Site.MetaFileSystem.EnumerateFileSystemEntries(upath.GetDirectory(), upath.GetName())) { var newLink = new BundleLink(bundle, link.Type, (string)file.Path, url + file.Path.GetName()); bundle.Links.Insert(i++, newLink); } // Cancel the double i++ i--; } // Collect minifier IContentMinifier minifier = null; if (bundle.Minify) { var minifierName = bundle.Minifier; foreach (var min in Minifiers) { if (minifierName == null || min.Name == minifierName) { minifier = min; break; } } if (minifier == null) { Site.Warning($"Minify is setup for bundle [{bundle.Name}] but no minifiers are registered (Minified requested: {minifierName ?? "default"})"); } } // Process links for (int i = 0; i < bundle.Links.Count; i++) { var link = bundle.Links[i]; var path = link.Path; var url = link.Url; if (url != null) { if (!UPath.TryParse(url, out _)) { Site.Error($"Invalid absolute url [{url}] in bundle [{bundle.Name}]"); } } if (path != null) { path = ((UPath)path).FullName; link.Path = path; var entry = new FileEntry(Site.MetaFileSystem, path); ContentObject currentContent; var isExistingContent = staticFiles.TryGetValue(entry.FullName, out currentContent); if (url == null) { var outputUrlDirectory = bundle.UrlDestination[link.Type]; // If the file is private or meta, we need to copy to the output // bool isFilePrivateOrMeta = Site.IsFilePrivateOrMeta(entry.FullName); url = outputUrlDirectory + Path.GetFileName(path); link.Url = url; } // Process file by existing processors if (currentContent == null) { if (entry.Exists) { currentContent = new ContentObject(Site, entry); } else { Site.Error($"Unable to find content [{path}] in bundle [{bundle.Name}]"); } } if (currentContent != null) { currentContent.Url = url; var listTemp = new PageCollection() { currentContent }; Site.Content.ProcessPages(listTemp, false); link.ContentObject = currentContent; bool isRawContent = link.Type == BundleObjectProperties.ContentType; // If we require concat and/or minify, we preload the content of the file if (!isRawContent && (bundle.Concat || bundle.Minify)) { try { link.Content = currentContent.Content ?? entry.ReadAllText(); // Minify content separately if (bundle.Minify && minifier != null) { Minify(minifier, link, bundle.MinifyExtension); } } catch (Exception ex) { Site.Error( $"Unable to load content [{path}] while trying to concatenate for bundle [{bundle.Name}]. Reason: {ex.GetReason()}"); } } // If we are concatenating if (!isRawContent && concatBuilders != null) { currentContent.Discard = true; // Remove this link from the list of links, as we are going to squash them after bundle.Links.RemoveAt(i); i--; concatBuilders[link.Type].Pages.Add(currentContent); concatBuilders[link.Type].Builder.AppendLine(link.Content); } else if (!isExistingContent) { Site.StaticFiles.Add(currentContent); staticFiles.Add(entry.FullName, currentContent); } } } } // Concatenate files if necessary if (concatBuilders != null) { foreach (var builderGroup in concatBuilders) { var builder = builderGroup.Value.Builder; if (builder.Length > 0) { var type = builderGroup.Key; var outputUrlDirectory = bundle.UrlDestination[type]; // If the file is private or meta, we need to copy to the output // bool isFilePrivateOrMeta = Site.IsFilePrivateOrMeta(entry.FullName); var url = outputUrlDirectory + bundle.Name + "." + type; var newStaticFile = new ContentObject(Site) { Url = url, Content = builder.ToString() }; Site.DynamicPages.Add(newStaticFile); // Add file dependencies foreach (var page in builderGroup.Value.Pages) { newStaticFile.Dependencies.Add(new PageContentDependency(page)); } var link = new BundleLink(bundle, type, null, url) { Content = newStaticFile.Content, ContentObject = newStaticFile }; bundle.Links.Add(link); } } } foreach (var link in bundle.Links) { var contentObject = link.ContentObject; if (contentObject != null) { link.Url = contentObject.Url; } } }