function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Asad Mahmood 6Asad Mahmood 6 

Trying to create single page application using LWC

Hi guys,

i'm new to salesforce and my main front end development is mainly Angular. 

I am trying to create a lightning web component and which will load/display different components based on user input (clicks). I thought, i will try to do this in SPA instead of if/hide.

I came across library called Navigo and I'm trying to import this library in my component (SFDX project) but it is failing with following error:

Invalid reference navigo of type module in file appContainer.js

i have added dev dependencies navigo:

  "devDependencies": {
    "@prettier/plugin-xml": "^0.7.0",
    "@salesforce/eslint-config-lwc": "^0.4.0",
    "@salesforce/sfdx-lwc-jest": "^0.7.0",
    "eslint": "^5.16.0",
    "prettier": "^1.19.1",
    "prettier-plugin-apex": "^1.0.0",
    "navigo": "^7.1.2"
  }

is it possible to create SPA in Salesforce using LWC?

thanks,
Asad
VinayVinay (Salesforce Developers) 
Hi Asad,

Yes, you can create SPA with lightning components.

Review below links.

https://developer.salesforce.com/events/webinars/singlepagelightning
https://developer.salesforce.com/blogs/2020/02/designing-lightning-pages-for-scale.html

Thanks,
Vinay Kumar
Piotr Gajek 19Piotr Gajek 19

Hello, 

You can create SPA using LWC quite easily. 

User-added image

Container

// spaContainer.html
<template>
    <h1 class="title">Single Page Application</h1>

    <div class="container" if:true={isLoaded}>
        <c-spa-navigation class="navigation" current-page-id={currentPageId} menu-items={menuItems} current-page-reference={currentPageReference}></c-spa-navigation>
        <c-spa-pages class="content" current-page-id={currentPageId}></c-spa-pages>
        <c-spa-footer class="footer"></c-spa-footer>
    </div>
</template>

// spaContainer.js 
import { LightningElement, wire } from 'lwc';
import { CurrentPageReference } from 'lightning/navigation';
import getPagesConfig from '@salesforce/apex/SpaController.getPagesConfig';

export default class SpaContainer extends LightningElement {
    currentPageReference;
    pagesConfig;
    menuItems;

    currentPageId;

    isCurrentPageReferenceLoaded = false;
    isPagesConfigLoaded = false;

    @wire(CurrentPageReference)
    wiredCurrentPageReference(currentPageReference) {
        if (!currentPageReference) {
            return;
        }

        this.currentPageReference = currentPageReference;
        this.isCurrentPageReferenceLoaded = true;

        this.setCurrentPage();
    }

    @wire(getPagesConfig)
    wiredPagesConfig({ data }) {
        if (!data) {
            return;
        }

        this.pagesConfig = data;

        this.setNavigationMenu();
        this.setLandingPage();

        this.isPagesConfigLoaded = true;

        this.setCurrentPage();
    }

    get isLoaded() {
        return this.isCurrentPageReferenceLoaded && this.isPagesConfigLoaded;
    }

    setNavigationMenu() {
        this.menuItems = [...this.pagesConfig]
            .sort((a, b) => (a.menuOrder > b.menuOrder ? 1 : -1))
            .map(page => ({
                label: page.name,
                pageId: page.pageId
            }));
    }

    setLandingPage() {
        this.landingPage = this.pagesConfig.find(page => page.isLandingPage);
    }

    setCurrentPage() {
        if (!this.isLoaded) {
            return;
        }

        this.currentPageId = this.currentPageReference?.state?.c__page || this.landingPage?.pageId;
    }
}

Navigation

// spaNavigation.html
<template>
    <div class="navigation" if:true={menuItems}>
        <lightning-vertical-navigation selected-item={currentPageId}>
            <lightning-vertical-navigation-section label="Main Menu" >
                <template for:each={menuItems} for:item="menuItem">
                    <lightning-vertical-navigation-item-icon key={menuItem.pageId} label={menuItem.label} data-page={menuItem.pageId} name={menuItem.pageId} onclick={navigate}>
                    </lightning-vertical-navigation-item-icon>
                </template>
            </lightning-vertical-navigation-section>
        </lightning-vertical-navigation>
    </div>
</template>
// spaNavigation.js
import { LightningElement, api } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';

export default class SpaNavigation extends NavigationMixin(LightningElement) {
    @api currentPageId;
    @api menuItems;
    @api currentPageReference;

    navigate(event) {
        this[NavigationMixin.Navigate](
            Object.assign({}, this.currentPageReference, {
                state: Object.assign({}, this.currentPageReference.state, {
                    c__page: event.target.dataset.page
                })
            }),
            false // Push to browser history stack
        );
    }
}
Pages
// spaPages.js
import { LightningElement, api } from 'lwc';

import home from './templates/home.html';
import services from './templates/services.html';
import about from './templates/about.html';
import contact from './templates/contact.html';
import notFound from './templates/404.html';

const PAGE_ID_TO_TEMPLATE = {
    home,
    services,
    about,
    contact,
    notFound
};

export default class SpaPages extends LightningElement {
    @api currentPageId;

    render() {
        return PAGE_ID_TO_TEMPLATE[this.currentPageId] || PAGE_ID_TO_TEMPLATE.notFound;
    }
}

Here you can find more details: https://beyondthecloud.dev/blog/salesforce-spa-using-lwc