Skip to content

Commit

Permalink
done PWA(progressive web app)
Browse files Browse the repository at this point in the history
  • Loading branch information
narr committed Jun 26, 2016
1 parent 0722860 commit 94aecff
Show file tree
Hide file tree
Showing 15 changed files with 310 additions and 20 deletions.
20 changes: 20 additions & 0 deletions config/my-loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// https://webpack.github.io/docs/loaders.html#writing-a-loader
// http://stackoverflow.com/questions/35479987/query-not-found-for-webpack-custom-loader

// don't change to ES6's arrow function because of 'this' context
module.exports = function (source) {
let rtn = source;
this.cacheable();
// console.log('// ================================');
// console.log(this._compilation);
// console.log(this);
if (this.query.indexOf('name=service-worker') > -1) {
rtn += `\n// ${Date.now()}`; // to change the hash value of service-worker.js on every build
} else { // index.html
if (this.options.metadata.github) {
rtn = rtn.replace(/\/asset\//g, '/narr/asset/');
}
}
// console.log(rtn);
return rtn;
};
48 changes: 48 additions & 0 deletions config/sw-cache-target.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// relative to output path

module.exports = {
include: {
'/': true,
},
exclude: {
'asset/img/ic/ic.favicon.ico': true,
'manifest.json': true,
'service-worker.js': true,
'js/main.bundle.js.map': true,
'css/main.bundle.css.map': true,
'js/polyfills.bundle.js.map': true,
'js/vendor.bundle.js.map': true,
'css/vendor.bundle.css.map': true
}
};

// const target = {
// '/': true,
// '/index.html': true,

// '/css/vendor.bundle.css': true,
// '/css/main.bundle.css': true,

// '/js/polyfills.bundle.js': true,
// '/js/vendor.bundle.js': true,

// '/asset/img/bg.jpg': true,
// '/asset/font/fontawesome-webfont.woff2': true,

// '/asset/img/ic/angular.png': true,

// '/asset/img/ic/ics-skill-language.png': true,
// '/asset/img/ic/ics-skill-framework&library.png': true,
// '/asset/img/ic/ics-skill-etc.png': true,

// '/asset/img/ic/ic.narr.128x128.png': true,
// '/asset/img/ic/ic.narr.144x144.png': true,
// '/asset/img/ic/ic.narr.152x152.png': true,
// '/asset/img/ic/ic.narr.192x192.png': true,
// '/asset/img/ic/ic.narr.256x256.png': true,

// '/asset/img/event.github.jpg': true,
// '/asset/img/event.innorix.jpg': true,
// '/asset/img/event.usoftation.jpg': true,
// '/asset/img/event.cps-telecom.jpg': true
// };
65 changes: 64 additions & 1 deletion config/webpack.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const copy = require('copy');
const webpack = require('webpack');
const WebpackMd5Hash = require('webpack-md5-hash');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const swCacheKeys = require('./sw-cache-target');

const IS_FOR_GITHUB_PAGE = helpers.hasProcessFlag('-my-ghp');
const BASE_URL = IS_FOR_GITHUB_PAGE ? '/narr/' : '/';
Expand Down Expand Up @@ -78,9 +79,68 @@ function rename(src, dest) {
rd.pipe(wr);
}

function setCacheTargetForServiceWorker(assets) {
let targetStr = '';
const include = swCacheKeys.include;
for (let key in include) {
if (include.hasOwnProperty(key)) {
if (key === '/') {
targetStr += '\'' + BASE_URL + '\',\n';
} else {
targetStr += '\'' + BASE_URL + key + '\',\n';
}
}
}
// console.log('\n' + targetStr);

const exclude = swCacheKeys.exclude;
let splitArray;
let name;
for (let key in assets) {
if (assets.hasOwnProperty(key)) {
splitArray = key.split('?');
name = splitArray[0];
if (!exclude[name]) {
targetStr += '\'' + BASE_URL + key + '\',\n';
}
}
}
targetStr = '[ ' + targetStr + ' ]';
// console.log(targetStr);
return targetStr;
}

function replaceCacheTargetForServiceWorker(targetStr) {
const swPath = OUTPUT_PATH + '/service-worker.js';
// console.log(swPath);
const readStream = fs.createReadStream(swPath, 'utf8');
let replaced = false;
let newStr = '';

readStream.on('data', chunk => {
// console.log(chunk.toString());
newStr += chunk.toString();
if (!replaced) {
newStr = newStr.replace('\'SW_CACHE_TARGET\'', targetStr);
replaced = true;
}
});

readStream.on('end', () => {
// console.log('Done reading service-worker.js..!!');
// console.log(newStr);
fs.writeFile(swPath, newStr, err => {
if (err) {
return console.log(err);
}
// console.log('Set Cache Target..!!');
});
});
}

module.exports = {
metadata: {
ga: IS_FOR_GITHUB_PAGE
github: IS_FOR_GITHUB_PAGE
// baseUrl: BASE_URL
},
devtool: 'source-map',
Expand Down Expand Up @@ -229,6 +289,9 @@ module.exports = {
const dest = helpers.join(OUTPUT_PATH, 'index.tmpl');
rename(src, dest);
copyAfterDone();

const targetStr = setCacheTargetForServiceWorker(stats.compilation.assets);
replaceCacheTargetForServiceWorker(targetStr);
}
});
}
Expand Down
28 changes: 28 additions & 0 deletions src/app/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,31 @@ if ('development' === ENV) {
require('@angular/core').enableProdMode();
document.addEventListener('DOMContentLoaded', () => main());
}

