diff --git a/app/package.json b/app/package.json
index d8497b6..0efaf23 100644
--- a/app/package.json
+++ b/app/package.json
@@ -34,6 +34,7 @@
"babel-loader": "^8.2.3",
"babel-plugin-formatjs": "^10.3.17",
"copy-webpack-plugin": "^10.0.0",
+ "css-loader": "^6.6.0",
"eslint": "^8.8.0",
"eslint-config-react-app": "^7.0.0",
"eslint-plugin-flowtype": "^8.0.3",
@@ -44,6 +45,7 @@
"html-webpack-plugin": "^5.3.1",
"jest": "^27.0.4",
"jq-cli-wrapper": "^1.6.1",
+ "mini-css-extract-plugin": "^2.5.3",
"msw": "^0.36.3",
"node-fetch": "^2.6.1",
"shell-loader": "^1.2.1",
@@ -58,6 +60,7 @@
"@badrap/bar-of-progress": "^0.1.2",
"@emotion/react": "^11.6.0",
"@emotion/styled": "^11.6.0",
+ "@fontsource/roboto": "^4.5.3",
"@mui/icons-material": "^5.1.1",
"@mui/material": "^5.1.1",
"@rehooks/local-storage": "2.4.0",
diff --git a/app/src/index.ejs b/app/src/index.ejs
index a56898e..5b62b3c 100644
--- a/app/src/index.ejs
+++ b/app/src/index.ejs
@@ -3,8 +3,6 @@
<%= htmlWebpackPlugin.options.title %>
-
-
diff --git a/app/src/index.tsx b/app/src/index.tsx
index 53e799c..4530201 100644
--- a/app/src/index.tsx
+++ b/app/src/index.tsx
@@ -4,6 +4,11 @@ import * as ReactDOM from "react-dom";
import App from "./app/App";
+import "@fontsource/roboto/300.css";
+import "@fontsource/roboto/400.css";
+import "@fontsource/roboto/500.css";
+import "@fontsource/roboto/700.css";
+
declare global {
interface Window {
/**
diff --git a/app/webpack.config.js b/app/webpack.config.js
index f59eba6..b6fc7c3 100644
--- a/app/webpack.config.js
+++ b/app/webpack.config.js
@@ -1,95 +1,106 @@
const CopyPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
+const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const Webpack = require("webpack");
const WorkboxPlugin = require("workbox-webpack-plugin");
-module.exports = {
- output: {
- clean: true,
- publicPath: "/",
- chunkFilename: "javascripts/chunks/[chunkhash].[name].js",
- filename: "javascripts/[contenthash].[name].js",
- },
- module: {
- rules: [
- {
- test: /\.(png|jpe?g|svg)$/i,
- type: "asset/resource",
- },
- {
- test: /\.tsx?$/,
- use: [
- {
- loader: "babel-loader",
- },
- ],
- },
- {
- test: /lang\/[a-z_-]+\.json$/i,
- type: "json",
- use: [
- {
- loader: "shell-loader",
- options: {
- script:
- "cat > /tmp/lang.json && formatjs compile /tmp/lang.json --ast",
+module.exports = (env, argv) => {
+ const config = {
+ output: {
+ clean: true,
+ publicPath: "/",
+ chunkFilename: "javascripts/chunks/[chunkhash].[name].js",
+ filename: "javascripts/[contenthash].[name].js",
+ },
+ module: {
+ rules: [
+ {
+ test: /\.(png|jpe?g|svg)$/i,
+ type: "asset/resource",
+ },
+ {
+ test: /\.tsx?$/,
+ use: ["babel-loader"],
+ },
+ {
+ test: /\.css$/i,
+ use: [MiniCssExtractPlugin.loader, "css-loader"],
+ },
+ {
+ test: /lang\/[a-z_-]+\.json$/i,
+ type: "json",
+ use: [
+ {
+ loader: "shell-loader",
+ options: {
+ script:
+ "cat > /tmp/lang.json && formatjs compile /tmp/lang.json --ast",
+ },
},
- },
- ],
+ ],
+ },
+ ],
+ },
+ resolve: {
+ alias: {
+ "@formatjs/icu-messageformat-parser":
+ "@formatjs/icu-messageformat-parser/no-parser",
},
- ],
- },
- resolve: {
- alias: {
- "@formatjs/icu-messageformat-parser":
- "@formatjs/icu-messageformat-parser/no-parser",
+ extensions: [".ts", ".tsx", ".js", ".jsx"],
},
- extensions: [".ts", ".tsx", ".js", ".jsx"],
- },
- optimization: {
- splitChunks: {
- chunks: "all",
- cacheGroups: {
- react: {
- test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
- name: "react",
+ optimization: {
+ splitChunks: {
+ chunks: "all",
+ cacheGroups: {
+ react: {
+ test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
+ name: "react",
+ },
},
},
},
- },
- plugins: [
- new CopyPlugin({
- patterns: [{ from: "public" }],
- }),
- new HtmlWebpackPlugin({
- title: "Diversity Puzzle Trails",
- meta: {
- "theme-color": "#1976d2",
- },
- }),
- new Webpack.EnvironmentPlugin({
- /**
- * API root without trailing slash, e.g. https://example.com/api
- */
- API_ROOT: "",
+ plugins: [
+ new CopyPlugin({
+ patterns: [{ from: "public" }],
+ }),
+ new HtmlWebpackPlugin({
+ title: "Diversity Puzzle Trails",
+ meta: {
+ "theme-color": "#1976d2",
+ },
+ }),
+ new Webpack.EnvironmentPlugin({
+ /**
+ * API root without trailing slash, e.g. https://example.com/api
+ */
+ API_ROOT: "",
- /**
- * Whether to use the mock service worker instead of the real API
- */
- API_USE_MOCK: false,
- }),
- new WorkboxPlugin.GenerateSW({
- exclude: [
- /.+LICENSE\.txt$/,
- "mockServiceWorker.js",
- "robots.txt",
- "_redirects",
- "manifest.json",
- ],
- }),
- ],
- devServer: {
- historyApiFallback: true,
- hot: true,
- },
+ /**
+ * Whether to use the mock service worker instead of the real API
+ */
+ API_USE_MOCK: false,
+ }),
+ new MiniCssExtractPlugin(),
+ ],
+ devServer: {
+ historyApiFallback: true,
+ hot: true,
+ },
+ };
+
+ if (argv.mode === "production") {
+ config.plugins.push(
+ new WorkboxPlugin.GenerateSW({
+ exclude: [
+ /.+LICENSE\.txt$/,
+ "mockServiceWorker.js",
+ "robots.txt",
+ "_redirects",
+ "manifest.json",
+ ],
+ })
+ );
+ }
+
+ return config;
};
diff --git a/app/yarn.lock b/app/yarn.lock
index 419ecc4..df7abab 100644
--- a/app/yarn.lock
+++ b/app/yarn.lock
@@ -1188,6 +1188,11 @@
minimatch "^3.0.4"
strip-json-comments "^3.1.1"
+"@fontsource/roboto@^4.5.3":
+ version "4.5.3"
+ resolved "https://registry.yarnpkg.com/@fontsource/roboto/-/roboto-4.5.3.tgz#c729ac22c35ae1c224cde10042ce7ab356bc4dda"
+ integrity sha512-NUvBTj332dFRdiVkLlavXbDGoD2zyyeGYmMyrXOnctg/3e4pq95+rJgNfUP+k4v8UBk2L1aomGw9dDjbRdAmTg==
+
"@formatjs/cli@^4.2.15":
version "4.8.2"
resolved "https://registry.yarnpkg.com/@formatjs/cli/-/cli-4.8.2.tgz#65b08c01d0ee0099d56c419ecd49c0bf2f947f56"
@@ -3718,6 +3723,20 @@ crypto-random-string@^2.0.0:
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
+css-loader@^6.6.0:
+ version "6.6.0"
+ resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.6.0.tgz#c792ad5510bd1712618b49381bd0310574fafbd3"
+ integrity sha512-FK7H2lisOixPT406s5gZM1S3l8GrfhEBT3ZiL2UX1Ng1XWs0y2GPllz/OTyvbaHe12VgQrIXIzuEGVlbUhodqg==
+ dependencies:
+ icss-utils "^5.1.0"
+ postcss "^8.4.5"
+ 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.2.0"
+ semver "^7.3.5"
+
css-select@^4.1.3:
version "4.2.1"
resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.2.1.tgz#9e665d6ae4c7f9d65dbe69d0316e3221fb274cdd"
@@ -3748,6 +3767,11 @@ css@^3.0.0:
source-map "^0.6.1"
source-map-resolve "^0.6.0"
+cssesc@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
+ integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+
cssom@^0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10"
@@ -5508,6 +5532,11 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24:
dependencies:
safer-buffer ">= 2.1.2 < 3"
+icss-utils@^5.0.0, icss-utils@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
+ integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
+
idb@^6.1.4:
version "6.1.5"
resolved "https://registry.yarnpkg.com/idb/-/idb-6.1.5.tgz#dbc53e7adf1ac7c59f9b2bf56e00b4ea4fce8c7b"
@@ -7060,6 +7089,13 @@ min-indent@^1.0.0:
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
+mini-css-extract-plugin@^2.5.3:
+ version "2.5.3"
+ resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz#c5c79f9b22ce9b4f164e9492267358dbe35376d9"
+ integrity sha512-YseMB8cs8U/KCaAGQoqYmfUuhhGW0a9p9XvWXrxVOkE3/IiISTLw4ALNt7JR5B2eYauFM+PQGSbXMDmVbR7Tfw==
+ dependencies:
+ schema-utils "^4.0.0"
+
minimalistic-assert@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
@@ -7689,7 +7725,48 @@ portfinder@^1.0.28:
debug "^3.1.1"
mkdirp "^0.5.5"
-postcss@^8.1.10:
+postcss-modules-extract-imports@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d"
+ integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==
+
+postcss-modules-local-by-default@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c"
+ integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==
+ dependencies:
+ icss-utils "^5.0.0"
+ postcss-selector-parser "^6.0.2"
+ postcss-value-parser "^4.1.0"
+
+postcss-modules-scope@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06"
+ integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==
+ dependencies:
+ postcss-selector-parser "^6.0.4"
+
+postcss-modules-values@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c"
+ integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==
+ dependencies:
+ icss-utils "^5.0.0"
+
+postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
+ version "6.0.9"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f"
+ integrity sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==
+ dependencies:
+ cssesc "^3.0.0"
+ util-deprecate "^1.0.2"
+
+postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
+ integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
+
+postcss@^8.1.10, postcss@^8.4.5:
version "8.4.6"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.6.tgz#c5ff3c3c457a23864f32cb45ac9b741498a09ae1"
integrity sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==
@@ -9299,7 +9376,7 @@ url-parse-lax@^1.0.0:
dependencies:
prepend-http "^1.0.1"
-util-deprecate@^1.0.1, util-deprecate@~1.0.1:
+util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=