Explore the Visualforce App Container
Learning Objectives
- Describe three differences between Visualforce pages running in Salesforce Classic compared to the same pages running in Lightning Experience.
- Describe two common code patterns that need updating to work in Lightning Experience.
- List two changes to Visualforce page default values when running in Lightning Experience.
Exploring the Visualforce App Container
This change to the execution context has a number of effects on the way Visualforce pages can affect the overall Salesforce application. We’ll talk about these changes in this unit, but save the full details of a few of them for their own units.
The Outer Lightning Experience Container
The process by which a single-page application loads its resources—usually a static HTML shell and a lot of JavaScript—is both interesting and complex. If you’ve worked with JavaScript frameworks like AngularJS or React, you’re reasonably familiar with the basics of how Lightning Experience, in the form of /lightning, starts up. And to be honest, the full details don’t matter. You don’t have any control over it, and the implementation continues to evolve.
Here’s what’s important to know: Lightning Experience, or /lightning, is in charge of the request. Your Visualforce page is not. Your page needs to work within constraints that Lightning Experience imposes upon it. Lightning Experience is the parent context, and your Visualforce page is the child context. Children need to obey their parents.
Some of these constraints, such as the size of the frame in which your Visualforce page is displayed, are imposed directly by Lightning Experience. They’re easier to understand and work with, and we’ll talk about them in a minute.
Other constraints are implicit, and enforced not by Lightning Experience but by the browser running it. These are mostly security and JavaScript execution constraints. Most pages aren’t impacted by these security constraints, and those that are usually fail early and with clear error messages. JavaScript errors are harder to discover and diagnose, but there are some general rules we’ll cover in a bit.
The Visualforce iframe
The advantage of running Visualforce pages inside an iframe is that, for pages that don’t need to access or change the top-level browsing context, running inside the iframe looks almost exactly like running as a page in Salesforce Classic. This is why you don’t need to modify all of your Visualforce pages to adapt to the wildly different behind-the-scenes request environment of Lightning Experience. It’s an important part of the “just works” strategy for supporting Visualforce.
Of course, the flip side is that pages that do need to access the top-level browsing context, well, there’s some things that need to change. We’ll cover some specifics in the next section.
If your page is communicating with services besides Salesforce, the iframe boundary might also result in you needing to update your organization’s CORS settings, remote site settings, clickjack settings, or content security policy. Since these depend on security policies and settings outside of Salesforce, we can’t provide a recipe for specific changes. We simply call it to your attention here.
Impact of the New Container
Again, we want to emphasize: many, or even most Visualforce pages won’t be affected by these issues. But for those that are, we’re thinking “forewarned is forearmed.” You’ll find the source of the problem faster if we’ve already talked about it together.
Security Impact
- Session maintenance and renewal
- Authentication
- Cross-domain requests
- Embedding restrictions
We discussed a few of these briefly already, the items dealing with cross-domain requests. That is, when the content in the full browser window comes from requests to different servers and services, there’s the potential for any of those requests to balk at being displayed in a context that it’s not prepared for. Your mission, should the need arise, is to prepare those services to handle requests intended to be put together within the Lightning Experience context. As we said before, the details vary, so we can’t provide specific answers here.
One thing we do want to mention specifically is session maintenance. A “session” for our purposes here is basically some kind of token that your browser re-uses from request to request so that you don’t need to enter your username and password for every request. You often need to access the current session using the global variable $Api.Session_ID .
Here’s the thing to keep in mind. $Api.Session_ID returns different values depending on the domain of the request. This is because the session ID varies during a session whenever you cross a hostname boundary, such as .salesforce.com to .force.com. Normally Salesforce transparently handles session hand-off between domains, but if you’re passing the session ID around yourself, be aware that you might need to re-access $Api.Session_ID from the right domain to ensure a valid session ID.
Lightning Experience and Visualforce pages are not only held in different browser contexts, they’re also served from different domains. So, even though it’s all showing in one browser window, the session ID inside the Visualforce iframe will be different than the session ID outside the iframe, in another part of Lightning Experience. Salesforce and Lightning Experience handle this transparently in normal use. But if you’re passing around the session ID like hors d'oeuvre at a party (not usually a good idea), you might need to review how you’re handling it.
Scope Impact
- DOM access and modification
- JavaScript scope, visibility, and access
- JavaScript global variables such as window.location
If this list sounds complicated or confusing, don’t worry, we can boil it down to something simple and easy to remember: Don’t touch someone else’s stuff. Specifically, your JavaScript code (and stylesheet rules, for that matter) can affect elements—DOM nodes, JavaScript variables, and so on—in your page’s browsing context, but it can’t access elements in any other browsing context, like the parent Lightning Experience context. Don’t touch other contexts’ stuff!
Practically speaking, the most common code pattern where you’d want to do this kind of thing is to manipulate window.location to navigate to another page. This is such a common thing to do, we’ve written up details on this specific issue...well, by the time you’re done with this module, you’ll be sick of hearing about it, we promise.
One last note. If you’re an experienced JavaScript developer, you’re probably already thinking you know how to deal with “I don’t have access to the parent browsing context” issues, by using contentWindow, window.parent, or the like. Please don’t. You’ll likely run afoul of the same-origin policy (Visualforce and Lightning Experience are served from different domains, remember?). Even if you don’t, you’re probably replacing obvious, blocking bugs with subtle, intermittent bugs. Where do you want to spend your time: Doing things right, or the debugger?
Doing things right means calling APIs we’ve made available in your Visualforce pages, primarily for navigation. If you really need to affect things across frame boundaries, use window.postMessage to send a message to receiving code in the other frame.
Visualforce Defaults and Environment Changes in Lightning Experience
Some of these changes are simple, and obvious once you think about them. For example, Visualforce pages that run in Lightning Experience always have the standard Salesforce Classic header and sidebar suppressed. Other changes aren’t as visible, but have just as large an impact.
<apex:page> showHeader and sidebar Attributes Are Always false
If your page is shared between Salesforce Classic and Lightning Experience, you can still set these attributes to the values you’d like to use when the page runs in Salesforce Classic.
The sforce.one JavaScript Utility Object
sforce.one is automatically injected into your page when it runs in Lightning Experience or the Salesforce app. You’ll see it in your JavaScript debugger console and web developer resources list. There’s nothing you need to do to add it, and there’s no way to suppress it, either. (Sadly, there’s no way to get sforce.one in your Visualforce pages in Salesforce Classic.)
sforce.one is primarily used to fire navigation events. The full details are in an upcoming unit, Managing Navigation .
____________________
* There is no Salesforce cantina. Alas.
Resources
- Modify Session Security Settings
- Visualforce Developer’s Guide
- Mozilla Development Network: HTML Inline Frame Element (<iframe>)
- Mozilla Development Network: Using Content Security Policy