Apex Demo

Demonstrates the sfdc-apex-provider plugin for @wire and imperative Apex calls

This page demonstrates the sfdc-apex-provider LWR plugin, which enables Salesforce @salesforce/apex/* imports to work in the LWR development environment.

Features

  • @wire support: Reactive data binding with automatic refresh
  • Imperative calls: Traditional .then() and async/await patterns
  • Mock data: Configure mock responses for development
  • Apex parsing: Automatically discovers @AuraEnabled methods from your Apex classes

Live Demo

Usage

1. Configure the plugin in lwr.config.json

{
  "moduleProviders": [
    [
      "$rootDir/plugins/sfdc-apex-provider/index.js",
      {
        "apexDir": "$rootDir/force-app/main/classes",
        "mockDataDir": "$rootDir/mock-data",
        "mockDelay": 100
      }
    ]
  ]
}

2. Create mock data (optional)

Create JSON files in your mockDataDir:

{
  "AccountController.getAccounts": [
    { "Id": "001...", "Name": "Acme Corp", "Industry": "Technology" }
  ],
  "AccountController.searchAccounts": [
    { "Id": "001...", "Name": "Acme Corp" }
  ]
}

3. Import and use in your LWC

import { LightningElement, track } from 'lwc';
import getAccounts from '@salesforce/apex/AccountController.getAccounts';
import searchAccounts from '@salesforce/apex/AccountController.searchAccounts';

export default class MyComponent extends LightningElement {
    @track accounts = null;

    // Load data on component mount
    connectedCallback() {
        getAccounts()
            .then(result => {
                this.accounts = result;
            })
            .catch(error => {
                console.error('Error:', error);
            });
    }

    // Imperative call
    handleSearch() {
        searchAccounts({ searchTerm: 'Acme' })
            .then(result => {
                console.log('Results:', result);
            })
            .catch(error => {
                console.error('Error:', error);
            });
    }
}

Source Code

Apex Controller

public with sharing class AccountController {
    @AuraEnabled(cacheable=true)
    public static List<Account> getAccounts() {
        return [SELECT Id, Name, Industry FROM Account LIMIT 10];
    }
    
    @AuraEnabled(cacheable=true)
    public static List<Account> searchAccounts(String searchTerm) {
        String pattern = '%' + searchTerm + '%';
        return [SELECT Id, Name FROM Account WHERE Name LIKE :pattern];
    }
    
    @AuraEnabled
    public static Account createAccount(String accountName) {
        Account acc = new Account(Name = accountName);
        insert acc;
        return acc;
    }
}

LWC Component

import { LightningElement, track } from 'lwc';
import getAccounts from '@salesforce/apex/AccountController.getAccounts';
import searchAccounts from '@salesforce/apex/AccountController.searchAccounts';
import createAccount from '@salesforce/apex/AccountController.createAccount';

export default class ApexDemo extends LightningElement {
    @track accounts = null;
    @track filterValue = '';
    @track searchResults = null;

    connectedCallback() {
        // Load accounts on mount
        getAccounts()
            .then(result => { this.accounts = result; })
            .catch(error => { console.error(error); });
    }

    handleSearch() {
        searchAccounts({ searchTerm: this.filterValue })
            .then(result => {
                this.searchResults = result;
            })
            .catch(error => {
                console.error(error);
            });
    }

    async handleCreate() {
        const result = await createAccount({ accountName: 'New Account' });
        console.log('Created:', result);
    }
}