Sunday 14 April 2019

Push Source Faster with the Salesforce CLI and VS Code

Push Source Faster with the Salesforce CLI and VS Code

Introduction

When working with SalesforceDX scratch orgs and VS Code, deploying source is as simple as opening the command palette and choosing the correct command. If there are errors, these are captured in the problems view and I can simply click on the problem to open the file:

Not too arduous right? Actually, it can be, especially when I’ve been on a train or plane and done a bunch of offline work that I’m then trying to deploy. After about a thousand push, fix, repeat cycles, opening the menu and choosing an option seems slow.

Configuring the Default Build Task

Note: this isn’t the way you want to do it when pushing source to a scratch org - it is for the metadata API and it’s also a useful thing to understand. I’m trying to build some suspense really.

As I’ve written before, I can configure any shell command as the default build task in VS Code.

To set up source push as the default, I :

  • open up the command palette and choose ‘Tasks: Configure Default Build Task’
  • choose ‘Create tasks.json file from template'
  • choose ‘Other’

I then replace the contents of the tasks.json file with :

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "command": "sfdx",
            "args": [
                "force:source:push"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

and I can now run the push as the default build task using the key sequence SHIFT+COMMAND+B (on a Mac):

There’s one downside to this and it’s quite a biggie - the problems view is empty so I have to look at the command output to figure the problem and manually locate the problem file and line. Luckily I can solve this relatively easily (it requires regular expressions so obviously there’s a number of attempts to get this right) by adding a problem matcher to parse the output and find any errors:

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "command": "sfdx",
            "args": [
                "force:source:push"
            ],
            "problemMatcher": [
                {
                    "owner": "KAB-apex",
                    "fileLocation": [
                        "relative",
                        "${workspaceFolder}"
                    ],
                    "pattern": {
                        "regexp": "^(.*)  (.*) \\((\\d+):(\\d+)\\)$",
                        "file": 1,
                        "line": 3,
                        "column": 4,
                        "message": 2
                    }
                },
                {
                    "owner": "KAB-lc",
                    "fileLocation": [
                        "relative",
                        "${workspaceFolder}"
                    ],
                    "pattern": {
                            "regexp": "^(.*) \\s \\w*:(\\w*:)(\\d+),(\\d+):\\s(.*)$",
                            "file": 1,
                            "line": 3,
                            "column": 4
                    }
                }
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

Now the problems view is populated again, so I have the same functionality with shortcut to kick the deployment off:

The Easy Way

Replacing the default build task is something that I’ve been doing on most of my projects to wire in a node script that manages deployments via the Metadata API. In that scenario I didn’t have any other options, but in this case it felt like I was having to recreate a lot of things to replace standard functionality. It felt like I should be able to create a shortcut to the entry in the command palette, but every time I googled I only got results around binding keyboard shortcuts to tasks.

A long time after I’d given up, I was looking to create a regular keyboard shortcut and opened the menu Code -> Preferences -> Keyboard Shortcuts and absent-mindedly typed ‘SFDX’ into the resulting screen, probably because it reminded me of the command palette:

The set of SFDX commands appeared! Scrolling down I found the source push command, and hovering over this showed a ‘+’ button that allowed me to define a shortcut key sequence - I choose SHIFT+OPTION+P:

Having configured this, I can now push the source simply by pressing that key combination, and I haven't had to replace any of the standard functionality:

As mentioned earlier, I’ve looked for a way to do this a number of times and had no luck - why that is the case I don’t know, but at least I got there in the end! As long as I don’t think about how much time I could have saved, it’s fine.

Related Posts

 

Saturday 6 April 2019

Lightning Web Component Animated Progress Bar

Lightning Web Component Animated Progress Bar

Introduction

Lightning Web Components went GA in Spring 19, to the delight of some and consternation of others. Rather than a critique, which would be pretty short at the moment given how little real life usage I’ve had out of them, I decided to take one of my Aura Components (remember, Lightning Components are renamed Aura Components to avoid confusion with Lightning Web Components) and convert that to a Lightning Web Component.

The component in question is from my Animated Lightning Progress Bar blog post, which as the name suggests animates a progress bar from the current value to the desired value. 

Tracking Values

Properties of the Lightning Web Component annotated with @track annotation are tracked (no kidding!) by the framework and the contents of the component are automatically re-rendered when a tracked value changes. In this example I have one tracked property:

  • value - the current value being displayed in the progress bar

As mentioned in the original blog post, animating a progress bar is simply a matter of making small changes to the current value via a timer function, until it matches the desired value, and redrawing the progress bar every time the current value changes. By binding the progress bar element to the value property, every time I change it in JavaScript the progress bar is redrawn. Nice.

The other great thing about this is that I don’t have to use any special functions to read or write the value of the tracked property - I just use it or set it as I need to and the framework takes care of the rest, simply because of the annotation. I don’t think I’ll miss the component.get/set(‘v.<name>’) type functions that are liberally sprinkled over my Aura Component controllers.

Re-Animator

One aspect immediately flagged up as different - I’m using the standard  lightning-input component with an onchange handler to fire when the user changes the value. The change handler is called every time the user types something, rather than when they tab out etc. Initially I was starting the animation as soon as the change event was received, but if the user then continued typing it wasn’t the greatest experience. To solve this, I delayed taking any action until 300ms after the user last pressed a key, via the standard JavaScript setTimeout function. When the change handler fires, it clears any existing timeout and detects if the value input by the user has changed. If it has, a  timeout is scheduled for 300ms time to start the animation. If the user continues typing then the timeout is continually cleared and rescheduled for another 300ms time. When the user finally stops typing (or stops for 300ms!) the timer fires and the animation is started.

The example animation increments or decrements the current value until it matches the amount input by the user, decrementing being used if a desired value is entered that is smaller than the current value. Another standard JavaScript function, setInterval, is used to execute a function every 100ms that updates the current value.  Once the final value matches the current value, the interval is cancelled.

 

 

What’s Different?

There are a few differences compared to the Aura component:

  • As mentioned above, property/attribute access is much cleaner. I also don’t have to pollute my markup with declarations of attributes.
  • In the Aura Component when the timer function fired it was outside the framework lifecycle, so needed to use the $A.getCallback function. In Lightning Web Components there’s no need to do this, I can just treat it as any other asynchronous Javascript function. This is very much the experience that I’ve been having with Lightning Web Components - everything feels a lot closer to standard JavaScript rather than programming against a library or framework.
  • My event handlers don’t have to have a “c.” prefix, again it looks like I’ve defined a regular JavaScript function and am using it.
  • Only one JavaScript file! No more JavaScript controllers that delegate to helpers, or business logic striped across these two and a renderer.
  • To make the component available to the Lightning App Builder, I add a targets stanza to the XML metadata for the Lightning Web Component, again avoiding polluting my markup with information for the framework.

The Code

There are three elements to this component, available at the following Gists:

One More Thing

In true Columbo style, there’s one more thing to mention that you’ll see in the component markup. The ESLint for Lightning Web Components will complain about setTimeout and setInterval. As I am using them for good reason, I don’t need to hear any more of it’s whining. I can stop this by adding a comment before the line of code that it dislikes:

// eslint-disable-next-line @lwc/lwc/no-async-operation
let timeoutRef = setInterval(function() {…});

Related Posts