Only this pageAll pages
Powered by GitBook
1 of 54

1.0.x

Loading...

Loading...

Loading...

Loading...

Loading...

The Manifest

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

The Service Worker

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Symfony UX

Loading...

Loading...

Loading...

Loading...

Image Management

Loading...

Loading...

Experimental Features

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Bundle Installation

To install the bundle, the recommended way is using Composer:

composer require spomky-labs/pwa-bundle

No Flex recipe exists for this bundle, but you can create a configuration file that will be modified as you progress in the integration of the features.

/config/packages/pwa.yaml
pwa: ~

The integration in your application is very simple. You are only required to add a Twig function inside the end of the <head> tag of your HTML pages.

<!DOCTYPE html>
<html lang="en">
<head>
  {{ pwa() }}
</head>
<body>
  ...
</body>
</html>

You may need to clear the cache after the bundle is installed

Deployment

As this bundle leverages Asset Mapper, the resources are served using this great component.

In the dev environment, the resources are automactilly handled and returned by your Symfony app.

For the prod environment, before deploy, you should run:

symfony console asset-map:compile

How To Create A PWA?

As the name suggests, the development of a Progressive Web App (PWA) is an incremental process. Two pivotal components define a PWA: the Manifest and the Service Worker. These elements are independent of each other and not obligatory.

By integrating these two elements, the Manifest and the Service Worker, a PWA delivers an optimal user experience with easy installation, offline accessibility, and heightened performance, all while retaining the flexibility of web development.

The Manifest

The Manifest, typically a JSON file, encompasses crucial metadata detailing the application, including its name, icons, theme, and launch configurations. This facilitates the installation of the PWA on the user's device and grants accessibility from the home screen, thereby creating an experience akin to that of a native app.

Below is an example:

/site.webmanifest
{
  "name": "My Progressive Web App",
  "short_name": "PWA",
  "description": "An example Progressive Web App",
  "start_url": "/index.html",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#4285f4",
  "icons": [
    {
      "src": "/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ]
}

This example manifest file includes essential information such as the app's name, a short name, description, start URL, display mode, and icons.

The Manifest file integration is done into your HTML file using appropriate tag:

<!DOCTYPE html>
<html lang="en">
<head>
  ...
  <link rel="manifest" href="/manifest.json">
</head>
<body>
  ...
</body>
</html>

The Service Worker

The Service Worker, a background-executed JavaScript script, stands as the other key element. It enables the application to function offline by intercepting network requests and providing cached responses. The Service Worker also contributes to features such as resource caching, push notification management, and overall performance enhancement.

Here's a simple example:

/service-worker.js
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('my-cache').then((cache) => {
      return cache.addAll([
        '/',
        '/index.html',
        '/styles/main.css',
        '/scripts/main.js',
        '/images/logo.png'
      ]);
    })
  );
});

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      return response || fetch(event.request);
    })
  );
});

This example service worker caches important files during the installation phase and then intercepts network requests, providing cached responses when available.

The Service Worker integration is done using appropriate script call:

<!DOCTYPE html>
<html lang="en">
<head>
  <script defer>
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('/service-worker.js')
        .then(function(registration) {
          console.log('Service Worker registered with scope:', registration.scope);
        })
        .catch(function(error) {
          console.error('Service Worker registration failed:', error);
        });
    }
  </script>
</head>
<body>
  ...
</body>
</html>

Application Information

For a Progressive Web App (PWA) to be installable, the manifest file must include certain mandatory information. These details help the browser understand how the application should be presented to the user and its behavior upon installation.

While not all of these properties are strictly mandatory, a manifest must at least contain the minimum information for the browser to prompt the user to install the application. In practice, it is recommended to include as much information as possible to enhance the user experience.

Here are the key properties of the manifest that are typically considered necessary for PWA installation:

  1. name: The name of the application.

  2. short_name: A short or abbreviated name for the application (used when space is limited, e.g., on a home screen).

  3. start_url: The relative or absolute URL from which the application should launch when opened.

  4. display: Determines how the application should be displayed. Common values include fullscreen, standalone,minimal-ui and browser.

  5. background_color: The background color of the application.

  6. theme_color: The color representing the main theme of the application.

Minimal example of a manifest:

/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        name: "My PWA"
        short_name: "PWA"
        start_url: "/index.html"
        display: "standalone"
        background_color: "#ffffff"
        theme_color: "#4285f4"

As it has an impact on the Twig pages, you may need to clear the cache when the manifest is enabled.

icons: An array of objects describing the application's icons for different sizes and resolutions. ()

see after

How To Install/Remove A PWA?

The PWA is not really installed. Your system will not download all the pages, assets, source code of your application and will not start a web server. The "installation" can be compared to a fully featured link to a web page, including application detail, icons or any other information defined in the manifest file. The browser will also "plus" application feautres to the host system.

To add or remove a Progressive Web App (PWA) from your browser, follow these general steps. Please note that the exact steps may vary slightly depending on the browser and version you are using.

These steps should help you add or remove a PWA from your browser, but keep in mind that the exact process might differ slightly based on updates and changes made to browsers over time.

Adding a PWA

Chrome

When navigating on a Progressive Web App, an icon will be visible on the right side of the URL toolbar. Clicking on it will open a dialog with the application detail and a button to install it.

This will create a shortcut on your desktop or in the app menu, and the PWA will open in a separate window.

Microsoft Edge

The installation of a PWA is very similar to Chrome.

Firefox

To be written

Safari (iOS)

To be written

Removing a PWA:

Chrome

From the application, click on the three vertical dots and select "Uninstall AppXxx" and confirm.

Microsoft Edge

From the application, click on the three horizontal dots and select "App settings".

The application manager window will open. From this panel, you will be able to clear the application data or uninstall it.

Firefox

To remove a PWA from Firefox, open the PWA from your desktop or application folder. Within the app, navigate to the Firefox menu in the upper right corner, represented by three horizontal bars. From the dropdown, select 'Remove Site' or 'Delete App', then confirm your choice. This removes the PWA from your device.

Safari (iOS)

Removing a PWA from an iOS device is straightforward. Locate the PWA icon on your home screen or in your app library. Press and hold the icon until a menu appears, then select 'Remove App'. Confirm the removal when prompted. This deletes the PWA from your iOS device.

Android

On an Android device, locate the PWA icon in your app drawer or home screen. Long-press the icon, then select the 'Uninstall' option. Confirm your choice if prompted. This will remove the PWA from your Android device.

Windows 10+

A Progresive Web App appears like a normal application in the software manager. Windows+X, "Install Applications" then select the three horizontal dots of the application you want uninstall and confirm.

For a Progressive Web App (PWA) to be installable, the Manifest file must include certain mandatory information that are listed .

Below an example on .

on this page
www.github.com

Scope

The scope parameter in a Progressive Web App (PWA) manifest file is an important feature as it defines the set of URLs that the browser considers to be within your app. When a user navigates to a URL within the scope, they are kept within the full app experience.

/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        scope: "/"

