PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/atlassian-plugins-webresource/src/main/java/com/atlassian/plugin/webresource/assembler/html/InteractiveHtmlTagWriter.java

https://bitbucket.org/atlassian/atlassian-plugins-webresource
Java | 95 lines | 55 code | 10 blank | 30 comment | 0 complexity | bea0262ba8d637f48604acf3add0f3cb MD5 | raw file
  1. package com.atlassian.plugin.webresource.assembler.html;
  2. import com.atlassian.plugin.webresource.ResourceUrl;
  3. import com.atlassian.plugin.webresource.assembler.ResourceUrls;
  4. import com.atlassian.plugin.webresource.impl.RequestState;
  5. import com.atlassian.plugin.webresource.impl.snapshot.resource.Resource;
  6. import com.atlassian.plugin.webresource.models.Requestable;
  7. import com.atlassian.webresource.api.UrlMode;
  8. import com.atlassian.webresource.api.assembler.resource.PluginUrlResource;
  9. import com.atlassian.webresource.api.assembler.resource.ResourcePhase;
  10. import com.google.common.collect.Maps;
  11. import javax.annotation.Nonnull;
  12. import java.io.Writer;
  13. import java.util.Arrays;
  14. import java.util.Collection;
  15. import java.util.LinkedHashMap;
  16. import java.util.List;
  17. import static java.util.Collections.emptyList;
  18. import static java.util.Objects.requireNonNull;
  19. import static java.util.stream.Collectors.toList;
  20. /**
  21. * Generates HTML to load CSS and JavaScript resources with an {@link ResourcePhase#INTERACTION} phase.
  22. * <p>
  23. * This strategy intentionally makes it the client-side's responsibility to request and load all interactive resources.
  24. * In the long run, it might not be a great idea. However, for the moment, it helps us work around more rigid internals
  25. * in the WRM.
  26. *
  27. * @since 5.0.0
  28. */
  29. final class InteractiveHtmlTagWriter extends HtmlTagWriter {
  30. InteractiveHtmlTagWriter(@Nonnull RequestState requestState, @Nonnull Writer writer, @Nonnull UrlMode urlMode) {
  31. // @todo: if should render prefetch links, add prefetch tag writers to the formatter
  32. super(requestState, writer, emptyList());
  33. }
  34. @Override
  35. public void writeHtmlTag(@Nonnull Collection<ResourceUrls> resources) {
  36. // Reduce the ResourceUrls that were split by content type. Keep them in order.
  37. LinkedHashMap<String, ResourceUrls> reducedResources = Maps.newLinkedHashMap();
  38. resources.forEach(resource -> reducedResources.put(resource.getResourceUrl().getKey(), resource));
  39. // Render a single script tag to make a call for multiple `ResourceUrl` objects, since it's more efficient
  40. // in the browser than having dozens of separate script tags.
  41. writeHtmlTag(generateRequireLazyScriptTag(reducedResources.values()));
  42. // @todo: if should render prefetch links, use super to do so
  43. // super.writeHtmlTag(resources);
  44. }
  45. @Nonnull
  46. @Override
  47. String generateHtmlTag(@Nonnull ResourceUrls resourceUrls, @Nonnull HtmlTagFormatter formatter) {
  48. requireNonNull(resourceUrls, "The resource urls are mandatory for the creation of the script tag.");
  49. requireNonNull(formatter, "The formatter is mandory for generating the tags.");
  50. return formatter.format(resourceUrls);
  51. }
  52. /**
  53. * A hackish approach to making the client request resources lazily.
  54. * <p>
  55. * This strategy reverts URLs for CSS/JS batches back in to the various requested keys that created them,
  56. * then uses those to write some &lt;code&gt;WRM.require(requestedKeys)&lt;/code&gt; JavaScript calls.
  57. */
  58. private String generateRequireLazyScriptTag(Collection<ResourceUrls> resources) {
  59. final List<String> formattedKeys = resources.stream()
  60. .map(ResourceUrls::getResourceUrl)
  61. .map(this::generateRequireLazyArguments)
  62. .flatMap(Collection::stream)
  63. .collect(toList());
  64. return formattedKeys.size() > 0 ?
  65. // The `defer` attribute is added in order to support defer-loading the WRM client, otherwise
  66. // we'd potentially make calls to it before it's loaded.
  67. String.format("<script defer>WRM.requireLazily([%s])</script>", String.join(",", formattedKeys)) :
  68. "";
  69. }
  70. /**
  71. * Reverts URLs for CSS/JS batches back in to the various requested keys that created them.
  72. *
  73. * @param batchedResources an abstraction over one or more {@link Resource} objects, addressable by URL.
  74. * @return loosely typed {@link Requestable} keys a user would need to request in order to retrieve the content.
  75. */
  76. private List<String> generateRequireLazyArguments(ResourceUrl batchedResources) {
  77. final String prefix = batchedResources.getBatchType().equals(PluginUrlResource.BatchType.CONTEXT) ? "wrc!" : "wr!";
  78. final String[] split = batchedResources.getKey().split(",");
  79. return Arrays.stream(split)
  80. // Remove exclusions; the client-side will handle that by inspecting `data-wrm-` attributes in HTML
  81. .filter(key -> !key.startsWith("-"))
  82. .map(key -> "\"" + prefix + key + "\"")
  83. .collect(toList());
  84. }
  85. }