feature: add Svelte framework to app, refactor tracking panel into Svelte component

This commit is contained in:
Ondřej Synáček 2020-12-15 10:23:20 +01:00
parent e3a2ebeaf2
commit a89777b91a
14 changed files with 511 additions and 89 deletions

View File

@ -0,0 +1,5 @@
<script>
import AppContainer from './AppContainer.svelte'
</script>
<AppContainer />

View File

@ -0,0 +1,14 @@
<script>
import TrackingPanel from './TrackingPanel.svelte'
import { configStore } from '../stores'
$: showTrackingPanel = $configStore.track === undefined
configStore.subscribe(console.log)
</script>
{#if showTrackingPanel}
<TrackingPanel />
{/if}

View File

@ -0,0 +1,46 @@
<style>
#tracking-panel {
position: fixed;
bottom: 0;
border: 3px solid navy;
background-color: lightyellow;
max-width: 600px;
margin: 5px;
padding: 5px;
}
#tracking-panel__yes-button,
#tracking-panel__no-button {
font-size: 1.2rem;
}
#tracking-panel__yes-button {
font-weight: 600;
margin-right: 5px;
}
</style>
<script>
import { configStore } from '../stores'
const handleYesButtonClick = () => {
configStore.setValue('track', true)
}
const handleNoButtonClick = () => {
configStore.setValue('track', false)
}
</script>
<div id="tracking-panel">
<p>
Can we store anonymous logs? This data is only saved to our internal database and is used to debug the parsing of the web pages. We'll ask you only this time and won't bother you again.
</p>
<button on:click={handleYesButtonClick} id='tracking-panel__yes-button'>
Ok
</button>
<button on:click={handleNoButtonClick} id='tracking-panel__no-button'>
Nope
</button>
</div>

17
lib/frontend/index.js Normal file
View File

@ -0,0 +1,17 @@
import App from './components/App.svelte'
import * as stores from './stores'
const boot = () => {
new App({
target: document.querySelector('#root'),
})
if (process.env.NODE_ENV === 'development') {
window._fb2ical = {
...stores,
}
}
}
export default boot

View File

@ -0,0 +1,30 @@
import { writable } from 'svelte/store'
const createConfigStore = () => {
const state = JSON.parse(localStorage.getItem('fb-to-ical-config') || '{}')
const { subscribe, set, update } = writable(state)
const setValue = (key, value) => {
update((prevState) => {
const nextState = {
...prevState,
[key]: value,
}
localStorage.setItem('fb-to-ical-config', JSON.stringify(nextState))
return nextState
})
}
return {
...state,
subscribe,
set,
update,
setValue,
}
}
export default createConfigStore()

View File

@ -0,0 +1,5 @@
import configStore from './configStore'
export {
configStore,
}

View File

@ -70,6 +70,8 @@
</table>
</div>
</article>
<div id="root"></div>
<footer>
v.<%= htmlWebpackPlugin.options.version %> ◆

View File

