Initial commit
This commit is contained in:
24
.dockerignore
Normal file
24
.dockerignore
Normal file
@@ -0,0 +1,24 @@
|
||||
# Ignore dependencies
|
||||
node_modules
|
||||
|
||||
# Ignore build output
|
||||
dist
|
||||
|
||||
# Ignore Git and VSCode configuration
|
||||
.git
|
||||
.vscode
|
||||
|
||||
# Ignore tests
|
||||
tests
|
||||
|
||||
# Ignore Docker files
|
||||
Dockerfile
|
||||
docker-compose.yml
|
||||
.dockerignore
|
||||
|
||||
# Ignore development-specific configuration
|
||||
.prettierignore
|
||||
cspell.json
|
||||
eslint.config.ts
|
||||
jest.config.js
|
||||
pnpm-workspace.yaml
|
||||
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Dependencies
|
||||
/node_modules
|
||||
|
||||
# Build output
|
||||
/dist
|
||||
/build
|
||||
|
||||
# Log files
|
||||
*.log
|
||||
|
||||
# Local environment variables
|
||||
.env*
|
||||
!.env.example
|
||||
|
||||
# OS-specific files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Test reports and coverage
|
||||
/coverage
|
||||
/jest-stare/
|
||||
1
.prettierignore
Normal file
1
.prettierignore
Normal file
@@ -0,0 +1 @@
|
||||
*.*
|
||||
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": [
|
||||
"source.fixAll.eslint"
|
||||
],
|
||||
"eslint.validate": ["javascript", "typescript"]
|
||||
}
|
||||
26
Dockerfile
Normal file
26
Dockerfile
Normal file
@@ -0,0 +1,26 @@
|
||||
# Use the official Node.js image.
|
||||
FROM node:22-slim
|
||||
|
||||
# Create and change to the app directory.
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Copy package.json and pnpm-lock.yaml
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
|
||||
# Install pnpm
|
||||
RUN npm install -g pnpm
|
||||
|
||||
# Install dependencies
|
||||
RUN pnpm install
|
||||
|
||||
# Copy the rest of the application's source code.
|
||||
COPY . .
|
||||
|
||||
# Build the project
|
||||
RUN pnpm run build
|
||||
|
||||
# Expose the port the app runs on
|
||||
EXPOSE 3000
|
||||
|
||||
# Serve the app
|
||||
CMD [ "pnpm", "start" ]
|
||||
308
README.md
Normal file
308
README.md
Normal file
@@ -0,0 +1,308 @@
|
||||
# Minimal Express.js Scaffolding
|
||||
|
||||
This project offers a streamlined and minimalistic scaffolding for Express.js applications. Unlike many generators that require extensive cleanup before you can begin, this boilerplate strikes a balance between simplicity and completeness. It provides just the essentials, allowing you to pull the repository, customize the project name, and start building your API immediately.
|
||||
|
||||
## Support the Project
|
||||
|
||||
If you find this project useful, consider supporting its development:
|
||||
|
||||
[![Donate using Liberapay][liberapay-logo]][liberapay-link]
|
||||
|
||||
[liberapay-logo]: https://liberapay.com/assets/widgets/donate.svg "Liberapay Logo"
|
||||
[liberapay-link]: https://liberapay.com/sfiorini/donate
|
||||
|
||||
## Installation
|
||||
|
||||
To install the project dependencies, run the following command:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
## Running the App
|
||||
|
||||
To run the application in development mode with live reloading, use:
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
To build and run the application for production, use:
|
||||
|
||||
```bash
|
||||
pnpm start
|
||||
```
|
||||
|
||||
## Customization
|
||||
|
||||
To rename the project, modify the `"name"` field in the `package.json` file.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "your-project-name"
|
||||
}
|
||||
```
|
||||
|
||||
## Technologies Used
|
||||
|
||||
* **Express:** Fast, unopinionated, minimalist web framework for Node.js.
|
||||
* **TypeScript:** Typed superset of JavaScript that compiles to plain JavaScript.
|
||||
* **Jest:** A delightful JavaScript Testing Framework with a focus on simplicity.
|
||||
* **Knip:** A tool to find unused files, dependencies, and exports in your JavaScript and TypeScript projects.
|
||||
* **ESLint:** A pluggable and configurable linter tool for identifying and reporting on patterns in JavaScript.
|
||||
* **Docker:** A platform for developing, shipping, and running applications in containers.
|
||||
* **tsx:** A CLI to seamlessly execute TypeScript and ESM.
|
||||
* **tsdown:** A tool for building TypeScript projects.
|
||||
|
||||
## Scripts
|
||||
|
||||
* `pnpm start`: Starts the production server after building the project.
|
||||
* `pnpm dev`: Runs the application in development mode with live reloading.
|
||||
* `pnpm build`: Builds the TypeScript project into JavaScript.
|
||||
* `pnpm test`: Runs the test suite using Jest and generates a coverage report.
|
||||
* `pnpm test:watch`: Runs the tests in watch mode, re-running them on file changes.
|
||||
* `pnpm knip`: Finds unused files, dependencies, and exports.
|
||||
* `pnpm lint`: Lints the codebase using ESLint and automatically fixes issues.
|
||||
|
||||
## Building This Scaffold From Scratch
|
||||
|
||||
Here is a detailed, step-by-step guide to creating this scaffold from the ground up.
|
||||
|
||||
### Requirements
|
||||
|
||||
* [Node.js](https://nodejs.org/)
|
||||
* [pnpm](https://pnpm.io/)
|
||||
|
||||
### Step-by-Step Guide
|
||||
|
||||
1. **Initialize the project:**
|
||||
|
||||
```bash
|
||||
pnpm init
|
||||
```
|
||||
|
||||
2. **Install Express:**
|
||||
|
||||
```bash
|
||||
pnpm install express
|
||||
```
|
||||
|
||||
3. **Set up TypeScript:**
|
||||
|
||||
```bash
|
||||
pnpm install --save-dev typescript @types/node @types/express
|
||||
npx tsc --init
|
||||
```
|
||||
|
||||
4. **Create the main application file:**
|
||||
Create a file at `src/index.ts`.
|
||||
|
||||
5. **Install `tsx` for development and `tsdown` for building:**
|
||||
|
||||
```bash
|
||||
pnpm install --save-dev tsx tsdown
|
||||
```
|
||||
|
||||
6. **Configure `tsdown`:**
|
||||
Create a `tsdown.config.ts` file:
|
||||
|
||||
```typescript
|
||||
import { defineConfig } from 'tsdown';
|
||||
|
||||
export default defineConfig({
|
||||
entry: 'src/index.ts',
|
||||
format: ["esm"],
|
||||
target: "ESNext",
|
||||
platform: "node"
|
||||
});
|
||||
```
|
||||
|
||||
7. **Configure `tsconfig.json`:**
|
||||
Modify your `tsconfig.json` to look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"baseUrl": "src",
|
||||
"paths": {
|
||||
"@*": ["*"]
|
||||
},
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
8. **Set up Jest for testing:**
|
||||
|
||||
```bash
|
||||
pnpm install --save-dev jest ts-jest @types/jest @types/supertest supertest
|
||||
npx ts-jest config:init
|
||||
```
|
||||
|
||||
This will create a `jest.config.js` file.
|
||||
|
||||
9. **Refactor the application for testability:**
|
||||
* Move all your Express app definition logic from `src/index.ts` into a new `src/server.ts` file.
|
||||
* The `src/index.ts` file should only contain the `server.listen()` part, which starts the server.
|
||||
* Create a `tests` folder and mirror the structure of your `src` folder for your test files.
|
||||
|
||||
10. **Install Knip to keep the project clean:**
|
||||
|
||||
```bash
|
||||
pnpm add -D knip
|
||||
```
|
||||
|
||||
11. **Set up ESLint for code linting:**
|
||||
|
||||
```bash
|
||||
pnpm add --save-dev eslint jiti @eslint/js typescript-eslint @stylistic/eslint-plugin eslint-plugin-n
|
||||
```
|
||||
|
||||
Create an `eslint.config.ts` file with the following settings (modify as needed):
|
||||
|
||||
```typescript
|
||||
import eslint from '@eslint/js';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import stylistic from '@stylistic/eslint-plugin';
|
||||
import nodePlugin from 'eslint-plugin-n';
|
||||
|
||||
export default tseslint.config(
|
||||
eslint.configs.recommended,
|
||||
nodePlugin.configs['flat/recommended-script'],
|
||||
...tseslint.configs.strictTypeChecked,
|
||||
...tseslint.configs.stylisticTypeChecked,
|
||||
{
|
||||
ignores: [
|
||||
'**/node_modules/*',
|
||||
'**/*.mjs',
|
||||
'**/*.js',
|
||||
],
|
||||
},
|
||||
{
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: './tsconfig.json',
|
||||
warnOnUnsupportedTypeScriptVersion: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
'@stylistic/js': stylistic,
|
||||
'@stylistic/ts': stylistic,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
},
|
||||
{
|
||||
rules: {
|
||||
'@typescript-eslint/explicit-member-accessibility': 'warn',
|
||||
'@typescript-eslint/no-misused-promises': 0,
|
||||
'@typescript-eslint/no-floating-promises': 0,
|
||||
'@typescript-eslint/no-confusing-void-expression': 0,
|
||||
'@typescript-eslint/no-unnecessary-condition': 0,
|
||||
'@typescript-eslint/restrict-template-expressions': [
|
||||
'error', { allowNumber: true },
|
||||
],
|
||||
'@typescript-eslint/restrict-plus-operands': [
|
||||
'warn', { allowNumberAndString: true },
|
||||
],
|
||||
'@typescript-eslint/no-unused-vars': 'warn',
|
||||
'@typescript-eslint/no-unsafe-enum-comparison': 0,
|
||||
'@typescript-eslint/no-unnecessary-type-parameters': 0,
|
||||
'@stylistic/js/no-extra-semi': 'warn',
|
||||
'max-len': [
|
||||
'warn',
|
||||
{
|
||||
'code': 80,
|
||||
},
|
||||
],
|
||||
'@stylistic/ts/semi': ['warn', 'always'],
|
||||
'@stylistic/ts/member-delimiter-style': ['warn', {
|
||||
'multiline': {
|
||||
'delimiter': 'comma',
|
||||
'requireLast': true,
|
||||
},
|
||||
'singleline': {
|
||||
'delimiter': 'comma',
|
||||
'requireLast': false,
|
||||
},
|
||||
'overrides': {
|
||||
'interface': {
|
||||
'singleline': {
|
||||
'delimiter': 'semi',
|
||||
'requireLast': false,
|
||||
},
|
||||
'multiline': {
|
||||
'delimiter': 'semi',
|
||||
'requireLast': true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}],
|
||||
'@typescript-eslint/no-non-null-assertion': 0,
|
||||
'@typescript-eslint/no-unused-expressions': 'warn',
|
||||
'comma-dangle': ['warn', 'always-multiline'],
|
||||
'no-console': 1,
|
||||
'no-extra-boolean-cast': 0,
|
||||
'indent': ['warn', 2],
|
||||
'quotes': ['warn', 'single'],
|
||||
'n/no-process-env': 1,
|
||||
'n/no-missing-import': 0,
|
||||
'n/no-unpublished-import': 0,
|
||||
'prefer-const': 'warn',
|
||||
},
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
12. **Set up Docker:**
|
||||
Create a `Dockerfile` file:
|
||||
|
||||
```text
|
||||
# Use the official Node.js image.
|
||||
FROM node:22-slim
|
||||
|
||||
# Create and change to the app directory.
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Copy package.json and pnpm-lock.yaml
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
|
||||
# Install pnpm
|
||||
RUN npm install -g pnpm
|
||||
|
||||
# Install dependencies
|
||||
RUN pnpm install
|
||||
|
||||
# Copy the rest of the application's source code.
|
||||
COPY . .
|
||||
|
||||
# Build the project
|
||||
RUN pnpm run build
|
||||
|
||||
# Expose the port the app runs on
|
||||
EXPOSE 3000
|
||||
|
||||
# Serve the app
|
||||
CMD [ "pnpm", "start" ]
|
||||
```
|
||||
|
||||
Create a `docker-compose.yml` file:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
exp-min:
|
||||
build: .
|
||||
container_name: "exp-min"
|
||||
ports:
|
||||
- "3000:3000"
|
||||
```
|
||||
9
cspell.json
Normal file
9
cspell.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"version": "0.2",
|
||||
"ignorePaths": ["src","dist", "node_modules", "coverage", "test", "tests", "package.json", "pnpm-lock.yaml", "pnpm-lock.yaml", "pnpm-lock.json", "pnpm-workspace.yaml", "cspell.json", "tsconfig.json", "tsconfig.build.json", "tsconfig.node.json", "tsconfig.test.json"],
|
||||
"dictionaryDefinitions": [],
|
||||
"dictionaries": [],
|
||||
"words": [],
|
||||
"ignoreWords": [],
|
||||
"import": []
|
||||
}
|
||||
6
docker-compose.yml
Normal file
6
docker-compose.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
services:
|
||||
exp-min:
|
||||
build: .
|
||||
container_name: "exp-min"
|
||||
ports:
|
||||
- "3000:3000"
|
||||
94
eslint.config.ts
Normal file
94
eslint.config.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import eslint from '@eslint/js';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import stylistic from '@stylistic/eslint-plugin';
|
||||
import nodePlugin from 'eslint-plugin-n';
|
||||
|
||||
export default tseslint.config(
|
||||
eslint.configs.recommended,
|
||||
nodePlugin.configs['flat/recommended-script'],
|
||||
...tseslint.configs.strictTypeChecked,
|
||||
...tseslint.configs.stylisticTypeChecked,
|
||||
{
|
||||
ignores: [
|
||||
'**/node_modules/*',
|
||||
'**/*.mjs',
|
||||
'**/*.js',
|
||||
],
|
||||
},
|
||||
{
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: './tsconfig.json',
|
||||
warnOnUnsupportedTypeScriptVersion: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
'@stylistic/js': stylistic,
|
||||
'@stylistic/ts': stylistic,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
},
|
||||
{
|
||||
rules: {
|
||||
'@typescript-eslint/explicit-member-accessibility': 'warn',
|
||||
'@typescript-eslint/no-misused-promises': 0,
|
||||
'@typescript-eslint/no-floating-promises': 0,
|
||||
'@typescript-eslint/no-confusing-void-expression': 0,
|
||||
'@typescript-eslint/no-unnecessary-condition': 0,
|
||||
'@typescript-eslint/restrict-template-expressions': [
|
||||
'error', { allowNumber: true },
|
||||
],
|
||||
'@typescript-eslint/restrict-plus-operands': [
|
||||
'warn', { allowNumberAndString: true },
|
||||
],
|
||||
'@typescript-eslint/no-unused-vars': 'warn',
|
||||
'@typescript-eslint/no-unsafe-enum-comparison': 0,
|
||||
'@typescript-eslint/no-unnecessary-type-parameters': 0,
|
||||
'@stylistic/js/no-extra-semi': 'warn',
|
||||
'max-len': [
|
||||
'warn',
|
||||
{
|
||||
'code': 80,
|
||||
},
|
||||
],
|
||||
'@stylistic/ts/semi': ['warn', 'always'],
|
||||
'@stylistic/ts/member-delimiter-style': ['warn', {
|
||||
'multiline': {
|
||||
'delimiter': 'comma',
|
||||
'requireLast': true,
|
||||
},
|
||||
'singleline': {
|
||||
'delimiter': 'comma',
|
||||
'requireLast': false,
|
||||
},
|
||||
'overrides': {
|
||||
'interface': {
|
||||
'singleline': {
|
||||
'delimiter': 'semi',
|
||||
'requireLast': false,
|
||||
},
|
||||
'multiline': {
|
||||
'delimiter': 'semi',
|
||||
'requireLast': true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}],
|
||||
'@typescript-eslint/no-non-null-assertion': 0,
|
||||
'@typescript-eslint/no-unused-expressions': 'warn',
|
||||
'comma-dangle': ['warn', 'always-multiline'],
|
||||
'no-console': 1,
|
||||
'no-extra-boolean-cast': 0,
|
||||
'indent': ['warn', 2],
|
||||
'quotes': ['warn', 'single'],
|
||||
'n/no-process-env': 1,
|
||||
'n/no-missing-import': 0,
|
||||
'n/no-unpublished-import': 0,
|
||||
'prefer-const': 'warn',
|
||||
},
|
||||
},
|
||||
);
|
||||
33
jest.config.js
Normal file
33
jest.config.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { createDefaultPreset } from "ts-jest";
|
||||
|
||||
const tsJestTransformCfg = createDefaultPreset().transform;
|
||||
|
||||
/** @type {import("jest").Config} **/
|
||||
export const testEnvironment = "node";
|
||||
export const transform = {
|
||||
...tsJestTransformCfg,
|
||||
'^.+\\.jsx?$': [
|
||||
'ts-jest',
|
||||
{
|
||||
tsconfig: {
|
||||
// Overrides the tsconfig.json module setting to allow for CommonJS modules in tests
|
||||
allowJs: true,
|
||||
},
|
||||
},
|
||||
]
|
||||
};
|
||||
export const moduleNameMapper = {
|
||||
// Handle module aliases
|
||||
'^@routers/(.*)$': '<rootDir>/src/routers/$1',
|
||||
}
|
||||
|
||||
export const coverageThreshold = {
|
||||
global: {
|
||||
branches: 80,
|
||||
functions: 80,
|
||||
lines: 80,
|
||||
statements: -10,
|
||||
},
|
||||
};
|
||||
|
||||
export const coverageReporters = ['text'];
|
||||
42
package.json
Normal file
42
package.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "exp-min",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node ./dist/index.mjs",
|
||||
"dev": "tsx --watch ./src/index.ts",
|
||||
"build": "tsdown",
|
||||
"prestart": "pnpm run build",
|
||||
"test": "jest --coverage",
|
||||
"test:watch": "jest --coverage --watchAll",
|
||||
"knip": "knip",
|
||||
"lint": "eslint --fix ."
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"packageManager": "pnpm@10.12.1",
|
||||
"dependencies": {
|
||||
"consola": "^3.4.2",
|
||||
"express": "^5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.29.0",
|
||||
"@stylistic/eslint-plugin": "^4.4.1",
|
||||
"@types/express": "^5.0.3",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/node": "^24.0.3",
|
||||
"@types/supertest": "^6.0.3",
|
||||
"eslint": "^9.29.0",
|
||||
"eslint-plugin-n": "^17.20.0",
|
||||
"jest": "^30.0.2",
|
||||
"knip": "^5.61.2",
|
||||
"supertest": "^7.1.1",
|
||||
"ts-jest": "^29.4.0",
|
||||
"tsdown": "^0.12.8",
|
||||
"tsx": "^4.20.3",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.34.1"
|
||||
}
|
||||
}
|
||||
5428
pnpm-lock.yaml
generated
Normal file
5428
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
3
pnpm-workspace.yaml
Normal file
3
pnpm-workspace.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
ignoredBuiltDependencies:
|
||||
- esbuild
|
||||
- unrs-resolver
|
||||
BIN
public/logo.png
Normal file
BIN
public/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 121 KiB |
13
src/index.ts
Normal file
13
src/index.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { consola } from 'consola';
|
||||
import server from './server';
|
||||
|
||||
const port = 3000;
|
||||
|
||||
// Start the server
|
||||
const httpServer = server.listen(port, () => {
|
||||
consola.info(`Example app listening on port ${port}`);
|
||||
});
|
||||
|
||||
httpServer.on('error', (err: Error) => {
|
||||
consola.error(err.message);
|
||||
});
|
||||
14
src/routers/firstRouter.ts
Normal file
14
src/routers/firstRouter.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Router, Request, Response } from 'express';
|
||||
const firstRouter: Router = Router();
|
||||
|
||||
firstRouter.get('/', (req: Request, res: Response) => {
|
||||
res.send('Hello from First Router root route');
|
||||
});
|
||||
|
||||
firstRouter.get('/somepath/:param', (req: Request, res: Response) => {
|
||||
res.send(
|
||||
'Hello from First Router somePath route with param: ' + req.params.param,
|
||||
);
|
||||
});
|
||||
|
||||
export default firstRouter;
|
||||
14
src/routers/secondRouter.ts
Normal file
14
src/routers/secondRouter.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Router, Request, Response } from 'express';
|
||||
const secondRouter: Router = Router();
|
||||
|
||||
secondRouter.get('/', (req: Request, res: Response) => {
|
||||
res.send('Hello from Second Router root route');
|
||||
});
|
||||
|
||||
secondRouter.get('/somepath/:param', (req: Request, res: Response) => {
|
||||
res.send(
|
||||
'Hello from Second Router somePath route with param: ' + req.params.param,
|
||||
);
|
||||
});
|
||||
|
||||
export default secondRouter;
|
||||
15
src/server.ts
Normal file
15
src/server.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import express, { Express, Request, Response } from 'express';
|
||||
import firstRouter from '@routers/firstRouter';
|
||||
import secondRouter from '@routers/secondRouter';
|
||||
|
||||
const app: Express = express();
|
||||
app.use(express.static('public'));
|
||||
|
||||
app.use('/firstroute', firstRouter);
|
||||
app.use('/secondroute', secondRouter);
|
||||
|
||||
app.get('/', (req: Request, res: Response) => {
|
||||
res.send('Application is running!');
|
||||
});
|
||||
|
||||
export default app;
|
||||
15
tests/routers/firstRouter.test.ts
Normal file
15
tests/routers/firstRouter.test.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import request from 'supertest';
|
||||
import server from '../../src/server';
|
||||
|
||||
it('should respond to /firstroute', async () => {
|
||||
const res = await request(server).get('/firstroute');
|
||||
expect(res.statusCode).toEqual(200);
|
||||
});
|
||||
|
||||
it('should respond to /firstroute/somepath/:para/', async () => {
|
||||
const res = await request(server).get('/firstroute/somepath/myparam');
|
||||
expect(res.statusCode).toEqual(200);
|
||||
expect(res.text).toEqual(
|
||||
'Hello from First Router somePath route with param: myparam',
|
||||
);
|
||||
});
|
||||
15
tests/routers/secondRouter.test.ts
Normal file
15
tests/routers/secondRouter.test.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import request from 'supertest';
|
||||
import server from '../../src/server';
|
||||
|
||||
it('should respond to /secondroute', async () => {
|
||||
const res = await request(server).get('/secondroute');
|
||||
expect(res.statusCode).toEqual(200);
|
||||
});
|
||||
|
||||
it('should respond to /secondroute/somepath/:para/', async () => {
|
||||
const res = await request(server).get('/secondroute/somepath/myparam');
|
||||
expect(res.statusCode).toEqual(200);
|
||||
expect(res.text).toEqual(
|
||||
'Hello from Second Router somePath route with param: myparam',
|
||||
);
|
||||
});
|
||||
10
tests/server.test.js
Normal file
10
tests/server.test.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import request from 'supertest'
|
||||
import app from '../src/server'
|
||||
|
||||
describe('Express App', () => {
|
||||
it('should respond with "Application is running!" at the root', async () => {
|
||||
const res = await request(app).get('/')
|
||||
expect(res.statusCode).toEqual(200)
|
||||
expect(res.text).toBe('Application is running!')
|
||||
})
|
||||
})
|
||||
15
tsconfig.json
Normal file
15
tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext", /* Specify what module code is generated. */
|
||||
"moduleResolution": "Bundler", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
"baseUrl": "src", /* Specify the base directory to resolve non-relative module names. */
|
||||
"paths": {
|
||||
"@*": ["*"]
|
||||
}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
||||
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
||||
8
tsdown.config.ts
Normal file
8
tsdown.config.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { defineConfig } from 'tsdown';
|
||||
|
||||
export default defineConfig({
|
||||
entry: 'src/index.ts',
|
||||
format: ['esm'],
|
||||
target: 'ESNext',
|
||||
platform: 'node',
|
||||
});
|
||||
Reference in New Issue
Block a user