Adobe UXP: Things you need to know! #3 UXP Developer Tool

In this episode I’ll talk about the new UXP Developer Tool, that you’re going to use to load, reload, watch, debug and scaffold new UXP plugins from templates!

If you find this content useful, please consider supporting me – 2020 is a hell of a year. I don’t have a Patreon page, but I’ve got two fairly cheap plugins on the Photoshop Marketplace, ALCE (Advanced Local Contrast Enhancer) and Double USM (on sharpening). If you happen to buy them, please leave a positive rating/review, it would greatly help. Or, you can

If you cannot, or don’t want to, that’s OK anyway.
Stay safe and thanks! 🙏🏻

The whole series so far


The transcripted video looks weird, but I’m told it helps to have it anyway because it’s easier to translate to other languages. Apologies for the lack of punctuation and the sloppy syntax.

Hey I’m Davide and this is Adobe UXP things you need to know! Today I’m talking about the UXP Developer Tool. Which is what you use to load, reload, watch, debug and eventually package into a .ccx file your UXP plugin. So one thing to know among the things you need to know is that as opposed to CEP where you could just move or sim-link the folder of your extension into the directory whatever slash CEP slash extensions, with UXP this is not enough. Why? Because it’s the CCD app, the Creative Cloud Desktop app, that manages what plugin is loaded into what application. It has its own internal database to check against, so eventually it will move the plugin folder into whatever slash UXP slash whatever else, but you cannot do this manually, so it’s not enough. You need to use the UXP Developer Tool. So let’s install that: first head to the documentation website, which you know because you’ve watched my previous video, and there is this Developer Tool tab here that you will click and you can find the macOS installer and the Windows installer. When you install it and launch it the first time it will ask you to enable the “developer mode” and you need to be an administrator to do so. If your user isn’t you can always create a JSON file called settings.json and with this content: developer true, and put it into one of those two folders: one for Mac and for Windows. There is also in Photoshop and you should check this as well in the plugins tab this “Enable Developer Mode” checkbox, so with this you should be ready to go. And here is the UXP Developer Tool so let’s add an existing plugin. Which one? Well you know that in the documentation, in the community tab, there is this UXP for Photoshop sample repo code on GitHub, and then you can download the entire zip and you have all those beautiful plugins for you to test. I’ve already done that so I can go back to the UXP DevTool, click “Add existing plugin” and I can point to the manifest.json of the ui-kitchen-sync. You have to use the manifest.json to load the plugin not into Photoshop, but first into the UI, right? You must see on the left column the host application: Adobe Photoshop 22, which is Photoshop 2021, otherwise this won’t work, of course. So this version of Photoshop is currently running. Now that you have it here, you can explicitly load it and this should bring it up in Photoshop: here it is, the kitchen-sink; I think I showed you this in the first video maybe. This is the spectrum typography, then you have the widgets all the things you can add, the native elements, HTML events, and whatnot so this is not really about the kitchen-sink but the UXP DevTool. One thing that you can do is, after we have loaded a plugin, to reload it in case you have changed its source code. I should have it here in Atom so this is the heading, this thing that you’re seeing here, let me add some exclamation marks. And I’m going to save and those changes are not caught by default in the plugin you have to reload this so let’s click this three dot button again and click reload and sure enough you see that the changes have been applied, right? But it’s kind of boring to have to manually reload it each time you may want to watch it for changes, so with this each time that you change something in the source folder is going to be reloaded the plugin is going to be reloaded automatically for you so let me remove those exclamation marks, save again and back to Photoshop: sure enough they’ve been removed, right? Fine. So let me close this and another thing that you can do besides loading reloading watching and unwatching, so let me unwatch this, is to create a plug-in, scaffolding a plug-in. So let me do that: Create plug-in, you have to add name, let’s call this Test UXP plugin, and then you have to add an ID and this ID is given you by the Adobe Dev Console which is where you upload your plugin to for admission into the Adobe marketplace. You can change this later on so let me add zero-zero-zero-zero-zero here, right? Plugin version must be three numbers so 1.0.0 is fine the host application Photoshop okay and the version at least 22.0.0. Then you can select between two different templates: the ps-starter is the vanilla javascript one and then you have a React-based one, I’m going to show you the vanilla one. So select folder you have to enclose that in a new folder otherwise it would just throw the files in here so let me call this UXP Test Folder, and create that, right? Plugin’s been created successfully you have the toast, green toast here. Here it says that you will need to run additional commands from your terminal in order to install various dependencies, and this is true only if you are scaffolding a React plugin not a vanilla one: vanilla one is ready to go, right? So here we have it and so let’s load it in Photoshop. Plugin has been loaded successfully, and this is it. You can click populate layers and nothing happens, which is fine because this works when you have an open document. So, let me open this in Atom, it was UXP Test Folder, this here, and you see the code is very basic: and index.html and then there’s the JS and the manifest and this is the ID that you can always change later on as well as all the other data here, right? Okay, now that we have this plugin open we might want to debug it so let’s click Debug and this pops up this Chrome DevTool-like window. I say that it’s like a Chrome DevTool because it’s not fully-fledged, you see that there are a lot of things missing here: you cannot install other things for instance the React DevTool – yet might be possible in the future – but it works exactly as the Chrome DevTool: you have the Console with an error, and I’m going to show you why in a minute. And one thing that you can do which is quite helpful is to use the Console to experiment with the Photoshop API. Let me try to make this… Oh no, I cannot make the font size bigger, and this is one of the limitation of the Console as it is right now: some of the keyboard shortcuts don’t work. For instance you can clear the console with ctrl+L but you cannot use Command + for instance to change the font size. So what you can do is to use this as I said Console to experiment: so let’s say const photoshop equal require Photoshop I’m typing this a lot so I already have it here. And then you have the Photoshop object, for what? Well to play: photoshop, and then dot, and then you can see everything that you have the app, the core… So let me pick app and then you click dot and you just see what’s in there right? If you knew the documentation like the back of your hand you would know what everything here is. I don’t so I’m just, you know, picking things: the actionTree, so what is this No idea, let’s check this out. So it turns out that it’s an array of actionSets and each actionSet is an object that contains properties, such as the action array, and the action array in turn has actions with an index, with the name, and an id. Okay, so I’ve learned a new thing, right? What can I do with an action? I don’t know, let’s try this again. So, so the actionTree is an array so let me pick the first element in the array, so the one with index of 0, so this is an object that has an actions property; the actions is an array so let me pick the first one, again. If I click dot I see all the things that I can do: and I can get the index, I can get the name, I can play it so this looks promising. Let’s try this: play seems an action so probably it’s going to be a function so let’s add a couple of parentheses here and click this, and it says… First of all something happened, which is cool, the command make is not currently available so let me stop, and what is this? Probably the action which is this one, so the first actionSet, the first action wants to make a snapshot but I don’t have any document open so this breaks which is fine. The point of all that is that you can use the Console and the auto-completion in the Console to just experiment things you can always then go back to the actual documentation and which is here Photoshop API, the modules, and Photoshop and here you see the actionTree then you have a confirmation that it outputs an actionSets array and so on so forth… You can educate yourself in the documentation; I would say that it’s better to use the documentation and then test things in the Console or you can also use the other way around it’s probably a little bit more fun. Okay, so back to our original panel here: when we click this populate layers we saw that we have an error. Cannot read property layers of null, so let’s debug the error. In the code, which is here, we see that we have this sp-button and mind you the plugin uses Spectrum Components so sp-something. You have an sp-body with id of layers and body is not really a body is like a paragraph, right? So it’s styled, it changes the color depending on the theme so it’s light when the theme is dark and vice versa. It says no layers, does it? Yes, and when you click this button with id of btn-populate what happens is that you have a listener for the click event for this button populate that runs the showLayerNames function which is up here. he showLayerNames uh first stores into the app constant the Photoshop app objectm and then checks for the layers of the active document and then maps all the layers so this is an array, allLayers is an array, and it creates a new array running this function here function that takes the layer as an argument and outputs or returns the layer name and stick that array of layer names into this allLayerNames array and then sorts it with the sort method and when you have this sortedNames array, so this is an array it, changes the innerHTML of this layers element which is this sp.body here so sp-body is not going to be “no layers” anymore but it’s going to be what? A string created using these backticks with an unordered list, and then you use – this is all modern JavaScript, so you have the backtick string and then you can interpolate with the dollar and open and closed curly braces. You have the sortedNames array then you map the sortedNames array so you run this function for each one of the sorted names: you take the name as a parameter, and then you output for each one of those a string with a list item, with the name in it, and then eventually you have this array of list item strings, and then you join it. So eventually it is just one long string of list items, and then you close the unordered list. By the way if you remember in the last video I told – last video? Yeah the last video – I told you that there is no such a thing as an unordered list in UXP, reason why in this plugin they are adding specific styles to the list items because otherwise it won’t have it by default, right? So let’s check this out in Photoshop, I want to create a dummy document and let me duplicate the layers some times and click Populate Layers. And you see that you have the background, layer one, copy, copy two, copy three, right? So this is okay but I want to fix this error here ,so let’s debug that. One thing that you can do is in the Sources to add a breaking point right? So you click here, it’s the same with Chrome DevTool, I’m showing this to you just in case you’re not really familiar with it. So you see that we have this Uncaught Type Error: cannot read property layers of null. So let me close the document so that we have no document, so we are able to recreate the error. I’ve added this breaking point; am I watching the source code? I’m not, so let me watch this, so that each time that I change the source code it’s automatically reloaded right? Okay and this time you should be able to click Populate Layers and have an error output, and when I click the button you see that the app is paused on that breakpoint: and I can use the step-over, step-in, step-out buttons as usual, so let me step-in. Let me try to make this a little bit bigger, I have the app object and it breaks here and the error is: “cannot read property layers of null” right? So we have seen how to create a breaking point we’ve got the error so now let’s fix this. Of course it can’t read the property layer because we don’t have any active document. So let’s get back to Atom, index.js, I want to stick that outside of the function because this might be useful to have for all the functions as well. So I need to check whether this app activeDocument exists or not so if not if we have no app activeDocument then just return, right? Well actually let’s say let’s console log something: console.log no docs and then return. All right, so let’s save this, Populate Layers: no docs, right? So this works. So one thing that I want to mention in this template: you have the index, you have the html, you have JavaScript, the manifest, but also this watch dot shell that uses this UXP plug-in load command. So if you try this if you try running this it’s not going to work because this was made when, in a pre-release, we had this UXP command-line utility. So the UXP DevTool initially existed as a command-line utility then evolved with the UI which is more easy to use and with more features. I am told that the command-line utility which I like very much because it’s easier if you will to plug into npm scripts, especially when you’re building a larger project, I’m told that this is going to be released as well so it’s going to be updated and matched feature-wise with the UXP DevTool with the GUI. So eventually in the future, probably, you’re going to have the choice to use either the command-line utility or this UXP DevTool as we use it now. So what else? We have loaded, reloaded, watched, debugged, logs, well logs just opens the the Console and there’s the possibility to package that plugin into a .ccx file. If you don’t remember where the folder is you can Open Folder and then it shows you in Finder and what? You have these options with breaking point and start, and all right: this Advanced with the plugin build folder here it says path should be relative to the selected manifest.json file. So this is useful when you use React plugins and should be documented in the DevTool working with React here watching your plugin. So basically the idea is that you tell the UXP DevTool to load the plugin based on the source manifest file, but when you use React you very likely have Webpack running and Webpack is going to output the final product into a /dist folder with its own manifest so you can tell the UXP DevTool where to find that distribution manifest so you say something like /dist, like that and this is better so that the UXP can manage with the hot-reloading thing. I think. What else? Here you can find the UXP DevTool preferences with the service port this is the port through which the UXP DevTool connects with Photoshop, and then you can change the theme from light to dark and vice versa of course this is built with spectrum components so it’s quite nice. All right I think this wraps it up I hope you enjoyed this one and if you did please consider supporting me, I’ve even added a donation button in my website. Or you can purchase ALCE and Double USM in the Photoshop marketplace and if you happen to buy them please leave a positive rating or review which will always help very much. Okay, thanks for watching and see you in the next one. Bye!