@ -13,12 +13,16 @@ import logger from './app/logger'
import { extractEventDataFromHTML } from '../../lib/services/ics-retriever'
import generateICS from '../../lib/services/ics-generator'
import boot from '../frontend'
(() => {
if (!window.fetch || !window.Promise || !window.URLSearchParams || !window.crypto) {
console.warn('JS features not available.')
return
}
document.addEventListener('DOMContentLoaded', boot)
const showTable = () => {
list.classList.remove('hidden')
}
@ -33,40 +37,6 @@ import generateICS from '../../lib/services/ics-generator'
row.remove()
}
const renderTrackingPanel = (storageContents) => {
const trackingPanel = document.createElement('div')
trackingPanel.id = 'tracking-panel'
const text = document.createElement('p')
text.innerText = `Can we store anonymous logs? This data is only saved to \
our internal database and is used to debug the parsing of the web pages.\n\
We'll ask you only this time and won't bother you again.`
const yesButton = document.createElement('button')
yesButton.id = 'tracking-panel__yes-button'
yesButton.innerText = 'Ok'
yesButton.addEventListener('click', () => {
updateConfigStorage(storageContents, 'track', true)
logger.setRemoteLogging(true)
trackingPanel.remove()
})
const noButton = document.createElement('button')
noButton.id = 'tracking-panel__no-button'
noButton.innerText = 'Nope'
noButton.addEventListener('click', () => {
updateConfigStorage(storageContents, 'track', false)
logger.setRemoteLogging(false)
trackingPanel.remove()
})
trackingPanel.appendChild(text)
trackingPanel.appendChild(yesButton)
trackingPanel.appendChild(noButton)
document.body.appendChild(trackingPanel)
}
const insertTableRow = ({ id, link, createdAt, startTime, title }) => {
showTable()
@ -158,21 +128,6 @@ We'll ask you only this time and won't bother you again.`
})
}
const hydrateConfig = () => {
if (!useStorage()) {
return
}
const prevStorage = getConfigStorage()
const storageContents = getStorageContents(prevStorage)
const useTrackingSet = storageContents.track !== undefined
if (!useTrackingSet) {
renderTrackingPanel(storageContents)
}
}
const configureLogger = (logger) => {
if (!logger || !useStorage()) {
return
@ -299,7 +254,6 @@ We'll ask you only this time and won't bother you again.`
}
hydrateList()
hydrateConfig()
configureLogger(logger)
const handleHTMLResponse = (html, url) => {

View File

@ -167,22 +167,3 @@ a.delete-record {
margin: 5px 0;
}
#tracking-panel {
position: fixed;
bottom: 0;
border: 3px solid navy;
background-color: lightyellow;
max-width: 600px;
margin: 5px;
padding: 5px;
}
#tracking-panel__yes-button,
#tracking-panel__no-button {
font-size: 1.2rem;
}
#tracking-panel__yes-button {
font-weight: 600;
margin-right: 5px;
}

334
package-lock.json generated
View File

