 {"id":319,"date":"2019-12-11T11:09:42","date_gmt":"2019-12-11T19:09:42","guid":{"rendered":"https:\/\/www.mavice.com\/blog\/?p=319"},"modified":"2020-09-01T18:11:16","modified_gmt":"2020-09-02T01:11:16","slug":"aem-syndicated-components-quick-tips-to-avoid-pitfalls","status":"publish","type":"post","link":"https:\/\/www.mavice.com\/blog\/aem-syndicated-components-quick-tips-to-avoid-pitfalls\/","title":{"rendered":"AEM &#038; Syndicated Components: Quick Tips to Avoid Pitfalls"},"content":{"rendered":"\n<p>An increasingly common use-case for enterprise web implementations is the need for components that support the ability to be displayed in context within a site, but also syndicated for consumption by third-party web applications.&nbsp; These third-party applications can be either internal or external (or often both) depending on the needs of the client.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" width=\"1000\" height=\"862\" src=\"https:\/\/www.mavice.com\/blog\/wp-content\/uploads\/2020\/01\/woman_pitfall.jpg\" alt=\"Blindfolded woman near pitfall\" class=\"wp-image-325\" srcset=\"https:\/\/www.mavice.com\/blog\/wp-content\/uploads\/2020\/01\/woman_pitfall.jpg 1000w, https:\/\/www.mavice.com\/blog\/wp-content\/uploads\/2020\/01\/woman_pitfall-300x259.jpg 300w, https:\/\/www.mavice.com\/blog\/wp-content\/uploads\/2020\/01\/woman_pitfall-768x662.jpg 768w, https:\/\/www.mavice.com\/blog\/wp-content\/uploads\/2020\/01\/woman_pitfall-640x552.jpg 640w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/><figcaption>Businesswoman blindfolded standing near a deep pitfall in the town<\/figcaption><\/figure>\n\n\n\n<p>Now obviously this is quite a broad topic and describing it in great depth could probably result in a small book.&nbsp; With that said, this article strives to touch on the high-level methodology of accommodating syndicated components when using Adobe Experience Manager as your content management platform.&nbsp; Additionally, it covers a few very common pitfalls when implementing syndication in real world scenarios.<\/p>\n\n\n\n<p>At least an intermediate understanding of Adobe Experience Manager (AEM) along with common front-end web technologies is assumed.<\/p>\n\n\n\n<h3>Selectors &amp; Template Structure<\/h3>\n\n\n\n<p>At a foundational level, AEM is based on Apache Sling, which helps us with regards to syndication before we\u2019ve even started, that is, if we\u2019ve designed our templates (and the page components which render them) correctly.&nbsp; This is because of a portion of the SlingHttpServletRequest called a \u2018selector\u2019, which represents the portion of the URI between the page name and the page extension:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Ex: \/path\/to\/my\/page.selector.html<\/code><\/pre>\n\n\n\n<p>This becomes extremely relevant when designing how your page components are structured, because each script within your page component is automatically addressable by means of a selector.&nbsp; For example, a very simple page component might consist of:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>page.html\nwhich includes:\n\thead.html\n\twhich includes:\n\t     headlibs.html\n\t     metadata.html\n\tbody.html\n\twhich includes:\n\t     header.html\n\t     content.html\n\t     footer.html\n\t     footlibs.html<\/code><\/pre>\n\n\n\n<p>Now, realistically speaking a page component structure is generally a little more complex than this, but the above will serve to illustrate how useful this can be when syndicating components.&nbsp; So, using the example above, we can retrieve the contents of the header on a specific page by requesting:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/path\/to\/my\/page.header.html<\/code><\/pre>\n\n\n\n<p>This is behavior that is built into Sling, and thus it works out-of-the-box with AEM.&nbsp;&nbsp;<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/path\/to\/my\/page.header.syndicated.html<\/code><\/pre>\n\n\n\n<p>Additionally, we can also add custom selectors that inform our scripts and Java objects to modify their behavior when present, so for example:<\/p>\n\n\n\n<p>The above example would invoke the \u2018header.html\u2019 script (because that is the first selector) but would make the \u2018syndicated\u2019 selector available throughout the application stack in order to apply custom business logic that is necessary only when the header is being syndicated.<\/p>\n\n\n\n<h3>Absolute URLs vs. Relative<\/h3>\n\n\n\n<p>Probably the simplest example of how logic needs to differ between a syndicated component vs. that same component rendered in its native environment is a link.&nbsp; In a native environment, the links in a site header or footer can all be relative, assuming they are linking internally.<\/p>\n\n\n\n<p>When that same component is syndicated, and especially when syndicated to an external environment, it becomes important that all links have absolute URLs, including protocol, host and uri.<\/p>\n\n\n\n<p>Thus, you could in theory use the \u2018syndicated\u2019 selector from our example in the previous section to inform the header to render absolute URLs rather than (assume its default behavior) relative.<\/p>\n\n\n\n<h3>Client Libraries<\/h3>\n\n\n\n<p>Now, obviously we know that in order to render a functional header component, likely we don\u2019t only need the HTML.&nbsp; Most likely there is CSS and Javascript needed in order for the component to look nice and function properly.  The thing is, we probably don\u2019t want to include <strong>all<\/strong> of the CSS and Javascript required for our native site \u2013 most likely it will be lighter on the consuming application if we only include the client-side scripts which are required to render the header.<\/p>\n\n\n\n<p>So, assuming our CSS (and perhaps some early Javascript logic) is included in our \u2018headlibs.html\u2019 script, we could add logic to that script to only include relevant scripts if our \u2018syndicated\u2019 selector is present.&nbsp; We can take this one step further by passing in a third selector which informs the script which component we\u2019re syndicating, for example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/path\/to\/my\/page.headlibs.syndicated.header.html<\/code><\/pre>\n\n\n\n<p>But what if we\u2019re syndicating multiple components (say, the header <strong>and<\/strong> the footer)?&nbsp; We can define that any selectors that follow the \u2018syndicated\u2019 selector define a <strong>list<\/strong> of components for which we will include the client-side logic.&nbsp; So:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/path\/to\/my\/page.headlibs.syndicated.header.footer.html<\/code><\/pre>\n\n\n\n<p>This same logic can be applied to the footlibs.html, which should contain Javascript that isn\u2019t needed in the &lt;head&gt; and thus can be included separately at the bottom of the page.<\/p>\n\n\n\n<h3>3<sup>rd<\/sup> Party Client-Side Dependencies<\/h3>\n\n\n\n<p>One especially crucial thing to be aware of is the potential for collisions between different versions of 3<sup>rd<\/sup> party client-side dependencies.&nbsp; Take Jquery for instance; many sites use this library, and there are many different versions.&nbsp; We need to ensure that, if our components are dependent on Jquery we do something to mitigate any conflicts between our components and the consuming application.<\/p>\n\n\n\n<p>There are many ways this can be accomplished, here are just a couple:<\/p>\n\n\n\n<ul><li>We can namespace our version of the library so that it is stored in MyApp.$ (just an example) and use that object exclusively to address Jquery in our components.&nbsp; This will ensure that \u2018$\u2019 is not overwritten within the consuming application.<\/li><li>We can exclude Jquery entirely and specify the library and the correct version as a dependency for the consuming app \u2013 this puts the onus on the consumer to ensure that they are including the appropriate version of the library prior to including our component(s).<\/li><\/ul>\n\n\n\n<p>There are likely more solutions for this issue, but you get the idea.&nbsp; The last thing we want is for a consumer to plug our component into their site and have things start breaking, so we need to be aware of all the ways this could potentially happen and do our best to solve in advance.<\/p>\n\n\n\n<h3>Conclusion<br><\/h3>\n\n\n\n<p>The ability to share components and their content between multiple applications is a powerful thing.&nbsp; It can go a long way towards optimizing the management of said components and enforce consistency across an organization\u2019s web properties.&nbsp; However, it also comes with challenges that need to be addressed, otherwise the exact functionality your client is asking you to deliver to optimize their processes could, in fact, do the opposite.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>An increasingly common use-case for enterprise web implementations is the need for components that support the ability to be displayed in context within a site, but also syndicated for consumption by third-party web applications.<\/p>\n","protected":false},"author":3,"featured_media":363,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[10,21,26,25],"_links":{"self":[{"href":"https:\/\/www.mavice.com\/blog\/wp-json\/wp\/v2\/posts\/319"}],"collection":[{"href":"https:\/\/www.mavice.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mavice.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mavice.com\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mavice.com\/blog\/wp-json\/wp\/v2\/comments?post=319"}],"version-history":[{"count":5,"href":"https:\/\/www.mavice.com\/blog\/wp-json\/wp\/v2\/posts\/319\/revisions"}],"predecessor-version":[{"id":372,"href":"https:\/\/www.mavice.com\/blog\/wp-json\/wp\/v2\/posts\/319\/revisions\/372"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mavice.com\/blog\/wp-json\/wp\/v2\/media\/363"}],"wp:attachment":[{"href":"https:\/\/www.mavice.com\/blog\/wp-json\/wp\/v2\/media?parent=319"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mavice.com\/blog\/wp-json\/wp\/v2\/categories?post=319"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mavice.com\/blog\/wp-json\/wp\/v2\/tags?post=319"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}