// @ Progressive Wep App
if ('production' === ENV && 'serviceWorker' in navigator) {
const filename = require('file?name=[name].js?[hash]!' +
'../../config/my-loader?name=service-worker!../service-worker.ts');

// to print out in a build version of webpack(as it removes 'console.log')
const myConsole = console;
// myConsole.log(filename);
(<any>navigator).serviceWorker.register(filename).then(() => {
myConsole.log('Service Worker Registered..!!');
}).catch(e => {
myConsole.log(e);
});

// unregister
// (<any>navigator).serviceWorker.getRegistration().then(ServiceWorkerRegistration => {
// // myConsole.log('Service Worker Unregistered..!!');
// ServiceWorkerRegistration.unregister();
// });
}

require('asset/img/icon/ic.narr.128x128.png');
require('asset/img/icon/ic.narr.144x144.png');
require('asset/img/icon/ic.narr.152x152.png');
require('asset/img/icon/ic.narr.192x192.png');
require('asset/img/icon/ic.narr.256x256.png');
// Progressive Wep App @
Binary file added src/asset/img/icon/ic.narr.128x128.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/asset/img/icon/ic.narr.144x144.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/asset/img/icon/ic.narr.152x152.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/asset/img/icon/ic.narr.192x192.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/asset/img/icon/ic.narr.256x256.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed src/asset/img/icon/ic.narr.png
Binary file not shown.
19 changes: 19 additions & 0 deletions src/custom-typings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,22 @@ declare var HMR: boolean;
declare var PROJECT_PATH: string;
declare var BASE_URL: string;
// Webpack DefinePlugin variables @

// @ service-worker
interface ServiceWorker {
caches: any;
fetch(request: any): Promise<any>;
skipWaiting(): Promise<any>;
clients: {
claim(): Promise<any>;
}
ServiceWorkerRegistration: any;
}
interface ServiceWorkerEvent {
waitUntil(promise: any): void;
request: any;
respondWith(promise: any): void;
}
interface Window extends ServiceWorker { }
interface Event extends ServiceWorkerEvent { }
// service-worker @
38 changes: 20 additions & 18 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,27 @@
<!--<base href="<%= webpackConfig.metadata.baseUrl %>">-->
<link href="<%= require('file?name=asset/img/ic/[name].[ext]?[hash]' +
'!asset/img/icon/ic.favicon.ico') %>" rel="shortcut icon" type="image/x-icon">
<link href="<%= require('file?name=[name].[ext]?[hash]!../config/my-loader!./manifest.json') %>"
rel="manifest">