@ -3536,6 +3536,17 @@
}
}
},
"clone-deep": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
"integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
"dev": true,
"requires": {
"is-plain-object": "^2.0.4",
"kind-of": "^6.0.2",
"shallow-clone": "^3.0.0"
}
},
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@ -3589,6 +3600,12 @@
"simple-swizzle": "^0.2.2"
}
},
"colorette": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz",
"integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
"dev": true
},
"colornames": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz",
@ -4221,6 +4238,110 @@
"integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=",
"dev": true
},
"css-loader": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.0.1.tgz",
"integrity": "sha512-cXc2ti9V234cq7rJzFKhirb2L2iPy8ZjALeVJAozXYz9te3r4eqLSixNAbMDJSgJEQywqXzs8gonxaboeKqwiw==",
"dev": true,
"requires": {
"camelcase": "^6.2.0",
"cssesc": "^3.0.0",
"icss-utils": "^5.0.0",
"loader-utils": "^2.0.0",
"postcss": "^8.1.4",
"postcss-modules-extract-imports": "^3.0.0",
"postcss-modules-local-by-default": "^4.0.0",
"postcss-modules-scope": "^3.0.0",
"postcss-modules-values": "^4.0.0",
"postcss-value-parser": "^4.1.0",
"schema-utils": "^3.0.0",
"semver": "^7.3.2"
},
"dependencies": {
"@types/json-schema": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
"dev": true
},
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"dev": true
},
"camelcase": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
"integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==",
"dev": true
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"loader-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
"dev": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"requires": {
"yallist": "^4.0.0"
}
},
"schema-utils": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
"integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.6",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
}
},
"semver": {
"version": "7.3.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
"integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
}
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
}
}
},
"css-select": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
@ -4237,6 +4358,12 @@
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
"integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg=="
},
"cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true
},
"cssom": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz",
@ -6516,6 +6643,12 @@
}
}
},
"icss-utils": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
"integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
"dev": true
},
"ieee754": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
@ -6568,6 +6701,12 @@
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
"dev": true
},
"indexes-of": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
"integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
"dev": true
},
"infer-owner": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
@ -9101,6 +9240,71 @@
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true
},
"mini-css-extract-plugin": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.3.tgz",
"integrity": "sha512-7lvliDSMiuZc81kI+5/qxvn47SCM7BehXex3f2c6l/pR3Goj58IQxZh9nuPQ3AkGQgoETyXuIqLDaO5Oa0TyBw==",
"dev": true,
"requires": {
"loader-utils": "^2.0.0",
"schema-utils": "^3.0.0",
"webpack-sources": "^1.1.0"
},
"dependencies": {
"@types/json-schema": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
"dev": true
},
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"dev": true
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"loader-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
"dev": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
},
"schema-utils": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
"integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.6",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
}
}
}
},
"minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
@ -9280,6 +9484,12 @@
"dev": true,
"optional": true
},
"nanoid": {
"version": "3.1.20",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz",
"integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==",
"dev": true
},
"nanomatch": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@ -9948,6 +10158,78 @@
"integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
"dev": true
},
"postcss": {
"version": "8.2.1",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.1.tgz",
"integrity": "sha512-RhsqOOAQzTgh1UB/IZdca7F9WDb7SUCR2Vnv1x7DbvuuggQIpoDwjK+q0rzoPffhYvWNKX5JSwS4so4K3UC6vA==",
"dev": true,
"requires": {
"colorette": "^1.2.1",
"nanoid": "^3.1.20",
"source-map": "^0.6.1"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"postcss-modules-extract-imports": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
"integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
"dev": true
},
"postcss-modules-local-by-default": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz",
"integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==",
"dev": true,
"requires": {
"icss-utils": "^5.0.0",
"postcss-selector-parser": "^6.0.2",
"postcss-value-parser": "^4.1.0"
}
},
"postcss-modules-scope": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz",
"integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==",
"dev": true,
"requires": {
"postcss-selector-parser": "^6.0.4"
}
},
"postcss-modules-values": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
"integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
"dev": true,
"requires": {
"icss-utils": "^5.0.0"
}
},
"postcss-selector-parser": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz",
"integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==",
"dev": true,
"requires": {
"cssesc": "^3.0.0",
"indexes-of": "^1.0.1",
"uniq": "^1.0.1",
"util-deprecate": "^1.0.2"
}
},
"postcss-value-parser": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
"integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
"dev": true
},
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
@ -10910,6 +11192,15 @@
"safe-buffer": "^5.0.1"
}
},
"shallow-clone": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
"integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
"dev": true,
"requires": {
"kind-of": "^6.0.2"
}
},
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
@ -11477,6 +11768,27 @@
}
}
},
"svelte": {
"version": "3.31.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.31.0.tgz",
"integrity": "sha512-r+n8UJkDqoQm1b+3tA3Lh6mHXKpcfOSOuEuIo5gE2W9wQYi64RYX/qE6CZBDDsP/H4M+N426JwY7XGH4xASvGQ=="
},
"svelte-dev-helper": {
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/svelte-dev-helper/-/svelte-dev-helper-1.1.9.tgz",
"integrity": "sha1-fRh9tcbNu9ZNdaMvkbiZi94yc8M=",
"dev": true
},
"svelte-loader": {
"version": "2.13.6",
"resolved": "https://registry.npmjs.org/svelte-loader/-/svelte-loader-2.13.6.tgz",
"integrity": "sha512-7uf7ZQdPAl+lwb1ldUYJFY/raZRUCuaNx7lMJ+F16jrVwN1+c35C2pBMGIY0mCqdKm5sm45jqELJJLGM3UG9Pw==",
"dev": true,
"requires": {
"loader-utils": "^1.1.0",
"svelte-dev-helper": "^1.1.9"
}
},
"symbol-tree": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
@ -11893,6 +12205,12 @@
"set-value": "^2.0.1"
}
},
"uniq": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
"integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
"dev": true
},
"unique-filename": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
@ -12548,6 +12866,16 @@
}
}
},
"webpack-merge": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.7.0.tgz",
"integrity": "sha512-UryoMJGRMwOOh/ie4NXZC1OtT0mkA7Ny2+C/MkWOwTRG+jVNEwChVV/+x8rd+ga2mVLeQ0m+QmzLAg7N36+oag==",
"dev": true,
"requires": {
"clone-deep": "^4.0.1",
"wildcard": "^2.0.0"
}
},
"webpack-sources": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
@ -12623,6 +12951,12 @@
"string-width": "^2.1.1"
}
},
"wildcard": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",
"integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
"dev": true
},
"winston": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz",

View File

