Skip to content

Commit bc59fb1

Browse files
committed
Cleanups
1 parent da7140e commit bc59fb1

File tree

4 files changed

+52
-32
lines changed

4 files changed

+52
-32
lines changed

src/StaticWebAssetsSdk/Tasks/ApplyCompressionNegotiation.cs

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ public class ApplyCompressionNegotiation : Task
2020
[Output]
2121
public ITaskItem[] UpdatedEndpoints { get; set; }
2222

23-
private readonly List<StaticWebAssetEndpointSelector> _selectorsList = new();
24-
private readonly List<StaticWebAssetEndpointResponseHeader> _headersList = new();
25-
private readonly List<StaticWebAssetEndpointResponseHeader> _tempHeadersList = new();
26-
private readonly List<StaticWebAssetEndpointProperty> _propertiesList = new();
23+
private readonly List<StaticWebAssetEndpointSelector> _selectorsList = [];
24+
private readonly List<StaticWebAssetEndpointResponseHeader> _headersList = [];
25+
private readonly List<StaticWebAssetEndpointResponseHeader> _tempHeadersList = [];
26+
private readonly List<StaticWebAssetEndpointProperty> _propertiesList = [];
2727
private const int ExpectedCompressionHeadersCount = 2;
2828

2929
public override bool Execute()
@@ -36,7 +36,9 @@ public override bool Execute()
3636

3737
var compressionHeadersByEncoding = new Dictionary<string, StaticWebAssetEndpointResponseHeader[]>(ExpectedCompressionHeadersCount);
3838

39-
ProcessCompressedAssets(assetsById, endpointsByAsset, updatedEndpoints, compressionHeadersByEncoding);
39+
using var jsonContext = new JsonWriterContext();
40+
41+
ProcessCompressedAssets(assetsById, endpointsByAsset, updatedEndpoints, compressionHeadersByEncoding, jsonContext);
4042
AddRemainingEndpoints(endpointsByAsset, updatedEndpoints);
4143
UpdatedEndpoints = StaticWebAssetEndpoint.ToTaskItems(updatedEndpoints);
4244
return true;
@@ -46,7 +48,8 @@ private void ProcessCompressedAssets(
4648
Dictionary<string, StaticWebAsset> assetsById,
4749
IDictionary<string, List<StaticWebAssetEndpoint>> endpointsByAsset,
4850
HashSet<StaticWebAssetEndpoint> updatedEndpoints,
49-
Dictionary<string, StaticWebAssetEndpointResponseHeader[]> compressionHeadersByEncoding)
51+
Dictionary<string, StaticWebAssetEndpointResponseHeader[]> compressionHeadersByEncoding,
52+
JsonWriterContext jsonContext)
5053
{
5154
foreach (var compressedAsset in assetsById.Values)
5255
{
@@ -74,8 +77,7 @@ private void ProcessCompressedAssets(
7477
StaticWebAssetEndpointResponseHeader.PopulateFromMetadataValue(compressedEndpoint.ResponseHeadersString, _headersList);
7578
var currentCompressionHeaders = GetOrCreateCompressionHeaders(compressionHeadersByEncoding, compressedAsset);
7679
_headersList.AddRange(currentCompressionHeaders);
77-
using var headerContext = new JsonWriterContext();
78-
var headersString = StaticWebAssetEndpointResponseHeader.ToMetadataValue(_headersList, headerContext);
80+
var headersString = StaticWebAssetEndpointResponseHeader.ToMetadataValue(_headersList, jsonContext);
7981
compressedEndpoint.SetResponseHeadersString(headersString);
8082
}
8183

@@ -91,14 +93,30 @@ private void ProcessCompressedAssets(
9193
continue;
9294
}
9395

94-
var endpointCopy = CreateUpdatedEndpoint(compressedAsset, quality, compressedEndpoint, compressedHeaders, relatedEndpointCandidate);
96+
var endpointCopy = CreateUpdatedEndpoint(compressedAsset, quality, compressedEndpoint, compressedHeaders, relatedEndpointCandidate, jsonContext);
9597
updatedEndpoints.Add(endpointCopy);
98+
// Since we are going to remove the endpoints from the associated item group and the route is
99+
// the ItemSpec, we want to add the original as well so that it gets re-added.
100+
// The endpoint pointing to the uncompressed asset doesn't have a Content-Encoding selector and
101+
// will use the default "identity" encoding during content negotiation.
96102
updatedEndpoints.Add(relatedEndpointCandidate);
97103
}
98104
}
99105
}
100106
}
101107

