use standard

This commit is contained in:
Nolan Lawson 2018-02-08 22:29:29 -08:00
parent 537a112adb
commit 2e83bc0ff9
66 changed files with 1269 additions and 448 deletions

View File

@ -11,7 +11,7 @@ const readFile = pify(fs.readFile.bind(fs))
const glob = pify(require('glob')) const glob = pify(require('glob'))
const rimraf = pify(require('rimraf')) const rimraf = pify(require('rimraf'))
const selectorRegex = /\n[ \t]*([0-9\w\- \t\.:#,]+?)[ \t]*\{/g const selectorRegex = /\n[ \t]*([0-9\w\- \t.:#,]+?)[ \t]*{/g
const styleRegex = /<style>[\s\S]+?<\/style>/ const styleRegex = /<style>[\s\S]+?<\/style>/
async function main () { async function main () {
@ -29,7 +29,7 @@ async function main() {
let text = await readFile(filename, 'utf8') let text = await readFile(filename, 'utf8')
let newText = text.replace(styleRegex, style => { let newText = text.replace(styleRegex, style => {
return style.replace(selectorRegex, selectorMatch => { return style.replace(selectorRegex, selectorMatch => {
return selectorMatch.replace(/\S[^\{]+/, selector => `:global(${selector})`) return selectorMatch.replace(/\S[^{]+/, selector => `:global(${selector})`)
}) })
}) })
let newFilename = path.join(path.dirname(filename), '.tmp-' + path.basename(filename)) let newFilename = path.join(path.dirname(filename), '.tmp-' + path.basename(filename))

View File

@ -22,5 +22,5 @@ module.exports = [
{id: 'fa-comments', src: 'node_modules/font-awesome-svg-png/white/svg/comments.svg', title: 'Conversations'}, {id: 'fa-comments', src: 'node_modules/font-awesome-svg-png/white/svg/comments.svg', title: 'Conversations'},
{id: 'fa-paperclip', src: 'node_modules/font-awesome-svg-png/white/svg/paperclip.svg', title: 'Paperclip'}, {id: 'fa-paperclip', src: 'node_modules/font-awesome-svg-png/white/svg/paperclip.svg', title: 'Paperclip'},
{id: 'fa-thumbtack', src: 'node_modules/font-awesome-svg-png/white/svg/thumb-tack.svg', title: 'Thumbtack'}, {id: 'fa-thumbtack', src: 'node_modules/font-awesome-svg-png/white/svg/thumb-tack.svg', title: 'Thumbtack'},
{id:'fa-bars', src:'node_modules/font-awesome-svg-png/white/svg/bars.svg', title: 'List'}, {id: 'fa-bars', src: 'node_modules/font-awesome-svg-png/white/svg/bars.svg', title: 'List'}
] ]

802
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
"description": "TODO", "description": "TODO",
"version": "0.0.1", "version": "0.0.1",
"scripts": { "scripts": {
"lint": "standard",
"dev": "npm run build-svg && concurrently --kill-others \"npm run build-sass-watch\" \"node server.js\"", "dev": "npm run build-svg && concurrently --kill-others \"npm run build-sass-watch\" \"node server.js\"",
"build": "npm run globalize-css && npm run build-sass && npm run build-svg && sapper build && npm run deglobalize-css", "build": "npm run globalize-css && npm run build-sass && npm run build-svg && sapper build && npm run deglobalize-css",
"start": "cross-env NODE_ENV=production node server.js", "start": "cross-env NODE_ENV=production node server.js",
@ -47,6 +48,7 @@
"rimraf": "^2.6.2", "rimraf": "^2.6.2",
"sapper": "nolanlawson/sapper#fix-style-loader-built", "sapper": "nolanlawson/sapper#fix-style-loader-built",
"serve-static": "^1.13.1", "serve-static": "^1.13.1",
"standard": "^10.0.3",
"style-loader": "^0.19.1", "style-loader": "^0.19.1",
"svelte": "^1.54.0", "svelte": "^1.54.0",
"svelte-extras": "^1.6.0", "svelte-extras": "^1.6.0",
@ -63,5 +65,25 @@
}, },
"engines": { "engines": {
"node": ">= 8" "node": ">= 8"
},
"standard": {
"globals": [
"fetch",
"IDBKeyRange",
"IDBObjectStore",
"indexedDB",
"requestAnimationFrame",
"requestIdleCallback",
"location",
"localStorage",
"URLSearchParams",
"IntersectionObserver",
"URL"
],
"ignore": [
"dist",
"cypress",
"routes/_utils/asyncModules.js"
]
} }
} }

View File

@ -6,8 +6,8 @@ import { database } from '../_database/database'
import { store } from '../_store/store' import { store } from '../_store/store'
import { updateVerifyCredentialsForInstance } from './instances' import { updateVerifyCredentialsForInstance } from './instances'
const REDIRECT_URI = (typeof location !== 'undefined' ? const REDIRECT_URI = (typeof location !== 'undefined'
location.origin : 'https://pinafore.social') + '/settings/instances/add' ? location.origin : 'https://pinafore.social') + '/settings/instances/add'
async function redirectToOauth () { async function redirectToOauth () {
let instanceName = store.get('instanceNameInSearch') let instanceName = store.get('instanceNameInSearch')
@ -42,9 +42,9 @@ export async function logInToInstance() {
} catch (err) { } catch (err) {
console.error(err) console.error(err)
let error = `${err.message || err.name}. ` + let error = `${err.message || err.name}. ` +
(navigator.onLine ? (navigator.onLine
`Is this a valid Mastodon instance?` : ? `Is this a valid Mastodon instance?`
`Are you offline?`) : `Are you offline?`)
store.set({logInToInstanceError: error}) store.set({logInToInstanceError: error})
} finally { } finally {
store.set({logInToInstanceLoading: false}) store.set({logInToInstanceLoading: false})
@ -95,4 +95,3 @@ export async function handleOauthCode(code) {
store.set({logInToInstanceLoading: false}) store.set({logInToInstanceLoading: false})
} }
} }

View File

@ -29,9 +29,9 @@ export async function logOutOfInstance(instanceName) {
let loggedInInstancesInOrder = store.get('loggedInInstancesInOrder') let loggedInInstancesInOrder = store.get('loggedInInstancesInOrder')
let currentInstance = store.get('currentInstance') let currentInstance = store.get('currentInstance')
loggedInInstancesInOrder.splice(loggedInInstancesInOrder.indexOf(instanceName), 1) loggedInInstancesInOrder.splice(loggedInInstancesInOrder.indexOf(instanceName), 1)
let newInstance = instanceName === currentInstance ? let newInstance = instanceName === currentInstance
loggedInInstancesInOrder[0] : ? loggedInInstancesInOrder[0]
currentInstance : currentInstance
delete loggedInInstances[instanceName] delete loggedInInstances[instanceName]
delete instanceThemes[instanceName] delete instanceThemes[instanceName]
store.set({ store.set({

View File

@ -1,8 +1,9 @@
import { post, paramsString } from '../_utils/ajax'
import { basename } from './utils'
const WEBSITE = 'https://pinafore.social' const WEBSITE = 'https://pinafore.social'
const SCOPES = 'read write follow' const SCOPES = 'read write follow'
const CLIENT_NAME = 'Pinafore' const CLIENT_NAME = 'Pinafore'
import { post, get, paramsString } from '../_utils/ajax'
import { basename } from './utils'
export function registerApplication (instanceName, redirectUri) { export function registerApplication (instanceName, redirectUri) {
const url = `${basename(instanceName)}/api/v1/apps` const url = `${basename(instanceName)}/api/v1/apps`

View File

@ -9,4 +9,3 @@ export function search(instanceName, accessToken, query) {
'Authorization': `Bearer ${accessToken}` 'Authorization': `Bearer ${accessToken}`
}) })
} }

View File

@ -71,7 +71,6 @@ virtualListStore.compute('heightWithoutFooter',
return sum return sum
}) })
virtualListStore.compute('height', virtualListStore.compute('height',
['heightWithoutFooter', 'showFooter', 'footerHeight'], ['heightWithoutFooter', 'showFooter', 'footerHeight'],
(heightWithoutFooter, showFooter, footerHeight) => { (heightWithoutFooter, showFooter, footerHeight) => {

View File

@ -3,17 +3,17 @@ import { accountsCache, relationshipsCache } from './cache'
import { getGenericEntityWithId, setGenericEntityWithId } from './helpers' import { getGenericEntityWithId, setGenericEntityWithId } from './helpers'
export async function getAccount (instanceName, accountId) { export async function getAccount (instanceName, accountId) {
return await getGenericEntityWithId(ACCOUNTS_STORE, accountsCache, instanceName, accountId) return getGenericEntityWithId(ACCOUNTS_STORE, accountsCache, instanceName, accountId)
} }
export async function setAccount (instanceName, account) { export async function setAccount (instanceName, account) {
return await setGenericEntityWithId(ACCOUNTS_STORE, accountsCache, instanceName, account) return setGenericEntityWithId(ACCOUNTS_STORE, accountsCache, instanceName, account)
} }
export async function getRelationship (instanceName, accountId) { export async function getRelationship (instanceName, accountId) {
return await getGenericEntityWithId(RELATIONSHIPS_STORE, relationshipsCache, instanceName, accountId) return getGenericEntityWithId(RELATIONSHIPS_STORE, relationshipsCache, instanceName, accountId)
} }
export async function setRelationship (instanceName, relationship) { export async function setRelationship (instanceName, relationship) {
return await setGenericEntityWithId(RELATIONSHIPS_STORE, relationshipsCache, instanceName, relationship) return setGenericEntityWithId(RELATIONSHIPS_STORE, relationshipsCache, instanceName, relationship)
} }

View File

@ -1,8 +1,3 @@
const openReqs = {}
const databaseCache = {}
const DB_VERSION = 1
import { import {
META_STORE, META_STORE,
STATUS_TIMELINES_STORE, STATUS_TIMELINES_STORE,
@ -13,6 +8,11 @@ import {
NOTIFICATION_TIMELINES_STORE NOTIFICATION_TIMELINES_STORE
} from './constants' } from './constants'
const openReqs = {}
const databaseCache = {}
const DB_VERSION = 1
export function getDatabase (instanceName) { export function getDatabase (instanceName) {
if (!instanceName) { if (!instanceName) {
throw new Error('instanceName is undefined in getDatabase()') throw new Error('instanceName is undefined in getDatabase()')
@ -29,7 +29,7 @@ export function getDatabase(instanceName) {
console.log('idb blocked') console.log('idb blocked')
} }
req.onupgradeneeded = (e) => { req.onupgradeneeded = (e) => {
let db = req.result; let db = req.result
db.createObjectStore(META_STORE, {keyPath: 'key'}) db.createObjectStore(META_STORE, {keyPath: 'key'})
db.createObjectStore(STATUSES_STORE, {keyPath: 'id'}) db.createObjectStore(STATUSES_STORE, {keyPath: 'id'})
db.createObjectStore(ACCOUNTS_STORE, {keyPath: 'id'}) db.createObjectStore(ACCOUNTS_STORE, {keyPath: 'id'})
@ -46,25 +46,25 @@ export function getDatabase(instanceName) {
} }
export async function dbPromise (db, storeName, readOnlyOrReadWrite, cb) { export async function dbPromise (db, storeName, readOnlyOrReadWrite, cb) {
return await new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const tx = db.transaction(storeName, readOnlyOrReadWrite) const tx = db.transaction(storeName, readOnlyOrReadWrite)
let store = typeof storeName === 'string' ? let store = typeof storeName === 'string'
tx.objectStore(storeName) : ? tx.objectStore(storeName)
storeName.map(name => tx.objectStore(name)) : storeName.map(name => tx.objectStore(name))
let res let res
cb(store, (result) => { cb(store, (result) => {
res = result res = result
}) })
tx.oncomplete = () => resolve(res) tx.oncomplete = () => resolve(res)
tx.onerror = () => reject(tx.error.name + ' ' + tx.error.message) tx.onerror = () => reject(tx.error)
}) })
} }
export function deleteDatabase (instanceName) { export function deleteDatabase (instanceName) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// close any open requests // close any open requests
let openReq = openReqs[instanceName]; let openReq = openReqs[instanceName]
if (openReq && openReq.result) { if (openReq && openReq.result) {
openReq.result.close() openReq.result.close()
} }
@ -72,6 +72,6 @@ export function deleteDatabase(instanceName) {
delete databaseCache[instanceName] delete databaseCache[instanceName]
let req = indexedDB.deleteDatabase(instanceName) let req = indexedDB.deleteDatabase(instanceName)
req.onsuccess = () => resolve() req.onsuccess = () => resolve()
req.onerror = () => reject(req.error.name + ' ' + req.error.message) req.onerror = () => reject(req.error)
}) })
} }

View File

@ -16,7 +16,7 @@ export async function getGenericEntityWithId(store, cache, instanceName, id) {
export async function setGenericEntityWithId (store, cache, instanceName, entity) { export async function setGenericEntityWithId (store, cache, instanceName, entity) {
setInCache(cache, instanceName, entity.id, entity) setInCache(cache, instanceName, entity.id, entity)
const db = await getDatabase(instanceName) const db = await getDatabase(instanceName)
return await dbPromise(db, store, 'readwrite', (store) => { return dbPromise(db, store, 'readwrite', (store) => {
store.put(entity) store.put(entity)
}) })
} }

View File

@ -19,7 +19,7 @@ async function getMetaProperty(instanceName, key) {
async function setMetaProperty (instanceName, key, value) { async function setMetaProperty (instanceName, key, value) {
setInCache(metaCache, instanceName, key, value) setInCache(metaCache, instanceName, key, value)
const db = await getDatabase(instanceName) const db = await getDatabase(instanceName)
return await dbPromise(db, META_STORE, 'readwrite', (store) => { return dbPromise(db, META_STORE, 'readwrite', (store) => {
store.put({ store.put({
key: key, key: key,
value: value value: value
@ -28,25 +28,25 @@ async function setMetaProperty(instanceName, key, value) {
} }
export async function getInstanceVerifyCredentials (instanceName) { export async function getInstanceVerifyCredentials (instanceName) {
return await getMetaProperty(instanceName, 'verifyCredentials') return getMetaProperty(instanceName, 'verifyCredentials')
} }
export async function setInstanceVerifyCredentials (instanceName, value) { export async function setInstanceVerifyCredentials (instanceName, value) {
return await setMetaProperty(instanceName, 'verifyCredentials', value) return setMetaProperty(instanceName, 'verifyCredentials', value)
} }
export async function getInstanceInfo (instanceName) { export async function getInstanceInfo (instanceName) {
return await getMetaProperty(instanceName, 'instance') return getMetaProperty(instanceName, 'instance')
} }
export async function setInstanceInfo (instanceName, value) { export async function setInstanceInfo (instanceName, value) {
return await setMetaProperty(instanceName, 'instance', value) return setMetaProperty(instanceName, 'instance', value)
} }
export async function getLists (instanceName) { export async function getLists (instanceName) {
return await getMetaProperty(instanceName, 'lists') return getMetaProperty(instanceName, 'lists')
} }
export async function setLists (instanceName, value) { export async function setLists (instanceName, value) {
return await setMetaProperty(instanceName, 'lists', value) return setMetaProperty(instanceName, 'lists', value)
} }

View File

@ -17,7 +17,7 @@ function createKeyRange(timeline, maxId) {
async function getNotificationTimeline (instanceName, timeline, maxId, limit) { async function getNotificationTimeline (instanceName, timeline, maxId, limit) {
let storeNames = [NOTIFICATION_TIMELINES_STORE, NOTIFICATIONS_STORE] let storeNames = [NOTIFICATION_TIMELINES_STORE, NOTIFICATIONS_STORE]
const db = await getDatabase(instanceName) const db = await getDatabase(instanceName)
return await dbPromise(db, storeNames, 'readonly', (stores, callback) => { return dbPromise(db, storeNames, 'readonly', (stores, callback) => {
let [ timelineStore, notificationsStore ] = stores let [ timelineStore, notificationsStore ] = stores
let keyRange = createKeyRange(timeline, maxId) let keyRange = createKeyRange(timeline, maxId)
@ -37,7 +37,7 @@ async function getNotificationTimeline(instanceName, timeline, maxId, limit) {
async function getStatusTimeline (instanceName, timeline, maxId, limit) { async function getStatusTimeline (instanceName, timeline, maxId, limit) {
let storeNames = [STATUS_TIMELINES_STORE, STATUSES_STORE] let storeNames = [STATUS_TIMELINES_STORE, STATUSES_STORE]
const db = await getDatabase(instanceName) const db = await getDatabase(instanceName)
return await dbPromise(db, storeNames, 'readonly', (stores, callback) => { return dbPromise(db, storeNames, 'readonly', (stores, callback) => {
let [ timelineStore, statusesStore ] = stores let [ timelineStore, statusesStore ] = stores
let keyRange = createKeyRange(timeline, maxId) let keyRange = createKeyRange(timeline, maxId)
@ -55,9 +55,9 @@ async function getStatusTimeline(instanceName, timeline, maxId, limit) {
} }
export async function getTimeline (instanceName, timeline, maxId = null, limit = 20) { export async function getTimeline (instanceName, timeline, maxId = null, limit = 20) {
return timeline === 'notifications' ? return timeline === 'notifications'
await getNotificationTimeline(instanceName, timeline, maxId, limit) : ? getNotificationTimeline(instanceName, timeline, maxId, limit)
await getStatusTimeline(instanceName, timeline, maxId, limit) : getStatusTimeline(instanceName, timeline, maxId, limit)
} }
function createTimelineId (timeline, id) { function createTimelineId (timeline, id) {
@ -112,15 +112,15 @@ async function insertTimelineStatuses(instanceName, timeline, statuses) {
} }
export async function insertTimelineItems (instanceName, timeline, timelineItems) { export async function insertTimelineItems (instanceName, timeline, timelineItems) {
return timeline === 'notifications' ? return timeline === 'notifications'
await insertTimelineNotifications(instanceName, timeline, timelineItems) : ? insertTimelineNotifications(instanceName, timeline, timelineItems)
await insertTimelineStatuses(instanceName, timeline, timelineItems) : insertTimelineStatuses(instanceName, timeline, timelineItems)
} }
export async function getStatus (instanceName, statusId) { export async function getStatus (instanceName, statusId) {
return await getGenericEntityWithId(STATUSES_STORE, statusesCache, instanceName, statusId) return getGenericEntityWithId(STATUSES_STORE, statusesCache, instanceName, statusId)
} }
export async function getNotification (instanceName, notificationId) { export async function getNotification (instanceName, notificationId) {
return await getGenericEntityWithId(NOTIFICATIONS_STORE, notificationsCache, instanceName, notificationId) return getGenericEntityWithId(NOTIFICATIONS_STORE, notificationsCache, instanceName, notificationId)
} }

View File

@ -70,5 +70,4 @@ export function instanceComputations(store) {
return list ? list.title : '' return list ? list.title : ''
} }
) )
} }

View File

@ -4,16 +4,16 @@ import { mixins } from './mixins'
import { LocalStorageStore } from './LocalStorageStore' import { LocalStorageStore } from './LocalStorageStore'
const KEYS_TO_STORE_IN_LOCAL_STORAGE = new Set([ const KEYS_TO_STORE_IN_LOCAL_STORAGE = new Set([
"currentInstance", 'currentInstance',
"currentRegisteredInstance", 'currentRegisteredInstance',
"currentRegisteredInstanceName", 'currentRegisteredInstanceName',
"instanceNameInSearch", 'instanceNameInSearch',
"instanceThemes", 'instanceThemes',
"loggedInInstances", 'loggedInInstances',
"loggedInInstancesInOrder", 'loggedInInstancesInOrder',
"autoplayGifs", 'autoplayGifs',
"markMediaAsSensitive", 'markMediaAsSensitive',
"pinnedPages" 'pinnedPages'
]) ])
class PinaforeStore extends LocalStorageStore { class PinaforeStore extends LocalStorageStore {

View File

@ -1,5 +1,5 @@
export async function post (url, body) { export async function post (url, body) {
return await (await fetch(url, { return (await fetch(url, {
method: 'POST', method: 'POST',
headers: { headers: {
'Accept': 'application/json', 'Accept': 'application/json',
@ -18,10 +18,10 @@ export function paramsString(paramsObject) {
} }
export async function get (url, headers = {}) { export async function get (url, headers = {}) {
return await (await fetch(url, { return (await fetch(url, {
method: 'GET', method: 'GET',
headers: Object.assign(headers, { headers: Object.assign(headers, {
'Accept': 'application/json', 'Accept': 'application/json'
}) })
})).json() })).json()
} }

View File

@ -20,10 +20,10 @@ export function imgLoad (node, callback) {
export function mouseover (node, callback) { export function mouseover (node, callback) {
function onMouseEnter () { function onMouseEnter () {
callback(true) callback(true) // eslint-disable-line
} }
function onMouseLeave () { function onMouseLeave () {
callback(false) callback(false) // eslint-disable-line
} }
node.addEventListener('mouseenter', onMouseEnter) node.addEventListener('mouseenter', onMouseEnter)
node.addEventListener('mouseleave', onMouseLeave) node.addEventListener('mouseleave', onMouseLeave)

View File

@ -1,23 +1,23 @@
export const isFullscreen = () => !!(document.fullscreenElement || export const isFullscreen = () => !!(document.fullscreenElement ||
document.webkitFullscreenElement || document.webkitFullscreenElement ||
document.mozFullScreenElement); document.mozFullScreenElement)
export const attachFullscreenListener = (listener) => { export const attachFullscreenListener = (listener) => {
if ('onfullscreenchange' in document) { if ('onfullscreenchange' in document) {
document.addEventListener('fullscreenchange', listener); document.addEventListener('fullscreenchange', listener)
} else if ('onwebkitfullscreenchange' in document) { } else if ('onwebkitfullscreenchange' in document) {
document.addEventListener('webkitfullscreenchange', listener); document.addEventListener('webkitfullscreenchange', listener)
} else if ('onmozfullscreenchange' in document) { } else if ('onmozfullscreenchange' in document) {
document.addEventListener('mozfullscreenchange', listener); document.addEventListener('mozfullscreenchange', listener)
}
} }
};
export const detachFullscreenListener = (listener) => { export const detachFullscreenListener = (listener) => {
if ('onfullscreenchange' in document) { if ('onfullscreenchange' in document) {
document.removeEventListener('fullscreenchange', listener); document.removeEventListener('fullscreenchange', listener)
} else if ('onwebkitfullscreenchange' in document) { } else if ('onwebkitfullscreenchange' in document) {
document.removeEventListener('webkitfullscreenchange', listener); document.removeEventListener('webkitfullscreenchange', listener)
} else if ('onmozfullscreenchange' in document) { } else if ('onmozfullscreenchange' in document) {
document.removeEventListener('mozfullscreenchange', listener); document.removeEventListener('mozfullscreenchange', listener)
}
} }
};

View File

@ -1,18 +1,18 @@
// Get the bounding client rect from an IntersectionObserver entry. // Get the bounding client rect from an IntersectionObserver entry.
// This is to work around a bug in Chrome: https://crbug.com/737228 // This is to work around a bug in Chrome: https://crbug.com/737228
let hasBoundingRectBug; let hasBoundingRectBug
export function getRectFromEntry (entry) { export function getRectFromEntry (entry) {
if (typeof hasBoundingRectBug !== 'boolean') { if (typeof hasBoundingRectBug !== 'boolean') {
const boundingRect = entry.target.getBoundingClientRect(); const boundingRect = entry.target.getBoundingClientRect()
const observerRect = entry.boundingClientRect; const observerRect = entry.boundingClientRect
hasBoundingRectBug = boundingRect.height !== observerRect.height || hasBoundingRectBug = boundingRect.height !== observerRect.height ||
boundingRect.top !== observerRect.top || boundingRect.top !== observerRect.top ||
boundingRect.width !== observerRect.width || boundingRect.width !== observerRect.width ||
boundingRect.bottom !== observerRect.bottom || boundingRect.bottom !== observerRect.bottom ||
boundingRect.left !== observerRect.left || boundingRect.left !== observerRect.left ||
boundingRect.right !== observerRect.right; boundingRect.right !== observerRect.right
} }
return hasBoundingRectBug ? entry.target.getBoundingClientRect() : entry.boundingClientRect; return hasBoundingRectBug ? entry.target.getBoundingClientRect() : entry.boundingClientRect
} }

View File

@ -2,8 +2,7 @@ import {
importURLSearchParams, importURLSearchParams,
importIntersectionObserver, importIntersectionObserver,
importRequestIdleCallback, importRequestIdleCallback,
importIndexedDBGetAllShim, importIndexedDBGetAllShim
importDialogPolyfill
} from './asyncModules' } from './asyncModules'
export function loadPolyfills () { export function loadPolyfills () {

View File

@ -19,8 +19,7 @@ const observe = online => {
meta.content = oldTheme || window.__themeColors['default'] meta.content = oldTheme || window.__themeColors['default']
} else { } else {
let offlineThemeColor = window.__themeColors.offline let offlineThemeColor = window.__themeColors.offline
if (meta.content !== offlineThemeColor) if (meta.content !== offlineThemeColor) { oldTheme = meta.content }
oldTheme = meta.content
meta.content = offlineThemeColor meta.content = offlineThemeColor
notifyOffline() notifyOffline()
} }
@ -30,5 +29,5 @@ if (!navigator.onLine) {
observe(false) observe(false)
} }
window.addEventListener('offline', () => observe(false)); window.addEventListener('offline', () => observe(false))
window.addEventListener('online', () => observe(true)); window.addEventListener('online', () => observe(true))

View File

@ -7,7 +7,7 @@ function onUpdateFound(registration) {
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) { if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
toast.say('Update available. Refresh to update.') toast.say('Update available. Refresh to update.')
} }
}); })
} }
if (!location.origin.match('localhost') && 'serviceWorker' in navigator) { if (!location.origin.match('localhost') && 'serviceWorker' in navigator) {

View File

@ -1,4 +1,4 @@
import { loadCSS } from 'fg-loadcss'; import { loadCSS } from 'fg-loadcss'
let meta = process.browser && document.querySelector('meta[name="theme-color"]') let meta = process.browser && document.querySelector('meta[name="theme-color"]')

View File

@ -1,24 +1,23 @@
const fs = require('fs'); const app = require('express')()
const app = require('express')(); const compression = require('compression')
const compression = require('compression'); const sapper = require('sapper')
const sapper = require('sapper'); const serveStatic = require('serve-static')
const static = require('serve-static');
const { PORT = 4002 } = process.env; const { PORT = 4002 } = process.env
// this allows us to do e.g. `fetch('/_api/blog')` on the server // this allows us to do e.g. `fetch('/_api/blog')` on the server
const fetch = require('node-fetch'); const fetch = require('node-fetch')
global.fetch = (url, opts) => { global.fetch = (url, opts) => {
if (url[0] === '/') url = `http://localhost:${PORT}${url}`; if (url[0] === '/') url = `http://localhost:${PORT}${url}`
return fetch(url, opts); return fetch(url, opts)
}; }
app.use(compression({ threshold: 0 })); app.use(compression({ threshold: 0 }))
app.use(static('assets')); app.use(serveStatic('assets'))
app.use(sapper()); app.use(sapper())
app.listen(PORT, () => { app.listen(PORT, () => {
console.log(`listening on port ${PORT}`); console.log(`listening on port ${PORT}`)
}); })

View File

@ -1,8 +1,12 @@
/* global __routes__ */
import { init } from 'sapper/runtime.js' import { init } from 'sapper/runtime.js'
import { offlineNotifiction } from '../routes/_utils/offlineNotification' import { offlineNotifiction } from '../routes/_utils/offlineNotification'
import { serviceWorkerClient } from '../routes/_utils/serviceWorkerClient' import { serviceWorkerClient } from '../routes/_utils/serviceWorkerClient'
import { loadPolyfills } from '../routes/_utils/loadPolyfills' import { loadPolyfills } from '../routes/_utils/loadPolyfills'
console.log(offlineNotifiction, serviceWorkerClient)
loadPolyfills().then(() => { loadPolyfills().then(() => {
// `routes` is an array of route objects injected by Sapper // `routes` is an array of route objects injected by Sapper
init(document.querySelector('#sapper'), __routes__) init(document.querySelector('#sapper'), __routes__)

View File

@ -1,10 +1,12 @@
/* global self, caches, __shell__, __assets__, __routes__ */
const timestamp = '__timestamp__' const timestamp = '__timestamp__'
const ASSETS = `cache${timestamp}` const ASSETS = `cache${timestamp}`
// `shell` is an array of all the files generated by webpack, // `shell` is an array of all the files generated by webpack,
// `assets` is an array of everything in the `assets` directory // `assets` is an array of everything in the `assets` directory
const to_cache = __shell__.concat(__assets__) const toCache = __shell__.concat(__assets__)
const cached = new Set(to_cache) const cached = new Set(toCache)
// `routes` is an array of `{ pattern: RegExp }` objects that // `routes` is an array of `{ pattern: RegExp }` objects that
// match the pages in your app // match the pages in your app
@ -14,7 +16,7 @@ self.addEventListener('install', event => {
event.waitUntil( event.waitUntil(
caches caches
.open(ASSETS) .open(ASSETS)
.then(cache => cache.addAll(to_cache)) .then(cache => cache.addAll(toCache))
.then(() => { .then(() => {
self.skipWaiting() self.skipWaiting()
}) })

View File

@ -4,7 +4,7 @@ const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin') const LodashModuleReplacementPlugin = require('lodash-webpack-plugin')
const isDev = config.dev; const isDev = config.dev
module.exports = { module.exports = {
entry: config.client.entry(), entry: config.client.entry(),
@ -82,11 +82,11 @@ module.exports = {
generateStatsFile: true, generateStatsFile: true,
statsOptions: { statsOptions: {
// allows usage with http://chrisbateman.github.io/webpack-visualizer/ // allows usage with http://chrisbateman.github.io/webpack-visualizer/
chunkModules: true, chunkModules: true
}, },
openAnalyzer: false, openAnalyzer: false,
logLevel: 'silent', // do not bother Webpacker, who runs with --json and parses stdout logLevel: 'silent' // do not bother Webpacker, who runs with --json and parses stdout
}), })
]).filter(Boolean), ]).filter(Boolean),
devtool: isDev && 'inline-source-map' devtool: isDev && 'inline-source-map'
}; }

View File

@ -1,7 +1,4 @@
const config = require('sapper/webpack/config.js'); const config = require('sapper/webpack/config.js')
const webpack = require('webpack');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
module.exports = { module.exports = {
entry: config.server.entry(), entry: config.server.entry(),
@ -27,4 +24,4 @@ module.exports = {
} }
] ]
} }
}; }