Defining Scope:

  • The scope can be a relative path or an absolute URL.

  • If omitted, it defaults to the location of the manifest.

  • The start_url must be within the scope.

Best Practices:

  1. Keep the scope as restrictive as possible to maintain control over your app's user experience.

  2. Set the start_url to a URL within the app's scope so it starts in the right context.

  3. Test the scope to ensure it includes all the necessary pages and excludes any that should not be part of the PWA experience.

ID

One of the parameters included in this file is the id property. This parameter is crucial as it uniquely identifies the PWA across browsers and devices, enabling a consistent user experience.

This id parameter should be consistent and not change, even if other manifest properties are updated. It's important for maintaining the application's identity for things like saved user preferences and home screen shortcuts.

When absent, an ID is determined using the start_url parameter, the manifest location and its scope. Adding an id to the manifest allows to change the start_url and the manifest path. Note that the domain shall not change.

/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        id: "/?homescreen=1"

To be written

Screenshots

Progressive Web App screenshots enable richer installation UI. As shown below, by default only the application name and short name are visible.

However, by including screenshots in the web app manifest, the installation experience can be significantly improved. These screenshots give users a visual preview of the app, enhancing their understanding and increasing the likelihood of installation.

Screenshots should showcase the most important functionalities of your application and be of high quality to attract users.

In the example below, a selection of screenshots are visible and the user can navigate to show them all. On mobile devices, the interface is different, but shows the same information.

Configuration

You can add as many screenshots as you need. But keep in mind that the host device or the platform may show only a selection of them.

/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        screenshots:
            - "images/screenshot-feature1.png"
            - 
              src: "images/screenshot-feature2.png"
              platform: "android"
              type: "image/png"
            -
              src: "images/screenshot-feature3.png"
              label: "Feature #3 in action"
              form_factor: "narrow"

src Parameter

Ensure that the screenshots you provide are of high quality. Crisp and clear images can make a significant difference in how users perceive your app. Always aim for the highest resolution possible, without compromising the load times or performance of the installation interface.

Remember, these screenshots are part of your app's first impression on potential users. Take the time to choose them wisely, ensuring they accurately represent your app and its key features.

type Parameter

label Parameter

The label parameter provides a way to give a brief description or caption for the screenshot. This helps users to understand what the feature or screen is about before they have installed the app. It assists in providing context and can be particularly useful when displaying a series of screenshots.

Example:

label: "Main dashboard view"

platform Parameter

The platform parameter can be used to specify which operating system the screenshot is intended for. This helps to display the appropriate screenshots for users on different devices. For instance, you might have specific screenshots for Android users versus those using a desktop browser.

Example:

platform: "android"

Possible values are listed below. This list is not exhaustive.

  • Device platform identifiers:

    • "android"

    • "chromeos"

    • "ipados"

    • "ios"

    • "kaios"

    • "macos"

    • "windows"

    • "xbox"

  • Distribution platform identifiers:

    • "chrome_web_store"

    • "itunes"

    • "microsoft-inbox"

    • "microsoft-store"

    • "play"

form_factor Parameter

The form_factor parameter allows you to define the intended device form factor for your screenshots. This can help cater to different device types, such as mobile, tablet, or desktop, ensuring that the screenshots displayed are relevant to the user's device.

Possible values include:

  • "narrow": Suggests the screenshot is best suited for narrow screen devices, like phones.

  • "wide": Implies the screenshot is intended for wider screen devices, such as tablets or desktops.

Example:

form_factor: "narrow"

See the description .

This parameter is similar to .

Categories

The categories member is a string list that describes the application categories to which the web application belongs. It is meant as a hint to catalogs or stores listing web applications and it is expected that these will make a best effort to find appropriate categories (or category) under which to list the web application. Like search engines and meta keywords, catalogs and stores are not required to honor this hint.

Manifest authors are encouraged to use lower-case.

/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        categories: ['games', 'kids']

List of known categories:

  • beauty

  • books

  • books & reference

  • business

  • cars

  • dating

  • design

  • developer

  • developer tools

  • development

  • education

  • entertainment

  • events

  • fashion

  • finance

  • fitness

  • food

  • fundraising

  • games

  • government

  • graphics

  • graphics & design

  • health

  • health & fitness

  • kids

  • lifestyle

  • magazines

  • medical

  • multimedia

  • multimedia design

  • music

  • navigation

  • network

  • networking

  • news

  • parenting

  • personalization

  • pets

  • photo

  • photo & video

  • politics

  • productivity

  • reference

  • security

  • shopping

  • social

  • social networking

  • sports

  • transportation

  • travel

  • utilities

  • video

  • weather

Protocol Handlers

Progressive Web Apps (PWAs) have the ability to handle web protocols, which means they can respond to specific URL schemes. For example, a PWA can register to handle mailto: links, so that clicking on an e-mail link can open a compose window in the PWA instead of opening the default mail client.

The application can declare custom protocols using the prefix web+.

With protocol handlers, your PWA can provide a more integrated user experience, functioning more like a native application.

Configuration

/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        protocol_handlers:
            - protocol: "mailto"
              url: "/compose?to=%s"
              title: "Compose Email"
            - protocol: "web+custom"
              url:
                  path: "app_feature1"
                  params:
                      foo: "bar"
              title: "Open with Feature #1"

Considerations When Using Protocol Handlers

  • Ensure that your PWA is served over HTTPS, as handling protocols can present security risks if not properly secured.

  • Test the protocol handlers thoroughly on different browsers, as support for this feature can vary.

  • Respect user choice. Always provide an easy way for users to opt-out of using the PWA as a default handler for specific protocols.

IARC Rating ID

The International Age Rating Coalition (IARC) rating system ID. This is not mandatory but is useful for digital content that requires an age rating.

/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        iarc_rating_id: "e.g. IARC certificate code"

Direction and Language

The PWA dir and lang parameters.

Progressive Web Apps (PWAs) can be tailored for different languages and writing directions through the use of the dir and lang parameters in the HTML tag.

By properly setting the dir and lang parameters, you ensure better user experience, accessibility, and potentially improved SEO for your PWA.

Please note that those values should be in accordance with the ones set as <html> tag attributes.

The dir Parameter

The dir parameter specifies the text directionality of the content in your PWA. It can have one of three values:

  • ltr: Left-to-right, which is used for languages that are read from the left to the right (like English).

  • rtl: Right-to-left, for languages read from the right to the left (like Arabic or Hebrew).

  • auto: Automatically determines the direction based on the content.

Example usage in HTML:

The lang Parameter

The lang parameter declares the default language of the text in the page. This is important for accessibility tools and search engines.

Configuration

Icons

To integrate the icon details into the Progressive Web App (PWA) manifest file, ensure that each icon listed is accompanied by its respective size. For example, icon-256x256.png is indicated as having a size of 256px by 256px. This is crucial for providing clear visual elements across different devices and resolutions.

