Guide to setting up a local development for Adobe Experience Manager, AEM. Covers important topics of local installation, Apache Maven, integrated development environments and debugging/troubleshooting. Development with Eclipse IDE, CRXDE Lite, Visual Studio Code, and IntelliJ are discussed.
Overview
Setting up a local development environment is the first step when developing for Adobe Experience Manager or AEM. Take the time to set up a quality development environment to increase your productivity and write better code, faster. We can break an AEM local development environment into four areas:
Local AEM instances
Apache Maven project
Integrated Development Environments (IDE)
Troubleshooting
Install local AEM Instances
When we refer to a local AEM instance, we are talking about a copy of Adobe Experience Manager that is running on a developer’s personal machine. All AEM development should start by writing and running code against a local AEM instance.
If you are new to AEM, there are two basic run modes can be installed: Author and Publish. The Authorrunmode is the environment that digital marketers use to create and manage content. When developing most of the time, you are deploying code to an Author instance. This allows you to create pages and add and configure components. AEM Sites is a WYSIWYG authoring CMS and therefore most of the CSS and JavaScript can be tested against an authoring instance.
It is also critical test code against a local Publish instance. The Publish instance is the AEM environment that visitors to your website interact with. While the Publish instance is the same technology stack as the Author instance, there are some major distinctions with configurations and permissions. The code must be tested against a local Publish instance before being promoted to higher-level environments.
Create a folder structure on your computer like the following:
~/aem-sdk
/author
/publish
Rename the QuickStart JAR to aem-author-p4502.jar and place it beneath the /author directory. Add the license.properties file beneath the /author directory.
Make a copy of the QuickStart JAR, rename it to aem-publish-p4503.jar and place it beneath the /publish directory. Add a copy of the license.properties file beneath the /publish directory.
Double-click the aem-author-p4502.jar file to install the Author instance. This starts the author instance, running on port 4502 on the local computer.
Double-click the aem-publish-p4503.jar file to install the Publish instance. This starts the Publish instance, running on port 4503 on the local computer.
NOTE
Depending on your development machine’s hardware, it may be difficult to have both an Author and Publish instance running at the same time. Rarely do you need to run both simultaneously on a local setup.
Using command line
An alternative to double clicking the JAR file is to launch AEM from the command line or create a script (.bat or .sh) depending on your local operating system flavor. Below is an example of the sample command:
Apache Maven is a tool to manage the build and deploy procedure for Java-based projects. AEM is a Java-based platform and Maven is the standard way to manage code for an AEM project. When we say AEM Maven Project or just your AEM Project, we are referring to a Maven project that includes all the custom code for your site.
All AEM Projects should be built off the latest version of the AEM Project Archetype: https://github.com/adobe/aem-project-archetype. The AEM Project Archetype provides a bootstrap of an AEM project with some sample code and content. The AEM Project Archetype also includes AEM WCM Core Components configured to be used on your project.
CAUTION
When starting a new project, it is a best practice to use the latest version of the archetype. Keep in mind that there are multiple versions of the archetype and not all versions are compatible with earlier versions of AEM.
In, the past addition of adobe-public Maven profile was needed to point nexus.adobe.com to download AEM artifacts. All AEM artifacts are now available via Maven Central and the adobe-public profile is not needed.
Set Up an Integrated Development Environment
An integrated development environment or IDE is an application that combines a text editor, syntax support, and build-tools. Depending on the type of development you are doing, one IDE might be preferable over another. Regardless of the IDE, it is important to be able to periodically push code to a local AEM instance in order to test it. It is important to occasionally pull configurations from a local AEM instance into your AEM project in order to persist to a source-control management system like Git.
Below are a few of the more popular IDEs that are used with AEM development with corresponding videos that show the integration with a local AEM instance.
NOTE
The WKND Project has been updated to default to work on AEM as a Cloud Service. It has been updated to be backwards compatible with 6.5/6.4. If using AEM 6.5 or 6.4, append the classic profile to any Maven commands.
When, using an IDE please make sure to check classic in your Maven Profile tab.
IntelliJ Maven Profile
Eclipse IDE
The Eclipse IDE is one of the more popular IDEs for Java™ development, in large part because it is open source and free! Adobe provides a plugin, AEM Developer Tools, for Eclipse to allow easier development with a nice GUI to synchronize code with a local AEM instance. The Eclipse IDE is recommended for developers new to AEM in large part because of the GUI support by AEM Developer Tools.
13:12 - Using the integrated debugging tools of Eclipse
IntelliJ IDEA
The IntelliJ IDEA is a powerful IDE for professional Java™ development. IntelliJ IDEA comes in two flavors, a free Community edition and a commercial (paid) Ultimate version. The free Community version of IntellIJ IDEA is sufficient for more AEM development, however the Ultimate expands its capability set.
In this video we’ll be taking a look at AEM development using the IntelliJ IDE. We’ll be using the Community Edition for this video. But if you have a license for the Ultimate, which is a commercial paid version, you can absolutely use that as well. So before we jump into IntelliJ, I’ll show you what I have setup here. So I am running an AEM instance on port 4502 that is a fresh install. So this only has the We.Retail site and no other custom installations. So in this video we’ll be using the wknd sites project as our code base and we’ll be building and installing that into our AEM instance. The last quick piece of setup that I want to go through is showing you how to update your settings at XML file for Maven to include the Adobe Public Repo. And the Adobe Public Repo contains all of the necessary libraries that you’re gonna need in order to build an AEM project. So at repo.adobe.com, it lists out the configuration needed for the Adobe Public Repo profile. So we can simply copy and paste this into our settings XML file. Open up the settings.xml. Mine is empty, I’ve actually just copied this from the Apache Maven website, so it has the bare-bone structure here. And what we’re gonna do is simply paste in the profile that we copied from repo.adobe.com. So let’s go ahead and just set our Adobe public profile to be the active profile and save our changes. So let’s start up IntelliJ and load in the wknd project. I’ve already cloned the wknd project into my code folder. So here’s our AEM guides of wknd project, including all the sub and even projects as well. Let’s fire up IntelliJ. We’re going to import our project because it is not yet an IntelliJ project, so we can’t simply open it. We want to select the base project folder. So we’ll select AEM - guides - wknd which contains all of these sub projects. It’s important that you select import projects from an external model and you pick Maven. Because this is a multi-module Maven project, my IntelliJ will be able to use this selection in order to properly extract all of the projects and set up the IntelliJ project properly. Since it is a multi-module Maven project, let’s search the project recursively to make sure we load all of these sub-projects. Just to show you really quickly under environment settings, we’re currently using the bundled Maven, if you’ve installed another version of Maven through Homebrew or some other means, you can feel free to use that. Especially if it is newer than the bundle Maven version. Under user settings file, it is pointing to our settings that XML file that we just updated with the Adobe public profile. The Adobe public profile is active by default, so this is checked here and we have some other ones that are provided by the wknd project. We’re gonna leave these unchecked, but we’ll be using these later on. So we are going to import the discovered projects. I’ll be using Java 8. This is the default. Let’s enable auto-import, so we don’t have to worry about sinking in Maven artifacts. IntelliJ will automatically detect if they’re missing and do it for us. Now, if we look at our project in IntelliJ, we see that we have our main reactor project here, along with all the sub projects, including core, which has our share bundle, our UI apps, which is our content project that deploys into the /apps folder, as well as UI content, which actually has the content that drives the wknd site. The last piece we’ll take a look at is over here on the right side, so under our Maven tab. IntelliJ will have inspected all of the Maven projects and sub projects and build out this tree, allowing us to interact with the different projects in different ways. So under profiles, we have all of the profiles, including the default active profile that we set, and then we have these other profiles that were provided by the wknd project that are going to allow us to install our artifacts to AEM in different ways. So auto-install bundle is going to install the OSGi bundle. So if we only make changes to that, we can use our auto-install bundle to deploy those. Auto-install package will install the content package before the project. Auto-install package publish will install the package to localhost for 503 if we have that running. Below that are all of the individual projects. We have our reactor project up here. So if we were to install this using our auto-install package, it would basically go through build all the projects, the OSGi bundle from core would get embedded into UI apps, the UI apps project would build its content project and get deployed into AEM, and the UI content project would build and deploy its content package in the AEM as well. We can also go and run these against individual projects. If we’re only working on our own bundle we could select auto-install bundle and just install the bundle through the core project. Likewise, we could do the same thing with UI apps and content if we don’t need to be installing our content package every time we could auto-install package and simply run it on the UI apps project. All right, so let’s try this out. Since we don’t have anything installed yet, let’s install everything at once and verify that it’s installed into our AEM instance. And for that we want to select auto-install package, which is going to install the package for UI apps as well as UI content like we discussed earlier. Now, we can simply run the install.
We’ll get some output here at the bottom of IntelliJ and we can head over to AEM and check to make sure that everything got installed. So let’s go ahead and go back to sites. We should have our wknd site here, so it looks great. Check out one of the article pages and everything is looking pretty good here. So we have all our content as well as our components. We can verify a few other things. So if we go to package manager, we can see that we have our AEM guides, wknd UI content as well as UI apps, which brought along our core components for us.
The OSGi console, system console bundles, let’s search for the wknd bundle and we can see that we have the bundle installed as well here and it is active. So everything looks great. We were able to load our project into IntelliJ and then build it and deploy it into our AEM author instance running on localhost for 502.
Let’s take a look at how we can use Maven profiles to deploy different artifacts to our local AEM instance. For this we’ll be making some changes to the byline component and they’ll fall into two categories. The first will be a change to the sling model, which is a Java implementation and deployed as part of the OSGi bundle, and the second is a change to the HDL render script, which is part of the UI apps package. So, let’s head to IntelliJ.
So we’ll want to open up the core project and navigate to the byline’s sling model implementation and we’ll be making a very simple change to this. All we’ll be doing is adding some static text to whatever get name returns. So we’ll be adding change from the sling model.
In order to deploy this change to our local AEM developer instance, we’re going to want to select auto-install bundle as our profile. And what this allows us to do is open up the core project and do an install from it. And this is going to deploy only the OSGi bundle to our AEM local developer instance. And I won’t go through and build all of the other projects and deploy those as well. So this is a great way to get your OSGi bundle out to your local AEM developer instance, so you can test out your functionality. Let’s head back to AEM, let’s refresh our page and there you go, you can see that we have our text that we added from the sling model post-fixed to the name.
Let’s do something very similar, but we’re going to be doing it via bylines HTML script, which is part of the UI apps project, which is deployed as a content package rather than a OSGi bundle.
Now that we have our byline HTML file open, we can make our change. I’ll simply add some text after the occupation and now we need to deploy it. So, similarly to our deployment of the OSGi bundle, we can use our profiles as well. So I’m gonna uncheck our auto-install bundle since we’re not installing a bundle and I’m gonna select auto-install package. And now I can navigate to the UI apps project and again do an install. And what this is gonna do is bundle up the UI apps project in its entirety and redeploy that out to our AEM instance.
All right, let’s scroll down and see if our changes were deployed. And here we go, we have our “a change from the HTL”, post-fixed it to the occupations list. So using these Maven profiles, we’re able to deploy changes from both the OSGi bundle, as well as the UI apps project out into our local AEM developer environment.
So now we’re gonna look at a slightly faster way to deploy changes from the UI apps project to our AEM instance. And this can apply to any project that is deployed as an AEM content package. So, for instance, UI apps or UI content. This is not applied to the core project, which is deployed as an OSGi bundle. All right, so we’re gonna take a look at repo and repo is just a little FTP-like tool that allows you to sync nodes or node trees in and out of AEM into your IntelliJ project. So this is actually a command line tool that is ID-diagnostic, but IntelliJ provides some really nice key bindings that make this very easy and efficient to use. So the first thing you’ll need to do is make sure that you have installed Repo. And this information can be found on the repo GitHub page. Since I’m on a Mac, I’ve used Homebrew to install repo.
So if I run repo -version, you can see I’m running version 1.4, but you should always try to use whatever the latest version of repo there is. So to integrate a repo with IntelliJ, the instructions are pretty straightforward. What you need to do is create a new external tool that simply points to the command line tool. And once you set up the external tools, you’ll just set up a few key mappings. So I’m gonna go through and quickly set this up on my local IntelliJ.
So back in IntelliJ, I can open my preferences, search for external tools and I can add a new external tool. So this would be a repo (put).
It’s gonna be sending. I’m gonna just assign it to a group called repo for organizational purposes. Here is our repo command. So this needs to be installed and available on your path and then we can copy in the argument that was provided in the documentation. So we’ll simply want to do this for all four commands.
And make sure you click Apply when you’re done.
The next thing we want to do is map these commands that we defined for our external tool to keyboard shortcuts. So this will make it very easy to invoke a repo from IntelliJ.
So I can select these and I can then right click on them to assign keyboard shortcuts. There are some suggested keyboard shortcuts provided in the repo documentation. However, you don’t have to use these, you can use any available keyboard shortcuts on your computer.
And then add a shortcut. And I actually like to use Ctrl + Command + Right Arrow. So this is kind of pushing it out of IntelliJ into AEM.
Now, after this, I’d like to do Ctrl + Command + Left Arrow. So this is kind of pulling it back in from the local AEM instance into my IntelliJ.
For repo status, Ctrl + Command + Up Arrow. You’ll find that some of these may be taken already, so you may have to remove them.
And for diff, let’s do Ctrl + Command + Down Arrow. So now that we have these key mapped, I can apply them hit. Hit okay, and there is one thing that we need to do. And this is outlined on the repo doc and that is creating a .repo file. And this tells repo what server and what credentials should be used to push and pull content to and from the AEM instance. So we’ll just copy this. And typically I like to put this at the root of my project. So it applies to any content package projects that are therein and pointing this to localhost for 502. So remember that if you are switching between AEM Author and AEM Publish, you may need to be changing this server around. The last thing that we’re gonna do is make sure that we ignore this file from git. So this is really kind of a developer setup file. So we want to make sure that we’re not committing this to source control. But for this we can simply edit the git ignore and add .repo to the git ignore list. So now we won’t be committing this accidentally to our git repository and causing problems for other developers. Now that we’ve done this, we can go to any content package project, navigate to anywhere under the JCR root and we can start invoking a repo from inside IntelliJ. So I’m gonna in and use it on the byline component. You can right-click on it and use the in-context menu here, so I can invoke repo status. So, as you can see, that is appears to be modified. And if we similarly do diff, we should be able to see what these changes are.
The real power of repo though, really comes from making changes in your IDE and pushing those out without having to do a full Maven build. For this, I’m gonna make a simple change to our violent HTML, sent via repo. Save our change here and we could again use the put command in the right-click menu, or when this file is active or selected, we can use our key mappings. So for this I mapped it to Ctrl + Command + Right Arrow, So I’m gonna tap that. So, as you can see it, it pushed only this file out to our local AEM instance at port 502. So let’s go ahead and verify that this happened.
And you can see we made our change here.
So keep in mind that we can make any change in our UI apps project. So we can make changes to the dialogue. So, for instance, I can change the title of this to be a dialogue change from repo, and we can even do interesting things like selecting top-level content tree roots so the byline component is selected here and I can actually push the entire sub-tree from IntelliJ out into our local AEM instance. So again, I can use my keyboard shortcut, of Ctrl + Command + Right Arrow. As you can see, since I had byline folder selected, it pushed that folder and everything under it out into AEM. So again, I can verify this by opening up the dialog and there we go, we have our dialogue title changed here.
Another extremely handy use for repo is syncing changes from AEM to our core project, so we can commit them into SEM. For example, it’s quite usual for at least a base configuration for an editable template to be maintained in source control. And this simply expedites the setup of new AEM instances that you might be deploying your code to. Editable templates are a great example of complex node structures that you probably don’t want to be managing entirely by hand and is much easier to manage via the AEM web UI.
So in this case, we’re going to be making a change to the list components policy. Let’s go ahead and just change the date format to be month then year.
So I’ve changed this policy and this is going to be stored under our comp wknd settings that we see in context-aware configuration. So we want to get this back into our IntelliJ project so we can commit it to SEM. So let’s check out how we can do that.
And we’ll want to go to the UI content project, which contains our content and configuration and sync that configuration back from our local AEM instance to our IntelliJ project. So we have our conf wknd in the CM folder and we have a series of folders here.
So one of the challenges is, it can be hard to understand where in the JCR those changes were persisted. So again we can use repo to help us understand exactly what we want to sync back in. So I can use my status, I’m using my shortcuts. So you can see that there are three new changes that are different between the definition of a comp wknd settings WCM in my IntelliJ project versus my local AEM instance. So here are those three nodes. So it looks like these were the three things that were changed when we updated the list policy, so we’re gonna want to sync these back in. We can simply select the policies node and again, using our shortcuts I’ll use Ctrl +Command + Left Arrow to pull the content back in from AEM to my IntelliJ.
And now I can check to make sure there’s no changes here. It looks like there are no changes, which is great, since I synced them in. We can do that again on the WCM node and it looks like we still need to sync the templates article page template. So you can go ahead and do the same thing using keyboard shortcut. We can get the no definitions from local AEM and save them to IntelliJ. So there we go, we’ve pulled those in and we can verify that everything is fine by going back to the WCM node and executing a repo status. And now we can tell that our state in our local AEM instance for this particular path is mirrored perfectly in IntelliJ and we could commit all these changes back into SEM and have a consistent experience as we deploy this out to new fresh AEM instances.
Next thing I’m gonna do is we can hook IntelliJ up to our AEM instance using a debugger. And this can be very helpful when you’re going through and trying to figure out what is going on in some AEM code. So for this we’re gonna have to restart AEM. I’m gonna head back and I’m gonna stop my local AEM instance, and I’ll wait for this to shut down.
And for this we’re gonna head over to our terminal window and we’re gonna start this up from the command line and we’re gonna do this because we want to pass some parameters to our jar file as we start it up.
So I’m in my AEM instance’s author folder, which contains my jar file. And I’m gonna start AEM using the following command. So what this does is it starts AEM in a mode that the IntelliJ debugger is able to hook up to, and the most important part here is that we are specifying this address. And this is gonna be the port number that we are going to connect IntelliJ up to our local AEM development environment with. So we need to remember our address 8888. Let’s go ahead and start our AEM instance up. And while we’re waiting for it to start up, we’ll head back to IntelliJ.
So we’re gonna add a new configuration. I’m gonna hit the plus sign and create a remote configuration here.
So I’m gonna call this AEM Debug.
It’s gonna be connecting to localhost, and this is where that port that we specified during startup comes in. So I’m gonna change this to 8888.
This is typically used for debugging Java code, but I like to set it at the root project level in case I have multiple projects that need debugging.
And with AEM Debug selected in my configuration, I can start debug mode. So upon successful connection, I will get this message here saying it’s connected to localhost port 888 and from here we can go into our Java code and put some debug breakpoints in. So again, I’ll just be using the byline component. And let’s go ahead and add a breakpoint to our get occupations method. I’ll head back to our article page, that has our byline component and refresh it. And because IntelliJ is hooked up to our local AEM instance, just notice that the byline implementation is under execution and stops at our break point here on line 56. And from here we can use the debugger in the usual manner.
We of course, have access to all the variables and we can even do interesting things like test expressions. So we can check to see what the resource is that is being processed. So we can see that it is the la-skateparks byline component.
All right, so I hope this video helps you develop for AEM a little bit more efficiently, using IntelliJ.
00:00 - Import Maven Project
05:47 - Build and deploy source code with Maven
08:17 - Push changes with Repo
14:39 - Pull changes with Repo
17:25 - Using the integrated debugging tools of IntelliJ IDEA
Visual Studio Code
Visual Studio Code has quickly become a favorite tool for front-end developers with enhanced JavaScript support, Intellisense, and browser debugging support. Visual Studio Code is open source, free, with many powerful extensions. Visual Studio Code can be set up to integrate with AEM with the help of an Adobe tool, repo. There are also several community-supported extensions that can be installed to integrate with AEM.
Visual Studio Code is a great choice for front-end developers who primarily write CSS/LESS, and JavaScript code to create AEM client libraries. This tool may not be the best choice for new AEM developers since node definitions (dialogs, components) need to be edited in raw XML. There are several Java™ extensions available for Visual Studio Code, however if primarily doing Java™ development Eclipse IDE or IntelliJ may be preferred.
04:03 - Push code changes with Repo command-line tool
08:29 - Pull code changes with Repo command-line tool
10:40 - Push code changes with aemfed tool
14:24 - Troubleshooting, Rebuild Client Libraries
CRXDE Lite
CRXDE Lite is a browser-based view of the AEM repository. CRXDE Lite is embedded in AEM and allows a developer to perform standard development tasks like editing files, defining components, dialogs, and templates. CRXDE Lite is not intended to be a full development environment but is effective as a debugging tool. CRXDE Lite is useful when extending or simply understanding product code outside of your code base. CRXDE Lite provides a powerful view of the repository and a way to effectively test and manage permissions.
CRXDE Lite should be used with other IDEs to test and debug code but never as the primary development tool. It has limited syntax support, no auto-complete capabilities, and limited integration with source control management systems.
Help! My code isn’t working! As with all development, there are times (probably many), where your code is not working as expected. AEM is a powerful platform, but with great power… comes great complexity. Below are a few high level-starting points when troubleshooting and tracking down issues (but far from an exhaustive list of things that can go wrong):
Verify Code Deployment
A good first step, when encountering an issue is to verify that the code has been deployed and installed successfully to AEM.
Check Package Manager to ensure that the code package has been uploaded and installed: http://localhost:4502/crx/packmgr/index.jsp. Check the time stamp to verify that the package has been installed recently.
If doing incremental file updates using a tool like Repo or AEM Developer Tools, check CRXDE Lite that the file has been pushed to the local AEM instance and that the file contents are updated: http://localhost:4502/crx/de/index.jsp
Check that the bundle is uploaded if seeing issues related to Java™ code in an OSGi bundle. Open the Adobe Experience Manager Web Console: http://localhost:4502/system/console/bundles and search for your bundle. Ensure that the bundle has an Active status. See below for more information related to troubleshooting a bundle in an Installed state.
Check the Logs
AEM is a chatty platform and logs useful information in the error.log. The error.log can be found where AEM has been installed: < aem-installation-folder>/crx-quickstart/logs/error.log.
A useful technique for tracking down issues is to add log statements in your Java™ Code:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
public class MyClass {
private final Logger log = LoggerFactory.getLogger(getClass());
...
String myVariable = "My Variable";
log.debug("Debug statement of myVariable {}", myVariable);
log.info("Info statement of myVariable {}", myVariable);
}
By default the error.log is configured to log INFO statements. If you want to change the log level, you can do so by going to Log Support: http://localhost:4502/system/console/slinglog. You may also find that the error.log is too chatty. You can use the Log Support to configure log statements for just a specified Java™ package. This is a best practice for projects, in order to easily separate custom code issues from OOTB AEM platform issues.
Bundle is in an Installed state bundle-active
All bundles (excluding Fragments) should be in an Active state. If you see your code bundle in an Installed state, then there is an issue that needs to be resolved. Most times this is a dependency issue:
In the above screenshot, the WKND Core bundle is an Installed state. This is because the bundle is expecting a different version of com.adobe.cq.wcm.core.components.models than is available on the AEM instance.
A useful tool that can be used is the Dependency Finder: http://localhost:4502/system/console/depfinder. Add the Java™ package name to inspect what version is available on the AEM instance:
Continuing with the above example, we can see that the version installed on the AEM instance is 12.2 vs 12.6 that the bundle was expecting. From there, you can work backwards and see if the Maven dependencies on AEM match the Maven dependencies in the AEM project. In, the above example Core Components v2.2.0 is installed on the AEM instance but the code bundle was built with a dependency on v2.2.2, hence the reason for the dependency issue.
AEM components must be backed by a Sling Model to encapsulate any business logic and ensure that the HTL rendering script remains clean. If experiencing issues where the Sling Model cannot be found, it may be helpful to check the Sling Models from the console: http://localhost:4502/system/console/status-slingmodels. This tells you if your Sling Model has been registered and which resource type (the component path) it is tied to.
Shows the registration of a Sling Model, BylineImpl that is tied to a component resource type of wknd/components/content/byline.
CSS or JavaScript Issues
For most CSS and JavaScript issues, using the browser’s development tools is the most effective way to troubleshoot. To narrow down the issue when developing against an AEM author instance, it is helpful to view the page “as Published”.
Open the Page Properties menu and click View as Published. This opens the page without the AEM Editor and with a query parameter set to wcmmode=disabled. This effectively disables the AEM authoring UI and makes troubleshooting/debugging front-end issues much easier.
Another commonly encountered issue when developing front-end code is old or outdated CSS/JS is being loaded. As a first step, ensure that the browser history has been cleared and if necessary start an incognito browsers or fresh session.
Debugging Client Libraries
With the different methods of categories and embeds to include multiple client libraries it can be cumbersome to troubleshoot. AEM exposes several tools to help with this. One of the most important tools is Rebuild Client Libraries which force AEM to recompile any LESS files and generate the CSS.
Dump Libs - Lists all the client libraries registered in the AEM instance. <host>/libs/granite/ui/content/dumplibs.html
Test Output - allows a user to see the expected HTML output of clientlib includes based on category. <host>/libs/granite/ui/content/dumplibs.test.html
Libraries Dependencies validation - highlights any dependencies or embedded categories that cannot be found. <host>/libs/granite/ui/content/dumplibs.validate.html
Rebuild Client Libraries - allows a user to force AEM to rebuild all the client libraries or invalidate the cache of client libraries. This tool is effective when developing with LESS as this can force AEM to recompile the generated CSS. In general, it is more effective to Invalidate Caches and then perform a page refresh versus rebuilding all the libraries. <host>/libs/granite/ui/content/dumplibs.rebuild.html
NOTE
If you are constantly having to invalidate the cache using the Rebuild Client Libraries tool, it may be worth it to do a one time rebuild of all client libraries. This may take around 15 minutes, but typically eliminates any caching issues in the future.