diff --git a/.devcontainer/bash_prompt.sh b/.devcontainer/bash_prompt.sh new file mode 100644 index 0000000..6cc453f --- /dev/null +++ b/.devcontainer/bash_prompt.sh @@ -0,0 +1,24 @@ +# from https://github.com/devcontainers/features/blob/2951f0481a488ea43a6f2ea6f18a47f0a0bf744d/src/common-utils/scripts/bash_theme_snippet.sh#L20 +# bash theme - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme +__bash_prompt() { + local userpart='`export XIT=$? \ + && [ ! -z "${GITHUB_USER:-}" ] && echo -n "\[\033[0;32m\]@${GITHUB_USER:-} " || echo -n "\[\033[0;32m\]\u " \ + && [ "$XIT" -ne "0" ] && echo -n "\[\033[1;31m\]➜" || echo -n "\[\033[0m\]➜"`' + local gitbranch='`\ + if [ "$(git config --get devcontainers-theme.hide-status 2>/dev/null)" != 1 ] && [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \ + export BRANCH="$(git --no-optional-locks symbolic-ref --short HEAD 2>/dev/null || git --no-optional-locks rev-parse --short HEAD 2>/dev/null)"; \ + if [ "${BRANCH:-}" != "" ]; then \ + echo -n "\[\033[0;36m\](\[\033[1;31m\]${BRANCH:-}" \ + && if [ "$(git config --get devcontainers-theme.show-dirty 2>/dev/null)" = 1 ] && \ + git --no-optional-locks ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \ + echo -n " \[\033[1;33m\]✗"; \ + fi \ + && echo -n "\[\033[0;36m\]) "; \ + fi; \ + fi`' + local lightblue='\[\033[1;34m\]' + local removecolor='\[\033[0m\]' + PS1="${userpart} ${lightblue}\w ${gitbranch}${removecolor}\$ " + unset -f __bash_prompt +} +__bash_prompt diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..53b5602 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,116 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-docker-compose +{ + "name": "m-tartari.github.io", + // Update the 'dockerComposeFile' list if you have more compose files or use different names. + // The .devcontainer/docker-compose.yml file contains any overrides you need/want to make. + "dockerComposeFile": [ + "docker-compose.yml" + ], + // The 'service' property is the name of the service for the container that VS Code should + // use. Update this value and .devcontainer/docker-compose.yml to the real service name. + "service": "devcontainer", + // The optional 'workspaceFolder' property is the path VS Code should open by default when + // connected. This is typically a file mount in .devcontainer/docker-compose.yml + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + // Features to add to the dev container. More info: https://containers.dev/features. + "features": { + "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {} + }, + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + // Uncomment the next line if you want start specific services in your Docker Compose config. + // "runServices": [], + // Uncomment the next line if you want to keep your containers running after VS Code shuts down. + // "shutdownAction": "none", + // Uncomment the next line to run commands after the container is created. + "postCreateCommand": "bash .devcontainer/post_create.sh", + "postStartCommand": "npm ci", + // Configure tool-specific properties. + "customizations": { + "vscode": { + "settings": { + // Workbench + "workbench.iconTheme": "vscode-icons", + // Files + "files.trimTrailingWhitespace": true, + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "files.exclude": { + "**/*.pyc": true, + "**/.git": false + }, + // Editor & Linting + "prettier.printWidth": 150, + "editor.suggestSelection": "first", + "editor.defaultFormatter": "esbenp.prettier-vscode", + "vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue", + "editor.detectIndentation": true, + "editor.insertSpaces": true, + "editor.tabSize": 2, + "editor.formatOnPaste": true, + "editor.formatOnSave": true, + "editor.formatOnType": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "editor.tokenColorCustomizations": { + "textMateRules": [ + { + "scope": [ + "comment" + ], + "settings": { + "fontStyle": "italic" + } + } + ] + }, + // git + "git.autofetch": true, + "git.confirmSync": false, + "git.enableSmartCommit": true, + "git-graph.dialog.rebase.ignoreDate": false, + "diffEditor.ignoreTrimWhitespace": false, + "diffEditor.wordWrap": "off", + // Javascript + "javascript.updateImportsOnFileMove.enabled": "always", + "typescript.preferences.importModuleSpecifier": "non-relative", + "typescript.updateImportsOnFileMove.enabled": "always", + "typescript.suggest.paths": true, + // JSON + "[json,jsonc]": { + "editor.defaultFormatter": "vscode.json-language-features", + "json.format.enable": true + }, + // Testing + "vitest.enable": true + }, + "extensions": [ + "adam-bender.commit-message-editor", + "christian-kohler.path-intellisense", + "codezombiech.gitignore", + "davidanson.vscode-markdownlint", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "firefox-devtools.vscode-firefox-debug", + "formulahendry.auto-close-tag", + "formulahendry.auto-rename-tag", + "github.copilot", + "github.copilot-chat", + "gruntfuggly.todo-tree", + "ibm.output-colorizer", + "mhutchie.git-graph", + "ms-azuretools.vscode-docker", + "naumovs.color-highlight", + "streetsidesoftware.code-spell-checker", + "vitest.explorer", + "vscode-icons-team.vscode-icons", + "waderyan.gitblame", + "wayou.vscode-todo-highlight" + ] + } + } + // Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "devcontainer" +} diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 0000000..6da77a2 --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -0,0 +1,20 @@ +services: + devcontainer: + image: m-tartari.github.io-dev + build: + context: .. + dockerfile: Dockerfile + target: development + container_name: devcontainer-m-tartari.github.io + hostname: m-tartari.github.io-dev + command: sleep infinity + ports: + - '5173:5173' + - '4173:4173' + volumes: + - ..:/workspaces/m-tartari.github.io:cached + # Uncomment the next four lines if you will use a ptrace-based debugger like C++, Go, and Rust. + # cap_add: + # - SYS_PTRACE + # security_opt: + # - seccomp:unconfined diff --git a/.devcontainer/post_create.sh b/.devcontainer/post_create.sh new file mode 100644 index 0000000..1fd30bb --- /dev/null +++ b/.devcontainer/post_create.sh @@ -0,0 +1,2 @@ +# Update the bash PS1 to include git details +cat .devcontainer/bash_prompt.sh >> $HOME/.bashrc diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..1cff1d1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,27 @@ +# compiled output +.vscode +node_modules +dist +npm-debug.log +.npmrc + +# git +.git +.gitignore +.github + +# code formatter +.eslintrc +.eslintignore +.editorconfig +.huskyrc +.lintstagedrc.json +.prettierrc + +# test +jest.config.js + +# docker +Dockerfile +docker-compose.yml +.dockerignore diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 9b1c8b1..0000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -/dist diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index 42b8cf4..0000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - root: true, - env: { browser: true, es2020: true }, - extends: [ - "prettier", - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:react-hooks/recommended', - "plugin:prettier/recommended" - ], - ignorePatterns: ['dist', '.eslintrc.cjs'], - parser: '@typescript-eslint/parser', - plugins: ['react-refresh'], - rules: { - 'react-refresh/only-export-components': [ - 'warn', - { allowConstantExport: true }, - ], - }, -} diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 35bdb1c..3b9b5a8 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,14 +12,22 @@ updates: prefix: '⬆️ chore' include: 'scope' groups: + vite: + patterns: + - 'vite*' vitest: patterns: - 'vitest' - '@vitest*' - typescript-eslint: + eslint: patterns: + - 'eslint*' - '@typescript-eslint*' mui: patterns: - '@mui/material' - '@mui/icons-material' + - '@emotion/*' + testing-library: + patterns: + - '@testing-library/*' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6d54dd7..cb7fe6d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,7 +1,7 @@ name: build on: push: - branches: ['master'] + branches: ['main'] pull_request: {} workflow_call: {} workflow_dispatch: {} @@ -19,7 +19,7 @@ jobs: node-version: 'lts/*' cache: 'npm' - - name: Install dependecies + - name: Install dependencies run: npm ci - name: Build diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9ce1f4f..4ff7ecc 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -4,7 +4,7 @@ name: deploy on: # Runs on pushes targeting the default branch push: - branches: ['master'] + branches: ['main'] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: @@ -36,9 +36,9 @@ jobs: node-version: 'lts/*' cache: 'npm' - name: Install dependencies - run: npm install + run: npm ci --omit=dev - name: Build - run: npm run build + run: npm run build:prod - name: Copy index.html to 404.html # see https://stackoverflow.com/a/76148302 run: cp ./dist/index.html ./dist/404.html diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..cfb43f9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,37 @@ +ARG PRODUCTION_IMAGE=nginx:alpine +ARG BASE_IMAGE=node:lts + +# --------------> The development image +FROM $BASE_IMAGE AS development + +ENV NODE_ENV=development +COPY --chown=1000:1000 . /workspaces/m-tartari.github.io +WORKDIR /workspaces/m-tartari.github.io +USER 1000:1000 + +CMD [ "sleep", "infinity" ] + +# --------------> The production build stage +FROM $BASE_IMAGE AS production-build + +ENV NODE_ENV=production +COPY . /app +WORKDIR /app + +RUN npm ci --omit=dev +RUN npm run build:prod + +# --------------> The production image +FROM ${PRODUCTION_IMAGE} AS production + +# Remove default nginx website +RUN rm -rf html; mkdir html + +COPY --from=production-build /app/dist /usr/share/nginx/html +# COPY .htpasswd /usr/share/nginx/html/.htpasswd +COPY ./nginx.conf /etc/nginx/ + +RUN chmod -R o+r /usr/share/nginx/html +WORKDIR /usr/share/nginx + +ENTRYPOINT ["nginx", "-g", "daemon off;"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..2ba39d1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,13 @@ +version: '3.8' + +services: + app: + image: git.m-tartari.eu/m-tartari.github.io + build: + context: . + dockerfile: Dockerfile + target: production + container_name: m-tartari.github.io + restart: unless-stopped + ports: + - '8080:8080' diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..c1ec3ca --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,66 @@ +import { fixupConfigRules } from '@eslint/compat' +import reactRefresh from 'eslint-plugin-react-refresh' +import globals from 'globals' +import tsParser from '@typescript-eslint/parser' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import js from '@eslint/js' +import { FlatCompat } from '@eslint/eslintrc' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all, +}) + +export default [ + { + ignores: ['**/dist', '**/.eslintrc.cjs', 'eslint.config.mjs'], + }, + ...fixupConfigRules( + compat.extends( + 'prettier', + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + 'plugin:prettier/recommended' + ) + ), + { + plugins: { + 'react-refresh': reactRefresh, + }, + + languageOptions: { + globals: { + ...globals.browser, + }, + + parser: tsParser, + ecmaVersion: 'latest', + sourceType: 'module', + + parserOptions: { + project: ['./tsconfig.json', './tsconfig.base.json'], + tsconfigRootDir: __dirname, + }, + }, + + settings: { + react: { + version: 'detect', + }, + }, + + rules: { + 'react-refresh/only-export-components': [ + 'warn', + { + allowConstantExport: true, + }, + ], + }, + }, +] diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..8971788 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,48 @@ +user nginx; + +worker_processes auto; + +events { worker_connections 1024; } + +http { + server { + server_tokens off; + + listen 8080; + root /usr/share/nginx/html; + include /etc/nginx/mime.types; + + location / { + # # This sets the authentication realm name + # auth_basic "Restricted Access"; + # # This specifies the location of the .htpasswd file + # auth_basic_user_file /usr/share/nginx/html/.htpasswd; + + try_files $uri $uri/ /index.html; + } + + gzip on; + gzip_vary on; + gzip_http_version 1.0; + gzip_comp_level 5; + gzip_types + application/atom+xml + application/javascript + application/json + application/rss+xml + application/vnd.ms-fontobject + application/x-font-ttf + application/x-web-app-manifest+json + application/xhtml+xml + application/xml + font/opentype + image/svg+xml + image/x-icon + text/css + text/plain + text/x-component; + gzip_proxied no-cache no-store private expired auth; + gzip_min_length 256; + gunzip on; + } +} diff --git a/package-lock.json b/package-lock.json index 45391ef..0e1ce82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@fontsource/roboto": "^5.1.0", "@mui/icons-material": "^6.1.9", "@mui/material": "^6.0.2", + "@vitejs/plugin-react-swc": "^3.7.2", "react": "^18.2.0", "react-dom": "^18.3.1", "react-router-dom": "^6.28.0", @@ -21,6 +22,7 @@ "vite-tsconfig-paths": "^5.1.3" }, "devDependencies": { + "@eslint/compat": "^1.2.3", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.0.1", "@testing-library/user-event": "^14.5.2", @@ -28,7 +30,6 @@ "@types/react-dom": "^18.3.1", "@typescript-eslint/eslint-plugin": "^8.17.0", "@typescript-eslint/parser": "^8.17.0", - "@vitejs/plugin-react-swc": "^3.7.2", "@vitest/coverage-istanbul": "^2.1.8", "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", @@ -989,6 +990,24 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/compat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.3.tgz", + "integrity": "sha512-wlZhwlDFxkxIZ571aH0FoK4h4Vwx7P3HJx62Gp8hTc10bfpwT2x0nULuAHmQSJBOWPgPeVf+9YtnD4j50zVHmA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.10.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, "node_modules/@eslint/config-array": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", @@ -1039,6 +1058,7 @@ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -1784,14 +1804,13 @@ ] }, "node_modules/@swc/core": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.26.tgz", - "integrity": "sha512-f5uYFf+TmMQyYIoxkn/evWhNGuUzC730dFwAKGwBVHHVoPyak1/GvJUm6i1SKl+2Hrj9oN0i3WSoWWZ4pgI8lw==", - "dev": true, + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.10.0.tgz", + "integrity": "sha512-+CuuTCmQFfzaNGg1JmcZvdUVITQXJk9sMnl1C2TiDLzOSVOJRwVD4dNo5dljX/qxpMAN+2BIYlwjlSkoGi6grg==", "hasInstallScript": true, "dependencies": { "@swc/counter": "^0.1.3", - "@swc/types": "^0.1.12" + "@swc/types": "^0.1.17" }, "engines": { "node": ">=10" @@ -1801,16 +1820,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.7.26", - "@swc/core-darwin-x64": "1.7.26", - "@swc/core-linux-arm-gnueabihf": "1.7.26", - "@swc/core-linux-arm64-gnu": "1.7.26", - "@swc/core-linux-arm64-musl": "1.7.26", - "@swc/core-linux-x64-gnu": "1.7.26", - "@swc/core-linux-x64-musl": "1.7.26", - "@swc/core-win32-arm64-msvc": "1.7.26", - "@swc/core-win32-ia32-msvc": "1.7.26", - "@swc/core-win32-x64-msvc": "1.7.26" + "@swc/core-darwin-arm64": "1.10.0", + "@swc/core-darwin-x64": "1.10.0", + "@swc/core-linux-arm-gnueabihf": "1.10.0", + "@swc/core-linux-arm64-gnu": "1.10.0", + "@swc/core-linux-arm64-musl": "1.10.0", + "@swc/core-linux-x64-gnu": "1.10.0", + "@swc/core-linux-x64-musl": "1.10.0", + "@swc/core-win32-arm64-msvc": "1.10.0", + "@swc/core-win32-ia32-msvc": "1.10.0", + "@swc/core-win32-x64-msvc": "1.10.0" }, "peerDependencies": { "@swc/helpers": "*" @@ -1822,13 +1841,12 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.26.tgz", - "integrity": "sha512-FF3CRYTg6a7ZVW4yT9mesxoVVZTrcSWtmZhxKCYJX9brH4CS/7PRPjAKNk6kzWgWuRoglP7hkjQcd6EpMcZEAw==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.10.0.tgz", + "integrity": "sha512-wCeUpanqZyzvgqWRtXIyhcFK3CqukAlYyP+fJpY2gWc/+ekdrenNIfZMwY7tyTFDkXDYEKzvn3BN/zDYNJFowQ==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -1838,13 +1856,12 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.7.26.tgz", - "integrity": "sha512-az3cibZdsay2HNKmc4bjf62QVukuiMRh5sfM5kHR/JMTrLyS6vSw7Ihs3UTkZjUxkLTT8ro54LI6sV6sUQUbLQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.10.0.tgz", + "integrity": "sha512-0CZPzqTynUBO+SHEl/qKsFSahp2Jv/P2ZRjFG0gwZY5qIcr1+B/v+o74/GyNMBGz9rft+F2WpU31gz2sJwyF4A==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -1854,13 +1871,12 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.26.tgz", - "integrity": "sha512-VYPFVJDO5zT5U3RpCdHE5v1gz4mmR8BfHecUZTmD2v1JeFY6fv9KArJUpjrHEEsjK/ucXkQFmJ0jaiWXmpOV9Q==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.10.0.tgz", + "integrity": "sha512-oq+DdMu5uJOFPtRkeiITc4kxmd+QSmK+v+OBzlhdGkSgoH3yRWZP+H2ao0cBXo93ZgCr2LfjiER0CqSKhjGuNA==", "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1870,13 +1886,12 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.26.tgz", - "integrity": "sha512-YKevOV7abpjcAzXrhsl+W48Z9mZvgoVs2eP5nY+uoMAdP2b3GxC0Df1Co0I90o2lkzO4jYBpTMcZlmUXLdXn+Q==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.10.0.tgz", + "integrity": "sha512-Y6+PC8knchEViRxiCUj3j8wsGXaIhuvU+WqrFqV834eiItEMEI9+Vh3FovqJMBE3L7d4E4ZQtgImHCXjrHfxbw==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1886,13 +1901,12 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.26.tgz", - "integrity": "sha512-3w8iZICMkQQON0uIcvz7+Q1MPOW6hJ4O5ETjA0LSP/tuKqx30hIniCGOgPDnv3UTMruLUnQbtBwVCZTBKR3Rkg==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.10.0.tgz", + "integrity": "sha512-EbrX9A5U4cECCQQfky7945AW9GYnTXtCUXElWTkTYmmyQK87yCyFfY8hmZ9qMFIwxPOH6I3I2JwMhzdi8Qoz7g==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1902,13 +1916,12 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.26.tgz", - "integrity": "sha512-c+pp9Zkk2lqb06bNGkR2Looxrs7FtGDMA4/aHjZcCqATgp348hOKH5WPvNLBl+yPrISuWjbKDVn3NgAvfvpH4w==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.10.0.tgz", + "integrity": "sha512-TaxpO6snTjjfLXFYh5EjZ78se69j2gDcqEM8yB9gguPYwkCHi2Ylfmh7iVaNADnDJFtjoAQp0L41bTV/Pfq9Cg==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1918,13 +1931,12 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.26.tgz", - "integrity": "sha512-PgtyfHBF6xG87dUSSdTJHwZ3/8vWZfNIXQV2GlwEpslrOkGqy+WaiiyE7Of7z9AvDILfBBBcJvJ/r8u980wAfQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.10.0.tgz", + "integrity": "sha512-IEGvDd6aEEKEyZFZ8oCKuik05G5BS7qwG5hO5PEMzdGeh8JyFZXxsfFXbfeAqjue4UaUUrhnoX+Ze3M2jBVMHw==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1934,13 +1946,12 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.26.tgz", - "integrity": "sha512-9TNXPIJqFynlAOrRD6tUQjMq7KApSklK3R/tXgIxc7Qx+lWu8hlDQ/kVPLpU7PWvMMwC/3hKBW+p5f+Tms1hmA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.10.0.tgz", + "integrity": "sha512-UkQ952GSpY+Z6XONj9GSW8xGSkF53jrCsuLj0nrcuw7Dvr1a816U/9WYZmmcYS8tnG2vHylhpm6csQkyS8lpCw==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -1950,13 +1961,12 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.26.tgz", - "integrity": "sha512-9YngxNcG3177GYdsTum4V98Re+TlCeJEP4kEwEg9EagT5s3YejYdKwVAkAsJszzkXuyRDdnHUpYbTrPG6FiXrQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.10.0.tgz", + "integrity": "sha512-a2QpIZmTiT885u/mUInpeN2W9ClCnqrV2LnMqJR1/Fgx1Afw/hAtiDZPtQ0SqS8yDJ2VR5gfNZo3gpxWMrqdVA==", "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "win32" @@ -1966,13 +1976,12 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.26.tgz", - "integrity": "sha512-VR+hzg9XqucgLjXxA13MtV5O3C0bK0ywtLIBw/+a+O+Oc6mxFWHtdUeXDbIi5AiPbn0fjgVJMqYnyjGyyX8u0w==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.10.0.tgz", + "integrity": "sha512-tZcCmMwf483nwsEBfUk5w9e046kMa1iSik4bP9Kwi2FGtOfHuDfIcwW4jek3hdcgF5SaBW1ktnK/lgQLDi5AtA==", "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -1984,14 +1993,12 @@ "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "dev": true + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==" }, "node_modules/@swc/types": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.12.tgz", - "integrity": "sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==", - "dev": true, + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.17.tgz", + "integrity": "sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==", "dependencies": { "@swc/counter": "^0.1.3" } @@ -2390,7 +2397,6 @@ "version": "3.7.2", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.7.2.tgz", "integrity": "sha512-y0byko2b2tSVVf5Gpng1eEhX1OvPC7x8yns1Fx8jDzlJp4LS6CMkCPfLw47cjyoMrshQDoQw4qcgjsU9VvlCew==", - "dev": true, "dependencies": { "@swc/core": "^1.7.26" }, diff --git a/package.json b/package.json index 9c35210..98bcfd7 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,10 @@ "start:dev": "npm run dev", "start:prod": "npm run preview", "dev": "vite", - "build": "tsc && vite build", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "build": "npm run build:dev", + "build:dev": "tsc && vite build", + "build:prod": "tsc --project tsconfig.prod.json && vite build", + "lint": "eslint . --report-unused-disable-directives --max-warnings 0", "lint:fix": "npm run lint -- --fix", "preview": "vite preview", "test": "vitest", @@ -21,6 +23,7 @@ "@fontsource/roboto": "^5.1.0", "@mui/icons-material": "^6.1.9", "@mui/material": "^6.0.2", + "@vitejs/plugin-react-swc": "^3.7.2", "react": "^18.2.0", "react-dom": "^18.3.1", "react-router-dom": "^6.28.0", @@ -29,6 +32,7 @@ "vite-tsconfig-paths": "^5.1.3" }, "devDependencies": { + "@eslint/compat": "^1.2.3", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.0.1", "@testing-library/user-event": "^14.5.2", @@ -36,7 +40,6 @@ "@types/react-dom": "^18.3.1", "@typescript-eslint/eslint-plugin": "^8.17.0", "@typescript-eslint/parser": "^8.17.0", - "@vitejs/plugin-react-swc": "^3.7.2", "@vitest/coverage-istanbul": "^2.1.8", "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", diff --git a/vitest.setup.ts b/src/setupTests.ts similarity index 100% rename from vitest.setup.ts rename to src/setupTests.ts diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..8e7753a --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "/tmp/tsconfig.tsbuildinfo", + "target": "ES2020", + "lib": [ + "ES2020", + "DOM", + "DOM.Iterable" + ], + "types": [ + "vite/client", + ], + "module": "ESNext", + "skipLibCheck": true, + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "baseUrl": "src", + }, + "include": [ + "src", + "vite.config.ts" + ] +} diff --git a/tsconfig.json b/tsconfig.json index 0dec944..fafac5e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,38 +1,18 @@ { + "extends": "./tsconfig.base.json", "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "lib": [ - "ES2020", - "DOM", - "DOM.Iterable" - ], - "module": "ESNext", - "skipLibCheck": true, - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - "baseUrl": "src", - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, + "sourceMap": true, + "noUnusedLocals": false, + "noUnusedParameters": false, "types": [ - "vitest/globals", "@testing-library/jest-dom", + "vitest/globals", + "vitest/jsdom" ], }, "include": [ - "src" + "src", + "vite.config.ts", + "vitest.config.ts" ], - "references": [ - { - "path": "./tsconfig.node.json" - } - ] } diff --git a/tsconfig.node.json b/tsconfig.node.json deleted file mode 100644 index 42872c5..0000000 --- a/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/tsconfig.prod.json b/tsconfig.prod.json new file mode 100644 index 0000000..90f466f --- /dev/null +++ b/tsconfig.prod.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "sourceMap": false, + "noUnusedLocals": true, + "noUnusedParameters": true + }, + "exclude": [ + "**/*.test.ts", + "**/*.test.tsx", + "**/tests/**/*", + "src/setupTests.ts" + ] +} diff --git a/vite.config.ts b/vite.config.ts index 407394e..829c656 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,21 +1,18 @@ -import { defineConfig } from 'vitest/config' +import { defineConfig } from 'vite' import react from '@vitejs/plugin-react-swc' import viteTsconfigPaths from 'vite-tsconfig-paths' // https://vitejs.dev/config/ export default defineConfig({ plugins: [react(), viteTsconfigPaths()], + resolve: { + alias: { + components: '/src/components', + style: '/src/style', + }, + }, server: { open: true, host: true, }, - test: { - watch: false, - globals: true, - environment: 'jsdom', - setupFiles: ['./vitest.setup.ts'], - coverage: { - provider: 'istanbul', - }, - }, }) diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..0863162 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,21 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + resolve: { + alias: { + components: '/src/components', + style: '/src/style', + }, + }, + test: { + watch: false, + globals: true, + environment: 'jsdom', + setupFiles: ['./src/setupTests.ts'], + coverage: { + provider: 'istanbul', + include: ['src'], + exclude: ['./**/*.d.ts', './src/*.ts', './**/mocks/*.*', './**/{m,M}ock*.*', './**/*.test.tsx', './**/*.stories.*'], + }, + }, +})