Java, JavaScript + HTML5, Sencha, Cordova/Ionic, Angular, RxJS + all things reactive
Sites Estáticos
Sites Dinâmicos
AJAX
Design Responsivo
PWAs
uma nova metodologia de desenvolvimento de software
um Progressive Web App pode ser visto como uma evolução híbrida entre as páginas da web regulares (ou sites) e um aplicativo móvel
Progressivo
Descobrível
Linkável
Responsivo
App-like
Sempre Atualizado
Instalável
Engajável
Seguro
Independente
Conexão
{
"name": "Loiane",
"short_name": "Loiane",
icons: [{
src: "images/touch/icon-96x96.png",
sizes: "96x96",
type: "image/png"
}, {
src: "images/touch/icon-128x128.png",
sizes: "128x128",
type: "image/png"
}, {
src: "images/touch/apple-touch-icon.png",
sizes: "152x152",
type: "image/png"
}, {
src: "images/touch/chrome-touch-icon-192x192.png",
sizes: "192x192",
type: "image/png"
}],
"start_url": "/index.html",
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone",
"orientation": "portrait"
}
{
"short_name": "Users",
"name": "Users PWA",
"icons": [
{
"src": "icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"scope": "/",
"start_url": "/index.html",
"orientation": "portrait",
"display": "standalone",
"theme_color": "#ffffff",
"background_color": "#ffffff"
}
<link rel="manifest" href="/manifest.json">
<link rel="stylesheet" href="assets/mdl/material.min.css" />
...
<body>
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<header class="mdl-layout__header">
<div class="mdl-layout__header-row">
<span class="mdl-layout-title">Ramdom Users</span>
<div class="mdl-layout-spacer"></div>
</div>
</header>
<main class="mdl-layout__content">
<div id="first-load" class="center">
<!-- svg: ícone dos usuários -->
<p>Loading users...</p>
</div>
<div id="connection-status" class="center"></div>
<div class="mdl-grid">
<!-- Conteúdo Dinâmico-->
</div>
<div class="center">
<button onclick="pageEvents.loadMore()" class="mdl-button">
Load More
</button>
</div>
</main>
</div>
...
</body>
var cacheFiles = [
'dist/app.js',
'index.html',
'assets/mdl/material.min.css',
'assets/mdl/material.min.js'
];
// Registrar o ServiceWorker na aplicação
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/sw.js', {scope:''})
.then((registration) => {
// SW registrado!
});
}
// http://bit.ly/sw-lifecycle
self.addEventListener('install', (event) => {
// SW foi baixado e instalado
// Passo 1 é cachear o App Shell
// Preparar a app para funcionar offline
});
self.addEventListener('activate', (event) => {
// SW está instalado e ativo
// Podemos terminar o setup
// Ou limpar cache antigo
});
self.addEventListener('fetch', (event) => {
// Escuta cada evento
// E faz alguma coisa para cada request
// feito da app para API server
});
var CACHE_NAME = 'usersCacheV1';
var CACHE_FILES = [
'dist/app.js',
'index.html',
'assets/js/localForage/localforage.min.js',
'assets/js/localForage/localforage-getitems.js',
'assets/js/localForage/localforage-setitems.js',
'assets/mdl/material.min.css',
'assets/mdl/material.min.js'
];
self.addEventListener('install', (event) => {
// abre o cache
event.waitUntil(
caches.open(CACHE_NAME)
// e add arquivos offline no cache
.then((cache) => {
return cache.addAll(CACHE_FILES));
})
// Arquivos já cacheado!
.then(() => self.skipWaiting())
);
});
self.addEventListener('fetch', function(event){
var requestUrl = new URL(event.request.url);
var requestPath = requestUrl.pathname;
// se for imagem, request online
if(requestPath == imagePath){
event.respondWith(networkFirstStrategy(event.request));
// se for request, tenta cache primeiro e depois online
} else{
event.respondWith(cacheFirstStrategy(event.request));
}
});
Estratégias: Cache first ou Online first
function cacheFirstStrategy(request){
return caches.match(request).then(function(cacheResponse){
return cacheResponse || fetchRequestAndCache(request);
});
}
function networkFirstStrategy(request){
return fetchRequestAndCache(request).catch(function(response){
return caches.match(request);
});
}
function fetchRequestAndCache(request){
return fetch(request).then(function(networkResponse){
caches.open(getCacheName(request)).then(function(cache){
cache.put(request, networkResponse);
});
return networkResponse.clone();
});
}
let plugins = [
new WorkboxPlugin({
globDirectory: DIST_DIR,
globPatterns: ['**/*.{html,js,css,json,png}'],
swDest: path.join(DIST_DIR, 'sw.js')
})
],
...;
const workboxSW = new WorkboxSW();
const networkFirst = workboxSW.strategies.networkFirst();
workboxSW.router.registerRoute('/users', networkFirst);
fechData() {
const me = this;
me.page++;
return new Promise(function(resolve, reject) {
fetch(me.getUrlRequest())
.then(function(response) {
return response.json();
})
.then(function(data) {
me.clientStorage
.addUsers(data.results, me.page, me.resultsQtd).then(function() {
data.results.forEach(me.preCacheUserDetails);
resolve('The connection is OK, showing results from server');
});
})
.catch(function(e) {
resolve('No connection, showing offline results');
});
setTimeout(function() {
resolve('Bad connection, showing offline results');
}, 3000);
});
}