<% if (webpackConfig.metadata.ga === true) { %>
<script>
(function(i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function() {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o),
m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script',
'https://www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-69400538-6', 'auto');
ga('send', 'pageview');
</script>
<% } %>
<% if (webpackConfig.metadata.github === true) { %>
<script>
(function(i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function() {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o),
m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script',
'https://www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-69400538-6', 'auto');
ga('send', 'pageview');
</script>
<% } %>
</head>

<body>
Expand Down
35 changes: 35 additions & 0 deletions src/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"background_color": "#2080a9",
"display": "standalone",
"icons": [
{
"src": "/asset/img/ic/ic.narr.128x128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "/asset/img/ic/ic.narr.144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "/asset/img/ic/ic.narr.152x152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "/asset/img/ic/ic.narr.192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/asset/img/ic/ic.narr.256x256.png",
"sizes": "256x256",
"type": "image/png"
}
],
"name": "Narr's Website",
"short_name": "Narr",
"start_url": "/index.html",
"theme_color": "#1667b7"
}
75 changes: 75 additions & 0 deletions src/service-worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// https://developers.google.com/web/fundamentals/getting-started/your-first-progressive-web-app/?hl=en
// https://github.com/GoogleChrome/sw-precache
// https://github.com/GoogleChrome/samples
// http://stackoverflow.com/questions/34160509/options-for-testing-service-workers-via-http

// cacheName should be replaced with new one to get new files
const cacheName = 'narr?' + Date.now();
const filesToCache = 'SW_CACHE_TARGET'; // 'SW_CACHE_TARGET' will be replace by webpack

// install
self.addEventListener('install', e => {
console.log('[ServiceWorker] ' + new Date().toString());

e.waitUntil(self.caches.open(cacheName).then(cache => {
console.log('[ServiceWorker] Caching app');
return cache.addAll(filesToCache);
}));

if (typeof self.skipWaiting === 'function') {
console.log('self.skipWaiting() is supported.');
e.waitUntil(self.skipWaiting());
} else {
console.log('self.skipWaiting() is not supported.');
}
});

// activate
self.addEventListener('activate', e => {
console.log('[ServiceWorker] Activate');

e.waitUntil(self.caches.keys().then(keyList => {
return Promise.all(keyList.map(key => {
if (key !== cacheName) {
console.log('[ServiceWorker] Removing old cache', key);
return self.caches.delete(key);
}
}));
}));

if (self.clients && typeof self.clients.claim === 'function') {
console.log('self.clients.claim() is supported.');
e.waitUntil(self.clients.claim());
} else {
console.log('self.clients.claim() is not supported.');
}
});

// fetch
self.addEventListener('fetch', e => {
console.log('[ServiceWorker] Fetch', e.request.url);

const mainBundleUrl = '/js/main.bundle.js';
if (e.request.url.indexOf(mainBundleUrl) > -1) {
e.respondWith(self.fetch(e.request) // to get the latest service-worker.js
.then(response => {
return self.caches.open(cacheName).then(cache => {
cache.put(e.request.url, response.clone());
console.log('[ServiceWorker] Fetched&Cached Data');
return response;
});
})
.catch(err => {
console.log('fetch error..!! and retrieve from cache..!!');
// console.log(err);
return self.caches.match(e.request).then(response => {
return response || self.fetch(e.request); // if no cache, try fetching one more
});
})
);
} else {
e.respondWith(self.caches.match(e.request).then(response => {
return response || self.fetch(e.request);
}));
}
});
2 changes: 1 addition & 1 deletion src/styles/base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ html.touch {
}

body {
background: url(~asset/img/bg.jpg) fixed;
background: url(~asset/img/bg.jpg) no-repeat fixed;
background-size: cover;
// disable scrolling horizontally when sidebar is open in a narrow width of window
// especially this is for IE 11 even though it is still scrollable horizontally(by translateX)
Expand Down

0 comments on commit 94aecff

Please sign in to comment.