Learn Architectural Concepts
- Describe how the Visualforce page paradigm and the Lightning component paradigm are different.
- Explain the concept of different containers, and how you insert a Lightning app or component into a container.
When you design a traditional Visualforce-based app, you usually create a set of pages, and users of the app navigate by moving from one page to another page. You start on a list view page, click a view link to go to a record view page, click an edit button to go to an edit record page, and so on.
Instead of navigating from page to page, users navigate from state to state. A state represents a mode that your app is currently in. The list view state, the view record state, and so on.
The SPA knows which components to load for each state, and those components know how to draw, or render, themselves.
Two takeaways for you. First, navigation is very different in Lightning components. Depending on how complex your app is and where it runs, you might never need to worry about navigation. Say goodbye to PageReference, $Action, and the anti-pattern of hand-constructed URLs. (The horror!)
More likely, though, you need to learn some new tricks. See the Resources section for pointers.
Second…actually, let’s break this out into a new concept.
Earlier we talked about how Visualforce pages and Lightning components are stored in Salesforce. While there are some differences in the details, at that level they’re still kinda the same. They’re a chunk of code, and that page chunk or component chunk is the fundamental building block you work with.
But how you build with the two different kinds of blocks is (you knew this was coming) very different.
Put simplistically, a Visualforce page is a “large” building block. While you can include it as a “widget” in a page layout, or pull one page into another with the <apex:include> tag, you’d only do this with a handful of pages. You don’t put together a collection of “small” pages to build a “medium” page, and then assemble a bunch of those to build a “large” page. Visualforce isn’t designed for that, and if you try you’ll get...problematic behavior.
A Lightning component is different. A “large” Lightning component can be composed of dozens or even hundreds of smaller components, which themselves can be composed of many even smaller components. The Lightning Component framework is designed to handle thousands of components assembled together into a single app.
Taking small, fine-grained components and assembling them into a “next level up” component, and then repeating, and repeating, and repeating is the fundamental design process when using Lightning components. In software design, this is called composition, and you can clearly see similarity in the words “component” and “composition” (com is the Latin root, meaning together, or with). It’s not accidental.
A Visualforce page is, by and large, intended to stand alone. That is, among other things, why you can access it with a unique, permanent URL.
A Lightning component, however, should be a piece of a larger whole—no matter how “big” that component is. You can’t access an individual component at a specific URL. To run a component, you must add it into something larger, as we did in the Lightning Component Skills & Tools module.
There’s more, far more, to this than we can go into here—whole books are written about using components in software design. For now, just remember this: Don’t treat a component like a page!
In preceding sections we ignored Visualforce components. That seems unfair. After all, the many built-in Visualforce framework “tags” are just components by another name. Obviously, Visualforce has components, and Visualforce pages can use hundreds of the built-in “tags,” so that sounds pretty similar to Lightning components. What’s the difference?
Simply put, when we at Salesforce build a new Visualforce component (or tag), we have access to more features than you do when you develop custom Visualforce components. We put a lot of those features back into the customer-facing side of Lightning components. Custom Visualforce components are less powerful, less functional than custom Lightning components.
Important note! We do have many customers creating custom Visualforce components effectively. Custom Visualforce components are good! Using them is great! They’re a sign of a sophisticated development shop, and usually lead to reduced costs of software development over time. We are not saying that Visualforce custom components are bad.
But Lightning components are better. They are more sophisticated and more powerful. Over time and with correct use, you can build richer, better software at a comparable cost.
Let’s get specific about a few of the biggest differences.
- Lightning components can fire and receive events to communicate between components. You
can work with framework or container events, or define your own. You write event handlers,
and the framework takes care of the details of invoking them when the right event occurs.
This is huge, and opens up entirely new frontiers in the design of your
There’s nothing comparable in Visualforce, unless you roll it yourself. At which point, congratulations, you have your own framework! Now you need an ironic name for it, a GitHub repo, and a hipster hat.
- The Lightning component bundle structure has separate artifacts for separate functions and
“auto-wires” them together. Being able to group the essential dependencies of a component,
while keeping different elements separate, is a terrific organization tool. Value providers
and so on makes it easy to use the different elements with minimal ceremony.
Again, getting something comparable in Visualforce means you’re writing framework code, not feature code.
- Lightning components can be used in more contexts. Indeed, because it’s client-side code, you can use Lightning Out to pull your “Salesforce” features into other, completely not Salesforce apps and contexts—can you say SharePoint? Server-bound Visualforce runs only on Salesforce.
This list could go on, but it’s probably better to move on to additional concepts. Hopefully by the end of this module, you’ll have a solid idea of why you might want to give Lightning components a serious look.
Application containers (containers for short) are a new concept for most Salesforce developers. Put simplistically, a container is an application context, or an environment in which your code runs. The most obvious container for your Lightning components is Lightning Experience. Because Lightning Experience and the Salesforce app share a lot of common code, which you access at the same URL, we sometimes refer to the two combined as the “one.app container.” (The common URL for both ends with one.app.)
You might have guessed that at least one additional container is the Salesforce Classic container. Here’s a (not necessarily complete) list of distinct containers where your code might run.
- Salesforce Classic
- Salesforce App
- Lightning Experience
- Lightning App Builder (LAB)
- Lightning console apps
- Lightning Components for Visualforce (LC4VF)
- Lightning Out
- Lightning for Outlook and Lightning for Gmail
- Stand-alone my.app
You’re probably thinking two things after reading this list.
- That’s a lot of containers. What’s the difference? Why do I care? (The short answer: container services.)
- Wait a minute. Aren’t some of these the same thing? Aren’t LAB pages just Lightning Experience? Why is Visualforce its own container, and how is it different from LC4VF? (The short answer: Russian dolls.)
Remember that a container is an application context, or an environment in which your code runs. Different environments offer different services.
For example, the one.app container (Lightning Experience and the Salesforce app) provides a number of services, including handling events to go to a record, create or edit a record, open a URL, and so on.
Other containers don’t provide these services. A component that depends on services in one container doesn’t work in a different container that doesn’t have those services. For example, if you use the force:createRecord event to create new records, that works great in Lightning Experience, but if you use that component in a stand-alone app, or Lightning Out, it stops working, because there’s nothing to handle that event.
If a tree falls in a forest but there’s no one there to hear it, does it make a sound? We’ll leave that one to the philosophers.
But—if you fire an event in a container where nothing is listening, does it have an effect? We can answer that one ourselves. No.
Beyond the Basics
What’s the work-around? Write your own container service to create records, and an event handler to catch the force:createRecord event and dispatch it to your custom service.
If that sounds like work, that’s because it is. Providing robust container services is hard. Whole engineering teams work on nothing but. Work up to this advanced topic, and in the meantime check AppExchange if you need services for use outside of Lightning Experience and the Salesforce app.
We don’t have space here to provide a complete list of services and map them to containers. Read the documentation for features you want to use, and keep your eyes out for disclaimers like this one.
Container Containment (a.k.a., The “Russian Doll” Situation)
A container has boundaries. Walls. Barriers. A container keeps inside things in, and outside things out.
This is true of application containers too. With web applications and frameworks the boundaries are frequently based on an HTML iframe, which is enforced by the browser. Code inside the iframe can’t directly access elements outside the iframe.
There are other boundaries. For example, the container itself can enforce a boundary, by trapping events fired inside it.
Here’s the fun part. You can put smaller containers inside of larger containers, creating multiple “layers” to the containment hierarchy. Nesting matryoshka dolls, popularly known as Russian dolls, are a terrific metaphor for application containers for your Lightning components.
You can have Lightning components (4) running in a Visualforce page (3) using LC4VF. Then you can add that Visualforce page to Lightning Experience. That’s three containers. Or you can use LAB to add the Visualforce page to a Lightning Page (2), then add that Lightning Page to Lightning Experience (1). That’s four containers. And it’s not hard to hit five, or even six containment layers.
Here’s the important part. Your Lightning component code can access only the services of the container it’s running inside of, even if that container is inside of another container.
So that Lightning component inside a Visualforce page? It can’t fire Lightning Experience events that work, because the Visualforce container doesn’t understand the events or pass them along to the next container above it, even if you add that Visualforce page to Lightning Experience. The iframe boundary between Visualforce and Lightning Experience blocks those events.
TL;DR: Your component can only count on the services of the container it runs in. If you create a component for multiple contexts, you need multiple code paths to account for different sets of services. See Lightning Components in Visualforce with Lightning Out for an example of this technique.