From 664e6092b2f3bd448e0544c9aaad8c4429d45505 Mon Sep 17 00:00:00 2001 From: Maciek Sitkowski <58401630+sitek94@users.noreply.github.com> Date: Sun, 26 Nov 2023 21:03:56 +0100 Subject: [PATCH] use turborepo * rename types lib * init getting started section * setup turbo; make lint and build work * refresh remix on changes in ui lib * update docs * fix lint and typecheck commands across monorepo * fix tests * use turbo to run lint, typecheck, tests and build * fix ui lint * use turbo for building * remove not needed steps * fix docs deploy build dir path --- .eslintignore | 3 - .github/workflows/ci.yml | 39 +- .gitignore | 4 + .npmrc | 1 + .vscode/settings.json | 5 + README.md | 40 +- apps/docs/.eslintrc.cjs | 16 +- apps/docs/package.json | 4 +- apps/docs/tsconfig.json | 15 +- apps/docs/turbo.json | 8 + apps/nestjs/.eslintrc.js | 20 +- apps/nestjs/jest.config.js | 3 - apps/nestjs/package.json | 10 +- apps/nestjs/src/app.controller.spec.ts | 3 +- apps/nestjs/src/cats/cats.controller.spec.ts | 6 +- apps/nestjs/src/cats/cats.controller.ts | 4 +- apps/nestjs/src/cats/cats.service.spec.ts | 7 +- apps/nestjs/src/cats/cats.service.ts | 2 +- apps/nestjs/src/cats/schemas/cat.schema.ts | 4 +- apps/nestjs/src/config/app.config.ts | 2 +- apps/nestjs/src/dogs/dogs.controller.spec.ts | 3 +- apps/nestjs/src/dogs/dogs.controller.ts | 2 +- apps/nestjs/src/dogs/dogs.service.spec.ts | 3 +- apps/nestjs/src/dogs/dogs.service.ts | 2 +- apps/nestjs/src/main.ts | 9 +- apps/nestjs/test/dogs.e2e-spec.ts | 5 +- apps/nestjs/tsconfig.json | 17 +- apps/nestjs/turbo.json | 8 + apps/remix/.eslintrc.cjs | 9 +- apps/remix/app/api/cats.api.ts | 20 +- apps/remix/app/entry.server.tsx | 4 +- apps/remix/app/root.tsx | 4 +- apps/remix/app/routes/_index.tsx | 9 +- apps/remix/package.json | 15 +- apps/remix/remix.config.js | 5 +- apps/remix/tsconfig.json | 19 +- apps/remix/turbo.json | 8 + libs/eslint-config/_base.js | 44 ++ libs/eslint-config/base.js | 47 -- libs/eslint-config/library.js | 35 + libs/eslint-config/nest.js | 42 ++ libs/eslint-config/package.json | 10 +- libs/eslint-config/react.js | 46 +- libs/eslint-config/remix.js | 45 ++ libs/eslint-config/storybook.js | 45 ++ libs/tailwind-config/.eslintrc.js | 4 - libs/tailwind-config/package.json | 1 - libs/tsconfig/nest.json | 22 + libs/types/.eslintrc.js | 2 +- libs/types/index.ts | 4 +- libs/types/package.json | 8 +- libs/types/tsconfig.json | 10 + libs/ui/.eslintrc.js | 2 +- libs/ui/package.json | 10 +- libs/ui/src/components/button.tsx | 2 +- libs/ui/tsup.config.ts | 3 +- libs/ui/turbo.json | 8 + package.json | 46 +- pnpm-lock.yaml | 753 +++++++++++++++---- tsconfig.json | 18 +- turbo.json | 43 ++ 61 files changed, 1156 insertions(+), 432 deletions(-) delete mode 100644 .eslintignore create mode 100644 .npmrc create mode 100644 .vscode/settings.json create mode 100644 apps/docs/turbo.json create mode 100644 apps/nestjs/turbo.json create mode 100644 apps/remix/turbo.json create mode 100644 libs/eslint-config/_base.js delete mode 100644 libs/eslint-config/base.js create mode 100644 libs/eslint-config/library.js create mode 100644 libs/eslint-config/nest.js create mode 100644 libs/eslint-config/remix.js create mode 100644 libs/eslint-config/storybook.js delete mode 100644 libs/tailwind-config/.eslintrc.js create mode 100644 libs/tsconfig/nest.json create mode 100644 libs/types/tsconfig.json create mode 100644 libs/ui/turbo.json create mode 100644 turbo.json diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 0e796c3..0000000 --- a/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules -dist -build \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71a3b1d..999374a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,9 +58,6 @@ jobs: - name: 📥 Install Dependencies run: pnpm install - - name: 📦 Build libs - run: pnpm build:ui - - name: 🔬 Lint run: pnpm lint @@ -86,9 +83,6 @@ jobs: - name: 📥 Install Dependencies run: pnpm install - - name: 📦 Build libs - run: pnpm build:ui - - name: 🔎 Type check run: pnpm typecheck @@ -143,7 +137,7 @@ jobs: run: pnpm test:e2e build: - name: 🏗️ Build apps + name: 🏗️ Build needs: [changes] runs-on: ubuntu-latest steps: @@ -164,8 +158,14 @@ jobs: - name: 📥 Install Dependencies run: pnpm install - - name: 🏗️ Build apps - run: pnpm build:apps + - name: 🏗️ Build + run: pnpm build + + - uses: actions/upload-artifact@v3 + if: needs.changes.outputs.docs == 'true' + with: + name: docs-artifacts + path: ./apps/docs/build deploy-nestjs: name: 🐯 Deploy NestJS App @@ -217,26 +217,15 @@ jobs: with: fetch-depth: 0 - - name: Setup pnpm - uses: pnpm/action-setup@v2.4.0 + - name: Download docs artifacts + uses: actions/download-artifact@v3 with: - version: 8 - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: pnpm - - - name: 📥 Install Dependencies - run: pnpm install - - - name: 🏗️ Build - run: pnpm build:docs + name: docs-artifacts + path: ./build - name: 🚀 Deploy to Chromatic uses: chromaui/action@v1 with: token: ${{ secrets.GITHUB_TOKEN }} projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} - storybookBuildDir: ./apps/docs/build + storybookBuildDir: ./build diff --git a/.gitignore b/.gitignore index b7f5e56..8492f17 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,10 @@ node_modules dist build public/build +.next + +## Monorepo +.turbo # Environment variables .env diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..ded82e2 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +auto-install-peers = true diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3046ad5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "turbo.json": "jsonc" + } +} diff --git a/README.md b/README.md index 33d285c..c6ae2d3 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,11 @@ - [x] build and deploy Storybook - [x] set unified path aliases for all apps and shared libs (done for `apps/`, because `libs/` probably don't need them anyway) - [x] add unused imports plugin to eslint -- [ ] research if it's worth using `turbo` - probably yes, to make it easier to run tasks that depend on each other +- [x] research if it's worth using `turbo` - probably yes, to make it easier to run tasks that depend on each other +- [ ] use turbo repo and ensure the following works + - [x] lint, test, build, develop + - [ ] gh actions + - [ ] deployment - [ ] create diagram - [ ] setup renovate @@ -31,6 +35,37 @@ | Remix | https://pnpm-monorepo-remix.fly.dev/ | | Docs (Storybook) | https://6562c63f0bbf6184dd3b3f1e-aulbjawzef.chromatic.com | +## Getting started + +### Pre-requisites + +- [pnpm](https://pnpm.io/installation) +- [Docker](https://docs.docker.com/get-docker/) + +### Install dependencies + +```sh +pnpm install +``` + +### Database + +```sh +docker compose up mongo +``` + +### Run NestJS app + +```sh +pnpm develop:nestjs +``` + +### Run Remix app + +```sh +pnpm develop:remix +``` + ## References - https://pnpm.io/next/filtering @@ -41,4 +76,5 @@ - https://github.com/vercel/turbo/tree/main/examples - turbo repo examples - https://github.com/storybookjs/storybook - https://storybook.js.org/tutorials/design-systems-for-developers/react/en/architecture/ -- +- https://turbo.build/repo/docs/getting-started/existing-monorepo +- https://github.com/vercel/style-guide/tree/canary diff --git a/apps/docs/.eslintrc.cjs b/apps/docs/.eslintrc.cjs index ce42dfb..fc05cfd 100644 --- a/apps/docs/.eslintrc.cjs +++ b/apps/docs/.eslintrc.cjs @@ -1,18 +1,4 @@ /** @type {import("eslint").Linter.Config} */ module.exports = { - extends: [ - '@repo/eslint-config/base', - '@repo/eslint-config/react', - 'plugin:storybook/recommended', - ], - overrides: [ - { - files: ['*.stories.tsx'], - rules: { - // For some reason it shows errors for imports from @repo/ui, even though they are resolved correctly. - // Both develop and build work fine, so I'm disabling it for now. - 'import/no-unresolved': 'off', - }, - }, - ], + extends: ['@repo/eslint-config/storybook'], } diff --git a/apps/docs/package.json b/apps/docs/package.json index 6f5e791..30fdb44 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -6,7 +6,9 @@ "build": "storybook build -o build", "start": "serve build", "clean": "rm -rf .turbo && rm -rf node_modules", - "lint": "eslint ./stories/*.stories.tsx --max-warnings 0" + "lint": "eslint .", + "lint:fix": "pnpm lint --fix", + "typecheck": "tsc --noEmit" }, "dependencies": { "@repo/ui": "workspace:*", diff --git a/apps/docs/tsconfig.json b/apps/docs/tsconfig.json index 8aa7634..1fdb38f 100644 --- a/apps/docs/tsconfig.json +++ b/apps/docs/tsconfig.json @@ -1,18 +1,5 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "allowJs": true, - "declaration": false, - "declarationMap": false, - "incremental": true, - "jsx": "preserve", - "lib": ["dom", "dom.iterable", "esnext"], - "module": "esnext", - "noEmit": true, - "resolveJsonModule": true, - "target": "es5", - "skipLibCheck": true - }, + "extends": "@repo/tsconfig/react-app.json", "include": ["."], "exclude": ["dist", "build", "node_modules"] } diff --git a/apps/docs/turbo.json b/apps/docs/turbo.json new file mode 100644 index 0000000..de2bc75 --- /dev/null +++ b/apps/docs/turbo.json @@ -0,0 +1,8 @@ +{ + "extends": ["//"], + "pipeline": { + "build": { + "outputs": ["build/**"] + } + } +} diff --git a/apps/nestjs/.eslintrc.js b/apps/nestjs/.eslintrc.js index d4b6c59..9088bcf 100644 --- a/apps/nestjs/.eslintrc.js +++ b/apps/nestjs/.eslintrc.js @@ -1,22 +1,4 @@ /** @type {import('eslint').Linter.Config} */ module.exports = { - extends: ['@repo/eslint-config/base'], - env: { - node: true, - }, - settings: { - 'import/resolver': { - typescript: { - project: 'apps/nestjs/tsconfig.json', - }, - }, - }, - overrides: [ - { - files: ['jest.config.js', 'jest-e2e.config.js'], - rules: { - '@typescript-eslint/no-var-requires': 'off', - }, - }, - ], + extends: ['@repo/eslint-config/nest'], } diff --git a/apps/nestjs/jest.config.js b/apps/nestjs/jest.config.js index 1df1ad6..ef0a05f 100644 --- a/apps/nestjs/jest.config.js +++ b/apps/nestjs/jest.config.js @@ -11,9 +11,6 @@ module.exports = { testEnvironment: 'node', rootDir: './src', testRegex: '.*\\.spec\\.ts$', - transform: { - '^.+\\.(t|j)s$': 'ts-jest', - }, collectCoverageFrom: ['**/*.(t|j)s'], coverageDirectory: './coverage', } diff --git a/apps/nestjs/package.json b/apps/nestjs/package.json index a2b1411..3349404 100644 --- a/apps/nestjs/package.json +++ b/apps/nestjs/package.json @@ -5,12 +5,15 @@ "build": "nest build", "develop": "nest start --watch", "develop:debug": "nest start --debug --watch", + "lint": "eslint .", + "lint:fix": "pnpm lint --fix", "start": "node build/main", "test": "jest", "test:watch": "jest --watch", "test:cov": "jest --coverage", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", - "test:e2e": "jest --config ./test/jest-e2e.config.js" + "test:e2e": "jest --config ./test/jest-e2e.config.js", + "typecheck": "tsc --noEmit" }, "dependencies": { "@nestjs/common": "^10.0.0", @@ -23,11 +26,12 @@ "rxjs": "^7.8.1" }, "devDependencies": { - "@repo/eslint-config": "workspace:*", - "@company/types": "workspace:*", "@nestjs/cli": "^10.0.0", "@nestjs/schematics": "^10.0.0", "@nestjs/testing": "^10.0.0", + "@repo/eslint-config": "workspace:*", + "@repo/tsconfig": "workspace:^", + "@repo/types": "workspace:*", "@types/express": "^4.17.17", "@types/jest": "^29.5.2", "@types/node": "^20.3.1", diff --git a/apps/nestjs/src/app.controller.spec.ts b/apps/nestjs/src/app.controller.spec.ts index 9dc5096..ae0ea53 100644 --- a/apps/nestjs/src/app.controller.spec.ts +++ b/apps/nestjs/src/app.controller.spec.ts @@ -1,4 +1,5 @@ -import { Test, TestingModule } from '@nestjs/testing' +import type { TestingModule } from '@nestjs/testing' +import { Test } from '@nestjs/testing' import { AppController } from './app.controller' import { AppService } from './app.service' diff --git a/apps/nestjs/src/cats/cats.controller.spec.ts b/apps/nestjs/src/cats/cats.controller.spec.ts index 7d72301..a2ef015 100644 --- a/apps/nestjs/src/cats/cats.controller.spec.ts +++ b/apps/nestjs/src/cats/cats.controller.spec.ts @@ -1,8 +1,9 @@ -import { Test, TestingModule } from '@nestjs/testing' +import type { TestingModule } from '@nestjs/testing' +import { Test } from '@nestjs/testing' import { CatsController } from './cats.controller' import { CatsService } from './cats.service' -import { CreateCatDto } from './dto/create-cat.dto' +import type { CreateCatDto } from './dto/create-cat.dto' describe('Cats Controller', () => { let controller: CatsController @@ -84,6 +85,7 @@ describe('Cats Controller', () => { age: 2, }, ]) + expect(service.findAll).toHaveBeenCalled() }) }) diff --git a/apps/nestjs/src/cats/cats.controller.ts b/apps/nestjs/src/cats/cats.controller.ts index 4e76bad..fefde95 100644 --- a/apps/nestjs/src/cats/cats.controller.ts +++ b/apps/nestjs/src/cats/cats.controller.ts @@ -2,7 +2,7 @@ import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common' import { CatsService } from './cats.service' import { CreateCatDto } from './dto/create-cat.dto' -import { Cat } from './schemas/cat.schema' +import type { Cat } from './schemas/cat.schema' @Controller('cats') export class CatsController { @@ -25,8 +25,6 @@ export class CatsController { @Delete(':id') async delete(@Param('id') id: string) { - console.log('id', id) - return this.catsService.delete(id) } } diff --git a/apps/nestjs/src/cats/cats.service.spec.ts b/apps/nestjs/src/cats/cats.service.spec.ts index 0158fe3..7e13ee9 100644 --- a/apps/nestjs/src/cats/cats.service.spec.ts +++ b/apps/nestjs/src/cats/cats.service.spec.ts @@ -1,9 +1,10 @@ import { getModelToken } from '@nestjs/mongoose' -import { Test, TestingModule } from '@nestjs/testing' -import { Model } from 'mongoose' +import type { TestingModule } from '@nestjs/testing'; +import { Test } from '@nestjs/testing' +import type { Model } from 'mongoose' import { CatsService } from './cats.service' -import { Cat } from './schemas/cat.schema' +import type { Cat } from './schemas/cat.schema' const mockCat = { name: 'Cat #1', diff --git a/apps/nestjs/src/cats/cats.service.ts b/apps/nestjs/src/cats/cats.service.ts index 55591e8..9425b65 100644 --- a/apps/nestjs/src/cats/cats.service.ts +++ b/apps/nestjs/src/cats/cats.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common' import { InjectModel } from '@nestjs/mongoose' import { Model } from 'mongoose' -import { CreateCatDto } from './dto/create-cat.dto' +import type { CreateCatDto } from './dto/create-cat.dto' import { Cat } from './schemas/cat.schema' @Injectable() diff --git a/apps/nestjs/src/cats/schemas/cat.schema.ts b/apps/nestjs/src/cats/schemas/cat.schema.ts index 019a4f5..3b8e4e0 100644 --- a/apps/nestjs/src/cats/schemas/cat.schema.ts +++ b/apps/nestjs/src/cats/schemas/cat.schema.ts @@ -1,6 +1,6 @@ -import type { Cat as CatInterface } from '@company/types' import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose' -import { HydratedDocument } from 'mongoose' +import type { Cat as CatInterface } from '@repo/types' +import type { HydratedDocument } from 'mongoose' export type CatDocument = HydratedDocument diff --git a/apps/nestjs/src/config/app.config.ts b/apps/nestjs/src/config/app.config.ts index 5dcc704..e85f890 100644 --- a/apps/nestjs/src/config/app.config.ts +++ b/apps/nestjs/src/config/app.config.ts @@ -1,6 +1,6 @@ import { registerAs } from '@nestjs/config' -export type AppConfig = { +export interface AppConfig { env: 'development' | 'production' | 'test' port: number } diff --git a/apps/nestjs/src/dogs/dogs.controller.spec.ts b/apps/nestjs/src/dogs/dogs.controller.spec.ts index e20b0e1..17760da 100644 --- a/apps/nestjs/src/dogs/dogs.controller.spec.ts +++ b/apps/nestjs/src/dogs/dogs.controller.spec.ts @@ -1,4 +1,5 @@ -import { Test, TestingModule } from '@nestjs/testing' +import type { TestingModule } from '@nestjs/testing'; +import { Test } from '@nestjs/testing' import { DogsController } from './dogs.controller' import { DogsService } from './dogs.service' diff --git a/apps/nestjs/src/dogs/dogs.controller.ts b/apps/nestjs/src/dogs/dogs.controller.ts index 72aadde..4c4a2e6 100644 --- a/apps/nestjs/src/dogs/dogs.controller.ts +++ b/apps/nestjs/src/dogs/dogs.controller.ts @@ -1,5 +1,5 @@ -import { Dog } from '@company/types' import { Controller, Get } from '@nestjs/common' +import type { Dog } from '@repo/types' import { DogsService } from './dogs.service' diff --git a/apps/nestjs/src/dogs/dogs.service.spec.ts b/apps/nestjs/src/dogs/dogs.service.spec.ts index 4227523..6f3ea2e 100644 --- a/apps/nestjs/src/dogs/dogs.service.spec.ts +++ b/apps/nestjs/src/dogs/dogs.service.spec.ts @@ -1,4 +1,5 @@ -import { Test, TestingModule } from '@nestjs/testing' +import type { TestingModule } from '@nestjs/testing'; +import { Test } from '@nestjs/testing' import { DogsService } from './dogs.service' diff --git a/apps/nestjs/src/dogs/dogs.service.ts b/apps/nestjs/src/dogs/dogs.service.ts index e498d3d..35c675f 100644 --- a/apps/nestjs/src/dogs/dogs.service.ts +++ b/apps/nestjs/src/dogs/dogs.service.ts @@ -1,5 +1,5 @@ -import { Dog } from '@company/types' import { Injectable } from '@nestjs/common' +import type { Dog } from '@repo/types' @Injectable() export class DogsService { diff --git a/apps/nestjs/src/main.ts b/apps/nestjs/src/main.ts index 9ddf551..2c4f809 100644 --- a/apps/nestjs/src/main.ts +++ b/apps/nestjs/src/main.ts @@ -8,12 +8,15 @@ async function bootstrap() { const logger = new Logger('NestApplication') const app = await NestFactory.create(AppModule) const configService = app.get(ConfigService) - const port = configService.get('app.port') - const host = configService.get('app.host') + const port = configService.get('app.port') + const host = configService.get('app.host') await app.listen(port, host) logger.log(`Nest application running on port ${port}`) } -bootstrap() +bootstrap().catch(error => { + console.error(error) + process.exit(1) +}) diff --git a/apps/nestjs/test/dogs.e2e-spec.ts b/apps/nestjs/test/dogs.e2e-spec.ts index 0ef757a..c94579f 100644 --- a/apps/nestjs/test/dogs.e2e-spec.ts +++ b/apps/nestjs/test/dogs.e2e-spec.ts @@ -1,5 +1,6 @@ -import { INestApplication } from '@nestjs/common' -import { Test, TestingModule } from '@nestjs/testing' +import type { INestApplication } from '@nestjs/common' +import type { TestingModule } from '@nestjs/testing'; +import { Test } from '@nestjs/testing' import request from 'supertest' import { DogsModule } from '~/dogs/dogs.module' diff --git a/apps/nestjs/tsconfig.json b/apps/nestjs/tsconfig.json index 7b3cb3e..3f3e327 100644 --- a/apps/nestjs/tsconfig.json +++ b/apps/nestjs/tsconfig.json @@ -1,21 +1,8 @@ { - "extends": "../../tsconfig.json", + "extends": "@repo/tsconfig/nest.json", "include": ["**/*.ts", "jest.config.js"], + "exclude": ["node_modules", "build"], "compilerOptions": { - "module": "commonjs", - "declaration": true, - "removeComments": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "outDir": "./build", - "incremental": true, - "strictNullChecks": false, - "noImplicitAny": false, - "strictBindCallApply": false, - "noFallthroughCasesInSwitch": false, - "resolveJsonModule": true, "baseUrl": "./", "paths": { "~/*": ["./src/*"] diff --git a/apps/nestjs/turbo.json b/apps/nestjs/turbo.json new file mode 100644 index 0000000..de2bc75 --- /dev/null +++ b/apps/nestjs/turbo.json @@ -0,0 +1,8 @@ +{ + "extends": ["//"], + "pipeline": { + "build": { + "outputs": ["build/**"] + } + } +} diff --git a/apps/remix/.eslintrc.cjs b/apps/remix/.eslintrc.cjs index 7c55da7..1ed3a25 100644 --- a/apps/remix/.eslintrc.cjs +++ b/apps/remix/.eslintrc.cjs @@ -1,11 +1,4 @@ /** @type {import('eslint').Linter.Config} */ module.exports = { - extends: ['@repo/eslint-config/base', '@repo/eslint-config/react'], - settings: { - 'import/resolver': { - typescript: { - project: 'apps/remix/tsconfig.json', - }, - }, - }, + extends: ['@repo/eslint-config/remix'], } diff --git a/apps/remix/app/api/cats.api.ts b/apps/remix/app/api/cats.api.ts index 72b5394..dc01aed 100644 --- a/apps/remix/app/api/cats.api.ts +++ b/apps/remix/app/api/cats.api.ts @@ -1,10 +1,16 @@ -import type { Cat } from '@company/types' -import axios from 'axios' +import type { Cat } from '@repo/types' -const client = axios.create({ - baseURL: process.env.API_URL || 'http://localhost:2222', -}) +const BASE_URL = process.env.API_URL || 'http://localhost:2222' -export const catsApi = { - getAll: () => client.get('/cats'), +interface CatsApi { + getAll: () => Promise +} + +export const catsApi: CatsApi = { + getAll: async () => { + const response = await fetch(`${BASE_URL}/cats`) + const data: unknown = await response.json() + + return data as Cat[] + }, } diff --git a/apps/remix/app/entry.server.tsx b/apps/remix/app/entry.server.tsx index 8de0944..a3e2a72 100644 --- a/apps/remix/app/entry.server.tsx +++ b/apps/remix/app/entry.server.tsx @@ -45,9 +45,9 @@ function handleBotRequest( let shellRendered = false const { pipe, abort } = renderToPipeableStream( , { onAllReady() { @@ -95,9 +95,9 @@ function handleBrowserRequest( let shellRendered = false const { pipe, abort } = renderToPipeableStream( , { onShellReady() { diff --git a/apps/remix/app/root.tsx b/apps/remix/app/root.tsx index 2666799..040729f 100644 --- a/apps/remix/app/root.tsx +++ b/apps/remix/app/root.tsx @@ -20,10 +20,10 @@ export const links: LinksFunction = () => [ export default function App() { return ( - + - + diff --git a/apps/remix/app/routes/_index.tsx b/apps/remix/app/routes/_index.tsx index 4c62c9b..5d67271 100644 --- a/apps/remix/app/routes/_index.tsx +++ b/apps/remix/app/routes/_index.tsx @@ -1,7 +1,6 @@ import { json, type MetaFunction } from '@remix-run/node' import { useLoaderData } from '@remix-run/react' -import { Button } from '@repo/ui' -import { Card } from '@repo/ui/components/card' +import { Button, Card } from '@repo/ui' import { catsApi } from '~/api/cats.api' @@ -14,9 +13,9 @@ export const meta: MetaFunction = () => { export const loader = async () => { try { - const { data: cats } = await catsApi.getAll() + const cats = await catsApi.getAll() return json({ cats }) - } catch (error) { + } catch (error: any) { console.log(`Error fetching cats: ${error}`) return json({ cats: [] }) } @@ -32,7 +31,7 @@ export default function Index() {

