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);
  }
}