Tweet |
Deploying Lightning Components - Go Big or Go Missing
Introduction
Another week, another discovery around Lightning Components. This week its around deployment of components via the Salesforce Metadata API. I currently use the Force CLI wherever possible, as it uses OAuth to access the target org rather than requiring credentials to be stored on disk where they are potentially at risk. The tool itself doesn’t affect the behaviour, but its the one that I’ll be using for the examples.
After a recent deployment, we found that we were missing a JavaScript element from the bundle which broke a component. I can’t take the credit for identifying the underlying issue - that was Justin Baidoo-Hackman, one of my colleagues on the BrightMedia team.
Example Component
The sample component for this post is actually an application. Its very simple, and just asks the user to press a button which outputs an alert:
The bundle contents are as simple as you would expect. The application markup:
<aura:application > <h1>Deployment Test Application</h1> <p>Click the button below to execute a controller method</p> <button onclick="{!c.clicked}">Click Me!!</button> </aura:application>
the controller:
({ clicked : function(component, event, helper) { helper.clicked(); } })
and finally the helper
({ clicked : function(component, event) { alert('You just clicked!'); } })
Deployment Process
I’m currently writing my Lightning Component code via the Developer Console (I know - I’m as surprised as you are!), which means that I have to retrieve them from the developer org and then deploy them to the target (usually customer) org. This is pretty easy with the Force CLI. First I login via the ‘force login’ command, which opens a browser window for me to login and authorise access to my org:
Once I have completed the login process, I can retrieve the Lightning Components metadata via the ‘force fetch’ command, specifying Aura as the metadata type to fetch:
This retrieves all of my Lightning Components and stores them in a metadata/aura subdirectory under my current directory.
To deploy the Lightning Components to my target org, I copy the components in question to a src/aura subdirectory and create a package.xml file describing what I want to deploy:
<?xml version="1.0" encoding="UTF-8"?> <Package xmlns="http://soap.sforce.com/2006/04/metadata"> <types> <members>*</members> <name>AuraDefinitionBundle</name> </types> <version>35.0</version> </Package>
and finally I deploy the components using the ‘force import’ command, specifying the src directory :
which all works fine.
Deploying Part of the Bundle
Obviously the deployment process that I use for real applications isn’t quite this simple, and I have a number of scripts to automate things. One feature that the scripts support is to deploy only those files that have been changed since the last deployment - when there are three or four thousand elements, you don’t want to deploy the whole lot each time - and it turns out that this was the cause of the broken component. The markup and controller had changed, but the helper hadn’t, and when only the changed files were deployed, the rest of the bundle disappeared.
To demonstrate this I copy just the application and controller, but not the helper, to a new subdirectory - srcgap (source with a gap - I’m so creative!) and execute the deployment again. Note that there are no issues and the number of successes is the same:
however if I execute my application again and click the button, I get a different result:
Looking in the developer console confirms that the bundle no longer contains a JavaScript helper.
A Bundle is a Single Metadata Component
I always find this type of behaviour unexpected when deploying, as these deployments are additive unless you specify a destructive changes file. The explanation, though, is simple - an AuraDefinitionBundle is a single metadata component, even though it encloses multiple files. So whatever I deploy replaces the existing bundle with that name, rather than merging the contents of the new component (the changed application and controller) with the contents of the existing component (the application, controller and helper).
At the risk of sounding like a UK politician, let’s be clear that this isn’t a bug - the metadata API is working in the intended way. The upshot of this, as the title of this post states, is that if you don’t go big and deploy the whole component, some of your code goes missing.
Related Posts
- Lightning Components - It's Inheritance, Jim, But Not As We Know It
- Lightning Components, Visualforce and SObject Parameters
- Lightning Component Events - Change Types with Care
- Lightning Component Events
- Lightning Components and Unobtrusive JavaScript
- Lightning Components and Custom Apex Classes
- Lightning Component Wrapper Classes
- Trailhead Unit - Handling Events with Client-Side Controllers