Cats fetched from NestJS

{JSON.stringify(cats, null, 2)}
- + Imported from internal @repo/ui package diff --git a/apps/remix/package.json b/apps/remix/package.json index 9f97194..2f81059 100644 --- a/apps/remix/package.json +++ b/apps/remix/package.json @@ -6,25 +6,28 @@ "scripts": { "build": "remix build", "develop": "remix dev --manual", - "start": "remix-serve ./build/index.js" + "start": "remix-serve ./build/index.js", + "lint": "eslint . ", + "lint:fix": "pnpm lint --fix", + "typecheck": "tsc --noEmit" }, "dependencies": { "@remix-run/css-bundle": "^2.3.1", "@remix-run/node": "^2.3.1", "@remix-run/react": "^2.3.1", "@remix-run/serve": "^2.3.1", - "@repo/ui": "workspace:^", - "axios": "^1.6.2", + "@repo/ui": "workspace:*", "isbot": "^3.6.8", "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { - "@repo/eslint-config": "workspace:*", - "@company/types": "workspace:*", "@remix-run/dev": "^2.3.1", "@remix-run/eslint-config": "^2.3.1", - "@repo/tailwind-config": "workspace:^", + "@repo/eslint-config": "workspace:*", + "@repo/tailwind-config": "workspace:*", + "@repo/tsconfig": "workspace:^", + "@repo/types": "workspace:*", "@tailwindcss/aspect-ratio": "^0.4.2", "@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/forms": "^0.5.7", diff --git a/apps/remix/remix.config.js b/apps/remix/remix.config.js index f76e073..62bc6f8 100644 --- a/apps/remix/remix.config.js +++ b/apps/remix/remix.config.js @@ -2,8 +2,7 @@ export default { ignoredRouteFiles: ['**/.*'], - // Bundle UI lib, so that it's not necessary to include build step within the lib itself. - // serverDependenciesToBundle: ['@repo/ui'], - // Restart server when UI lib changes + // Restart server when UI lib changes as described in this discussion: + // https://github.com/remix-run/remix/pull/3188 watchPaths: ['../../libs/ui/**/*'], } diff --git a/apps/remix/tsconfig.json b/apps/remix/tsconfig.json index aff1fc3..8c4cebc 100644 --- a/apps/remix/tsconfig.json +++ b/apps/remix/tsconfig.json @@ -1,20 +1,11 @@ { - "extends": "../../tsconfig.json", + "extends": "@repo/tsconfig/remix.json", + "exclude": ["node_modules", "build"], "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], "compilerOptions": { - "lib": ["dom", "dom.iterable", "esnext"], - "isolatedModules": true, - "jsx": "react-jsx", - "moduleResolution": "Bundler", - "resolveJsonModule": true, - "skipLibCheck": true, - "baseUrl": "./", + "baseUrl": ".", "paths": { "~/*": ["./app/*"] - }, - - // Remix takes care of building everything in `remix build`. - "noEmit": true - }, - "exclude": ["node_modules", "build", "dist"] + } + } } diff --git a/apps/remix/turbo.json b/apps/remix/turbo.json new file mode 100644 index 0000000..f449b51 --- /dev/null +++ b/apps/remix/turbo.json @@ -0,0 +1,8 @@ +{ + "extends": ["//"], + "pipeline": { + "build": { + "outputs": ["build/**", "public/build/**"] + } + } +} diff --git a/libs/eslint-config/_base.js b/libs/eslint-config/_base.js new file mode 100644 index 0000000..a771162 --- /dev/null +++ b/libs/eslint-config/_base.js @@ -0,0 +1,44 @@ +/** @type {import('eslint').Linter.Config} */ +module.exports = { + ignorePatterns: [ + 'node_modules/', + 'dist/', + 'build/', + 'public/build/', + '.eslintrc.js', + '**/*.css', + ], + rules: { + 'import/order': [ + 'error', + { + alphabetize: { caseInsensitive: true, order: 'asc' }, + groups: ['builtin', 'external', 'internal', 'parent', 'sibling'], + 'newlines-between': 'always', + }, + ], + 'import/no-default-export': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + + // ⚠️ + // Following rules are disabled during setup, but should probably be enabled later: + + // Errors as unknown, etc. + 'no-console': 'off', + '@typescript-eslint/no-explicit-any': 'off', + + // Some weird type issues when calling `catsApi` in Remix index route + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + + '@typescript-eslint/require-await': 'off', + '@typescript-eslint/no-unnecessary-condition': 'off', + '@typescript-eslint/no-extraneous-class': 'off', + '@typescript-eslint/unbound-method': 'off', + '@typescript-eslint/consistent-type-imports': 'off', + '@typescript-eslint/no-floating-promises': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + }, +} diff --git a/libs/eslint-config/base.js b/libs/eslint-config/base.js deleted file mode 100644 index 22a7f80..0000000 --- a/libs/eslint-config/base.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * References: - * https://github.com/remix-run/indie-stack/blob/main/.eslintrc.js - */ - -/** @type {import('eslint').Linter.Config} */ -module.exports = { - root: true, - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint', 'import', 'unused-imports'], - extends: [ - 'plugin:@typescript-eslint/recommended', - 'plugin:import/recommended', - 'plugin:import/typescript', - 'plugin:prettier/recommended', - ], - settings: { - 'import/parsers': { - '@typescript-eslint/parser': ['.ts', '.tsx'], - }, - 'import/internal-regex': '^~/', - }, - rules: { - 'import/order': [ - 'error', - { - alphabetize: { caseInsensitive: true, order: 'asc' }, - groups: ['builtin', 'external', 'internal', 'parent', 'sibling'], - 'newlines-between': 'always', - }, - ], - '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], - }, - - overrides: [ - // Jest/Vitest Testing - { - files: ['**/*.{spec,test}.{js,jsx,ts,tsx}'], - env: { - jest: true, - }, - rules: { - '@typescript-eslint/no-explicit-any': 'off', - }, - }, - ], -} diff --git a/libs/eslint-config/library.js b/libs/eslint-config/library.js new file mode 100644 index 0000000..2da8d6a --- /dev/null +++ b/libs/eslint-config/library.js @@ -0,0 +1,35 @@ +const { resolve } = require('node:path') + +const project = resolve(process.cwd(), 'tsconfig.json') + +/* + * This is a custom ESLint configuration for use with + * typescript packages. + * + * This config extends the Vercel Engineering Style Guide. + * For more information, see https://github.com/vercel/style-guide + * + */ + +module.exports = { + extends: [ + '@vercel/style-guide/eslint/node', + '@vercel/style-guide/eslint/typescript', + './_base', + ].map(require.resolve), + parserOptions: { + project, + }, + plugins: ['only-warn'], + globals: { + React: true, + JSX: true, + }, + settings: { + 'import/resolver': { + typescript: { + project, + }, + }, + }, +} diff --git a/libs/eslint-config/nest.js b/libs/eslint-config/nest.js new file mode 100644 index 0000000..9947695 --- /dev/null +++ b/libs/eslint-config/nest.js @@ -0,0 +1,42 @@ +const { resolve } = require('node:path') + +const project = resolve(process.cwd(), 'tsconfig.json') + +/* + * This is a custom ESLint configuration for use with NestJS apps. + * + * This config extends the Vercel Engineering Style Guide. + * For more information, see https://github.com/vercel/style-guide + */ + +/** @type {import('eslint').Linter.Config} */ +module.exports = { + extends: [ + '@vercel/style-guide/eslint/node', + '@vercel/style-guide/eslint/typescript', + './_base', + ].map(require.resolve), + parserOptions: { + project, + }, + env: { + node: true, + es6: true, + }, + settings: { + 'import/resolver': { + typescript: { + project, + }, + }, + }, + overrides: [ + // Jest configs + { + files: ['jest.config.js', 'jest-e2e.config.js'], + rules: { + '@typescript-eslint/no-var-requires': 'off', + }, + }, + ], +} diff --git a/libs/eslint-config/package.json b/libs/eslint-config/package.json index 677f9c9..eb57e9f 100644 --- a/libs/eslint-config/package.json +++ b/libs/eslint-config/package.json @@ -1,7 +1,9 @@ { "name": "@repo/eslint-config", - "files": [ - "base.js", - "react.js" - ] + "devDependencies": { + "@vercel/style-guide": "^5.1.0", + "eslint-config-turbo": "^1.10.16", + "eslint-plugin-only-warn": "^1.1.0", + "eslint-plugin-storybook": "^0.6.15" + } } diff --git a/libs/eslint-config/react.js b/libs/eslint-config/react.js index 075eefa..fc684f9 100644 --- a/libs/eslint-config/react.js +++ b/libs/eslint-config/react.js @@ -1,23 +1,39 @@ -/** @type {import('eslint').Linter.Config} */ +const { resolve } = require('node:path') + +const project = resolve(process.cwd(), 'tsconfig.json') + +/* + * This is a custom ESLint configuration for use a library + * that utilizes React. + * + * This config extends the Vercel Engineering Style Guide. + * For more information, see https://github.com/vercel/style-guide + * + */ + module.exports = { - plugins: ['react', 'jsx-a11y'], extends: [ - 'plugin:react/recommended', - 'plugin:react/jsx-runtime', - 'plugin:react-hooks/recommended', - 'plugin:jsx-a11y/recommended', - ], + '@vercel/style-guide/eslint/browser', + '@vercel/style-guide/eslint/typescript', + '@vercel/style-guide/eslint/react', + './_base', + ].map(require.resolve), + parserOptions: { + project, + }, + plugins: ['only-warn'], + globals: { + JSX: true, + }, settings: { - react: { - version: 'detect', + 'import/resolver': { + typescript: { + project, + }, }, - formComponents: ['Form'], - linkComponents: [ - { name: 'Link', linkAttribute: 'to' }, - { name: 'NavLink', linkAttribute: 'to' }, - ], }, + // add rules configurations here rules: { - 'react/jsx-no-leaked-render': ['warn', { validStrategies: ['ternary'] }], + 'import/no-default-export': 'off', }, } diff --git a/libs/eslint-config/remix.js b/libs/eslint-config/remix.js new file mode 100644 index 0000000..ad32c50 --- /dev/null +++ b/libs/eslint-config/remix.js @@ -0,0 +1,45 @@ +const { resolve } = require('node:path') + +const project = resolve(process.cwd(), 'tsconfig.json') + +/* + * This is a custom ESLint configuration for use a library + * that utilizes React. + * + * This config extends the Vercel Engineering Style Guide. + * For more information, see https://github.com/vercel/style-guide + * + */ + +module.exports = { + extends: [ + '@vercel/style-guide/eslint/browser', + '@vercel/style-guide/eslint/typescript', + '@vercel/style-guide/eslint/react', + './_base', + ].map(require.resolve), + parserOptions: { + project, + }, + env: { + browser: true, + node: true, + }, + globals: { + JSX: true, + }, + settings: { + 'import/resolver': { + typescript: { + project, + }, + }, + }, + + // add rules configurations here + rules: { + 'import/no-default-export': 'off', + 'no-param-reassign': 'off', + 'no-console': 'off', + }, +} diff --git a/libs/eslint-config/storybook.js b/libs/eslint-config/storybook.js new file mode 100644 index 0000000..d34f3be --- /dev/null +++ b/libs/eslint-config/storybook.js @@ -0,0 +1,45 @@ +const { resolve } = require('node:path') + +const project = resolve(process.cwd(), 'tsconfig.json') + +/* + * This is a custom ESLint configuration for use with + * typescript packages. + * + * This config extends the Vercel Engineering Style Guide. + * For more information, see https://github.com/vercel/style-guide + * + */ + +module.exports = { + extends: [ + 'plugin:storybook/recommended', + ...[ + '@vercel/style-guide/eslint/node', + '@vercel/style-guide/eslint/typescript', + '@vercel/style-guide/eslint/browser', + '@vercel/style-guide/eslint/react', + './_base', + ].map(require.resolve), + ], + parserOptions: { + project, + }, + plugins: ['only-warn'], + globals: { + React: true, + JSX: true, + }, + settings: { + 'import/resolver': { + typescript: { + project, + }, + }, + }, + + // Custom rules configurations + rules: { + 'import/no-default-export': 'off', + }, +} diff --git a/libs/tailwind-config/.eslintrc.js b/libs/tailwind-config/.eslintrc.js deleted file mode 100644 index d5ff108..0000000 --- a/libs/tailwind-config/.eslintrc.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('eslint').Linter.Config} */ -module.exports = { - extends: ['@repo/eslint-config/base'], -} diff --git a/libs/tailwind-config/package.json b/libs/tailwind-config/package.json index ef2dec7..2cce6e5 100644 --- a/libs/tailwind-config/package.json +++ b/libs/tailwind-config/package.json @@ -3,7 +3,6 @@ "main": "index.ts", "types": "index.ts", "devDependencies": { - "@repo/eslint-config": "workspace:^", "@tailwindcss/forms": "^0.5.7", "@tailwindcss/typography": "^0.5.10", "tailwindcss": "^3.3.5" diff --git a/libs/tsconfig/nest.json b/libs/tsconfig/nest.json new file mode 100644 index 0000000..3c4a735 --- /dev/null +++ b/libs/tsconfig/nest.json @@ -0,0 +1,22 @@ +{ + "extends": "./base.json", + "$schema": "https://json.schemastore.org/tsconfig", + "display": "NestJS", + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "sourceMap": true, + "outDir": "./build", + "incremental": true, + "strictNullChecks": false, + "noImplicitAny": false, + "strictBindCallApply": false, + "noFallthroughCasesInSwitch": false, + "resolveJsonModule": true, + "baseUrl": "." + } +} diff --git a/libs/types/.eslintrc.js b/libs/types/.eslintrc.js index d5ff108..5aa5452 100644 --- a/libs/types/.eslintrc.js +++ b/libs/types/.eslintrc.js @@ -1,4 +1,4 @@ /** @type {import('eslint').Linter.Config} */ module.exports = { - extends: ['@repo/eslint-config/base'], + extends: ['@repo/eslint-config/library'], } diff --git a/libs/types/index.ts b/libs/types/index.ts index c91a68f..8309e28 100644 --- a/libs/types/index.ts +++ b/libs/types/index.ts @@ -1,11 +1,11 @@ -export type Cat = { +export interface Cat { _id: string name: string age: number breed: string } -export type Dog = { +export interface Dog { _id: string name: string } diff --git a/libs/types/package.json b/libs/types/package.json index 8d04376..ff8a33b 100644 --- a/libs/types/package.json +++ b/libs/types/package.json @@ -1,9 +1,15 @@ { - "name": "@company/types", + "name": "@repo/types", "private": true, "main": "index.ts", + "scripts": { + "lint": "eslint .", + "lint:fix": "pnpm lint --fix", + "typecheck": "tsc --noEmit" + }, "devDependencies": { "@repo/eslint-config": "workspace:*", + "@repo/tsconfig": "workspace:^", "typescript": "^5.3.2" } } diff --git a/libs/types/tsconfig.json b/libs/types/tsconfig.json new file mode 100644 index 0000000..be12885 --- /dev/null +++ b/libs/types/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@repo/tsconfig/base.json", + "include": ["."], + "exclude": ["dist", "node_modules"], + "compilerOptions": { + "lib": ["ES2015"], + "module": "CommonJS", + "outDir": "./dist" + } +} diff --git a/libs/ui/.eslintrc.js b/libs/ui/.eslintrc.js index 67d09da..5aa5452 100644 --- a/libs/ui/.eslintrc.js +++ b/libs/ui/.eslintrc.js @@ -1,4 +1,4 @@ /** @type {import('eslint').Linter.Config} */ module.exports = { - extends: ['@repo/eslint-config/base', '@repo/eslint-config/react'], + extends: ['@repo/eslint-config/library'], } diff --git a/libs/ui/package.json b/libs/ui/package.json index b3e28b7..b8cdf2e 100644 --- a/libs/ui/package.json +++ b/libs/ui/package.json @@ -20,15 +20,17 @@ "scripts": { "build": "tsup", "lint": "eslint src/", + "lint:fix": "pnpm lint --fix", "develop": "tsup --watch", - "check-types": "tsc --noEmit" + "typecheck": "tsc --noEmit" }, "devDependencies": { - "@repo/eslint-config": "workspace:^", - "@repo/tailwind-config": "workspace:^", - "@repo/tsconfig": "workspace:^", + "@repo/eslint-config": "workspace:*", + "@repo/tailwind-config": "workspace:*", + "@repo/tsconfig": "workspace:*", "@types/react": "^18.2.5", "autoprefixer": "^10.4.13", + "eslint": "^8.54.0", "postcss": "^8.4.20", "react": "^18.2.0", "tailwindcss": "^3.3.5", diff --git a/libs/ui/src/components/button.tsx b/libs/ui/src/components/button.tsx index 37e1a76..3ee5e02 100644 --- a/libs/ui/src/components/button.tsx +++ b/libs/ui/src/components/button.tsx @@ -7,7 +7,7 @@ export const Button = ({ children, ...props }: ButtonProps) => { return (