Are you thinking and planning to integrate Modern TYPO3 PWA to your TYPO3 website? If yes, then Congratulations! In this article, you will learn the basics of TYPO3 PWA and TYPO3 Headless CMS. Keep reading!
PWA is one of the most modern web technologies! Also, it’s getting more attention from the people who believe in keeping their business websites updated. Fortunately, our beloved TYPO3 community also stays up-to-date with modern technologies like TYPO3 Headless CMS, TYPO3 PWA, etc. Are you excited to know in-depth about buzzing words like TYPO3 PWA, TYPO3 Headless, TYPO3 APIs etc? Let’s go!
At T3Planet and NITSAN; We wrote some of the articles on TYPO3 PWA and TYPO3 Headless CMS. I recommend reading exciting articles too.
- Trending: What Is TYPO3 Headless CMS?
- How to use TYPO3 + ReactJS [2021]
- All About Progressive Web Apps (PWA) and its implementation in TYPO3
My dear TYPO3 reader; As you know, my ritual is to Appreciate the work of TYPO3 people. I want to dedicate this blog to the Headless/PWA TYPO3 initiative in the TYPO3 community. Give a big hand for their dedicated contribution to bring TYPO3 to the next level. #T3Kudos to everyone!
“Progressive Web App (PWA) is a term used to denote a new software development methodology. Unlike traditional applications, progressive web apps are a hybrid of regular web pages (or websites) and mobile applications. This new application model attempts to combine features offered by most modern browsers with the benefits of mobile experience.”
- Wikipedia
Make no mistake: Progressive Web Applications are still websites. They simply appear and experience like an app, thanks to modern web technology. This means customers will browse Progressive Web Apps on their browser with an URL much like they do any website, however right when they land at the PWA, and they get the enjoyment of the use of an “app”, right on their browser, without the want to download and install. How cool is that!
All in all, PWA is a new, future-proof technology. They are preferred and promoted via way of means of Google and proven to expose break-thru outcomes via way of means of a number of the most essential names inside the industry:
What are the Features and Benefits of TYPO3 PWA?
- Instant Loading Time
- Offline Browsing
- Push Notification
- Ready for App & Play Stores
- Home Screen Save
- No Updates Required
- Linkability & Indexing
- Lightweight
When is a good time to start TYPO3 PWA? NOW!
Yes, the answer is NOW; You should consider implementing the important fundamentals of TYPO3 PWA.
- The biggest and best brands are already using PWA.
- The Mobile-first era is here.
- Google announced mobile-first indexing as default.
3 Main Block Building of TYPO3 PWA
It doesn’t take a whole lot to install a PWA. There are three belongings you want to provide before your site turns into a valid PWA.
#1 Secure Connection (HTTPS)
PWAs only work on trusted connections; you need to serve them over a secure connection. This isn't always handiest for security reasons. However, it’s additionally a critical trust factor for users.
#2 Service Worker
A service worker is a chunk of a script that runs in the background. This enables you to decide a way to take care of network requests in your PWA, making it feasible to do more complex work.
#3 Manifest.json
This JSON file contains information on how your PWA has to seem and function. Here, you determine the name, description, icons, colors, et cetera.
Here’s a pattern show up from Google:
// Create manifest.json
{
"short_name": "Weather",
"name": "Weather: Do I need an umbrella?",
"description": "Weather forecast information",
"icons": [
{
"src": "/images/icons-192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/images/icons-512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": "/?source=pwa",
"background_color": "#3367D6",
"display": "standalone",
"scope": "/",
"theme_color": "#3367D6"
}
// Include at TYPO3 code
<link rel="manifest" href = "/manifest.json">
Best Practice to Add Favicons & Manifest.json in TYPO3
Here is the sample code to ideally insert favicons and manifest.json for TYPO3 PWA.
<!-- Create Favicons.html -->
<html data-namespace-typo3-fluid="true" xmlns:f="http://typo3.org/ns/TYPO3/Fluid/ViewHelpers">
<link rel="apple-touch-icon" sizes="57x57" href="{f:uri.resource(path:'Favicons/apple-touch-icon-57x57.png')}">
<link rel="apple-touch-icon" sizes="60x60" href="{f:uri.resource(path:'Favicons/apple-touch-icon-60x60.png')}">
<link rel="apple-touch-icon" sizes="72x72" href="{f:uri.resource(path:'Favicons/apple-touch-icon-72x72.png')}">
<link rel="apple-touch-icon" sizes="76x76" href="{f:uri.resource(path:'Favicons/apple-touch-icon-76x76.png')}">
<link rel="apple-touch-icon" sizes="114x114" href="{f:uri.resource(path:'Favicons/apple-touch-icon-114x114.png')}">
<link rel="apple-touch-icon" sizes="120x120" href="{f:uri.resource(path:'Favicons/apple-touch-icon-120x120.png')}">
<link rel="apple-touch-icon" sizes="144x144" href="{f:uri.resource(path:'Favicons/apple-touch-icon-144x144.png')}">
<link rel="apple-touch-icon" sizes="152x152" href="{f:uri.resource(path:'Favicons/apple-touch-icon-152x152.png')}">
<link rel="apple-touch-icon" sizes="180x180" href="{f:uri.resource(path:'Favicons/apple-touch-icon-180x180.png')}">
<link rel="icon" type="image/png" href="{f:uri.resource(path:'Favicons/favicon-32x32.png')}" sizes="32x32">
<link rel="icon" type="image/png" href="{f:uri.resource(path:'Favicons/android-chrome-192x192.png')}" sizes="192x192">
<link rel="icon" type="image/png" href="{f:uri.resource(path:'Favicons/favicon-96x96.png')}" sizes="96x96">
<link rel="icon" type="image/png" href="{f:uri.resource(path:'Favicons/favicon-16x16.png')}" sizes="16x16">
<link rel="manifest" href="{f:uri.resource(path:'Favicons/manifest.json')}">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="msapplication-TileImage" content="{f:uri.resource(path:'Favicons/mstile-144x144.png')}">
</html>
// Call Favicons.html File at TypoScript
page.headerData.2039 = FLUIDTEMPLATE
page.headerData.2039 {
file = EXT:my_ext/Resources/Private/Templates/Favicons.html
extbase.controllerExtensionName = MyExt
}
Addition in Site Configuration
# Addition in Site Configuration
webmanifest:
full_name: 'Full name of website'
short_name: 'Short name'
theme_color: '#000000'
favicon_path: 'EXT:sitepackage/Resources/Public/Images/Favicons/'
favicon_192: android-chrome-192x192.png
favicon_512: android-chrome-512x512.png
Add RequestMiddlewares.php
<?php
return [
'frontend' => [
'yourvendor/webmanifest' => [
'target' => \YourVendor\Sitepackage\Middleware\Webmanifest::class,
'before' => [
'typo3/cms-frontend/page-resolver',
],
'after' => [
'typo3/cms-frontend/site',
],
],
],
];
Add Webmanifest.php
<?php
namespace YourVendor\Sitepackage\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use TYPO3\CMS\Core\Http\JsonResponse;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\Resource\Exception\InvalidFileException;
use TYPO3\CMS\Core\Site\Entity\Site;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\PathUtility;
class Webmanifest implements MiddlewareInterface
{
protected ServerRequestInterface $request;
final const MANIFEST_PATH = '/site.webmanifest';
final const MANIFEST_NAME = 'site.webmanifest';
/**
* @throws InvalidFileException
*/
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
$this->request = $request;
if ($this->isWebmanifestRequest()) {
ob_clean();
return (new JsonResponse())->setPayload($this->generateWebmanifest());
}
$this->addWebmanifestToHead();
return $handler->handle($this->request);
}
protected function isWebmanifestRequest(): bool
{
return $this->request->getUri()->getPath() === self::MANIFEST_PATH;
}
protected function addWebmanifestToHead(): void
{
$siteUrl = $this->request->getAttribute('normalizedParams')->getSiteUrl();
$headerData = '<link rel="manifest" href="' . $siteUrl . self::MANIFEST_NAME . '">';
GeneralUtility::makeInstance(PageRenderer::class)->addHeaderData($headerData);
}
/**
* @return array{background_color: string, display: string, icons: never[]|array<int, array{src: mixed, type: string, sizes: string}>, name?: mixed, short_name?: string, theme_color?: mixed}
* @throws InvalidFileException
*/
protected function generateWebmanifest(): array
{
$siteConfig = $this->getSiteConfig();
$webmanifest = [
'background_color' => '#ffffff',
'display' => 'browser',
'icons' => [],
];
$name = $siteConfig['fullName'] ?? '';
if (!empty($name)) {
$webmanifest['name'] = $name;
}
$shortName = $siteConfig['shortName'] ?? '';
if (!empty($shortName)) {
$webmanifest['short_name'] = $shortName;
}
$themeColor = $siteConfig['themeColor'] ?? '';
if (!empty($themeColor)) {
$webmanifest['theme_color'] = $themeColor;
}
$faviconPath = $siteConfig['faviconPath'] ?? '';
$favicon192 = $siteConfig['favicon192'] ?? '';
$favicon512 = $siteConfig['favicon512'] ?? '';
if (!empty($faviconPath)) {
$icon192 = PathUtility::getPublicResourceWebPath($faviconPath . $favicon192);
if (!empty($icon192)) {
$webmanifest['icons'][] = ['src' => $icon192, 'type' => 'image/png', 'sizes' => '192x192'];
}
$icon512 = PathUtility::getPublicResourceWebPath($faviconPath . $favicon512);
if (!empty($icon512)) {
$webmanifest['icons'][] = ['src' => $icon512, 'type' => 'image/png', 'sizes' => '512x512'];
}
}
return $webmanifest;
}
/**
* @return array{fullName: ?string,shortName: ?string,themeColor: ?string,faviconPath: ?string,favicon192: ?string,favicon512: ?string}
*/
protected function getSiteConfig(): array
{
/** @var Site $site */
$site = $this->request->getAttribute('site');
$configuration = $site->getConfiguration();
return [
'fullName' => $configuration['webmanifest']['full_name'] ?? null,
'shortName' => $configuration['webmanifest']['short_name'] ?? null,
'themeColor' => $configuration['webmanifest']['theme_color'] ?? null,
'faviconPath' => $configuration['webmanifest']['favicon_path'] ?? null,
'favicon192' => $configuration['webmanifest']['favicon_192'] ?? null,
'favicon512' => $configuration['webmanifest']['favicon_512'] ?? null,
];
}
}
Introduce TYPO3 PWA Initiative
"Progressive Web Apps are a hot topic currently. It allows mobile websites to look and feel like native apps, work offline or be installable, and more. TYPO3 should make it easy to build progressive web applications. What is also worth mentioning is that Google promotes the PWA technology as a best practice for the web applications."
- Team TYPO3 PWA
TYPO3 PWA is 100% free and open-source!
Your Awesome Website = TYPO3 CMS + TYPO3PWA (Headless & Reactjs/Vuejs).
Two Different Ways to Setup TYPO3 PWA
To implement TYPO3 PWA, You can choose the easy way (using EXT.pwa_manifest) and better way (using EXT.headless). Let’s drive in-depth for both approaches to develop the TYPO3 PWA application.
#1 Using EXT.pwa_manifest (+ TYPO3 Fluid)
This extension provides a feature to add PWA features to your existing TYPO3 site developed with TypoScript and Fluid. Your website will have a PWA manifest and ServiceWorker. You don’t require any technical or coding skills - just install and configure the extension:
// Check Requirements
The extension requires TYPO3 in version at least 9.5.
// Installation of EXT.pwa_manifest
Install: composer require friendsoftypo3/pwa_manifest
Include TypoScript Template
Access frontend with ?type=835
// Configuration at Your Site
Go to Sites Module > Site Management > Edit your site.
Offline Feature of PWA
The Offline feature of PWA is excellent! Unfortunately, EXT.pwa_manifest does not provide it. To get full features, you can consider EXT.headless + Any of your favour JS frameworks like Vujes/Reactjs; You can easily create an offline feature using such cool JS-stuff. For the quick and simple solution, you may consider online tools like www.pwabuilder.com You can grab ready-to-use Javascript code and configure it to your TYPO3 site
#2 Using EXT.headless (+ Reactjs/Vuejs)
This is a modern approach to creating your site using APIs called “TYPO3 Headless CMS”. Suppose you plan to develop a new website. In that case, you can consider this model with TYPO3 Headless APIs for the backend and any fantastic Javascript framework (like Reactjs/Vuejs) for the frontend rendering.
Team TYPO3 Headless Initiative created two repositories; 1. TYPO3 Headless Extension, 2. Vuejs/Nextjs based Frontend application.
// Check System Requirements for TYPO3 PWA
All you need is ddev in version at least v1.11.2.
// Installation of TYPO3 PWA
git clone github.com/TYPO3-Initiatives/pwa-demo.git
cd pwa-demo
ddev start
ddev pwa-front start
Frontend: pwa-demo.ddev.site
Backend: api.pwa-demo.ddev.site/typo3/ (admin:password)
// Frontend TYPO3 PWA (with Vuejs/Nuxtjs)
git clone github.com/TYPO3-Initiatives/nuxt-typo3.git
cd nuxt-typo3 && yarn install
yarn link
cd front && yarn link "nuxt-typo3"
yarn dev
Read more in-depth article Trending: What Is TYPO3 Headless CMS? Also, Team T3Planet proudly developed and launched the first-everTYPO3 React template How to use TYPO3 + ReactJS [2021]
Closure!
Thanks for reading my TYPO3 blog. I hope you found it helpful.
We can’t say that PWA will kill Native Apps in the future. Nevertheless, there's a developing interest in this method in the community. PWAs are still in their infancy, with a variety of challenges to be addressed. Yet, they have the potential to create a shift in the way the web works.
Food for Thought
According to Henrik Joreteg, “PWA is the single biggest thing to happen on the mobile web since Steve introduced the iPhone!”
Debatable? Controversial? Agreeable?
Think before the time flies!
Sanjay Chauhan
CTO - T3Planet & NITSANSanjay Chauhan, Mitbegründer von NITSAN (Preisgekrönte TYPO3 Agentur) und Pionier von T3Planet, dem ersten TYPO3 Shop weltweit.
Ein wahrer TYPO3-Fanatiker seit 2010.
Mit meinem umfangreichen technischen Wissen und…
More From Author
Sanjay Chauhan
CTO at T3Planet & NITSANSanjay Chauhan, Co-Founder of NITSAN (Award winning TYPO3 agency) and Pioneer of T3Planet (first-ever TYPO3 Shop).
A true TYPO3 fanatic since 2010. I bring strong TYPO3 experience in building customer-business…
More From Author