From 686cea3fd5bd3f2147da8b35499dc4e8d5e3073b Mon Sep 17 00:00:00 2001 From: Derek Herman Date: Fri, 30 Jul 2021 15:45:16 -0700 Subject: [PATCH 01/15] Add daily deployments to staging to keep URL live --- .github/workflows/daily.yaml | 85 ++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 .github/workflows/daily.yaml diff --git a/.github/workflows/daily.yaml b/.github/workflows/daily.yaml new file mode 100644 index 0000000..6f6a475 --- /dev/null +++ b/.github/workflows/daily.yaml @@ -0,0 +1,85 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Daily + +on: + schedule: + - cron: '0 16 * * *' + +jobs: + + lint-js: + name: Lint JS + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + ref: develop + + - name: Get npm cache directory + id: npm-cache + run: echo "::set-output name=dir::$(npm config get cache)" + + - name: Configure npm cache + uses: actions/cache@v2 + with: + path: ${{ steps.npm-cache.outputs.dir }} + key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-npm- + + - name: Install Node dependencies + run: npm ci + + - name: Detect coding standard violations + run: npm run lint + + deploy-staging: + needs: [lint-js] + name: Deploy Staging + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + ref: develop + + - name: Get npm cache directory + id: npm-cache + run: echo "::set-output name=dir::$(npm config get cache)" + + - name: Configure npm cache + uses: actions/cache@v2 + with: + path: ${{ steps.npm-cache.outputs.dir }} + key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-npm- + + - name: Install Node dependencies + run: npm ci + + - name: Build Assets + run: npm run build + + - name: Deploy to Firebase + uses: FirebaseExtended/action-hosting-deploy@v0 + with: + repoToken: "${{ secrets.GITHUB_TOKEN }}" + firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT }}" + expires: 30d + projectId: "${{ secrets.FIREBASE_PROJECT_ID }}" + channelId: staging From fd614b5f5bd4f820bfcadae04a372b55bf2dc9d0 Mon Sep 17 00:00:00 2001 From: Derek Herman Date: Fri, 30 Jul 2021 15:47:27 -0700 Subject: [PATCH 02/15] Update dynamic hosting URL for staging --- cors.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cors.json b/cors.json index 12b947d..53864a1 100644 --- a/cors.json +++ b/cors.json @@ -2,7 +2,7 @@ { "origin": [ "https://kinoweb-dev.web.app", - "https://kinoweb-dev--staging-5ooakhlz.web.app", + "https://kinoweb-dev--staging-2ra3ji0i.web.app", "https://kinoweb.dev", "http://localhost:5000" ], From a50300415e4547d161c367aaf9e9ba38e8aaa44c Mon Sep 17 00:00:00 2001 From: Derek Herman Date: Fri, 30 Jul 2021 16:06:17 -0700 Subject: [PATCH 03/15] Bump version 1.0.0-beta3 --- package-lock.json | 2 +- package.json | 2 +- src/js/constants.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e59db0f..114cdd4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "kino", - "version": "1.0.0-beta2", + "version": "1.0.0-beta3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index dbd8c11..02e3ec1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kino", - "version": "1.0.0-beta2", + "version": "1.0.0-beta3", "description": "A sample offline streaming video PWA built for web.dev/media", "main": "src/index.js", "author": "Google", diff --git a/src/js/constants.js b/src/js/constants.js index 999a280..8481c29 100644 --- a/src/js/constants.js +++ b/src/js/constants.js @@ -23,7 +23,7 @@ * There may be adjacent caches used for other purposes and we * want to let the SW know which caches it should purge on upgrade. */ -export const SW_CACHE_NAME = 'static-assets-v1.0.0-beta2'; +export const SW_CACHE_NAME = 'static-assets-v1.0.0-beta3'; export const SW_CACHE_FORMAT = /^static-assets-v[a-z0-9.-]+$/; /** From 701533318833a42d784726d97577a1680ae5a165 Mon Sep 17 00:00:00 2001 From: Derek Herman Date: Fri, 30 Jul 2021 16:07:45 -0700 Subject: [PATCH 04/15] Set cron schedule to every hours for testing --- .github/workflows/daily.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily.yaml b/.github/workflows/daily.yaml index 6f6a475..a4c083f 100644 --- a/.github/workflows/daily.yaml +++ b/.github/workflows/daily.yaml @@ -16,7 +16,7 @@ name: Daily on: schedule: - - cron: '0 16 * * *' + - cron: '10 * * * *' jobs: From 6e0007711634eae451b43f1c8e1cbf18fdcb3bb3 Mon Sep 17 00:00:00 2001 From: Derek Herman Date: Fri, 30 Jul 2021 16:15:41 -0700 Subject: [PATCH 05/15] Set schedule to 30 mins after the hour --- .github/workflows/daily.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily.yaml b/.github/workflows/daily.yaml index a4c083f..f4fa89c 100644 --- a/.github/workflows/daily.yaml +++ b/.github/workflows/daily.yaml @@ -16,7 +16,7 @@ name: Daily on: schedule: - - cron: '10 * * * *' + - cron: '30 * * * *' jobs: From b4c7cd0ef356416d497044e9bc14941b365de57d Mon Sep 17 00:00:00 2001 From: Derek Herman Date: Fri, 30 Jul 2021 16:37:33 -0700 Subject: [PATCH 06/15] Deploy staging at 6:20am every day --- .github/workflows/daily.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily.yaml b/.github/workflows/daily.yaml index f4fa89c..e54fb8a 100644 --- a/.github/workflows/daily.yaml +++ b/.github/workflows/daily.yaml @@ -16,7 +16,7 @@ name: Daily on: schedule: - - cron: '30 * * * *' + - cron: '20 6 * * *' jobs: From 72c05ded3ff3c0fcbc69c803d5665cbb432a6a26 Mon Sep 17 00:00:00 2001 From: Derek Herman Date: Fri, 30 Jul 2021 16:59:15 -0700 Subject: [PATCH 07/15] Schedule cron job to deploy staging every Monday at 6:20am --- .github/workflows/{daily.yaml => cron-schedule.yaml} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .github/workflows/{daily.yaml => cron-schedule.yaml} (98%) diff --git a/.github/workflows/daily.yaml b/.github/workflows/cron-schedule.yaml similarity index 98% rename from .github/workflows/daily.yaml rename to .github/workflows/cron-schedule.yaml index e54fb8a..e177aad 100644 --- a/.github/workflows/daily.yaml +++ b/.github/workflows/cron-schedule.yaml @@ -12,11 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -name: Daily +name: Cron Schedule on: schedule: - - cron: '20 6 * * *' + - cron: '20 6 * * 1' jobs: From ac2dc00af2ebf505960844ae75c27602118c5c5f Mon Sep 17 00:00:00 2001 From: Derek Herman Date: Fri, 30 Jul 2021 19:59:05 -0700 Subject: [PATCH 08/15] Add @rollup/plugin-json to convert .json files to ES6 modules --- package-lock.json | 9 +++++++++ package.json | 1 + rollup.config.js | 2 ++ 3 files changed, 12 insertions(+) diff --git a/package-lock.json b/package-lock.json index 114cdd4..9dacdae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1719,6 +1719,15 @@ "fastq": "^1.6.0" } }, + "@rollup/plugin-json": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", + "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.8" + } + }, "@rollup/pluginutils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", diff --git a/package.json b/package.json index 02e3ec1..f3a68b8 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@babel/eslint-parser": "^7.14.4", "@babel/eslint-plugin": "^7.13.16", "@babel/preset-env": "^7.14.4", + "@rollup/plugin-json": "^4.1.0", "chokidar-cli": "^2.1.0", "eslint": "^7.27.0", "eslint-config-airbnb-base": "^14.2.1", diff --git a/rollup.config.js b/rollup.config.js index 7e5a1ea..8d9d7ad 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -17,6 +17,7 @@ import css from 'rollup-plugin-import-css'; import generateApi from './src/js/utils/generateApi.js'; import generateAssetsToCache from './src/js/utils/generateAssetsToCache'; +import json from '@rollup/plugin-json'; async function setupApi() { try { @@ -35,6 +36,7 @@ export default [ format: 'cjs', }, plugins: [ + json(), css(), ], }, From 5d9043209731de49e43fc99fefe1bff252f8461e Mon Sep 17 00:00:00 2001 From: Derek Herman Date: Fri, 30 Jul 2021 20:02:27 -0700 Subject: [PATCH 09/15] Route missing pages to a basic 404 handler --- src/index.js | 21 ++++++++++++++++----- src/js/pages/Error.js | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 src/js/pages/Error.js diff --git a/src/index.js b/src/index.js index c89c4e2..7559bd0 100644 --- a/src/index.js +++ b/src/index.js @@ -20,6 +20,7 @@ import Router from './js/classes/Router'; import VideoDownloaderRegistry from './js/classes/VideoDownloaderRegistry'; import ConnectionStatus from './js/classes/ConnectionStatus'; +import api from '../public/api.json'; /** * Web Components implementation. @@ -39,6 +40,7 @@ import VideoPage from './js/pages/Video'; import CategoryPage from './js/pages/Category'; import DownloadsPage from './js/pages/Downloads'; import SettingsPage from './js/pages/Settings'; +import ErrorPage from './js/pages/Error'; /** * Settings @@ -118,15 +120,24 @@ const router = new Router({ videoDownloaderRegistry, connectionStatus, }); -router.route('^/settings/?', SettingsPage); -router.route('^/downloads/?', DownloadsPage); -router.route('^/category/([^/]*)/?', CategoryPage); router.route('^/?$', HomePage); +router.route('^/downloads/$', DownloadsPage); +router.route('^/settings/$', SettingsPage); /** - * Consider all else a single video page. + * Add the category pages. */ -router.route('.*', VideoPage); +api.categories.forEach((category) => router.route(`^/category/${category.slug}/$`, CategoryPage)); + +/** + * Add the video pages. + */ +api.videos.forEach((video) => router.route(`^/${video.id}/$`, VideoPage)); + +/** + * Consider all else an error. + */ +router.route('.*', ErrorPage); /** * Register Service Worker. diff --git a/src/js/pages/Error.js b/src/js/pages/Error.js new file mode 100644 index 0000000..e74f682 --- /dev/null +++ b/src/js/pages/Error.js @@ -0,0 +1,43 @@ +/** + * Copyright 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @param {RouterContext} routerContext Context object passed by the Router. + */ +export default (routerContext) => { + const { + mainContent, + } = routerContext; + + mainContent.innerHTML = ` + +
+ +
+ `; + + const meta = document.createElement('meta'); + meta.name = 'robots'; + meta.content = 'noindex'; + document.head.appendChild(meta); +}; From 66376113a72853de65c4d36a028379d184e91302 Mon Sep 17 00:00:00 2001 From: Derek Herman Date: Fri, 30 Jul 2021 20:16:09 -0700 Subject: [PATCH 10/15] Update error text --- src/js/pages/Error.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/js/pages/Error.js b/src/js/pages/Error.js index e74f682..fde2115 100644 --- a/src/js/pages/Error.js +++ b/src/js/pages/Error.js @@ -20,18 +20,20 @@ export default (routerContext) => { const { mainContent, + path, } = routerContext; mainContent.innerHTML = `
`; From 305bf94329440cca372e87e8e119857bd6d87bce Mon Sep 17 00:00:00 2001 From: Derek Herman Date: Fri, 30 Jul 2021 21:15:39 -0700 Subject: [PATCH 11/15] Ignore file when missing from CI/CD pipeline --- .eslintrc.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.eslintrc.json b/.eslintrc.json index 3f0a65a..c120c02 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -32,6 +32,13 @@ "src/js/utils/generateApi.js" ] } + ], + "import/no-unresolved": [ + "error", { + "ignore": [ + "../public/api.json" + ] + } ] } } From 35c8fcc39837d9f511abaef15e6ba8c906fc7c3c Mon Sep 17 00:00:00 2001 From: Derek Herman Date: Fri, 30 Jul 2021 21:19:23 -0700 Subject: [PATCH 12/15] Ensure API is generated for both rollup input files --- rollup.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/rollup.config.js b/rollup.config.js index 8d9d7ad..8dc4536 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -36,6 +36,7 @@ export default [ format: 'cjs', }, plugins: [ + setupApi(), json(), css(), ], From 6afa69b9ee6e3035c7adc4abee28d012e0d0476b Mon Sep 17 00:00:00 2001 From: Derek Herman Date: Thu, 5 Aug 2021 15:33:47 -0700 Subject: [PATCH 13/15] Optimize the Rollup API & Cache generator plugins --- rollup.config.js | 15 +---- src/js/utils/generateApi.js | 27 ++++---- ...erateAssetsToCache.js => generateCache.js} | 62 ++++++++++--------- 3 files changed, 52 insertions(+), 52 deletions(-) rename src/js/utils/{generateAssetsToCache.js => generateCache.js} (56%) diff --git a/rollup.config.js b/rollup.config.js index 8dc4536..e72e2fb 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -16,18 +16,9 @@ import css from 'rollup-plugin-import-css'; import generateApi from './src/js/utils/generateApi.js'; -import generateAssetsToCache from './src/js/utils/generateAssetsToCache'; +import generateCache from './src/js/utils/generateCache'; import json from '@rollup/plugin-json'; -async function setupApi() { - try { - const api = await generateApi(); - await generateAssetsToCache(api); - } catch (err) { - console.error(err); - } -} - export default [ { input: 'src/index.js', @@ -36,7 +27,7 @@ export default [ format: 'cjs', }, plugins: [ - setupApi(), + generateApi(), json(), css(), ], @@ -48,7 +39,7 @@ export default [ format: 'cjs', }, plugins: [ - setupApi(), + generateCache(), ], }, ]; diff --git a/src/js/utils/generateApi.js b/src/js/utils/generateApi.js index 7f9c99c..556060f 100644 --- a/src/js/utils/generateApi.js +++ b/src/js/utils/generateApi.js @@ -83,19 +83,22 @@ const generateApiData = async () => { }; /** - * Generates the JSON API. + * Generates the public JSON API. * - * @returns {object} The API object. + * @returns {object} The plugin configuration. */ -export default async function generateApi() { - const start = Date.now(); - const apiData = await generateApiData(); - const apiDataJSON = JSON.stringify(apiData, undefined, 2); +export default function generateApi() { + return { + name: 'generate-api', + buildStart: async () => { + const start = Date.now(); + const apiData = await generateApiData(); + const apiDataJSON = JSON.stringify(apiData, undefined, 2); - fs.writeFile(apiDestFile, apiDataJSON, { encoding: 'utf-8' }, () => { - const time = Date.now() - start; - process.stdout.write(`\x1b[32mcreated \x1b[1m${apiDestFile}\x1b[22m in \x1b[1m${time}ms\x1b[22m\x1b[89m\n`); - }); - - return apiData; + fs.writeFile(apiDestFile, apiDataJSON, { encoding: 'utf-8' }, () => { + const time = Date.now() - start; + process.stdout.write(`\x1b[32mcreated \x1b[1m${apiDestFile}\x1b[22m in \x1b[1m${time}ms\x1b[22m\x1b[89m\n`); + }); + }, + }; } diff --git a/src/js/utils/generateAssetsToCache.js b/src/js/utils/generateCache.js similarity index 56% rename from src/js/utils/generateAssetsToCache.js rename to src/js/utils/generateCache.js index b121b17..880944c 100644 --- a/src/js/utils/generateAssetsToCache.js +++ b/src/js/utils/generateCache.js @@ -40,34 +40,38 @@ async function* getFiles(dir) { /** * Generates the cached assets for the service worker. * - * @param {object} api The video files API. + * @returns {object} The plugin configuration. */ -export default async function generateAssetsToCache(api) { - const start = Date.now(); - const filesRegExp = /\.(html|css|js|svg|png|jpeg|jpg|ico)$/i; - const excludeFiles = ['sw.js', '404.html']; - const assetsToCache = ['/', '/api.json']; - const folder = 'public'; +export default function generateCache() { + return { + name: 'generate-cache', + buildStart: async () => { + const start = Date.now(); + const api = JSON.parse(fs.readFileSync(`${process.cwd()}/public/api.json`, 'utf8')); + const filesRegExp = /\.(html|css|js|svg|png|jpeg|jpg|ico)$/i; + const excludeFiles = ['sw.js', '404.html']; + const assetsToCache = ['/', '/api.json']; + const folder = 'public'; - // eslint-disable-next-line - for await (const file of getFiles(folder)) { - const fileName = path.basename(file); - const filePath = file.replace(`${process.cwd()}/${folder}`, ''); - if (fileName.match(filesRegExp) && !excludeFiles.includes(fileName)) { - assetsToCache.push(filePath); - } - } + // eslint-disable-next-line + for await (const file of getFiles(folder)) { + const fileName = path.basename(file); + const filePath = file.replace(`${process.cwd()}/${folder}`, ''); + if (fileName.match(filesRegExp) && !excludeFiles.includes(fileName)) { + assetsToCache.push(filePath); + } + } - // Add files from the API. - api.videos.forEach((video) => { - if (Array.isArray(video.thumbnail)) { - video.thumbnail.forEach((thumbnail) => assetsToCache.push(thumbnail.src)); - } else if (Object.prototype.toString.call(video.thumbnail) === '[object String]') { - assetsToCache.push(video.thumbnail); - } - }); + // Add files from the API. + api.videos.forEach((video) => { + if (Array.isArray(video.thumbnail)) { + video.thumbnail.forEach((thumbnail) => assetsToCache.push(thumbnail.src)); + } else if (Object.prototype.toString.call(video.thumbnail) === '[object String]') { + assetsToCache.push(video.thumbnail); + } + }); - const data = `/* + const data = `/* Copyright 2021 Google LLC Licensed under the Apache License, Version 2.0 (the "License"); @@ -85,8 +89,10 @@ limitations under the License. export default [\n '${assetsToCache.join("',\n '")}',\n];\n`; - fs.writeFile('src/js/sw/cache.js', data, () => { - const time = Date.now() - start; - process.stdout.write(`\x1b[32mcreated \x1b[1msrc/js/sw/cache.js\x1b[22m in \x1b[1m${time}ms\x1b[22m\x1b[89m\n`); - }); + fs.writeFile('src/js/sw/cache.js', data, () => { + const time = Date.now() - start; + process.stdout.write(`\x1b[32mcreated \x1b[1msrc/js/sw/cache.js\x1b[22m in \x1b[1m${time}ms\x1b[22m\x1b[89m\n`); + }); + }, + }; } From 2906981bed19bb8f65eeff84dc6dc3881bda64d3 Mon Sep 17 00:00:00 2001 From: Derek Herman Date: Thu, 5 Aug 2021 15:45:58 -0700 Subject: [PATCH 14/15] Update the repository organization --- README.md | 2 +- public/index.html | 2 +- src/api/streaming/06-adaptive-streaming.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8e2e452..b635304 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Start by creating a new project from the [Firebase Console](https://console.fire Clone this repository: - git clone git@github.com:xwp/kino.git + git clone git@github.com:GoogleChrome/kino.git Go to the project folder: diff --git a/public/index.html b/public/index.html index 6facead..f19c825 100644 --- a/public/index.html +++ b/public/index.html @@ -98,7 +98,7 @@ - See the source code + See the source code

diff --git a/src/api/streaming/06-adaptive-streaming.md b/src/api/streaming/06-adaptive-streaming.md index 2dbe9fe..2584e1e 100644 --- a/src/api/streaming/06-adaptive-streaming.md +++ b/src/api/streaming/06-adaptive-streaming.md @@ -87,4 +87,4 @@ PWA and building more features and writing new content. If you want to contribut to the code that runs this site, make a suggestion, request a feature, or just want to see how it was built go check out the [source code]. -[source code]: https://github.com/xwp/kino/ +[source code]: https://github.com/GoogleChrome/kino/ From 4228ba261440948d8868fa908afde3f15728551e Mon Sep 17 00:00:00 2001 From: Derek Herman Date: Thu, 5 Aug 2021 17:43:06 -0700 Subject: [PATCH 15/15] Update the main app description --- README.md | 2 +- src/js/pages/Home.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b635304..5483759 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Kino -This is a sample media (VOD) app to demonstrate media functionality in the context of a Progressive Web App. +This is a sample Video on demand (VOD) app to demonstrate media functionality in the context of a Progressive Web App (PWA). ## Running the site locally diff --git a/src/js/pages/Home.js b/src/js/pages/Home.js index 05df312..8d6fece 100644 --- a/src/js/pages/Home.js +++ b/src/js/pages/Home.js @@ -26,7 +26,8 @@ export default (routerContext) => {
`;