feat: RsPack Bun Dockerfile
All checks were successful
ci/woodpecker/manual/workflow Pipeline was successful

This commit is contained in:
hadestructhor 2025-01-05 18:06:10 +01:00
parent ec5b3de9cf
commit eb0d43e589
28 changed files with 452 additions and 17951 deletions

View file

@ -5,4 +5,5 @@ Dockerfile
.git
.gitignore
build
dist
assets

32
.gitignore vendored
View file

@ -1,23 +1,13 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
# Local
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
*.local
*.log*
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Dist
node_modules
dist/
# IDE
.vscode/*
!.vscode/extensions.json
.idea

View file

@ -21,5 +21,5 @@ steps:
- /var/run/docker.sock:/var/run/docker.sock
commands:
- docker login forgejo.transprot.eu -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
- docker build -t 'forgejo.transprot.eu/public/react-nginx-alpine:latest' .
- docker push forgejo.transprot.eu/public/react-nginx-alpine:latest
- docker build -t 'forgejo.transprot.eu/public/react-bun-rspack:latest' .
- docker push forgejo.transprot.eu/public/react-bun-rspack:latest

View file

@ -1,13 +1,11 @@
# Build stage of the application
FROM node:18-alpine AS build
FROM oven/bun AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
RUN bun i && bun run build
# Production stage to run the application
FROM nginx:stable-alpine AS production
COPY --from=build /app/build /usr/share/nginx/html
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

131
README.md
View file

@ -52,6 +52,7 @@ docker image ls | from ssv | where repository starts-with 'react'
```
Here's the result of running this command that shows how shamefully big the image is:
![Size of the image](./assets/react-simple-size.png)
### First optimisation: using a .dockerignore file and multi-stage build
@ -97,12 +98,8 @@ You can run the following command to build the image:
docker build -t 'react-multistage' .
```
You can run the following command to verify that the new image size is smaller than the previous one:
```shell
docker image ls
```
I am still usig Nushell on my end to have a pretty print and filter on the images that I want which gives me the following output:
![Multistage image size](./assets/react-multistage-size.png)
The image now weighs `44 MB` less, which is 1.27 times smaller, and a whopping 21.67% reduction in size!
@ -135,12 +132,8 @@ You can rebuild the image by running the following command:
docker build -t 'react-multistage-alpine' .
```
You can also verify the image sizes by running the following command:
```shell
docker image ls
```
And as always, I'm using Nushell to have a prettier output, which gives me the following results which are incredibly impressive:
![Taille image node alpine](./assets/react-multistage-alpine-size.png)
A size reduction of `1.82 GB`, which is an image that is 9.8 smaller than the first one and is equivalent to a size reduction of 89.8% !!!!
@ -181,14 +174,10 @@ To run this image, you will need to run the following command:
docker run -d -p 80:80 --name react react-nginx
```
And you can also run the following command to check the size of the image:
```shell
docker image ls
```
But there's a tiny problem with this solution, this only optimizes the perfomance of the image but the size of the regular Nginx server is bigger than the Node Alpine version.
Here's an image showing the size of all the images so far:
![Nginx image size](./assets/react-nginx-size.png)
### Fourth optimization: The obvious, Nginx Alpine
@ -219,21 +208,49 @@ You can run the following build command to generate the image:
docker build -t 'react-nginx-alpine' .
```
To run this image, you will need to run the following command:
```shell
docker run -d -p 80:80 --name react react-nginx-alpine
```
And you can also run the following command to check the size of the image:
```shell
docker image ls
```
Here's an image showing the size of all the images so far:
![Nginx alpine image size](./assets/react-nginx-alpine-size.png)
The image now weighs 1 954,5 MB less, which is 26,88 times smaller, and a whopping 96,28% reduction in size!!!!! And with better perfomances of the server to top it off!!!
### Fifth optimization: Using a modern toolchain: RsBuild, Bun
The blank application generated by default using the command on their website uses WebPack under the hood to build the application.
[RsPack](https://rspack.dev/) is a Rust rewrite of WebPack, and [RsBuild](https://rsbuild.dev/index) is a build tool based on RsPack.
You can find how to generate a React application by [following this guide](https://rsbuild.dev/guide/framework/react).
For the sake of this demonstration, I decided to delete the whole default React app generated by the `create-react-app` and use the command in the guide I listed above.
[Bun](https://bun.sh/) is a fast JavaScript Runtime and [is faster than npm (and other package managers) to install dependencies](https://bun.sh/).
This is what the Dockerfile now looks like:
```Dockerfile
# Build stage of the application
FROM oven/bun AS build
WORKDIR /app
COPY . .
RUN bun i && bun run build
# Production stage to run the application
FROM nginx:stable-alpine AS production
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```
You can run the following command to build the image:
```sh
docker build -t 'react-bun-rspack' .
```
Here's an image showing the size of all the images so far:
![Rspack bun size](./assets/react-bun-rspack-size.png)
We even have a slight improvement in the final size, a whopping 1.2 MB less than the previous iteration, and a reduction of 1 955,7 MB of difference with the first image, which is 27.32 times smaller and a reduction of 96,33% in size!!!!!
But again, this optimization is mainly to speed up the package installation time and build time of the react application, which in turns speeds up the docker build.
# Français
@ -288,6 +305,7 @@ docker image ls | from ssv | where repository starts-with 'react'
```
Voici un aperçu de ce que cette commande m'affiche avec le poids de l'image assez désastreux:
![Taille de cette image](./assets/react-simple-size.png)
### Première optimisation: utilisation de .dockerignore et multi-stage
@ -333,12 +351,8 @@ Vous pouvez lancer la commande suivante pour construire l'image:
docker build -t 'react-multistage' .
```
Vous pouvez relancer la comande suivante pour vérifier que la taille a bien diminué cette fois-ci:
```shell
docker image ls
```
Pour ma part j'utilise toujours Nushell pour avoir cette belle présentation des résultats filtré:
![Taille de l'image multistage](./assets/react-multistage-size.png)
L'image pèse maintenant `44 MB` de moins, on a une image 1.27 fois plus petite, soit une diminution de la taille de 21.67% !
@ -371,12 +385,8 @@ Puis vous pouvez reconstruire l'image en lançant la commande suivante:
docker build -t 'react-multistage-alpine' .
```
Vous pouvez maintenant lancer la commande suivante vérifier la taille de votre image:
```shell
docker image ls
```
Et comme d'habitude, j'utilise Nushell pour avoir un meilleur rendu visuelle, et voici les résultats qui sont impréssionnants:
![Taille image node alpine](./assets/react-multistage-alpine-size.png)
On a une réduction de `1.82 GB`, soit une image 9.8 fois plus petite et une réduction de 89.8% !!!!
@ -416,14 +426,10 @@ Pour démarrer un conteneur, vous pouvez lancer la commande suivante:
docker run -d -p 80:80 --name react react-nginx
```
Vous pouvez également vérifier la taille de l'image en lançant cette commande:
```shell
docker image ls
```
Mais il y a un petit hic avec cette solution, l'image est plus performante mais plus volumineuse, étant donnée que l'image classique de Nginx est plus volumineuse que celle de Node Alpine.
Voici une image de la taille de nos images docker jusqu'à présent :
![Nginx image size](./assets/react-nginx-size.png)
### Quatrième optimisation: l'évident, Nginx Alpine
@ -454,17 +460,46 @@ Vous pouvez lancer la commande suivante pour construire l'image:
docker build -t 'react-nginx-alpine' .
```
Pour démarrer un conteneur, vous pouvez lancer la commande suivante:
```shell
docker run -d -p 80:80 --name react react-nginx-alpine
Voici une image de la taille de nos images docker jusqu'à présent:
![Nginx alpine image size](./assets/react-nginx-alpine-size.png)
L'image pèse 1 954,5 MB de moins que celle de départ, ce qui est 26,88 fois plus petit, et une énorme reduction 96,28% de la taille de l'image !!!!! Et pour couronner le tout, avec de meilleur performances !!!
### Cinquième optimisation: Utiliser une toolchain moderne: RsBuild, Bun
L'application blanche généré par défault via la commande donnée par le site de React officiel utilises WebPack pour construire l'application.
[RsPack](https://rspack.dev/) est une ré écriture en Rust de WebPack, et [RsBuild](https://rsbuild.dev/index) est une chaîne de build basé sur RsPack.
Vous pouvez trouver la commande pour générer une application React via en [suivant ce tutoriel](https://rsbuild.dev/guide/framework/react).
Pour cette démonstration, j'ai décidé de supprimer l'application blanche généré via la commande `create-react-app` et d'utiliser la commande du tutoriel juste au dessus pour regénérer une application avec RsBuild.
[Bun](https://bun.sh/) est un runtime performant et rapide de JavaScript et il [est plus rapide que npm (et d'autre package manager) pour installer des dependencies](https://bun.sh/).
Voici le Dockerfile à présent:
```Dockerfile
# Build stage of the application
FROM oven/bun AS build
WORKDIR /app
COPY . .
RUN bun i && bun run build
# Production stage to run the application
FROM nginx:stable-alpine AS production
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```
Vous pouvez également vérifier la taille de l'image en lançant cette commande:
```shell
docker image ls
Vous pouvez construire l'image avec la commande suivante :
```sh
docker build -t 'react-bun-rspack' .
```
Voici une image de la taille de nos images docker jusqu'à présent:
![Nginx alpine image size](./assets/react-nginx-alpine-size.png)
L'image pèse 1 954,5 MB de moins que celle de départ, ce qui est 26,88 fois plus petit, et une énorme reduction 96,28% de la taille de l'image !!!!! Et pour couronner le tout, avec de meilleur performances !!!
![Rspack bun size](./assets/react-bun-rspack-size.png)
On a même une taille plus réduite de l'image avec une amélioration drastique de l'image final qui pèse maintenant 1.2 MB de moins que l'image précédente, avec une différence de 1 955,7 MB par rapport à la première image, ce qui est 27.32 fois plus petit et une réduction de 96,33% de la taille !!!!!
Mais pour réitérer, le but de ces optimisations est d'installer les dépendances et de construire l'application React plus rapidement, ce qui réduit le temps de construction de l'image docker par conséquence.

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

17931
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,39 +1,21 @@
{
"name": "docker_react",
"version": "0.1.0",
"name": "docker_rspack",
"private": true,
"dependencies": {
"cra-template": "1.2.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-scripts": "5.0.1",
"serve": "^14.2.4"
},
"version": "1.0.0",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
"dev": "rsbuild dev --open",
"build": "rsbuild build",
"preview": "rsbuild preview"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"web-vitals": "^4.2.4"
"@rsbuild/core": "^1.1.8",
"@rsbuild/plugin-react": "^1.0.7",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"typescript": "^5.7.2"
}
}

0
public/.gitkeep Normal file
View file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -1,43 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View file

@ -1,25 +0,0 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View file

@ -1,3 +0,0 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

6
rsbuild.config.ts Normal file
View file

@ -0,0 +1,6 @@
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';
export default defineConfig({
plugins: [pluginReact()],
});

View file

@ -1,38 +1,26 @@
.App {
text-align: center;
body {
margin: 0;
color: #fff;
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
background-image: linear-gradient(to bottom, #020917, #101725);
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
.content {
display: flex;
min-height: 100vh;
line-height: 1.1;
text-align: center;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
.content h1 {
font-size: 3.6rem;
font-weight: 700;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
.content p {
font-size: 1.2rem;
font-weight: 400;
opacity: 0.5;
}

View file

@ -1,25 +0,0 @@
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;

View file

@ -1,8 +0,0 @@
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

12
src/App.tsx Normal file
View file

@ -0,0 +1,12 @@
import './App.css';
const App = () => {
return (
<div className="content">
<h1>Rsbuild with React</h1>
<p>Start building amazing things with Rsbuild.</p>
</div>
);
};
export default App;

1
src/env.d.ts vendored Normal file
View file

@ -0,0 +1 @@
/// <reference types="@rsbuild/core/types" />

View file

@ -1,13 +0,0 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

View file

@ -1,17 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

13
src/index.tsx Normal file
View file

@ -0,0 +1,13 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const rootEl = document.getElementById('root');
if (rootEl) {
const root = ReactDOM.createRoot(rootEl);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
}

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -1,13 +0,0 @@
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;

View file

@ -1,5 +0,0 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

23
tsconfig.json Normal file
View file

@ -0,0 +1,23 @@
{
"compilerOptions": {
"lib": ["DOM", "ES2020"],
"jsx": "react-jsx",
"target": "ES2020",
"noEmit": true,
"skipLibCheck": true,
"useDefineForClassFields": true,
/* modules */
"module": "ESNext",
"isolatedModules": true,
"resolveJsonModule": true,
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
/* type checking */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true
},
"include": ["src"]
}