<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet href="https://lukesecomb.digital/rss/styles.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:atom="http://www.w3.org/2005/Atom">
    <id>https://lukesecomb.digital/</id>
    <title>Articles Feed | Luke Secomb</title>
    <updated>2026-03-03T12:39:05.995Z</updated>
    <generator>https://lukesecomb.digital/</generator>
    <author>
        <name>Luke Secomb</name>
        <email>rss@lukesecomb.digital</email>
        <uri>https://lukesecomb.digital/</uri>
    </author>
    <link rel="alternate" href="https://lukesecomb.digital/"/>
    <link rel="self" href="https://lukesecomb.digital/atom.xml"/>
    <subtitle>Various articles by Luke Secomb</subtitle>
    <icon>https://lukesecomb.digital/favicon.jpg</icon>
    <rights>Copyright 2026 Luke Secomb</rights>
    <entry>
        <title type="html"><![CDATA[Another site rebuild...]]></title>
        <id>https://lukesecomb.digital/blog/another-site-rebuild</id>
        <link href="https://lukesecomb.digital/blog/another-site-rebuild"/>
        <updated>2025-05-06T10:30:00.000Z</updated>
        <summary type="html"><![CDATA[test]]></summary>
        <content type="html"><![CDATA[<h2>Background</h2><p>After almost 10 years building websites, this site has been the one I've rebuilt the most. I'm never 100% happy with how it looks and what is on here, but today that all changes... maybe. (I'm sure this site will be rebuilt again in a couple years).</p><p>Years ago, as a soon-to-be university graduate eager for my first dev gig, I needed something eye-catching to land my first dev gig. Whether the site at the time helped in that or not, I managed to land a solid job a couple days before finishing up university. Even after securing my first web dev job, I continued redesigning, rebuilding and updating this site, with no real purpose but for something to point to when people asked what I did. It became a portfolio site for friends and family, and whoever else stumbled across it.</p><p>A couple years back I started up a separate site with a few tutorial/blog style posts. It purposely sat separate from this site as it was more informative and less "showcasey". These posts have been migrated to this site and now live <a rel="nofollow noreferrer" href=https://lukesecomb.digital/blog target=_blank>here</a>. Their old home was fine - nothing wrong with it - but after some thinking, it didn't really make sense having two separate sites.</p><h2>The spark</h2><p>The main driver to the new site design was a blog post I found late into the AM at the start of 2025, <a rel="nofollow noreferrer" href=https://localghost.dev/blog/this-page-is-under-construction/ target=_blank>This page is under construction: A love letter to the personal website</a>.</p><blockquote><p>If you take just one thing away from this article, I want it to be this: <strong>please build your own website</strong>. A little home on the independent web.</p></blockquote><p>Even though I'm relatively young and didn’t experience the GeoCities and MySpace revolution firsthand, I have still built my fair share of websites over the past 10yrs+. I can appreciate that a personal website can be more than just a portfolio site, it can be <em>anything</em> you want it to be.</p><h2>Maybe build your own site?</h2><p>I'd encourage anyone and everyone to build a personal site. Even if it's only to appreciate the art of building a website, HTML/CSS and maybe some JavaScript. Tools like <a rel="nofollow noreferrer" href=https://astro.build/ target=_blank>Astro</a> (this site is currently built with) or <a rel="nofollow noreferrer" href=https://11ty.dev/ target=_blank>11ty</a> are great places to start. It doesn't have to be fancy, it doesn't need RSS feeds, funky animations, light/dark mode switches. It could be a vanilla HTML page sharing a few thoughts about something you're passionate about, hobbies or just life.</p><p>Another approach would be to use tools like <a rel="nofollow noreferrer" href=https://wordpress.org/ target=_blank>Wordpress</a>, <a rel="nofollow noreferrer" href=https://webflow.com/ target=_blank>Webflow</a> or <a rel="nofollow noreferrer" href=https://www.squarespace.com/ target=_blank>SquareSpace</a>. These days it's fairly easy to get a simple site up and running without requiring prior development or design knowledge.</p><h2>Back to the spark</h2><p>With this spark lit, I embarked on rebuilding my portfolio site (again) - turning it into a more personal website. This site is now full of <a rel="nofollow noreferrer" href=https://lukesecomb.digital/photography target=_blank>photographs</a> from the last 20yrs+ (not <em>all</em> of them, but some of my favourites), <a rel="nofollow noreferrer" href=https://lukesecomb.digital/blog target=_blank>blog posts</a> I'd previously hosted elsewhere (and a home for new ones), and a more personalised spin on the previous content hosted on this site.</p><h2>Final thoughts</h2><p>I'm still not 100% sure on the direction I'll take this site, but we'll see where it goes. For now, enjoy the content here, and keep an eye out for future updates – you can subscribe via <a rel="nofollow noreferrer" href=https://lukesecomb.digital/rss target=_blank>RSS</a> if that’s your thing.</p>]]></content>
        <author>
            <name>Luke Secomb</name>
            <email>rss@lukesecomb.digital</email>
            <uri>https://lukesecomb.digital/</uri>
        </author>
        <published>2025-05-06T10:30:00.000Z</published>
        <media:thumbnail url="https://lukesecomb.digital/blog/another-site-rebuild/og.jpg"/>
        <media:content medium="image" url="https://lukesecomb.digital/blog/another-site-rebuild/og.jpg"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Local LWC Development with real @AuraEnabled method calls]]></title>
        <id>https://lukesecomb.digital/blog/local-lwc-development-with-aura-enabled-apex</id>
        <link href="https://lukesecomb.digital/blog/local-lwc-development-with-aura-enabled-apex"/>
        <updated>2025-01-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[test]]></summary>
        <content type="html"><![CDATA[<h2>Introduction</h2><p>This article explains how to call real <code>@AuraEnabled</code> Apex methods from your local development server. We will use <a href="https://lwc.garden/?utm_campaign=blog-lukesecomb-digital" target=_blank>LWC Garden</a> as our server of choice. However, this approach can also work within a vanilla LWR setup if required.</p><p>Let's begin with an example Apex class to get us started:</p><pre><code class=language-apex>public with sharing class AccountController {

  /**
   * @description Method to fetch Accounts by a list of Ids
   * @param accountIds Account Ids to query for
   * @return List of matching Accounts
   */
  public static List&lt;Account> getAccountsById(Set&lt;Id> accountIds) {
    return accountIds.size() == 0 ? new List&lt;Account>() : [
      SELECT Id, Name
      FROM Account 
      WHERE Id IN :accountIds
    ];
  }

  /**
   * @description Method to fetch Accounts by a list of Names
   * @param accountNames Account Names to query for
   * @return List of matching Accounts
   */
  public static List&lt;Account> getAccountsByName(Set&lt;String> accountNames) {
    return accountIds.size() == 0 ? new List&lt;Account>() : [
      SELECT Id, Name
      FROM Account 
      WHERE Name IN :accountNames
    ];
  }
}
</code></pre><h2>Folder Structure</h2><p>Here’s a quick look at the folder structure:</p><pre><code>.
├── __mocks__/
│   └── @salesforce/
│       └── apex/
│           ├── AccountController.js (or the following two files)
│           ├── AccountController.getAccountsById.js
│           └── AccountController.getAccountsByName.js
├── force-app/
│   └── main/
│       └── default/
│           ├── apex/
│           │   └── AccountController.cls
│           └── lwc/
│               └── accountManager/
│                   ├── accountManager.css
│                   ├── accountManager.html
│                   ├── accountManager.js
│                   └── accountManager.js-meta.xml
├── package.json
├── lwr.config.json (or lwc.config.json)
└── sfdx-project.json
</code></pre><blockquote><p>Depending on approach, you may only require a single mock file for the Apex class (e.g. <code>AccountController.js</code>) instead of one file per method. Checkout the <a href="https://lwc.garden/packages/apex?utm_campaign=blog-lukesecomb-digital" target=_blank><code>@lwc-garden/utils</code></a> documentation if you're unsure.</p></blockquote><h2>Configuration</h2><p>Before diving into calling real <code>@AuraEnabled</code> methods, let's review a simpler form of method mocking. Depending on your use case, this might be enough to get you running locally.</p><p>We'll focus on the vanilla approach for now, which requires creating a new JavaScript file for each Apex Method. If you'd prefer a single file per Apex class, checkout the <a href="https://lwc.garden/packages/apex?utm_campaign=blog-lukesecomb-digital" target=_blank><code>@lwc-garden/utils</code></a> documentation.</p><p>lwr.config.json</p><pre><code class=language-json>{
  "modules": [
    {
      "name": "@salesforce/apex/AccountController.getAccountsById",
      "path": "./__mocks__/@salesforce/apex/AccountController.getAccountsById.js"
    },
    {
      "name": "@salesforce/apex/AccountController.getAccountsByName",
      "path": "./__mocks__/@salesforce/apex/AccountController.getAccountsByName.js"
    }
  ]
}
</code></pre><p>This configuration maps standard on-platform imports to your local mock JavaScript files.</p><h2>Writing the Apex Mocks</h2><p>Now we'll configure our mocks:</p><pre><code class=language-js>// ./__mocks__/@salesforce/apex/AccountController.getAccountsById.js
export default function getAccountsById() {
  return [
    {
      Id: "001dL00000jNfdgQAC"
      Name: "Google Inc."
    },
    {
      Id: "001dL00000jOfdhQAC"
      Name: "Google Inc."
    }
  ]
}
</code></pre><pre><code class=language-js>// ./__mocks__/@salesforce/apex/AccountController.getAccountsByName.js
export default function getAccountsByName() {
  return [
    {
      Id: "001dL00000jNfdgQAC"
      Name: "Google"
    },
    {
      Id: "001dL00000jOfdhQAC"
      Name: "Microsoft"
    }
  ]
}
</code></pre><p>You may choose to add some smarts to your mocks if you wish. Here is an example:</p><pre><code class=language-js>// ./__mocks__/@salesforce/apex/AccountController.getAccountsById.js
const ACCOUNTS = [
  {
    Id: "001dL00000jNfdgQAC"
    Name: "Google"
  },
  {
    Id: "001dL00000jOfdhQAC"
    Name: "Microsoft"
  }
]

export default function getAccountsById({ accountIds }) {
  return ACCOUNTS.filter((item) => accountIds.contains(item.Id))
}
</code></pre><h2>Calling real <code>@AuraEnabled</code> Apex Methods</h2><p>To call real Apex methods, we need a local server to bypass browser-based CORS errors. We'll use <a rel="nofollow noreferrer" href=https://hono.dev/ target=_blank>Hono</a>, though other frameworks (e.g., Express, Koa, Fastify) can also work.</p><h3>Hono Configuration</h3><p>To get started install the following packages:</p><pre><code class=language-bash>pnpm add hono @hono/node-server
pnpm add -D @types/node tsx
</code></pre><p>Once installed, add a new entry to your <code>package.json</code> <code>"scripts"</code> object:</p><pre><code class=language-json>"scripts": {
  "run-server": "tsx watch server.ts"
},
</code></pre><p>Create a <code>server.ts</code> file to hold our Hono configuration:</p><pre><code class=language-ts>// server.ts
import { Hono } from 'hono'
import { cors } from 'hono/cors'
import { serve } from '@hono/node-server'

const app = new Hono()

app.use('/proxy', cors())

app.all('/proxy', async (c) => {
  const url = c.req.query('q')

  const res = await fetch(url, {
    method: c.req.method,
    headers: c.req.raw.headers,
    body: c.req.raw.body,
    duplex: 'half',
  })
  const headers = { ...res.headers }
  const newResponse = new Response(res.body, { headers })
  return newResponse
})

const port = 3003
console.log(`Server is running on http://localhost:${port}`)

serve({
  fetch: app.fetch,
  port,
})
</code></pre><p>To run the Hono server, run the <code>pnpm run-server</code> command we added above.</p><p>To test this is running correctly, open your browser and go to <a href="http://localhost:3003/proxy?q=https://example.com" rel="nofollow noreferrer" target=_blank>http://localhost:3003/proxy?q=https://example.com</a>. If you are greeted with some HTML, it means the server is running correctly.</p><h3>Editing the Apex Mocks</h3><p>For these mocks, we'll use the <a href="https://lwc.garden/packages/utils?utm_campaign=blog-lukesecomb-digital" target=_blank><code>@lwc-garden/utils</code></a> package to allow us to define all our methods within a single JavaScript file.</p><pre><code class=language-bash>pnpm add @lwc-garden/utils
</code></pre><p>Once installed, we will need to edit our <code>lwr.config.json</code> file to tell LWC Garden where to find our apex methods.</p><p>lwr.config.json</p><pre><code class=language-json>"hooks": [
  [
    "@lwc-garden/utils/resolvers/apex.ts",
    {
      "paths": ["__mocks__/@salesforce/apex/"]
    }
  ],
]
</code></pre><blockquote><p>For more information on <code>@lwc-garden/utils</code> configuration, including extra configuration for Static Resources and Custom Labels, checkout the <a href="https://lwc.garden/?utm_campaign=blog-lukesecomb-digital" target=_blank>LWC Garden</a> documentation.</p></blockquote><p>Now that we have our mapping configured, lets create our JavaScript file to call our <code>@AuraEnabled</code> apex.</p><p>Before we jump in, we'll need to find two things.</p><ol><li><code>SALESFORCE_URL</code>: This is your Experience Cloud BASE URL. e.g. <code>https://company--dev.sandbox.my.site.com/mycommunity</code></li><li><code>CLASS_NAME_ID</code>: This is a unique Id that is assigned to each Apex Class. This can be found by inspecting the request payload when calling the method on-platform.</li></ol><pre><code class=language-js>// __mocks__/@salesforce/apex/AccountController.js
const PROXY_BASE_URL = 'http://localhost:3003'
const WEBRUNTIME_URL = '/webruntime/api/apex/execute'

// TODO: REPLACE THIS
const SALESFORCE_URL = `https://company--dev.sandbox.my.site.com/mycommunity`

// TODO: REPLACE THIS
const CLASS_NAME_ID = '@udd/01p8r000008CmFZ'

const BASE_URL = `${PROXY_BASE_URL}/proxy?q=${SALESFORCE_URL}/${WEBRUNTIME_URL}`

const fetchHelper = async (methodName, params, isWire) => {
  const myHeaders = new Headers()
  myHeaders.append('Content-Type', 'application/json')
  myHeaders.append(
    'Cookie',
    'CookieConsentPolicy=0:1; LSKey-c$CookieConsentPolicy=0:1'
  )

  const raw = JSON.stringify(
    {
      namespace: '',
      classname: CLASS_NAME_ID,
      method: methodName,
      isContinuation: false,
      params,
      cacheable: false,
    }
  )

  const response = await fetch(
    `${BASE_URL}?language=en-US&asGuest=true&htmlEncode=false`,
    {
      method: 'POST',
      headers: myHeaders,
      body: raw,
      redirect: 'follow',
    }
  )

  const json = await response.json()

  if (json.cacheable) {
    return {
      data: json.returnValue,
      error: undefined,
    }
  } else {
    return json.returnValue
  }
}

export const getAccountsById = async (params) =>
  fetchHelper('getAccountsById', params)

export const getAccountsByName = async (params) =>
  fetchHelper('getAccountsByName', params)
</code></pre><h2>Wrapping up</h2><p>And thats it, boot up your local dev server using <code>npx @lwc-garden/core dev</code> and your apex methods will now be calling your actual Salesforce Org.</p>]]></content>
        <author>
            <name>Luke Secomb</name>
            <email>rss@lukesecomb.digital</email>
            <uri>https://lukesecomb.digital/</uri>
        </author>
        <published>2025-01-26T00:00:00.000Z</published>
        <media:thumbnail url="https://lukesecomb.digital/blog/local-lwc-development-with-aura-enabled-apex/og.jpg"/>
        <media:content medium="image" url="https://lukesecomb.digital/blog/local-lwc-development-with-aura-enabled-apex/og.jpg"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[SFDX: How to setup a Scratch Org]]></title>
        <id>https://lukesecomb.digital/blog/sfdx-how-to-setup-a-scratch-org</id>
        <link href="https://lukesecomb.digital/blog/sfdx-how-to-setup-a-scratch-org"/>
        <updated>2023-04-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[test]]></summary>
        <content type="html"><![CDATA[<p>How the heck do I set up a scratch org using sfdx? Well, you're in the right place.</p><p>Firstly, you will need to have SFDX (<a rel="nofollow noreferrer" href=https://developer.salesforce.com/tools/sfdxcli target=_blank>Salesforce CLI</a>) installed and VS Code. You will also need your own Salesforce DevHub instance setup (need a hand with setting up your dev hub? check out this <a rel="nofollow noreferrer" href=https://trailhead.salesforce.com/en/content/learn/modules/sfdx_app_dev/sfdx_app_dev_setup_dx target=_blank>trailhead unit</a>.</p><h2>Create a Salesforce DX Project</h2><p>The second step is to create a (SF)DX project.</p><pre><code class=language-shell>sf project generate -n YOUR_PROJECT_NAME
</code></pre><p><div>Replaces the deprecated <code>sfdx force:project:create</code> command.</div><h2>Auth your DevHub</h2><p>Next, we need to connect your DevHub with your new project</p><pre><code class=language-shell>sf org login web -d -r https://login.salesforce.com -a ALIAS_FOR_YOUR_DEV_HUB 
</code></pre><p><div>Replaces the deprecated <code>sfdx force:auth:web:login</code> command.</div><ul><li><code>-d</code> sets this as the default Dev Hub.</li><li><code>-r</code> sets the login URL for the org.</li><li><code>-a</code> sets this alias for the org.</li></ul><blockquote><p>If you have already auth'd, set your default username using <code>sf config set defaultdevhubusername=lukesfakeemail@force.com</code></p></blockquote><h2>Login To Sandboxes</h2><p>In addition to DebHubs, we can also connect to standard salesforce Sandboxes. This can be handy when it comes to pulling components into your scratch org</p><pre><code class=language-shell>sf org login web -r https://test.salesforce.com -a ALIAS_FOR_YOUR_SANDBOX
</code></pre><p><div>Replaces the deprecated <code>sfdx force:auth:web:login</code> command.</div><blockquote><p>Remember, don't use the <code>-d</code> flag. If you do, the CLI thinks the org is your Dev Hub, and then you'll see an error when you try to create a scratch org.</p></blockquote><p>If ~~<code>force:auth:web:login</code>~~ <code>sf org login web</code> isnt working, use ~~<code>sfdx force:auth:device:login</code>~~ <code>sf org login device</code> instead.</p><h2>Rename (add) Alias</h2><pre><code class=language-shell>sf alias set NEW_ALIAS_FOR_YOUR_SANDBOX=current@sandbox.user.com
sf alias set OLD_ALIAS_FOR_YOUR_SANDBOX=
</code></pre><p><div>Replaces the deprecated <code>sfdx force:alias:set</code> command.</div><h2>Logout of Sandboxes</h2><p>logout/remove the sandbox from the <code>sfdx force:org:list</code></p><pre><code class=language-shell>sf org logout -o ALIAS_FOR_YOUR_SANDBOX
</code></pre><p><div>Replaces the deprecated <code>sfdx force:auth:logout</code> command.</div><h2>Create your scratch org</h2><p>Now for the fun part, creating your scratch org.</p><blockquote><p>if you want to set the scratch org name, or adjust other config options, edit the <code>./config/project-scratch-def.json</code> file before progressing</p></blockquote><pre><code class=language-shell>sf org create scratch -v ALIAS_OF_YOUR_DEBHUB -f config/project-scratch-def.json -a ALIAS_FOR_SCRATCH_ORG -y 30 -w 10
</code></pre><p><div>Replaces the deprecated <code>sfdx force:org:create</code> command.</div><ul><li><code>-v</code> optional param to choose your DevHub (not needed if you have a default DevHub set)</li><li><code>-s</code> sets this as the default sratch org</li><li><code>-f</code> sets the location for the config file (to build the org)</li><li><code>-a</code> sets the alias for the scratch org</li><li><code>-y</code> sets the expiry to 30 days</li><li><code>-w</code> sets the wait time to 10mins</li><li><code>-e</code> edition to use (developer, enterprise, group, professional, partner-developer, partner-enterprise, partner-group, partner-professional)</li></ul><h3>View Scratch Org Config/Details</h3><pre><code class=language-shell>sf org display -o SCRATCH_ORG_ALIAS
</code></pre><p><div>Replaces the deprecated <code>sfdx force:org:display</code> command.</div><h3>Generate Password Scratch Org</h3><pre><code class=language-shell>sf force user password generate -u SCRATCH_ORG_ALIAS
</code></pre><p><div>Replaces the deprecated <code>sfdx force:user:password:generate</code> command.</div><h3>Delete Scratch Org</h3><pre><code class=language-shell>sf org delete scratch -o SCRATCH_ORG_ALIAS
</code></pre><p><div>Replaces the deprecated <code>sfdx force:org:delete</code> command.</div><h3>Assign Permission Set</h3><p>Before you can start pushing code, we have to set up some permission sets to allow us.</p><pre><code class=language-shell>sf org assign permset -n NAME_OF_PERMISSION_SET
</code></pre><p><div>Replaces the deprecated <code>sfdx force:user:permset:assign</code> command.</div><blockquote><p>most likely named <code>SalesConsoleUser</code> on default scratch orgs</p></blockquote><h3>Deploy code back to DevHub</h3><p>Deploy all of type</p><pre><code class=language-shell>sf deploy metadata -m ApexPage, ApexClasses, LightningComponentBundle -o ALIAS_FOR_YOUR_DEV_HUB
</code></pre><p><div>Replaces the deprecated <code>sfdx force:source:deploy</code> command.</div><p>Deploy specific component by path</p><pre><code class=language-shell>sf deploy metadata -p force-app/main/default/lwc/SINGLE_COMPONENT_NAME -o ALIAS_FOR_YOUR_DEV_HUB
</code></pre><p><div>Replaces the deprecated <code>sfdx force:source:deploy</code> command.</div><h2>Deploy code to a Sandbox</h2><blockquote><p>NOTE: These are the same deploy commands as above but with the extra <code>project</code> keyword in the command.</p></blockquote><p>Deploy all of type</p><pre><code class=language-shell>sf project deploy metadata -m ApexPage, ApexClasses, LightningComponentBundle -o ALIAS_FOR_YOUR_DEV_HUB
</code></pre><p><div>Replaces the deprecated <code>sfdx force:source:deploy</code> command.</div><p>Deploy specific component by path</p><pre><code class=language-shell>sf project deploy metadata -p force-app/main/default/lwc/SINGLE_COMPONENT_NAME -o ALIAS_FOR_YOUR_DEV_HUB
</code></pre><p><div>Replaces the deprecated <code>sfdx force:source:deploy</code> command.</div><h2>Retrieve / Fetch / Pull Data</h2><p>Retrieve all ApexClasses, ApexPages and LWC's</p><pre><code class=language-shell>sf project retrieve metadata -m ApexClass, ApexPage, LightningComponentBundle -o ALIAS_FOR_YOUR_DEV_HUB
</code></pre><p><div>Replaces the deprecated <code>sfdx force:source:retrieve</code> command.</div><p><a rel="nofollow noreferrer" href=https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_types_list.htm target=_blank>Metadata Ref</a></p><h2>Create Data</h2><p>Specify the Object type and the fields 'n values</p><pre><code class=language-shell>sf data create record -s Account -v "Name='Marriott Marquis' BillingStreet='780 Mission St' BillingCity='San Francisco' BillingState='CA' BillingPostalCode='94103' Phone='(415) 896-1600' Website='www.marriott.com'" -o SCRATCH_ORG_ALIAS
</code></pre><p><div>Replaces the deprecated <code>sfdx force:data:record:create</code> command.</div><h4>Export Data</h4><p>Using SQL to JSON data</p><pre><code class=language-shell>sf data export tree -q "SELECT Name, BillingStreet, BillingCity, BillingState, BillingPostalCode, Phone, Website FROM Account WHERE BillingStreet != NULL AND BillingCity != NULL and BillingState != NULL" -d ./data -o SCRATCH_ORG_ALIAS
</code></pre><p><div>Replaces the deprecated <code>sfdx force:data:tree:export</code> command.</div><h4>Import Data</h4><pre><code class=language-shell>sf data import tree -f data/Account.json
</code></pre><p><div>Replaces the deprecated <code>sfdx force:data:tree:import</code> command.</div><h2>Create an Apex Class</h2><pre><code class=language-shell>sf apex generate class -n YourClassName -d force-app/main/default/classes
</code></pre><p><div>Replaces the deprecated <code>sfdx force:apex:class:create</code> command.</div><h2><code>config/project-scratch-def.json</code></h2><p>Disable Lightning Experience caching</p><pre><code class=language-json>"settings": {
  "orgPreferenceSettings": {
    "s1EncryptedStoragePref2": false
  }
}
</code></pre><blockquote><p>Disabling secure and persistent browser caching has a significant negative performance impact on Lightning Experience. Always enable the setting in production orgs.</p></blockquote><h2>Useful Links</h2><ul><li><a rel="nofollow noreferrer" href=https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_types_list.htm target=_blank>Salesforce Metadata Ref</a></li><li><a rel="nofollow noreferrer" href=https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_top.htm target=_blank>Salesforce CLI (<code>sf</code>/<code>sfdx</code>)</a></li></ul>]]></content>
        <author>
            <name>Luke Secomb</name>
            <email>rss@lukesecomb.digital</email>
            <uri>https://lukesecomb.digital/</uri>
        </author>
        <published>2019-12-09T00:00:00.000Z</published>
        <media:thumbnail url="https://lukesecomb.digital/blog/sfdx-how-to-setup-a-scratch-org/og.jpg"/>
        <media:content medium="image" url="https://lukesecomb.digital/blog/sfdx-how-to-setup-a-scratch-org/og.jpg"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Lightning Web Components: Custom Nested Components]]></title>
        <id>https://lukesecomb.digital/blog/lwc-nested-components</id>
        <link href="https://lukesecomb.digital/blog/lwc-nested-components"/>
        <updated>2023-03-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[test]]></summary>
        <content type="html"><![CDATA[<p>Lightning Web Runtime, or LWR for short was released back in <a href="https://help.salesforce.com/s/articleView?id=release-notes.rn_experiences_developers_lwr.htm&release=230&type=5" rel="nofollow noreferrer" target=_blank>Spring 21 (v51.0)</a>. Even before the release of LWR, most developers dreamed of being able to build custom nested components. We could see that OOTB (Out Of The Box) components could use them (see Tabs component).</p><p>Salesforce recently released the ability to build custom LWCs with child <code>&lt;slot/></code>'s, to allow nesting of components. Nested LWCs allow you to compose multiple components together into a single component. The child components maintain their own life cycle and can communicate with each other through events, making it easy to create flexible and dynamic apps.</p><blockquote><p>Before continuing, Aura based Communities are (sadly) not supported. So if you're currently using them it might be time to make the switch to LWR.</p></blockquote><h2>Code Example</h2><p>Enough talk, lets jump into the code and see the magic happen.</p><h3>HTML</h3><p>We'll start by creating the HTML template to hold our <code>&lt;slot/></code>'s.</p><pre><code class=language-html>&lt;template>
  &lt;template if:false={isAura}>
    &lt;div class="container">
      &lt;div>
        &lt;slot name="region1">&lt;/slot>
      &lt;/div>
      &lt;div>
        &lt;slot name="region2">&lt;/slot>
      &lt;/div>
      &lt;div>
        &lt;slot name="region3">&lt;/slot>
      &lt;/div>
    &lt;/div>
  &lt;/template>
&lt;/template>
</code></pre><h3>JavaScript</h3><p>Now lets have a look at the JavaScript. The important part (or magic) here is the <code>@slot</code> definitions in the comment directly above the LWC export. Without these definitions, the dynamic components will not work.</p><p>The <code>isAura</code> check also ensures this component shows a warning in the experience builder when it is being used from within an Aura based community.</p><pre><code class=language-javascript>import { LightningElement } from 'lwc'

/**
 * @slot region1
 * @slot region2
 * @slot region3
 */
export default class NestedLWCs extends LightningElement {
  get isAura() {
    return window['$A'] !== undefined && window['$A'] !== null
  }
}
</code></pre><h3>Metadata XML</h3><p>Make sure your <code>.xml</code> file is setup to be available in the experience builder. The key values are setting <code>isExposed</code> to <code>true</code> and including both <code>lightningCommunity__Page</code> and <code>lightningCommunity__Default</code> as <code>targets</code>.</p><pre><code class=language-xml>&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
  &lt;apiVersion>57.0&lt;/apiVersion>
  &lt;isExposed>true&lt;/isExposed>
  &lt;masterLabel>Nested LWCs&lt;/masterLabel>
  &lt;description>Nested LWC magic&lt;/description>
  &lt;targets>
    &lt;target>lightningCommunity__Page&lt;/target>
    &lt;target>lightningCommunity__Default&lt;/target>
  &lt;/targets>
&lt;/LightningComponentBundle>
</code></pre><h2>Experience Builder</h2><p>Now lets open up the Experience Builder and see our custom LWC in action.</p><p><img alt="Experience Builder: Dragging our custom LWC onto the page" src=https://lukesecomb.digital/_astro/nested-lwc-1.Bn2aedvP_Z1oF6CW.webp></p><p>We can also nest components within other nested components. I am not aware of any limitation here. I was able to place up to 10 levels deep without any issues, noting theses are very barebones test LWCs. More complex LWCs may start affecting performance.</p><p><img alt="Experience Builder: Dragging our custom LWC onto the page" src=https://lukesecomb.digital/_astro/nested-lwc-2.UO-odwl3_20lt0D.webp></p><h2>Wrapping Up</h2><p>In summary, nested LWCs provide a powerful and flexible way for developers to create custom components that can be composed of multiple other components, making it easier to build dynamic and reusable apps on the Experience Cloud platform.</p>]]></content>
        <author>
            <name>Luke Secomb</name>
            <email>rss@lukesecomb.digital</email>
            <uri>https://lukesecomb.digital/</uri>
        </author>
        <published>2023-03-20T00:00:00.000Z</published>
        <media:thumbnail url="https://lukesecomb.digital/blog/lwc-nested-components/og.jpg"/>
        <media:content medium="image" url="https://lukesecomb.digital/blog/lwc-nested-components/og.jpg"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Lightning Web Components: Custom Mixins]]></title>
        <id>https://lukesecomb.digital/blog/lwc-custom-mixins</id>
        <link href="https://lukesecomb.digital/blog/lwc-custom-mixins"/>
        <updated>2023-03-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[test]]></summary>
        <content type="html"><![CDATA[<p>Mixins (or Abstract subclasses) are templates for classes that allow us to write generic functionality to be reused. Given the nature of classes, it is not possible to have more than one superclass. Mixins allow us to pass the base class as a property and unlock nested inheritance.</p><h2>JavaScript Mixin Usage</h2><p>Before we dive into an LWC example, lets look at how we can use mixins in a plain javascript environment.</p><p>Firstly, we must create a mixin function that our classes can use. This should be a piece of generic functionality that multiple classes can utalise.</p><pre><code class=language-javascript>// A simple Mixin method
// adds the `windowSize()` method to classes that implement this mixin
export const WindowSizeMixin = (BaseClass) =>
  class extends BaseClass {
    get windowSize() {
      return {
        width: window.innerWidth,
        height: window.innerHeight,
      }
    }
  }
</code></pre><pre><code class=language-javascript>import { WindowSizeMixin } from './windowSizeMixin'

// Implementing the `WindowSizeMixin` gives us access to the
// `this.windowSize` getter
class Header extends WindowSizeMixin(BaseClass) {
  getWindowSize() {
    return this.windowSize
  }
}
</code></pre><p>In the above example, calling the <code>getWindowSize()</code> function on our Header class will return the object defined in the <code>WindowSizeMixin</code>.</p><h2>LWC Mixin Usage</h2><p>Now we have a basic understanding of how mixins work in JavaScript, lets look at how the concept applies to LWC. Using mixins in LWC is almost identical with one difference, your <code>BaseClass</code> should be <code>LightningElement</code> (or another class that has extended <code>LightningElement</code>).</p><p>We'll assume the same above mixin source code that we used above (<code>WindowSizeMixin</code>) but instead our implementation will be a LWC component.</p><pre><code class=language-javascript>// don't forget to import LightningElement, we need to extend it as our base class
import { LightningElement } from 'lwc'

// assume our mixin has been created as a separate LWC to be used by multiple components
import { WindowSizeMixin } from 'c/windowSizeMixin'

// LWC expects a default export of our `LightingElement` extended component
export default class Header extends WindowSizeMixin(LightningElement) {
  getWindowSize() {
    // available via the WindowSizeMixin
    return this.windowSize
  }
}
</code></pre><h2>Stacking Mixins</h2><p>The beauty of mixins is that you can use more than one. This can be useful for creating smaller snippet mixins for similar functionality that is used across multiple LWCs.</p><p>Lets have a quick look at an example. We will create another mixin method.</p><pre><code class=language-javascript>export const DateMixin = (BaseClass) =>
  class extends BaseClass {
    // a function that returns the current date as an object
    getDate() {
      const date = new Date()
      return {
        day: date.getDate(),
        month: date.getMonth() + 1,
        year: date.getFullYear(),
      }
    }
  }
</code></pre><p>Lets update our LWC example from above to include the new <code>DateMixin</code>.</p><pre><code class=language-javascript>// don't forget to import LightningElement, we need to extend it as our base class
import { LightningElement } from 'lwc'

// assume our mixins have been created as a separate LWC to be used by multiple components
import { WindowSizeMixin } from 'c/windowSizeMixin'
import { DateMixin } from 'c/dateMixin'

// LWC expects a default export of our component
// we can stack mixins here
export default class Header extends DateMixin(
  WindowSizeMixin(LightningElement)
) {
  getWindowSize() {
    // available via the WindowSizeMixin
    return this.windowSize
  }
  getCurrentDate() {
    // available via the DateMixin
    return this.getDate()
  }
}
</code></pre><h2>Using <code>@wire</code> in a Custom Mixin</h2><p><a rel="nofollow noreferrer" href=https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.data_wire_service_about target=_blank><code>@wire</code></a> is a service that streams immutable data to the component. This is heavily used in on platform development and a must when it comes to building dynamic components.</p><p>Lets have a look at a simple example mixin that uses the standard <a rel="nofollow noreferrer" href=https://developer.salesforce.com/docs/component-library/documentation/en/lwc/reference_wire_adapters_record target=_blank><code>getRecord</code></a> wire method.</p><pre><code class=language-javascript>import { wire } from 'lwc'
import { getRecord } from 'lightning/uiRecordApi'

export const AccountWireMixin = (BaseClass) =>
  class extends BaseClass {
    // explicitly not setting recordId so that the consuming
    // component can choose how it wishes to implement it (e.g @api, get/set)
    // recordId

    // this can be dynamically changed by the implementing class if needed
    // this array acts as a default field list
    fieldRef = ['Account.Id', 'Account.Name', 'Account.Phone']

    @wire(getRecord, {
      recordId: '$recordId',
      fields: '$fieldRef',
    })
    wiredGetRecord(response) {
      // you can choose to either set the data to a variable for you component to consume
      // or fire off a function that your consuming component can override.
      // for this example, we will call a method
      this.handleWiredAccount(response)
    }

    /**
     * This method should be overriden by the consuming component
     */
    handleWiredAccount = (response) => {
      const { error, data } = response

      if (error) {
        // TODO: handle errors
      } else if (data) {
        // TODO: handle success
      }
    }
  }
</code></pre><p>We can update our above example and stack the <code>AccountWireMixin</code> on top.</p><pre><code class=language-javascript>// don't forget to import LightningElement, we need to extend it as our base class
import { LightningElement } from 'lwc'

// assume our mixins have been created as a separate LWC to be used by multiple components
import { WindowSizeMixin } from 'c/windowSizeMixin'
import { DateMixin } from 'c/dateMixin'
import { AccountWireMixin } from 'c/accountWireMixin'

// LWC expects a default export of our component
// we can stack mixins here
export default class Header extends AccountWireMixin(
  DateMixin(WindowSizeMixin(LightningElement))
) {
  // ... existing code

  // override the shell method defined in the AccountWireMixin
  handleWiredAccount = (response) => {
    const { error, data } = response

    if (error) {
      // TODO: handle errors
      console.error('Oh no, something went wrong ', error)
    } else if (data) {
      // TODO: handle success
      console.log('We have account data, yay ', data)
    }
  }
}
</code></pre><h2>Wrapping up</h2><p>In conclusion, mixins are an incredibly useful tool in LWC development. They allow us to write generic, reusable functionality that can be shared between multiple components. By stacking multiple mixins, we are able to compose complex components from smaller, focused mixins. Mixins help keep our code DRY (Don't Repeat Yourself) and maintainable.</p>]]></content>
        <author>
            <name>Luke Secomb</name>
            <email>rss@lukesecomb.digital</email>
            <uri>https://lukesecomb.digital/</uri>
        </author>
        <published>2023-02-26T00:00:00.000Z</published>
        <media:thumbnail url="https://lukesecomb.digital/blog/lwc-custom-mixins/og.jpg"/>
        <media:content medium="image" url="https://lukesecomb.digital/blog/lwc-custom-mixins/og.jpg"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Salesforce Trekken: Salesforce CMS Migration Tool]]></title>
        <id>https://lukesecomb.digital/blog/salesforce-trekken-cms-migration-tool</id>
        <link href="https://lukesecomb.digital/blog/salesforce-trekken-cms-migration-tool"/>
        <updated>2023-01-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[test]]></summary>
        <content type="html"><![CDATA[<p><img alt="Salesforce Trekken: Banner" src=https://lukesecomb.digital/_astro/banner.DbjOpuRQ_ZRKL2t.webp></p><p>The Salesforce CMS data migration experience is lacking. There is no bulk export, and there is no sorting/filtering of content and you are sent an email link instead of being able to directly download the zip file.</p><p>Salesforce Trekken aims to rethink the Salesforce CMS migration experience. Using modern web technologies and thoughtful a user experience, migrating Salesforce CMS data has never been easier.</p><h2>How does it work?</h2><p>Salesforce Trekken allows users to authenticate using one of two methods:</p><ul><li>The <a rel="nofollow noreferrer" href=https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm target=_blank>sfdx cli</a></li><li>Access Token (and Instance URL)</li></ul><p>The <a rel="nofollow noreferrer" href=https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_rest.htm target=_blank>Salesforce REST API</a> is used to fetch CMS Channels and the CMS Content after a specific channel has been selected.</p><h2>Features</h2><ul><li>Multiple Authentication Methods (<code>sfdx cli</code> or ACCESS_TOKEN)</li><li>Channel Selection: Choose the right CMS Channel to export data from</li><li>Feature Rich Export Table</li><li>Bundled Zip file export, ready to be imported into your target org.</li></ul><h2>Walkthrough</h2><h4>Select Your Authentication Method</h4><p><img alt="Salesforce Trekken: Select Authentication Method Screenshot" src=https://lukesecomb.digital/_astro/authentication.DwLJiE0v_ZcBasc.webp></p><h4>Select An Org</h4><p><img alt="Salesforce Trekken: Select An Org Screenshot" src=https://lukesecomb.digital/_astro/select-an-org.BOdVUIQt_lH3yY.webp></p><h4>Select A CMS Channel</h4><p><img alt="Salesforce Trekken: Select A CMS Channel Screenshot" src=https://lukesecomb.digital/_astro/select-channel.BcXXdPZy_sT13r.webp></p><h4>Search/Filter/Sort and Select Content</h4><p><img alt="Salesforce Trekken: Select CMS Content Screenshot" src=https://lukesecomb.digital/_astro/select-cms-content.Xkh95X5k_2atFSD.webp></p><h4>Select An Output Folder</h4><p>and whether to include images as part of the export.</p><p><img alt="Salesforce Trekken: Select An Output Folder Screenshot" src=https://lukesecomb.digital/_astro/select-output-folder.Bgv4cePh_175oeB.webp></p><h4>Success</h4><p>Either open the source folder or start over.</p><p><img alt="Salesforce Trekken: Successful Export Screenshot" src=https://lukesecomb.digital/_astro/success.B7Hf4rDi_4EvCI.webp></p><p>Your content is now ready to import into your target org.</p><blockquote><p>If you are working with <code>cms_image</code>, make sure you import your images zip file first</p></blockquote><h2>Closing</h2><p>Now you've seen the powers of Salesforce Trekken and its improved user experience compared to the standard salesforce experience.</p><p>Want to find out more and/or download, checkout the <a rel="nofollow noreferrer" href=https://trekken.lukesecomb.digital/ target=_blank>Salesforce Trekken site</a></p>]]></content>
        <author>
            <name>Luke Secomb</name>
            <email>rss@lukesecomb.digital</email>
            <uri>https://lukesecomb.digital/</uri>
        </author>
        <published>2023-01-13T00:00:00.000Z</published>
        <media:thumbnail url="https://lukesecomb.digital/blog/salesforce-trekken-cms-migration-tool/og.jpg"/>
        <media:content medium="image" url="https://lukesecomb.digital/blog/salesforce-trekken-cms-migration-tool/og.jpg"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Spotify Playlist Backup using Github Actions]]></title>
        <id>https://lukesecomb.digital/blog/spotify-playlist-backup-using-github-actions</id>
        <link href="https://lukesecomb.digital/blog/spotify-playlist-backup-using-github-actions"/>
        <updated>2022-11-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[test]]></summary>
        <content type="html"><![CDATA[<p>Platforms come and go, and Spotify most likely wont be around forever. What would you do if you woke up tomorrow and Spotify was gone. I know I wouldn't be too happy, after spending countless hours carefully curating well over 200 playlists.</p><p>So, to save your playlists from being erased from the internet forever, lets create a small python script to back them up. This post outlines the steps to configue and a basic walkthrough of my <a rel="nofollow noreferrer" href=https://github.com/lukethacoder/spotify-playlist-backup target=_blank>spotify-playlist-backup</a> project.</p><p><a rel="nofollow noreferrer" href=https://github.com/lukethacoder/spotify-playlist-backup target=_blank><img alt="spotify-playlist-backup project banner" src=https://github.com/lukethacoder/spotify-playlist-backup/raw/main/docs/banner.jpg></a></p><h2>Spotify Developer Application</h2><p>Before we can jump into the code we need to setup our own <a rel="nofollow noreferrer" href=https://developer.spotify.com/dashboard/applications target=_blank>Spotify Developer Application</a>. This will require you to have a Spotify account (a free account should work). Once logged in, create a new application and save the <code>CLIENT_ID</code> and <code>CLIENT_SECRET</code> for later. Make sure you set <code>http://localhost:3000/callback</code> as a return url for your application.</p><p><img alt="spotify dashboard application page" src=https://github.com/lukethacoder/spotify-playlist-backup/raw/main/docs/spotify-developer-app-dashboard.jpg></p><h2>Into the code</h2><p>Clone the <a rel="nofollow noreferrer" href=https://github.com/lukethacoder/spotify-playlist-backup target=_blank>spotify-playlist-backup</a> repo and create a new <code>.env</code> file. Copy and paste in the following code snippet and replace the values with your configuration.</p><pre><code># .env file
# Values from your Spotify Developer Application
SPOTIFY_CLIENT_ID=laboriselitutenimdoculpa
SPOTIFY_CLIENT_SECRET=laboriselitutenimdoculpa

# Your Spotify Username
SPOTIFY_USERNAME=12345678910

# Your Spotify Password
SPOTIFY_PASSWORD=abcdefghijklmnopqrstuvwxyz

# Comma separated list of usernames of playlist authors.
# This allows you to back up other peoples playlists (that you follow) if you want.
# if left blank, all of your followed/created playlists will be backed up.
SPOTIFY_OWNER_IDS=snoopdogg,drdre,spotify
</code></pre><h2>Run the script</h2><p>Once you have setup the <code>.env</code> file, you're ready to run the script.</p><pre><code class=language-shell>python script.py
</code></pre><blockquote><p>This assumes you already have python installed.</p></blockquote><p>Yes, it is that easy. After running the above script you will have a local copy of all your playlist data in beautiful <code>json</code> format.</p><h2>Github Action setup</h2><p>Before your Github Action will run successfully, you must setup the above <code>.env</code> variables correctly within the repo.</p><blockquote><p>Make sure your fork is a private repository</p></blockquote><p><img alt="Github actions dashboard screenshot" src=https://github.com/lukethacoder/spotify-playlist-backup/raw/main/docs/github-actions-secrets-setup.jpg></p><h2>Cron Job</h2><p>Lets go one step further and set our Github Action to run once a week. By default, the CRON Job Github Action is disabled. To enable this within your repo, open the <code>.github/workflows/python-app.yml</code> file and uncomment the schedule code block.</p><pre><code class=language-yaml>on:
  schedule:
    # scheduled to run each week at 3am on a Tuesday
    - cron: '0 3 * * 2'
  workflow_dispatch:
    inputs:
      logLevel:
        description: 'Log level'
        required: true
        default: 'warning'
        type: choice
        options:
          - info
          - warning
          - debug
</code></pre><blockquote><p>You can use the<div>crontab</div> tool to calculate when and how often you want to run the Github Action.</blockquote>]]></content>
        <author>
            <name>Luke Secomb</name>
            <email>rss@lukesecomb.digital</email>
            <uri>https://lukesecomb.digital/</uri>
        </author>
        <published>2022-11-27T00:00:00.000Z</published>
        <media:thumbnail url="https://lukesecomb.digital/blog/spotify-playlist-backup-using-github-actions/og.jpg"/>
        <media:content medium="image" url="https://lukesecomb.digital/blog/spotify-playlist-backup-using-github-actions/og.jpg"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Up Your VS Code Game with Workspaces]]></title>
        <id>https://lukesecomb.digital/blog/up-your-vs-code-game-with-workspaces</id>
        <link href="https://lukesecomb.digital/blog/up-your-vs-code-game-with-workspaces"/>
        <updated>2019-06-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[test]]></summary>
        <content type="html"><![CDATA[<p>VS Code's Workspaces allow you to customise both the UI and functionality of the IDE at a project level. Workspaces settings override <code>User Settings</code> and are useful for sharing project settings with other devs and allow for project specific functionality and customisation.</p><p>To open Workspace Settings use the shortcut<div>Ctrl</div> + <div>,</div>. You can either edit the settings using the UI on this view or click the <code>{ }</code> in the top right corner to edit the <code>JSON</code> file. <h3>What are they good for?</h3><ul><li>Adjusting <code>titleBar</code> colors to differentiate between multiple projects.</li><li><code>search.exclude</code> to hide <code>dist</code> / <code>plugins</code> / <code>vendor</code> / <code>node_modules</code> folders from search results.</li><li>Exportable config allows sharing with co-workers on a per project basis.</li><li>Multiple folder paths on one project (handy if frontend and backend live in separate repositories)</li></ul><pre><code class=language-json>{
  "folders": [
    {
      "path": "C:\\laragon\\www\\backend_server"
    },
    {
      "path": "C:\\Github\\front_end_ui"
    }
  ]
}
</code></pre><h3>My Workspace Starter Settings</h3><p>This is what I copy in to when I spool up a new project as a base -<div>Gist</div><pre><code class=language-json>{
  "folders": [
    {
      "path": "C:\\Github\\PROJECT_NAME"
    }
  ],
  "settings": {
    "workbench.colorCustomizations": {
      "titleBar.activeBackground": "#141414",
      "titleBar.activeForeground": "#FFC87F",
      "titleBar.inactiveBackground": "#696969",
      "titleBar.inactiveForeground": "#FFC87F",
      "sash.hoverBorder": "#FFC87F"
    },
    "search.exclude": {
      ".cache": true,
      ".vscode": true,
      "node_modules": true
    },
    "window.title": "${rootName}",
    "editor.cursorSmoothCaretAnimation": true
  }
}
</code></pre><h3>So what do you use?</h3><p>What other handy settings should other developers be using with their workspaces?</p><h3>References</h3><p><a rel="nofollow noreferrer" href=https://code.visualstudio.com/docs/getstarted/settings target=_blank>User and Workspace Settings</a></p>]]></content>
        <author>
            <name>Luke Secomb</name>
            <email>rss@lukesecomb.digital</email>
            <uri>https://lukesecomb.digital/</uri>
        </author>
        <published>2019-06-07T00:00:00.000Z</published>
        <media:thumbnail url="https://lukesecomb.digital/blog/up-your-vs-code-game-with-workspaces/og.jpg"/>
        <media:content medium="image" url="https://lukesecomb.digital/blog/up-your-vs-code-game-with-workspaces/og.jpg"/>
    </entry>
</feed>