The sizes attribute indicates the size of the icon to the browser. For PNG or JPEG icons, specify the dimensions (e.g., 48, 96, 256). For vector icons, you can use "any" as they are scalable without losing quality. The format attribute is also important as it tells the browser what the file format is, helping it to render the image correctly or the browser to select the most suitable format.

src Parameter

sizes Parameter

The sizes parameter indicates the suitable sizes for the icon. The expected value is an positive integer or a list of positive integers.

0 means any size and is suitable only for vector images.

The recommended sizes for application icons are as 48, 72, 96, 144, 168, 192, 256 and 512 pixels.

format Parameter

The format parameter corresponds to the mime type of the icon.

If this value is omitted and the component symfony/mime is present, the bundle will guess the correct type.

In general, browsers can read image/png and image/jpg types. Modern browsers may support image/webp.

purpose Parameter

The purpose maskable icons indicates the icon has a security margin and borders can be cropped on certain devices.

Shortcuts

PWA shortcuts can be added to any web app manifest by including the shortcuts property, which is an array of objects each representing a shortcut. This can enhance user engagement and make your app more accessible.

When designing shortcuts for your Progressive Web App, keep the following tips in mind:

  • Keep It Simple: Shortcuts should be straightforward and provide clear value to the user.

  • Use Icons: Visual representation makes shortcuts more recognizable and user-friendly.

  • Limit the Number: Too many shortcuts can overwhelm users; focus on the most important actions.

Adding shortcuts is a small but effective addition to enhance your PWA's user experience.

Remember to periodically review your shortcuts to ensure they remain relevant and beneficial to your users. Shortcuts are a dynamic feature and should evolve as your application grows and changes.

Configuration

name and short_name Parameters

The name parameter in each shortcut object is used to define the full name of the shortcut, which will be displayed to the user. It should be descriptive enough to communicate the action that will be taken when the shortcut is activated, but also concise enough to be quickly understood.

Best Practices for Naming Shortcuts:

  • Be Descriptive: Choose a name that clearly explains what the shortcut does (e.g., "Add to Favorites" is better than just "Add").

  • Be Consistent: Use a consistent naming convention across all shortcuts to prevent user confusion.

  • Avoid Jargon: Use language that is easily understandable by all users, regardless of their technical knowledge.

Don't forget to include the short_name parameter if the name is too long to be displayed in full on all devices. The short_name is a more concise version of name, which can be used when there's insufficient space.

url Parameter

The url parameter specifies the URL to which the user should be navigated when they activate the shortcut. It indicates the location or feature within the application that corresponds to that specific shortcut.

The URL can be a controller route name, with or without parameters, an absolute or a relative URL.

