diff --git a/lib/frontend/components/App.svelte b/lib/frontend/components/App.svelte
new file mode 100644
index 0000000..208abda
--- /dev/null
+++ b/lib/frontend/components/App.svelte
@@ -0,0 +1,5 @@
+
+
+
diff --git a/lib/frontend/components/AppContainer.svelte b/lib/frontend/components/AppContainer.svelte
new file mode 100644
index 0000000..4669fbc
--- /dev/null
+++ b/lib/frontend/components/AppContainer.svelte
@@ -0,0 +1,14 @@
+
+
+{#if showTrackingPanel}
+
+{/if}
+
diff --git a/lib/frontend/components/TrackingPanel.svelte b/lib/frontend/components/TrackingPanel.svelte
new file mode 100644
index 0000000..4f0e9fb
--- /dev/null
+++ b/lib/frontend/components/TrackingPanel.svelte
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+ 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.
+
+
+
+ Ok
+
+
+ Nope
+
+
diff --git a/lib/frontend/index.js b/lib/frontend/index.js
new file mode 100644
index 0000000..0be492e
--- /dev/null
+++ b/lib/frontend/index.js
@@ -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
diff --git a/lib/frontend/stores/configStore.js b/lib/frontend/stores/configStore.js
new file mode 100644
index 0000000..adcaace
--- /dev/null
+++ b/lib/frontend/stores/configStore.js
@@ -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()
diff --git a/lib/frontend/stores/index.js b/lib/frontend/stores/index.js
new file mode 100644
index 0000000..40e2cb9
--- /dev/null
+++ b/lib/frontend/stores/index.js
@@ -0,0 +1,5 @@
+import configStore from './configStore'
+
+export {
+ configStore,
+}
diff --git a/lib/static/index.html b/lib/static/index.html
index 4f70a40..81be266 100644
--- a/lib/static/index.html
+++ b/lib/static/index.html
@@ -70,6 +70,8 @@
+
+
v.<%= htmlWebpackPlugin.options.version %> ◆
diff --git a/lib/static/index.js b/lib/static/index.js
index 8ee6608..0aa68f3 100644
--- a/lib/static/index.js
+++ b/lib/static/index.js
@@ -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) => {
diff --git a/lib/static/style.css b/lib/static/style.css
index 7d51b37..538d14c 100644
--- a/lib/static/style.css
+++ b/lib/static/style.css
@@ -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;
-}
diff --git a/package-lock.json b/package-lock.json
index e71ab8d..31498e9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 1da6c4d..6fc6ca8 100644
--- a/package.json
+++ b/package.json
@@ -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"
}
}
diff --git a/webpack.config.js b/webpack.common.js
similarity index 65%
rename from webpack.config.js
rename to webpack.common.js
index 2abffad..f15cfcf 100644
--- a/webpack.config.js
+++ b/webpack.common.js
@@ -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,
diff --git a/webpack.dev.js b/webpack.dev.js
new file mode 100644
index 0000000..df7ac03
--- /dev/null
+++ b/webpack.dev.js
@@ -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,
+})
diff --git a/webpack.prod.js b/webpack.prod.js
new file mode 100644
index 0000000..da927f7
--- /dev/null
+++ b/webpack.prod.js
@@ -0,0 +1,7 @@
+const { merge } = require('webpack-merge')
+
+const baseConfig = require('./webpack.common')
+
+module.exports = merge(baseConfig, {
+ mode: 'production',
+})