108+
// Before we return the updated endpoints we need to capture any other endpoint whose asset is not associated
109+
// with the compressed asset. This is because we are going to remove the endpoints from the associated item group
110+
// and the route is the ItemSpec, so it will cause those endpoints to be removed.
111+
// For example, we have css/app.css and Link/css/app.css where Link=css/app.css and the first asset is a build asset
112+
// and the second asset is a publish asset.
113+
// If we are processing build assets, we'll mistakenly remove the endpoints associated with the publish asset.
114+
115+
// Iterate over the endpoints and find those endpoints whose route is in the set of updated endpoints but whose asset
116+
// is not, and add them to the updated endpoints.
117+
118+
// Reuse the map we created at the beginning.
119+
// Remove all the endpoints that were updated to avoid adding them again.
102120
private void AddRemainingEndpoints(
103121
IDictionary<string, List<StaticWebAssetEndpoint>> endpointsByAsset,
104122
HashSet<StaticWebAssetEndpoint> updatedEndpoints)
@@ -115,6 +133,9 @@ private void AddRemainingEndpoints(
115133
endpointsByAsset.Remove(endpoint.AssetFile);
116134
}
117135

136+
// We now have only endpoints that might have the same route but point to different assets
137+
// and we want to include them in the updated endpoints so that we don't incorrectly remove
138+
// them from the associated item group when we update the endpoints.
118139
var endpointsByRoute = GetEndpointsByRoute(endpointsByAsset);
119140
var additionalUpdatedEndpoints = new HashSet<StaticWebAssetEndpoint>(updatedEndpoints.Count, StaticWebAssetEndpoint.RouteAndAssetComparer);
120141
foreach (var updatedEndpoint in updatedEndpoints)
@@ -203,7 +224,8 @@ private StaticWebAssetEndpoint CreateUpdatedEndpoint(
203224
string quality,
204225
StaticWebAssetEndpoint compressedEndpoint,
205226
HashSet<string> compressedHeaders,
206-
StaticWebAssetEndpoint relatedEndpointCandidate)
227+
StaticWebAssetEndpoint relatedEndpointCandidate,
228+
JsonWriterContext jsonContext)
207229
{
208230
Log.LogMessage(MessageImportance.Low, "Processing related endpoint '{0}'", relatedEndpointCandidate.Route);
209231
var encodingSelector = new StaticWebAssetEndpointSelector
@@ -214,28 +236,24 @@ private StaticWebAssetEndpoint CreateUpdatedEndpoint(
214236
};
215237
Log.LogMessage(MessageImportance.Low, " Created Content-Encoding selector for compressed asset '{0}' with size '{1}' is '{2}'", encodingSelector.Value, encodingSelector.Quality, relatedEndpointCandidate.Route);
216238

217-
// Build selectors using reusable list to avoid array allocation
218239
StaticWebAssetEndpointSelector.PopulateFromMetadataValue(relatedEndpointCandidate.SelectorsString, _selectorsList);
219240
_selectorsList.Add(encodingSelector);
220-
using var selectorContext = new JsonWriterContext();
221-
var selectorsString = StaticWebAssetEndpointSelector.ToMetadataValue(_selectorsList, selectorContext);
241+
var selectorsString = StaticWebAssetEndpointSelector.ToMetadataValue(_selectorsList, jsonContext);
222242

223243
var endpointCopy = new StaticWebAssetEndpoint
224244
{
225245
AssetFile = compressedAsset.Identity,
226246
Route = relatedEndpointCandidate.Route,
227247
};
228248

229-
// Set selectors and properties using string methods to avoid array allocations
230249
endpointCopy.SetSelectorsString(selectorsString);
231250
endpointCopy.SetEndpointPropertiesString(relatedEndpointCandidate.EndpointPropertiesString);
232251

233252
// Build headers using reusable list
234253
_headersList.Clear();
235254
ApplyCompressedEndpointHeaders(_headersList, compressedEndpoint, relatedEndpointCandidate.Route);
236255
ApplyRelatedEndpointCandidateHeaders(_headersList, relatedEndpointCandidate, compressedHeaders);
237-
using var headerContext = new JsonWriterContext();
238-
var headersString = StaticWebAssetEndpointResponseHeader.ToMetadataValue(_headersList, headerContext);
256+
var headersString = StaticWebAssetEndpointResponseHeader.ToMetadataValue(_headersList, jsonContext);
239257
endpointCopy.SetResponseHeadersString(headersString);
240258

241259
// Update the endpoint
@@ -347,9 +365,9 @@ private void ApplyCompressedEndpointHeaders(List<StaticWebAssetEndpointResponseH
347365

348366
private void ApplyRelatedEndpointCandidateHeaders(List<StaticWebAssetEndpointResponseHeader> headers, StaticWebAssetEndpoint relatedEndpointCandidate, HashSet<string> compressedHeaders)
349367
{
350-
StaticWebAssetEndpointResponseHeader.PopulateFromMetadataValue(relatedEndpointCandidate.ResponseHeadersString, _tempHeadersList);
368+
StaticWebAssetEndpointResponseHeader.PopulateFromMetadataValue(relatedEndpointCandidate.ResponseHeadersString, _headersList);
351369

352-
foreach (var header in _tempHeadersList)
370+
foreach (var header in _headersList)
353371
{
354372
// We need to keep the headers that are specific to the compressed asset like Content-Length,
355373
// Last-Modified and ETag. Any other header we should add it.

src/StaticWebAssetsSdk/Tasks/ComputeEndpointsForReferenceStaticWebAssets.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public override bool Execute()
2525
var result = CandidateEndpoints;
2626

2727
// Reusable list for optimized endpoint property parsing
28-
var endpointPropertiesList = new List<StaticWebAssetEndpointProperty>(16);
28+
var endpointPropertiesList = new List<StaticWebAssetEndpointProperty>(4);
2929

3030
using var context = StaticWebAssetEndpointProperty.CreateWriter();
3131

@@ -68,9 +68,8 @@ public override bool Execute()
6868
if (propertiesModified)
6969
{
7070
// Serialize modified properties back using optimized method
71-
((ITaskItem)candidateEndpoint).SetMetadata(nameof(StaticWebAssetEndpoint.EndpointProperties),
71+
candidateEndpoint.SetEndpointPropertiesString(
7272
StaticWebAssetEndpointProperty.ToMetadataValue(endpointPropertiesList, context));
73-
candidateEndpoint.MarkProperiesAsModified();
7473
}
7574

7675
Log.LogMessage(MessageImportance.Low, "Adding endpoint {0} for asset {1} with updated route {2}.", candidateEndpoint.Route, candidateEndpoint.AssetFile, candidateEndpoint.Route);

src/StaticWebAssetsSdk/Tasks/DefineStaticWebAssetEndpoints.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ public override bool Execute()
4040
Log,
4141
contentTypeProvider),
4242
static (i, loop, state) => state.Process(i, loop),
43-
static worker => worker.Finally());
43+
static (worker) =>
44+
{
45+
worker.Finally();
46+
worker.Dispose();
47+
});
4448

4549
Endpoints = StaticWebAssetEndpoint.ToTaskItems(endpoints);
4650

@@ -120,6 +124,8 @@ private readonly struct ParallelWorker(
120124
private readonly List<StaticWebAssetEndpointResponseHeader> _headersList = new(6);
121125
private readonly List<StaticWebAssetEndpointProperty> _propertiesList = new(10);
122126

127+
private readonly JsonWriterContext _serializationContext = new();
128+
123129
private void CreateAnAddEndpoints(
124130
StaticWebAsset asset,
125131
string length,
@@ -172,10 +178,8 @@ private void CreateAnAddEndpoints(
172178

173179
var finalRoute = asset.IsProject() || asset.IsPackage() ? StaticWebAsset.Normalize(Path.Combine(asset.BasePath, route)) : route;
174180

175-
using var headerContext = new JsonWriterContext();
176-
using var propertyContext = new JsonWriterContext();
177-
var headersString = StaticWebAssetEndpointResponseHeader.ToMetadataValue(_headersList, headerContext);
178-
var propertiesString = StaticWebAssetEndpointProperty.ToMetadataValue(_propertiesList, propertyContext);
181+
var headersString = StaticWebAssetEndpointResponseHeader.ToMetadataValue(_headersList, _serializationContext);
182+
var propertiesString = StaticWebAssetEndpointProperty.ToMetadataValue(_propertiesList, _serializationContext);
179183

180184
var endpoint = new StaticWebAssetEndpoint()
181185
{
@@ -216,6 +220,11 @@ internal void Finally()
216220
}
217221
}
218222

223+
public void Dispose()
224+
{
225+
_serializationContext.Dispose();
226+
}
227+
219228
internal ParallelWorker Process(int i, ParallelLoopState _)
220229
{
221230
var asset = StaticWebAsset.FromTaskItem(CandidateAssets[i]);

src/StaticWebAssetsSdk/Tasks/FilterStaticWebAssetEndpoints.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,6 @@ private bool MeetsAllCriteria(
9191
{
9292
case "Property":
9393
var meetsPropertyCriteria = criteria.ExcludeOnMatch();
94-
95-
// Parse properties from string to avoid accessing endpoint.EndpointProperties array
9694
var propertiesString = endpoint.EndpointPropertiesString;
9795
StaticWebAssetEndpointProperty.PopulateFromMetadataValue(propertiesString, _propertiesList);
9896

@@ -113,8 +111,6 @@ private bool MeetsAllCriteria(
113111
break;
114112
case "Selector":
115113
var meetsSelectorCriteria = criteria.ExcludeOnMatch();
116-
117-
// Parse selectors from string to avoid accessing endpoint.Selectors array
118114
var selectorsString = endpoint.SelectorsString;
119115
StaticWebAssetEndpointSelector.PopulateFromMetadataValue(selectorsString, _selectorsList);
120116

@@ -135,8 +131,6 @@ private bool MeetsAllCriteria(
135131
break;
136132
case "Header":
137133
var meetsHeaderCriteria = criteria.ExcludeOnMatch();
138-
139-
// Parse headers from string to avoid accessing endpoint.ResponseHeaders array
140134
var headersString = endpoint.ResponseHeadersString;
141135
StaticWebAssetEndpointResponseHeader.PopulateFromMetadataValue(headersString, _headersList);
142136

0 commit comments

Comments
 (0)