@ -8,10 +8,10 @@
"node": "10.15.0"
},
"scripts": {
"build": "npm run clean:build && webpack --mode=production",
"build:dev": "npm run clean:build && webpack --mode=development",
"build:firebase:hosting": "npm run clean:build && NODE_ENV=production NODE_APP=firebase webpack --mode=production",
"build:firebase:hosting:dev": "npm run clean:build && NODE_ENV=development NODE_APP=firebase webpack --mode=development",
"build": "npm run clean:build && webpack --config=./webpack.prod.js",
"build:dev": "npm run clean:build && webpack --config=./webpack.dev.js",
"build:firebase:hosting": "npm run clean:build && NODE_ENV=production NODE_APP=firebase webpack --config=./webpack.prod.js",
"build:firebase:hosting:dev": "npm run clean:build && NODE_ENV=development NODE_APP=firebase webpack --config=./webpack.dev.js",
"clean:build": "rm dist/** || true",
"deploy:firebase": "npm run build:firebase:hosting && firebase deploy",
"start": "npm run build && node lib/index.js",
@ -41,6 +41,7 @@
"ics": "^2.22.1",
"request": "^2.88.0",
"serve-favicon": "^2.5.0",
"svelte": "^3.31.0",
"winston": "^3.2.1",
"winston-daily-rotate-file": "^4.2.1",
"yargs": "^15.4.1"
@ -50,12 +51,16 @@
"chai-sinon": "^2.8.1",
"concurrently": "^5.2.0",
"copy-webpack-plugin": "^6.0.3",
"css-loader": "^5.0.1",
"html-webpack-plugin": "^4.3.0",
"jest": "^26.1.0",
"mini-css-extract-plugin": "^1.3.3",
"nodemon": "^1.19.3",
"sinon": "^9.0.2",
"svelte-loader": "^2.13.6",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12",
"webpack-merge": "^5.7.0",
"workbox-webpack-plugin": "^5.1.3"
}
}

View File

@ -3,10 +3,10 @@ const fs = require('fs')
const pkg = require('./package.json')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const { GenerateSW } = require('workbox-webpack-plugin')
const destination = path.join(__dirname, 'dist')
const isDevelopment = Boolean(process.argv[2] && process.argv[2].includes('mode=development'))
const isFirebaseEnv = process.env.NODE_APP === 'firebase'
const firebaseConfigFilePath = path.join(__dirname, '.firebaserc')
const hasFirebaseConfig = fs.existsSync(firebaseConfigFilePath)
@ -15,26 +15,37 @@ if (isFirebaseEnv && hasFirebaseConfig) {
console.info('Prepare build for Firebase hosting')
}
const getFirebaseUrl = () => {
const contents = fs.readFileSync(firebaseConfigFilePath)
const rawContents = contents.toString()
const json = JSON.parse(rawContents)
const projectName = json.projects ? json.projects.default : null
if (isDevelopment) {
return `http://localhost:5001/${projectName}/uscentral-1/app`
}
return `${projectName}.web.app/app`
}
module.exports = {
entry: path.join(__dirname, 'lib', 'static', 'index.js'),
watch: isDevelopment,
output: {
filename: '[name].[hash].js',
path: destination,
},
resolve: {
alias: {
svelte: path.resolve('node_modules', 'svelte'),
},
extensions: [ '.mjs', '.js', '.svelte' ],
mainFields: [ 'svelte', 'browser', 'module', 'main' ],
},
module: {
rules: [
{
test: /\.(svelte)$/,
exclude: /node_modules/,
use: {
loader: 'svelte-loader',
options: {
emitCss: true,
},
},
},
{
test: /\.css$/,
use: [ MiniCssExtractPlugin.loader, 'css-loader' ],
},
],
},
plugins: [
new CopyWebpackPlugin({
patterns: [
@ -44,9 +55,9 @@ module.exports = {
new HtmlWebpackPlugin({
template: path.join(__dirname, 'lib', 'static', 'index.html'),
version: pkg.version,
serverURL: (isFirebaseEnv && hasFirebaseConfig) ? getFirebaseUrl() : '',
inject: 'body',
}),
new MiniCssExtractPlugin(),
new GenerateSW({
swDest: 'sw.js',
clientsClaim: true,

11
webpack.dev.js Normal file
View File

@ -0,0 +1,11 @@
const { merge } = require('webpack-merge')
const baseConfig = require('./webpack.common')
const isDevelopment = Boolean(process.argv[2] && process.argv[2].includes('mode=development'))
module.exports = merge(baseConfig, {
mode: 'development',
devtool: 'eval-source-map',
watch: true,
})

7
webpack.prod.js Normal file
View File

@ -0,0 +1,7 @@
const { merge } = require('webpack-merge')
const baseConfig = require('./webpack.common')
module.exports = merge(baseConfig, {
mode: 'production',
})