From 2b4cbd84ef308fb2555e687947f4bb93122c5664 Mon Sep 17 00:00:00 2001 From: Josh Creek Date: Sat, 17 Dec 2022 15:13:17 +0000 Subject: [PATCH] chore(*): Add base project files --- .devcontainer/Dockerfile | 14 +++++ .devcontainer/base.Dockerfile | 17 ++++++ .devcontainer/devcontainer.json | 51 ++++++++++++++++++ .eslintignore | 2 + .eslintrc.json | 33 ++++++++++++ .gitattributes | 1 + .gitignore | 2 + .vscode/launch.json | 19 +++++++ src/custom.d.ts | 4 ++ src/loadServiceWorker.ts | 28 ++++++++++ src/serviceWorker.js | 26 ++++++++++ tsconfig.json | 8 +++ webpack.common.js | 91 +++++++++++++++++++++++++++++++++ webpack.dev.js | 23 +++++++++ webpack.prod.js | 19 +++++++ 15 files changed, 338 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/base.Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 .eslintignore create mode 100644 .eslintrc.json create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 src/custom.d.ts create mode 100644 src/loadServiceWorker.ts create mode 100644 src/serviceWorker.js create mode 100644 tsconfig.json create mode 100644 webpack.common.js create mode 100644 webpack.dev.js create mode 100644 webpack.prod.js diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..c1541c7 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,14 @@ +# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster +ARG VARIANT=16-bullseye +FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:0-${VARIANT} + +# [Optional] Uncomment this section to install additional OS packages. +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install --no-install-recommends inotify-tools + +# [Optional] Uncomment if you want to install an additional version of node using nvm +# ARG EXTRA_NODE_VERSION=10 +# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}" + +# [Optional] Uncomment if you want to install more global node packages +# RUN su node -c "npm install -g " diff --git a/.devcontainer/base.Dockerfile b/.devcontainer/base.Dockerfile new file mode 100644 index 0000000..35b6654 --- /dev/null +++ b/.devcontainer/base.Dockerfile @@ -0,0 +1,17 @@ +# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster +ARG VARIANT=16-bullseye +FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT} + +# Install tslint, typescript. eslint is installed by javascript image +ARG NODE_MODULES="tslint-to-eslint-config typescript" +COPY library-scripts/meta.env /usr/local/etc/vscode-dev-containers +RUN su node -c "umask 0002 && npm install -g ${NODE_MODULES}" \ + && npm cache clean --force > /dev/null 2>&1 + +# [Optional] Uncomment this section to install additional OS packages. +# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ +# && apt-get -y install --no-install-recommends + +# [Optional] Uncomment if you want to install an additional version of node using nvm +# ARG EXTRA_NODE_VERSION=10 +# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..982ad31 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,51 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.238.0/containers/typescript-node +{ + "name": "Node.js & TypeScript", + "build": { + "dockerfile": "Dockerfile", + // Update 'VARIANT' to pick a Node version: 18, 16, 14. + // Append -bullseye or -buster to pin to an OS version. + // Use -bullseye variants on local on arm64/Apple Silicon. + "args": { + "VARIANT": "16-bullseye" + } + }, + + // Configure tool-specific properties. + "customizations": { + // Configure properties specific to VS Code. + "vscode": { + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "formulahendry.auto-rename-tag", + "EditorConfig.EditorConfig", + "dbaeumer.vscode-eslint", + "bierner.github-markdown-preview", + "eamodio.gitlens", + "xabikos.JavaScriptSnippets", + "ritwickdey.LiveServer", + "yzhang.markdown-all-in-one", + "bierner.markdown-emoji", + "bierner.markdown-footnotes", + "bierner.markdown-preview-github-styles", + "bierner.markdown-yaml-preamble", + "DavidAnson.vscode-markdownlint", + "PKief.material-icon-theme", + "christian-kohler.npm-intellisense", + "christian-kohler.path-intellisense", + "esbenp.prettier-vscode", + "gencer.html-slim-scss-css-class-completion" + ] + } + }, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000], + + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "npm install", + + // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "node" +} diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..db4c6d9 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +dist +node_modules \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..f81e888 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "airbnb-base", + "plugin:import/errors", + "plugin:import/warnings", + "plugin:import/typescript" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "import/extensions": [ + "error", + "ignorePackages", + { + "js": "never", + "jsx": "never", + "ts": "never", + "tsx": "never" + } + ], + "quotes": [2, "single", { "avoidEscape": true }] + } +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..94f480d --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..db4c6d9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +dist +node_modules \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..ea2269b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,19 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch via NPM", + "request": "launch", + "runtimeArgs": [ + "run", + "dev" + ], + "runtimeExecutable": "npm", + "skipFiles": [ + "/**" + ], + "type": "node", + "stopOnEntry": true, + } + ] +} \ No newline at end of file diff --git a/src/custom.d.ts b/src/custom.d.ts new file mode 100644 index 0000000..60bd434 --- /dev/null +++ b/src/custom.d.ts @@ -0,0 +1,4 @@ +declare module '*.svg' { + const content: any; + export default content; +} diff --git a/src/loadServiceWorker.ts b/src/loadServiceWorker.ts new file mode 100644 index 0000000..dd378ce --- /dev/null +++ b/src/loadServiceWorker.ts @@ -0,0 +1,28 @@ +export default function loadServiceWorker() { + let deferredPrompt; + + window.addEventListener('beforeinstallprompt', (e) => { + const installApp = document.getElementById('install-app-btn-container'); + + installApp.addEventListener('click', async () => { + if (deferredPrompt !== null) { + deferredPrompt.prompt(); + const { outcome } = await deferredPrompt.userChoice; + if (outcome === 'accepted') { + deferredPrompt = null; + } + } + }); + + document.getElementById('install-app-btn-container').style.display = 'block'; + deferredPrompt = e; + }); + + window.addEventListener('load', () => { + navigator.serviceWorker.register('/service-worker.js'); + }); + + if (window.matchMedia('(display-mode: standalone)').matches) { + document.getElementById('install-app-btn-container').style.display = 'none'; + } +} diff --git a/src/serviceWorker.js b/src/serviceWorker.js new file mode 100644 index 0000000..cc1e0f4 --- /dev/null +++ b/src/serviceWorker.js @@ -0,0 +1,26 @@ +import { precacheAndRoute } from 'workbox-precaching'; +import * as navigationPreload from 'workbox-navigation-preload'; +import { NetworkFirst, CacheFirst, StaleWhileRevalidate } from 'workbox-strategies'; +import { registerRoute, NavigationRoute, Route } from 'workbox-routing'; + +// Precache the manifest +// eslint-disable-next-line no-underscore-dangle, no-restricted-globals +precacheAndRoute(self.__WB_MANIFEST); + +const navigationRoute = new NavigationRoute(new NetworkFirst({ + cacheName: 'navigations', +})); + +const imageAssetRoute = new Route(({ request }) => request.destination === 'image', new CacheFirst({ + cacheName: 'image-assets', +})); + +registerRoute(navigationRoute); +registerRoute(imageAssetRoute); + +registerRoute( + ({ url }) => url.origin === 'https://fonts.googleapis.com', + new StaleWhileRevalidate({ + cacheName: 'google-fonts-stylesheets', + }), +); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..8e7ab13 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "preserveConstEnums": true, + "sourceMap": true + }, + "include": ["src/**/*", "src/custom.d.ts", "src/audio.d.ts"], + "exclude": ["node_modules", "**/*.spec.ts"] +} diff --git a/webpack.common.js b/webpack.common.js new file mode 100644 index 0000000..e84827b --- /dev/null +++ b/webpack.common.js @@ -0,0 +1,91 @@ +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin'); +const { WebpackManifestPlugin } = require('webpack-manifest-plugin'); + +const options = {}; + +module.exports = { + target: 'web', + entry: { + bundle: path.resolve(__dirname, 'src/index.ts'), + }, + output: { + path: path.resolve(__dirname, 'dist'), + filename: '[name].[contenthash].js', + clean: true, + assetModuleFilename: '[name].[contenthash][ext]', + publicPath: '', + }, + watchOptions: { poll: true }, + module: { + rules: [ + { + // Use these loaders for any matching scss file types + test: /\.scss$/, + use: [ + 'style-loader', + 'css-loader', + 'sass-loader', + ], + }, + { + // Add backwards compatibility + test: /\.(js|ts)$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader', + options: { + presets: ['@babel/preset-env', '@babel/preset-typescript'], + }, + }, + }, + { + // Add support for images + test: /\.(png|jpg|jpeg|gif)$/i, + type: 'asset/resource', + }, + { + // Add support for favicon + test: /\.ico$/, + use: [ + { + loader: 'file-loader', + options: { + name: '[name].[ext]', // <-- retain original file name + }, + }, + ], + }, + { + // Add support for manifest + test: /\.webmanifest$/i, + use: 'webpack-webmanifest-loader', + type: 'asset/resource', + }, + { + // Add support for audio + test: /\.(mp3)$/i, + type: 'asset/resource', + }, + { + // Add inlining of SVG + test: /\.svg$/i, + type: 'asset/inline', + }, + ], + }, + resolve: { + // Specify the order in which to resolve files by their extension + extensions: ['*', '.js', '.ts'], + }, + plugins: [ + new HtmlWebpackPlugin({ + inject: 'body', + filename: 'index.html', + template: 'src/template.html', + }), + new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/.*/]), + new WebpackManifestPlugin(options), + ], +}; diff --git a/webpack.dev.js b/webpack.dev.js new file mode 100644 index 0000000..624551e --- /dev/null +++ b/webpack.dev.js @@ -0,0 +1,23 @@ +const path = require('path'); +const { merge } = require('webpack-merge'); +const common = require('./webpack.common'); + +module.exports = merge(common, { + mode: 'development', + devtool: 'inline-source-map', + devServer: { + static: { + directory: path.resolve(__dirname, 'dist'), + }, + port: 3000, + open: true, + hot: true, + compress: true, + historyApiFallback: true, + devMiddleware: { + index: true, + mimeTypes: { phtml: 'text/html' }, + writeToDisk: true, + }, + }, +}); diff --git a/webpack.prod.js b/webpack.prod.js new file mode 100644 index 0000000..52c5077 --- /dev/null +++ b/webpack.prod.js @@ -0,0 +1,19 @@ +const { merge } = require('webpack-merge'); +const { InjectManifest } = require('workbox-webpack-plugin'); +const common = require('./webpack.common'); + +common.plugins.push(new InjectManifest({ + swSrc: './src/serviceWorker.js', + swDest: 'service-worker.js', + maximumFileSizeToCacheInBytes: 50000000, +})); + +module.exports = merge(common, { + mode: 'production', + devtool: 'source-map', + performance: { + hints: false, + maxEntrypointSize: 512000, + maxAssetSize: 512000, + }, +});