The path_type_reference option expects an integer where:

  • 0: absolute URL (e.g. https://app.com/foo/bar)

  • 1: absolute path (e.g. /foo/bar)

  • 2: relativepath (e.g. ../bar)

  • 3: network path (e.g. //app.com/foo/bar)

description Parameter

The description parameter helps the user understanding the purpose of the shortcut.

icons Parameter

Adding icons to shortcuts not only makes them visually appealing but also helps users to quickly identify the action they represent. Icons for shortcuts can be defined within the icons array and it's important that these are clear and relevant to the function of the shortcut. Icons should be provided in multiple sizes to ensure that they display well on all devices.

The presence of a 96x96 icon is highly recommended for shortcuts.

File Handlers

If your PWA is able to load certain type of files, you can declare in the Manifest file the supported MIME types and tell the host system you are able to manage those files.

To declare the supported file types, you can add a file_handlers entry to your web app manifest. This entry specifies the types of files that the app can open, along with an action URL that handles the opening of those files.

By adding a file handler for the above image types, your PWA will announce to the operating system that it can handle these types of files. When users open files with these extensions, your PWA will be suggested as an application to open them with.

The action property refers to the URL within the PWA context that will handle the file interaction. Ensure that your PWA is properly set up to handle file interactions at the specified URL.

GitHub installation UI
GitHub installation from Chrome
GitHub installation from Microsoft Edge

The src parameter is the path to the resource file. It can be an , a relative path or an absolute path to the resource.

With absolut URLs, please make sure the Request Context is set. See for more informaiton.

See the definition .

The action property can be a relative URL, absolute URL or an route name. It is managed the same way as showed in the shortcuts section.

<html dir="ltr" lang="en">
</html>
/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        dir: "ltr"
        lang: "en"
/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        icons:
            - src: "icons/icon-192x192.png"
              sizes: [192]
            - src: "icons/icon-192x192.png"
              sizes: [192]
              purpose: "maskable"
            - src: "icons/icon.svg"
              sizes: 0
/config/packages/pwa.yaml
pwa:
    manifest:
        icons:
            - src: "icons/icon-48x48.png"
              sizes: [48]
            - src: "/home/project/foo/bar/icon-48x48.png"
              sizes: [48]
            - src: "src/resources/data/icon-48x48.png"
              sizes: [48]
/config/packages/pwa.yaml
pwa:
    manifest:
        icons:
            - src: "icons/icon-192x192.png"
              sizes: [48, 96, 192]
            - src: "icons/icon.svg"
              sizes: 0
on the icon page
the format parameter for the icons
/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        shortcuts:
            - name: "Start New Conversation"
              short_name: "New Chat"
              description: "Create a new conversation."
              url: "/start-chat"
              icons":          
                - src: "icons/feature1-96x96.png"
                  sizes: [96]
            - name: "View Unread Messages"
              short_name: "Unread"
              description: "View unread messages."
              url: "/unread-messages"
              icons:
                - src: "icons/feature2-96x96.png"
                  sizes: [96]
/config/packages/pwa.yaml
pwa:
    manifest:
        shortcuts:
            - name: "Feature #1"
              short_name: "feature-1"
              url: "app_feature1" # route name
            - name: "Feature #2"
              short_name: "feature-2"
              url:
                  path: "app_feature2" # route name
                  params: # route parameters
                      key: "value2"
            - name: "Feature #3"
              short_name: "feature-3"
              url: "/feature/3" # relative URL
            - name: "Feature #4"
              short_name: "feature-4"
              url: "https://foo.com/bar/feature-4" # absolute URL
            - name: "Feature #5"
              short_name: "feature-5"
              url:
                  path: "app_feature5" # route name
                  path_type_reference: 3 # Network URL
/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        file_handlers:
            - action: "/open"
              accept:
                  - "image/png": [".png"]
                  - "image/jpeg": [".jpg", ".jpeg"]
Maskable image safe area

Description

The description member is a string that allows the developer to describe the purpose of the web application. It serves as the accessible description of an installed web application.

/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        description: "This application helps you donate to worthy causes."

Orientation

The orientation property in the Progressive Web Application (PWA) manifest dictates the default orientation that the web application will be displayed in. The allowed values are:

  • portrait-primary: The orientation is in the primary portrait mode.

  • landscape-primary: The orientation is in the primary landscape mode.

  • portrait: Either of the portrait orientations.

  • landscape: Either of the landscape orientations.

  • any: Any orientation.

Setting the orientation helps ensure that the PWA looks good and functions well on mobile devices.

Example:

/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        orientation: "landscape"

With the above manifest configuration, the application will default to landscape orientation when launched from a device's home screen.

Complete Example

pwa:
    manifest:
        enabled: true
        background_color: "#ffffff"
        theme_color: "#212529"
        name: 'My Awesome Application'
        short_name: 'awesome-app'
        id: '/?manifest=1'
        description: 'With application will help you to change the world'
        orientation: "any"
        display: "standalone"
        scope: "/"
        display_override: ['fullscreen', 'minimal-ui', 'window-controls-overlay']
        id: "/"
        start_url: "./"
        icons:
            - src: "images/favicon.ico"
              sizes: [48]
            - src: "images/favicon-512x512.png"
              sizes: [512]
            - src: "images/favicon.svg"
              sizes: [0]
            - src: "images/favicon.svg"
              purpose: 'maskable'
              sizes: [0]
        screenshots:
            - "images/screenshots/homepage-1303x1718.png"
            - src: "images/screenshots/feature1-1303x1718.png"
              label: "Feature 1 in action"
            - src: "images/screenshots/feature2-2056x1080.png"
              label: "Feature 2 and available options"
            - src: "images/screenshots/feature3-2056x1080.png"
              label: "Feature 3 at its best"
        categories: ['utility', 'productivity']
        shortcuts:
            - name: "Feature 1"
              short_name: "feature1"
              description: "See Feature #1 in live action"
              url: "app_feature1"
              icons:
                  - src: "images/feature1.svg"
                    sizes: [0]
                  - src: "images/feature1-96x96.png"
                    sizes: [96]
Asset Mapper resource
the router configuration
on the icon page
the url parameter

PHPWA Bundle

Turn your Symfony App into a Progressive Web App

Hi 👋🏼,

You're definitely here to learn more about Progressive Web Apps (PWA) and how to integrate them into your Symfony application. If you've landed here thanks to the wheel of fortune, no problem! Let's first explore what a PWA is.

What is a PWA?

Progressive Web Apps are modern web applications that provide a user experience similar to native apps, with the added advantage of being accessible directly from a web browser. Before delving into how to incorporate them into your Symfony application, let's take a closer look at what makes PWAs so compelling and powerful.

PWA benefits

Cost Efficiency and Development:

  • PWAs are generally cheaper to build compared to native apps, saving on development expenses. No need for supporting several languages or platforms.

PWAs enhance the user experience and accessibility:

  • Apps-Like UI and Feel: PWAs provide an app-like user interface and feel, easily installable on users' devices.

  • Offline Capabilities: PWAs function seamlessly offline, ensuring users can access content even without an internet connection.

  • Push Notifications: PWAs support push notifications, enhancing user engagement by keeping them informed.

  • Better and Faster Performance: PWAs deliver better and faster performance, offering a smooth and responsive user experience.

PWAs excel in discoverability and maintenance aspects:

  • SEO Friendly: PWAs are SEO-friendly, making them easily discoverable through search engines.

  • Automatic Updates: PWAs can be set up for automatic updates, ensuring users always have the latest version without manual interventions.

PWAs come with technical advantages for developers:

  • Bypass the App Stores: PWAs can be distributed independently, bypassing the need for app store approval.

  • Device API Access: PWAs have access to device APIs, providing developers with more control and flexibility.

  • Faster Loading Times: PWAs load quickly, contributing to an efficient and responsive user experience.

Share Target

The Share Target feature enhances the functionality of Progressive Web Apps (PWAs) by seamlessly integrating them into the native operating system's sharing capabilities. This means that when users come across content that they want to share from any app or browser, your PWA can appear in the list of sharing options alongside other native applications.

In the example below, the PWA indicates it can receive image files. The files are sent to the application using a POST request to /share-target and multipart/form-data encoding. The shared file is in the request body file member.

/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
            share_target:
              action: "/share-target"
              method: "POST"
              enctype: "multipart/form-data"
              params:
                  files:
                      - name: "file",
                        accept: ["image/*"]

The POST request is ideally replied with an HTTP 303 See Other redirect to avoid multiple POST requests from being submitted if a page refresh was initiated by the user, for example.

action Parameter

method Parameter

The HTTP request method to use. Either GET or POST.

Use POST if the shared data includes binary data like image(s), or if it changes the target app, for example, if it creates a data point like a bookmark.

enctype Parameter

The encoding of the share data when a POST request is used. Ignored with GET requests.

params Parameter

An object to configure the share parameters.

Object values can be specified and will be used as query parameters. Unless otherwise noted, members are optional.

  • title: Name of the query parameter to use for the title of the document being shared.

  • text: Name of the query parameter for the text (or body) of the message being shared.

  • url : Name of the query parameter for the URL to the resource being shared.

  • files: a list defining which files are accepted by the share target. Each item requires the following properties:

    • name: Name of the form field used to share files.

    • accept : a list of accepted MIME types or file extensions.

Site Manifest Cache

The Site Manifest file can be cache by the bundle. This feature is enabled by default and mainly used to avoid error messages in the console and adds no significant benefits over the time.

Configuration

"sw.js" is served by Asset Mapper and refers to the file in /assets/sw.js folder of your project. It can be stored elsewhere if needed.

To start, just put an empty file. It will be automatically populated by the bundle and will evolves depending on your application needs.

The following example is exactly the same:

As it has an impact on the Twig pages, you may need to clear the cache when the service worker is enabled.

By default, the public URL of the service worker will be /sw.js. You can change this URL using the dest configuration option.

Service Worker Initialization

The Service Worker initialization script uses either Workbox Window if enabled or a smiliar Vanilla JS script.

When Workbox is enabled, its initialization script typically loads from an external URL. However, for improved performance and security, we advise installing it via Asset Mapper instead of relying on remote loading.

The two other options are also available:

Other Options

The Service worker section has other options you may be interested in.

Scope

Cache

The use_cache parameter is enable by default. It is a boolean that sets how the HTTP cache is used for service worker script resources during updates.

Skip Waiting

The skip_waiting parameter is disabled by default. It ensures that any new versions of a service worker will take over the page and become activated immediately. It is safe in general, but may create issues when the old service worker is handling events while it is updated.

Content Security Policy

If your application uses Content Security Policy (CSP) to declare and restrict script execution, the Service Worker will not be loaded as expected.

Fortunately, you are able to pass attributes such as a nonce to the script directive.

The URL of the share target. See the for the details.

The Service Worker is a Javascript file you can declare in the configuration file. It will be automatically served by the bundle as long as your template file uses the .

The scope parameter defaults to /. It is a string representing the service worker's registration scope. It should be aligned with the .

In the example below, the nonce attribute is managed by .

URL parameter
/config/packages/pwa.yaml
pwa:
    serviceworker:
        workbox:
            cache_manifest: true
/config/packages/pwa.yaml
pwa:
    serviceworker: "sw.js"
/config/packages/pwa.yaml
pwa:
    serviceworker:
        enabled: true
        src: "sw.js"
/config/packages/pwa.yaml
pwa:
    serviceworker:
        enabled: true
        src: "sw.js"
        dest: "/foo/service-worker.js"
symfony console importmap:require workbox-window
/config/packages/pwa.yaml
pwa:
    serviceworker:
        enabled: true
        src: "sw.js"
        dest: "/foo/service-worker.js"
        scope: "/"
        use_cache: true
        skip_waiting: false
<!DOCTYPE html>
<html lang="en">
<head>
  {{ pwa(swAttributes= {nonce: csp_nonce('script')}) }}
</head>
<body>
  ...
</body>
</html>
PWA Logo
PWA Logo

Custom Service Worker Rule

If needed, you can define custom sections in the service worker appended by your own services and depending on your application configuration or requirements.

To do so, you can create a service that implements SpomkyLabs\PwaBundle\ServiceWorkerRule\ServiceWorkerRule.

The method process shall return valid JS as a string. This script will be executed by browsers.

<?php

declare(strict_types=1);

namespace Acme;

use SpomkyLabs\PwaBundle\ServiceWorkerRule\ServiceWorkerRule;

final readonly class MyCustomRule implements ServiceWorkerRule
{
    private Workbox $workbox;

    public function __construct(
        ServiceWorker $serviceWorker,
    ) {
        $this->workbox = $serviceWorker->workbox;
    }

    public function process(bool $debug = false): string
    {
        return <<<HELLO_WORLD
// This will be added to the Service Worker
console.log('FOO-BAR from the Service Worker!');
HELLO_WORLD;
    }
}

Workbox

This bundle provides a simple Workbox integration path. Service Workers are not that easy to write. It can become a nightmare when dealing with mutliple caching rules or offline capabilities.

Workbox takes the pain out of service worker creation by providing a set of tools and best practices that can be used out of the box. It’s like having an expert by your side, guiding you through the complexities of browser caching and service worker logic.

This bundle builds on top of Workbox and includes several options so you don't need to write a line of Javascript to have a fully functional Service Worker.

Workbox provides various caching strategies to make it easy to manage how requests are handled by the service worker. One of the features is the ability to maintain a page cache for certain URLs or routes.

A warm cache refers to pre-loading URLs during the service worker installation phase. This ensures that those URLs are cached and readily available even before they are requested by the user.

The URLs to be pre-loaded are likely the pages that users will definitely navigate to. For example, the main functionality of your application, the pricing page or a page with the latest news that users will definitely read.

When the service worker is installed, Workbox will automatically cache the resources specified in the list. These files will remain cached and will be instantly available to the user, contributing to a swift user experience.

Hereafter the main benefits of Precache:

  • Faster Load Times: Since assets are stored locally, web applications can load faster, providing a better user experience.

  • Offline Support: Precached assets ensure that the application is usable even without a network connection.

  • Consistency: All users receive the same version of files, ensuring a consistent experience.

  • Background Updates: Assets are updated in the background, preventing any interruption to the user experience.

Key Features

  • Precaching: Workbox can precache the assets in your web app and keep them up to date.

  • Runtime Caching: Flexible strategies for handling runtime requests, such as stale-while-revalidate, cache first, and network first.

  • Request Routing: Easily define how different types of requests are handled by your service worker.

  • Background Sync: Integrate background sync to replay failed requests once connectivity is restored.

  • Offline Fallback: allow your service worker to serve a web page, image, or font if there's a routing error for any of the three, for instance if a user is offline and there isn't a cache hit.

Disabling Workbox

Workbox is enabled by default. You can disable it completely if you do not need it.

/config/packages/pwa.yaml
pwa:
    serviceworker:
        enabled: true
        src: "sw.js"
        workbox:
            enabled: false
Twig pwa method
Manifest scope
nelmio/security-bundle

Asset Caching

Contains a breaking change compared to v1.0.x

The cache is populated with all assets managed by Asset Mapper. By default, it includes all types of well recognized assets such as images, stylesheets or scripts:

This can be changed using the next configuration options:

CDN and Versions

By default, the bundle uses Workbox 7.0.0 which was released end of May 2023. The files are provided by the bundle so that all files are served by your server.

If needed, you can use a CDN and a different version.

BackgoundSync

Background Sync is a feature provided by service workers that enables your Progressive Web App to defer actions until the user has stable connectivity. This is particularly useful for ensuring any requests or data submitted by the user are not lost if their internet connection is unreliable.

  • queue_name: Unique queue name for each queue to easily identify and manage separate background sync processes. This is essential for categorizing different types of requests such as API calls and form submissions.

  • method: Specifies the HTTP method (e.g., POST) for the requests to be queued. This helps in filtering which request methods should be considered for background synchronization.

  • max_retention_time: The maximum time (in minutes) that a request will be retried in the background. This is crucial for managing storage and ensuring outdated requests are not unnecessarily retried.

  • force_sync_fallback: (Optional) A boolean value that, when set to true, forces the background sync to attempt a sync even under conditions where it might not normally do so. Useful in critical data submission scenarios.

match_callback: .

broadcast_channel: Specifies the name of the Broadcast Channel API channel used to communicate the status of the background sync process to the rest of the application. This enables real-time update capabilities on the user interface regarding the sync status. See for communication between the Service Worker and the frontend.

/\.(css|js|json|xml|txt|map|ico|png|jpe?g|gif|svg|webp|bmp)$/
/config/packages/pwa.yaml
pwa:
    serviceworker:
        enabled: true
        src: "sw.js"
        workbox:
            asset_cache:
                enabled: true
                regex: '/\.(css|jsx?)$/'
/config/packages/pwa.yaml
pwa:
    serviceworker:
        enabled: true
        src: "sw.js"
        workbox:
            use_cdn: true
            version: 6.5.4
/config/packages/pwa.yaml
pwa:
    serviceworker:
        enabled: true
        src: "sw.js"
        workbox:
            background_sync:
                - queue_name: 'api'
                  match_callback: startsWith: /api/ # All requests starting with /api/
                  method: POST
                  max_retention_time: 7_200 # 5 days in minutes
                  force_sync_fallback: true #Optional
                  broadcast_channel: 'api-list'
                - queue_name: 'contact'
                  regex: /\/contact-form\// # All requests starting with /contact-form/
                  method: POST
                  max_retention_time: 120 # 2 hours in minutes
the Stimulus Component

Font Caching

By default, 30 fonts can be cached for 1 year. This only comprises fonts served directly by your application. The supported fonts are as follows:

/\.(ttf|eot|otf|woff2)$/

This can be changed using the next configuration options:

/config/packages/pwa.yaml
pwa:
    serviceworker:
        enabled: true
        src: "sw.js"
        workbox:
            font_cache:
                enabled: true
                max_entries: 10
                max_age: 30 days

Google Font Caching

Fonts served by Google Fonts have a dedicated rule. It is enabled by default and you can disable it or customize some parameters.

/config/packages/pwa.yaml
pwa:
    serviceworker:
        enabled: true
        src: "sw.js"
        workbox:
            google_fonts:
                enabled: true
                cache_prefix: 'goolge-fonts'
                max_entries: 20
                max_age: 1 day

Offline Fallbacks

Workbox makes it easy to create robust offline experiences in web applications. When a user navigates to a page without an internet connection, instead of showing an error, your application can serve a predefined fallback page, image or font.

/config/packages/pwa.yaml
pwa:
    serviceworker:
        enabled: true
        src: "sw.js"
        workbox:
            offline_fallback:
                page: 'app_offline_page'
                image: 'images/offline.svg'
                font: 'fonts/normal.ttf'

image_fallback and font_fallback refer to assets delivered by Asset Mapper or an URL to the font file.

page_fallback can be a relative URL, a route name or a route name with parameters. See for more information.

URL parameter

Image Caching

By default, a maximum of 60 images are cached for 1 year. The supported image extensions extensions are as follows:

/\.(ico|png|jpe?g|gif|svg|webp|bmp)$/

This can be changed using the next configuration options

/config/packages/pwa.yaml
pwa:
    serviceworker:
        enabled: true
        src: "sw.js"
        workbox:
            image_cache:
                enabled: true
                max_age: 30 days
                max_entries: 200
                regex: '/\.(png|jpe?g|svg|webp)$/'

This cache is different from the Asset one as it corresponds to images that are not managed by Asset Mapper

see on this page

Resource Caching

Developers can build more resilient and user-friendly web applications that perform reliably under various network conditions. Also, it is possible to warm cache a selection of resources. This is powerfull as it allows applications to partially work offline.

The default strategy applied for resources is Network First i.e. the resource from the web server is fetched first. In case of failure, the cached data is served. By default, the service worker will wait 3 seconds before serving the cached version. This value can be configured.

/config/packages/pwa.yaml
pwa:
    serviceworker:
        enabled: true
        src: "sw.js"
        workbox:
            resource_caches:
                - match_callback: 'startsWith: /pages/'
                  cache_name: 'static-pages'
                  strategy: 'NetworkFirst'
                  network_timeout: 2 # Wait only 2 seconds (only when strategy is networkFirst or NetworkOnly)
                  preload_urls: # List of URLs to preload. The URLs shall match the value in match_callback option
                      - 'page_tos'
                      - 'page_legal'
                - match_callback: 'regex: \/articles\/.*$'
                  cache_name: 'articles'
                  strategy: 'StaleWhileRevalidate'
                  broadcast: true # Broadcast changes only when strategy = staleWhileRevalidate
                  preload_urls: # List of URLs to precache. The URL shall be comprised within the regex
                      - 'app_articles'
                      - path: 'app_top_articles'
                        params:
                            display: 5

Please note that you can refer to any URLs, but only URLs served by your application will be cached.

Match Callback

The match_callback option is designed to specify the condition used to determine which requests should be cached based on the request URL. This option can take different types of values, such as

  • A regular expression

  • A Javasrcipt callback

  • A prefixed statement

Regular Expression

You can directly pass a regular expression as a string or using the JS RegExp object.

  • match_callback: '"/styles/.*\.css"'

  • match_callback: 'new RegExp("/styles/.*\.css")'

Quotes are important!

Javascript Callback

Workbox gives you the url, the params, the request and the event objects. You can use any of those parameters to match with your cache.

  • match_callback: '({url}) => url.pathname === "/special/url"'

  • match_callback: '({request}) => request.destination === "image"'

Quotes are important!

Prefixed Statements

This bundle allows the use of handlers to avoid the use of JS and simplify the way you declare the callbacks.

For instance, using startsWith: /pages/ as the match_callback value means that any request URL that begins with /pages/ will be considered a match and thus eligible for caching under the defined cache_name.

Or destination: image is identical to match_callback: '({request}) => request.destination === "image"'.

This approach empowers developers to optimize their web application's performance by strategically caching resources based on URL patterns, ensuring that users enjoy faster load times and a smoother overall experience, even in offline scenarios or under suboptimal network conditions.

Provided Match Callback Handlers:

Pattern
Description
Example

navigate

Matches all resources the user navigates to.

No example. This is an exact match

destination:

  • destination: audio

  • destination: style

  • destination: video

route:

Matches the exact Symfony route. Shall not have required parameters

  • route: app_homepage

  • route: app_princing

pathname:

Matches an exact pathname

  • pathname: /foo/bar.docx

  • pathname: /report.pdf

origin:

Matches all requests to the origin

  • origin: example.com

  • origin: google.com

startsWith:

Matches all pathnames starting with the value

  • startsWith: /dashboard

  • startsWith: /admin

endsWith:

Matches all pathnames ending with the value

  • endsWith: .css

  • endsWith: -report.pdf

Custom Match Callback Handler

In the following example, setting match_callback: my-videos is a simplified way to match only videos served from a specific origin.

<?php

declare(strict_types=1);

use SpomkyLabs\PwaBundle\MatchCallbackHandler\MatchCallbackHandler;

namespace Acme\MatchCallbackHandler;

final readonly class MyVideosMatchCallbackHandler implements MatchCallbackHandler
{
    public function supports(string $matchCallback): bool
    {
        return $matchCallback === 'my-videos';
    }

    public function handle(string $matchCallback): string
    {
        return sprintf("({url, request}) => (url.origin === 'videos.s3.storage.com' && request.destination === 'video');
    }
}

The class shall be declared as a service.

Cache Name Parameter

The cache_name parameter is used to customize the cache name. If not set, a default value is defined.

Strategy Parameter

The strategy option corresponds to the Workbox strategy.

CacheFirst (Cache Falling Back to Network)

This strategy serves responses from the cache first, falling back to the network if the requested resource is not in the cache. It is ideal for assets that do not update frequently.

NetworkFirst (Network Falling Back to Cache)

The reverse of Cache First, this strategy tries to fetch the response from the network first. If the request fails (e.g., due to being offline), it falls back to the cache. Suitable for content where freshness is more critical.

StaleWhileRevalidate

This strategy serves cached responses immediately while silently fetching an updated version from the network in the background for future use. It is a good compromise for resources that need to be updated occasionally without compromising the user experience with loading delays.

NetworkOnly

A strategy that only uses the network, not attempting to cache or match responses from the cache. This is useful for non-cachable responses such as API requests returning user-specific data.

CacheOnly

Conversely, the Cache Only strategy serves responses from the cache, ignoring the network. This is ideal for offline applications where you want to ensure that only cached resources are served.

Leveraging Workbox strategies allows you to fine-tune how your application handles caching, ensuring that your users get the best possible experience whether they are online or offline.

Network Timeout

The Workbox network_timeout option indicates the number of seconds before the request falls back to the strategy. It is only available with NetworkFirst and NetworkOnly.

Max Entries / Max Age

When set, this indicates the expiration strategy used for the resource cache. max_age can be in seconds or a human-readable string

max_age: 3600 and max_age: 1 hour are similar.

max_entries is a positive number. When the cache reaches the number of cached resources, old resources are removed.

Range Requests

When making a request, a range header can be set that tells the server to return only a portion of the full request. This is useful for certain files like a video file, where a user might change where to play the video.

By setting the range_requests: true, this type of requests will be supported.

Broadcast Parameter

When accessing a page with the StaleWhileRevalidate strategy, the Service Worker will verify if a page update exists and will save it in the cache if any.

The broadcast parameter will tell the Service Worker to send a broadcast message in case of an update. This is usefull to warn the user it is reading an outdated version of the page and ask for a page reload.

In the example below, the message is catched and, if it is of type "workbox-broadcast-update" and the URL matches with the current URL, a toast notification is displayed for 5 seconds.

navigator.serviceWorker.addEventListener('message', async event => {
    if (event.data.meta === 'workbox-broadcast-update') {
        const {updatedURL} = event.data.payload;
        if (updatedURL === window.location.href) {
            const toast = document.getElementById('toast-refresh');
            toast.classList.remove('hidden');
            setTimeout(() => {
                toast.classList.add('hidden');
            }, 5000);
        }
    }
});

Broadcast Header

By default, the page header used to check if the page is outdated or not are Content-Length, ETag, Last-Modified. These headers can be changed.

/config/packages/pwa.yaml
pwa:
    serviceworker:
        workbox:
            resource_caches:
                - ...
                  broadcast_headers:
                      - 'X-App-Cache'

Cacheable Responses

By default, all responses with a 0 or 200 status code and that match with the match_callback option will be cached. It is possible to tell Workbox to cache only resources with a dedicated header or other status codes:

/config/packages/pwa.yaml
pwa:
    serviceworker:
        enabled: true
        src: "sw.js"
        workbox:
            resource_caches:
                - match_callback: 'startsWith: /pages/'
                  cacheable_response_headers:
                    'X-Is-Cacheable': 'true'
                  cacheable_response_statuses: [200]

Matches a certain type of resource. Available values are listed on the .

If needed, you can create your own Match Callback Handler. It must implement SpomkyLabs\PwaBundle\MatchCallbackHandler\MatchCallbackHandler and should return a value compatible with.

the capture argument of the Workbox method registerRoute

Cache Cleaning

When the service worker changes and is activated, the cache is purged. This feature is made to avoid the cache to grow in size and prevent your application to reach the limit of the host system or browser.

You can disable the cache purge, however you have to make sure the cached data is managed by other means.

/config/packages/pwa.yaml
pwa:
    serviceworker:
        enabled: true
        workbox:
            clear_cache: false # Default to true
Request object documentation

Complete Example

To be written

Push Notifications

As handling Web Push notifications can differ from one application to another, this bundle does not provide easy way to manage them. You will have to write your own logic into the Service Worker.

Hereafter an example where the received notifications are displayed.

More examples to come

If you are interested in Web Push notifications from the server side, please read about the bundle we maintain:

self.addEventListener('push', async function (event) {
    if (!(self.Notification && self.Notification.permission === 'granted')) {
        return;
    }
    const {title, options}= event.data.json();
    event.waitUntil(self.registration.showNotification(title, options));
});
https://web-push.spomky-labs.com/

Connection Status

The Connection Status component is designed to monitor and react to changes in the user's internet connection status. This component provides a simple way to show a notification or change the state of your application when the user's device goes offline or comes back online.

Usage

To use the Connection Status component, include it in your application and initialize it with the necessary options. Below is an example of how to integrate the Connection Status component into your project:

<div class="mx-auto max-w-screen-xl text-center px-4" {{ stimulus_controller('@pwa/connection-status') }}>
    <div
        {{ stimulus_target('@pwa/connection-status', 'attribute') }}
        class="flex items-center p-4 mb-4 text-sm border rounded-lg online:text-green-800 online:bg-green-50 online:dark:bg-gray-800 online:dark:text-green-400 offline:text-yellow-800 offline:bg-yellow-50 offline:dark:bg-gray-800 offline:dark:text-yellow-300"
        role="alert"
    >
        <div>
            <span class="font-medium">
                Connection status
            </span>: 
            <span {{ stimulus_target('@pwa/connection-status', 'message') }}>
                We are trying to guess what is the current status of your Internet connection
            </span>
        </div>
    </div>
</div>

Parameters

  • onlineMessage: Message displayed when online

  • offlineMessage: Message displayed when offline

Actions

None

Targets

  • message: HTML tag to update with the connection status message. Multiple targets allowed.

  • attribute: HTML attribute data-connection-status="ONLINE" (or "OFFLINE") will be set depending on the connection status. In the example above, this attribute is used to change the applicable classes

Events

On status change, the event status-changed is dispatched. The payload property contains the following data:

  • status: "OFFLINE" or "ONLINE"

  • message: the message set as parameter or the default value.

Prefetch on demand

Modern browsers are able to prefetch pages. Let say an article is displayed to the user. This article has related articles or pages the user may read. These pages can be prefetched so that when the user will click on the related link, the page will be available instantly.

To acheive that, you can add the follwing HTML tag:

<link rel="prefetch" href="/article-2">
<link rel="prefetch" href="/article-3">
<link rel="prefetch" href="/author-18">

Another approch could be the use of the provided Stimulus Component to prefetch on demand and depending on the user navigation on the page. For example, no link tags are set and mouseover or any other user action will trigger the prefetch of the related pages.

Usage

<section {{ stimulus_controller('@pwa/prefetch-on-demand') }}>
    <main>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
        Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
        Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    </main>
    <aside {{ stimulus_action('@pwa/prefetch-on-demand', 'mouseover', 'prefetch', {urls: ['/author-18', '/article-2', '/article-3']}) }}>
        Author: <a href="/author-18">John Doe</a>
        Other articles: <a href="/article-2">How to Foo</a>
        Other articles: <a href="/article-3">How to Bar</a>
    </aside>
</section>

Parameters

None

Actions

  • prefetch: asks the Service Worker to prefetch a list of URLs set in the urls parameter.

Targets

None

Events

None

Custom Cache Strategy

TO BE WRITTEN

Screenshots

Taking screenshots of your application has great benefits.It may become difficult to manage screenshot updates as the application evolves, in particular if multiple sizes are managed.

This command requires dependencies and should be executed in dev environnement only.

composer require --dev symfony/panther
composer require --dev dbrekelmans/bdi && vendor/bin/bdi detect drivers

Image Processor

Taking Screenshots

From your shell, you can use the following command line to take a screenshot of a given URL.

symfony console pwa:create:screenshot https://example.com

This will create a folder in assets/screenshots with screenshot. In addition, the console output will give you the best configuration to use these new image files by copy-pasting.

pwa:
    manifest:
        screenshots:
            - src: screenshots/screenshot-1200x1100.png
              width: 1200
              height: 1100
              type: image/png
            - ...

Formats And Sizes

You can change the format and sizes by setting the values you need as options. It is recommended to provide mobile and desktop views of your application.

symfony console pwa:create:screenshot https://example.com --format="webp" --width=750 --height=1334

Output Folder

Similarily, if you want to change the output folder, you can set it as an option.

symfony console pwa:create:screenshot https://example.com --output="/foo/bar"

Please read the section on .

the Icons page

Icons

Progressive Web Apps may have icons of multiple formats and sizes to be correctly shown on targeted plaforms. This task may become boring as your application evolves. The bundle provides a simple console command to ease the creation of these icons.

Icons shall be square images

Image Processor

The icon command requires an image processor to work to be declared in the configuration file. Two Image Processors are provided by the bundle.

  • pwa.image_processor.imagick: requires the PHP Imagick extension

  • pwa.image_processor.gd: requires the PHP GD extension

You can use a custom service if needed. It must implement the interface SpomkyLabs\PwaBundle\ImageProcessor\ImageProcessor.

/config/packages/pwa.yaml
pwa:
    image_processor: 'pwa.image_processor.imagick'

Resizing Icons

From your shell, you can use the following command line to convert an image to a preset of sizes and using the same format as the input:

symfony console pwa:create:icons /path/to/the/image.png

This will create a folder in assets/icons with icons of sizes 16x16, 32x32, 48x48, 96x96, 144x144, 180x180, 256x256, 512x512 and 1024x1024. In addition, the console output will give you the best configuration to use these new image files by copy-pasting.

pwa:
    manifest:
        icons:
            - src: icons/icon-16x16.jpg
              sizes:
                - 16
              type: image/png
            - ...

This configuration is to be adapt depending on the icon type (application, shortcut, widget...)

Formats And Sizes

You can change the format and sizes by setting the values you need as options

symfony console pwa:create:icons /path/to/the/image.png --format="jpg" 48 96 256

Output Folder

Similarily, if you want to change the output folder, you can set it as an option.

symfony console pwa:create:icons /path/to/the/image.png --output="/foo/bar"

Non-Standard Parameters

The following parameters are not standard and may not work properly on all browsers and systems. Please use with caution.

Sync Broadcast

TO BE WRITTEN

Usage

Parameters

None

Actions

Targets

None

Events

None

EDGE Side Panel

Progressive Web Apps can opt-in to be pinned to the sidebar in Microsoft Edge.

The sidebar in Microsoft Edge allows users to easily access popular websites and utilities alongside their browser tabs. The content in the sidebar augments the user's primary task by enabling side-by-side browsing and minimizing the need to switch contexts between browser tabs.

/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        edge_side_panel: ~

You can tell EDGE your PWA should only be loaded in the sidebar and the minimum sidebar size.

/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        display: "browser"
        edge_side_panel:
            preferred_width: 400

Display Override

The display_override property in a PWA manifest allows developers to specify a preferred display mode with fallbacks for cases where a certain display mode is not supported by the platform or browser. This ensures that the best possible display mode is used for the PWA without errors.

In the example below, the browser will consider the following display-mode fallback chain in this order: fullscreen → minimal-ui → standalone.

/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        display: "standalone"
        display_override: ["fullscreen", "minimal-ui"]

Display override objects are display-mode strings, the possible values are:

Display Mode
Description

fullscreen

All of the available display area is used and no user agent UI is shown.

standalone

The application will look and feel like a standalone application. This can include the application having a different window, its own icon in the application launcher, etc. In this mode, the user agent will exclude UI elements for controlling navigation, but can include other UI elements such as a status bar.

minimal-ui

The application will look and feel like a standalone application, but will have a minimal set of UI elements for controlling navigation. The elements will vary by browser.

browser

The application opens in a conventional browser tab or new window, depending on the browser and platform. This is the default.

window-controls-overlay

This display mode only applies when the application is in a separate PWA window and on a desktop operating system. The application will opt-in to the Window Controls Overlay feature, where the full window surface area will be available for the app's web content and the window control buttons (maximize, minimize, close, and other PWA-specific buttons) will appear as an overlay above the web content.

Related Applications

The prefer_related_applications member is a boolean value that specifies that applications listed in related_applications should be preferred over the web application.

If the prefer_related_applications member is set to true, the user agent might suggest installing one of the related applications instead of this web application.

/config/packages/pwa.yaml
pwa:
    manifest:
        prefer_related_applications: true
        related_applications:
            - platform: "play"
              url: "https://play.google.com/store/apps/details?id=com.example.app1"
              id: "com.example.app1"
            - platform: "itunes"
              url: "https://itunes.apple.com/app/example-app1/id123456789"
            - platform: "windows"
              url: "https://apps.microsoft.com/store/detail/example-app1/id123456789"

Currently known possible values for the platform member are as follows;

"chrome_web_store": .

"play": .

"chromeos_play": .

"webapp": .

"windows": .

"f-droid": .

"amazon": .

Google Chrome Web Store
Google Play Store
Chrome OS Play
Web apps
Windows Store
F-droid
Amazon App Store

BackgroundSync Form

TO BE WRITTEN

Usage

Parameters

None

Actions

Targets

None

Events

None

Translations

The bundle leverages on Symfony Translation component is available. The texts you pass for almost all names, short names, descriptions, labels... can be translation keys.

This feature is in early development stage and may not work as expected. Use with caution

/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        name: "app.name"
        short_name: "app.short_name"
        start_url: "/index.html"
        displa": "standalone"
        background_color: "#ffffff"
        theme_color: "#4285f4"
        shortcuts:
            - name: "app.feature1.shorcut.name"
              short_name: "app.feature1.shorcut.short_name"
              description: "app.feature1.shorcut.description"
              url: "/start-chat"
              icons":          
                - src: "icons/feature1-96x96.png"
                  sizes: [96]

Launch Handler

The Launch Handler API allows developers to control how your PWA is launched. For example if it uses an existing window or creates a new one, and how the app's target launch URL is handled.

This has one sub-field, client_mode, which contains a string value specifying how the app should be launched and navigated to.

/config/packages/pwa.yaml
pwa:
    manifest:
        enabled: true
        launch_handler:
            client_mode: "focus-existing"

If not specified, the default client_mode value is auto. Available values are:

  • focus-existing: The most recently interacted with browsing context in a web app window is chosen to handle the launch. This will populate the target launch URL in the targetURL property of the LaunchParams object passed into the window.launchQueue.setConsumer()'s callback function. As you'll see below, this allows you to set custom launch handing functionality for your app.

  • navigate-existing: The most recently interacted with browsing context in a web app window is navigated to the target launch URL. The target URL is still made available via window.launchQueue.setConsumer() to allow additional custom launch navigation handling to be implemented.

  • navigate-new: A new browsing context is created in a web app window to load the target launch URL. The target URL is still made available via window.launchQueue.setConsumer() to allow additional custom launch navigation handling to be implemented.

  • auto: The user agent decides what works best for the platform. For example, navigate-existing might make more sense on mobile, where single app instances are commonplace, whereas navigate-new might make more sense in a desktop context. This is the default value used if provided values are invalid.

Widgets (Win10+)

To be written