Skip to content

Monorepo template for bootstrapping and quick setup of CTF UI Projects

License

Notifications You must be signed in to change notification settings

cometbid-sfi/pnpm-monorepo-template

The Cometbid Technology Foundation(TCTF) Portal Frontend

✨ Your new, shiny Nx workspace is almost ready ✨.

Learn more about this workspace setup and its capabilities or run npx nx graph to visually explore what was created. Now, let's get you up to speed!

Setting Up a Monorepo with pnpm

Install pnpm:
Start by Installing pnpm globally if you haven't already:

npm install -g pnpm

Initialize a Workspace:

Create a new directory for your monorepo and initialize a pnpm workspace:

mkdir pnpm-monorepo-template
cd pnpm-monorepo-template
pnpm init

Configure the Workspace:

Create a pnpm-workspace.yaml file in the root of your monorepo to define the packages in the workspace:

packages:
  - "packages/*"
  - "apps/*"
  - "libs/*"

Create Applications:

Create apps for react and nest apps. And packages for re-useable libraries:

mkdir apps
mkdir packages

Initialize the React Application:

To create the react app using vite run following command from root of monorepo.

pnpm create vite apps/ui

Initialize the Nest Application:

To create the nestjs app using nestjs/cli run following command from root of monorepo.

pnpx @nestjs/cli new apps/api

Build the Dependencies

pnpm --filter @pnpmworkspace/logger build

Run the react(UI) app:

Make sure to build dependencies first, or you will into an error:

pnpx nx build ui 
or
pnpm --filter ui build

pnpm --filter ui start:dev
pnpm --filter ui start:prod

Run the nestjs(api) app:

pnpx nx build api 
or
pnpm --filter api build

pnpm --filter api start:dev
pnpm --filter api start:prod

Scripts and Automation:

Update the package.json file on root. Add some scripts in package.json to start both apps with single command:

"scripts": {
  "start:ui": "pnpm --filter ui dev",
  "start:api": "pnpm --filter api start:dev",
  "start": "pnpm run start:ui & pnpm run start:api",
  "build": "pnpm recursive run build",
  "test": "pnpm recursive run test"
}
pnpm start:ui // It will run UI app
pnpm start:api // It will run API app
pnpm start // It will run both apps
pnpm test // it will test on all workspaces

Explanation of pnpm commands:

— filter: It will filter the app you want to run in out case ui and api are two apps.

— ui/api: Name of the app

— dev/start:dev: Script in package.json of app. dev is script command in scripts object in ui app. and start:dev is the script command in api app.

— recursive: It will run the specifies command like build and test on all workspaces. If some workspace doesn’t have test script, it will ignore it.

Create a Shared Logger Package:

Create a new folder for your shared logger package inside the packages folder:

mkdir -p packages/logger
cd packages/logger
pnpm init

Implement the Logger Package:

Add a simple logger implementation in packages/logger/src/index.ts:

export const Logger = (message: string) => {
    console.log(`${'Logger - ' + new Date().toISOString() + ': ' + message}`)
}

export default Logger;

Add dependencies:

Add the dependencies for logger, in our case it’s only typescript. Run the following command on root of project.

pnpm add --filter logger typescript

Update package.json: package.json file of logger should look like:

{
  "name": "@pnpmworkspace/logger",
  "version": "1.0.0",
  "description": "",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "keywords": [],
  "author": "",
  "license": "ISC",
  "scripts": {
    "build": "tsc"
  },
  "dependencies": {
    "typescript": "^5.5.3"
  }
}

tsconfig.json:

{
  "compilerOptions": {
    "target": "ES6",
    "module": "commonjs",
    "allowJs": true,
    "declaration": true,
    "outDir": "./dist",
    "strict": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src"]
}

Build Logger package (Run from root):

pnpm --filter logger build

Add Logger as dependency(Run from root):

pnpm add ./packages/logger --workspace-root

Above command will add the package logger into root node_module folder.

— workspace-root: It will add package in root node_module folder.

Use Logger Package: You can use @pnpmworkspace/logger into both ui and api apps.

import { Logger } from "@pnpmworkspace/logger";

Run both apps:

pnpm start

This ensures that build and test commands are executed for all projects within the monorepo.

Build individual Projects:

pnpx nx build api
pnpx nx build ui

Run build command on all apps:

Following command run all build command on all apps at once.

pnpx nx run-many -t=build

Using Nx with pnpm:

Nx provides a rich CLI and graphical interface for managing your projects. You can run build, test, and lint commands for specific projects.

pnpx nx run-many --targets=lint,test,build --projects=api

Or for all projects.

pnpx nx run-many --targets=lint,test,build

How to Setup Nx in a pnpm Workspace

Nx enhances the monorepo experience by providing advanced tooling for building, testing, and deploying applications. When combined with pnpm, it offers efficient dependency management and powerful workspace capabilities.

Add Nx to Your Workspace:

Initialize the Nx workspace in your project

pnpx nx@latest init

Add @nx/next:app to a pnpm monorepo

  1. First, ensure you have a proper pnpm workspace setup by creating/checking your pnpm-workspace.yaml file in your root directory:
packages:
  - "apps/*"
  - "libs/*"
  1. Install the required dependencies using pnpm:
pnpm add -D @nx/next nx @nx/react --workspace-root
  1. If you're using a newer version of pnpm, you might need to configure dependency hoisting. Create or update your .npmrc file in the root:

node-linker=hoisted shamefully-hoist=true

  1. Install the peer dependencies:
pnpm remove next react react-dom --workspace-root
pnpm add next react react-dom --workspace-root
  1. Clear your pnpm store and reinstall dependencies:
pnpm store prune
pnpm install
  1. After installation, you can create a new Next.js app using:
pnpm nx g @nx/next:app your-app-name
pnpm approve-builds

If you're still experiencing issues, try these additional troubleshooting steps:

i. Clear the Nx cache:

pnpm nx reset

ii. Make sure your package.json has the correct dependencies:

{
  "devDependencies": {
    "@nx/next": "latest",
    "@nx/react": "latest",
    "nx": "latest"
  },
  "dependencies": {
    "next": "^13.0.0 || ^14.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  }
}

iii. If you have a nx.json file, ensure it's properly configured:

{
  "extends": "nx/presets/npm.json",
  "$schema": "./node_modules/nx/schemas/nx-schema.json",
  "affected": {
    "defaultBase": "main"
  },
  "tasksRunnerOptions": {
    "default": {
      "runner": "nx/tasks-runners/default"
    }
  }
}

Relevant Blogs:

Add new Nextjs projects

While you could add new projects to your workspace manually, you might want to leverage Nx plugins and their code generation feature.

Use the plugin's generator to create new projects.

To generate a new application, use:

pnpx nx g @nx/next:app app-name

for example:

pnpx nx g @nx/next:app apps/ctf-dashboard
pnpx nx g @nx/next:app apps/ctf-main

To generate a new library, use:

npx nx g @nx/react:lib mylib

You can use npx nx list to get a list of installed plugins. Then, run npx nx list <plugin-name> to learn about more specific capabilities of a particular plugin. Alternatively, install Nx Console to browse plugins and generators in your IDE.

Learn more about Nx plugins » | Browse the plugin registry »

After creation, you can verify the project setup by running the task.

Run tasks

To run the dev server for your app, use:

pnpx nx dev tctf-member-dashboard
pnpx nx dev tctf-main-portal

To create a production bundle:

pnpx nx build tctf-member-dashboard
pnpx nx build tctf-main-portal

To see all available targets to run for a project, run:

pnpx nx show project tctf-member-dashboard
pnpx nx show project tctf-main-portal

These targets are either inferred automatically or defined in the project.json or package.json files.

More about running tasks in the docs »

Remove Nextjs project

  1. First, to remove the existing Next.js project, you can use the nx remove command:
pnpx nx g @nx/next:remove ctf-dashboard ctf-dashboard-e2e

Add Bootstrap to Nextjs Project

  1. Install Bootstrap and React-Bootstrap using npm, yarn, or pnpm.

Navigate to the root of the Nx project that requires Bootstrap library:

pnpm i bootstrap react-bootstrap
  1. Go to the globals.css file present inside app directory. At the top of file add the following code:
@import "~bootstrap/dist/css/bootstrap.min.css";

OR

Go to the layout.tsx file present inside app directory. At the top of file add the following code:

import "bootstrap/dist/css/bootstrap.min.css";
  1. You can add the bootstrap styling to elements using className.

To use bootstrap components like Container, Button, Form etc, you can import them from react-bootstrap and use them like normal components.

E.g:

import { Button, Col, Container, Row } from "react-bootstrap";

export default function Home() {
  return (
    <Container>
      <Row>
        <Col>
          <h1 className="text-danger fw-bold">Home</h1>
          <Button variant="primary" className="mt-5">
            Click Me
          </Button>
        </Col>
      </Row>
    </Container>
  );
}

That's it, you are all set to use bootstrap in your Next.js application

Add Tailwind CSS to Nextjs Project

  1. Install Tailwind CSS and its peer dependencies:
pnpm add -D tailwindcss@latest postcss@latest autoprefixer@latest
  1. Creates two files:
  • Create tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./app/**/*.{js,ts,jsx,tsx,mdx}",
    "./pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./components/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};
  • Create postcss.config.js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};
  1. Make sure your package.json has the correct dependencies:
{
  "devDependencies": {
    "tailwindcss": "latest",
    "postcss": "latest",
    "autoprefixer": "latest"
  }
}
  1. Add Tailwind's CSS directives to your global CSS file ( app/globals.css or styles/globals.css):
@tailwind base;
@tailwind components;
@tailwind utilities;
  1. If you're using the App Router, make sure your layout.js or layout.tsx imports the global CSS file:
import './globals.css';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode,
}) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}
  1. Test it by adding some Tailwind classes to any component:
export default function Home() {
  return (
    <div className="flex min-h-screen items-center justify-center">
      <h1 className="text-3xl font-bold text-blue-600">Hello Tailwind CSS!</h1>
    </div>
  );
}
  1. After setting this up, run pnpm install again to ensure all dependencies are properly installed.

Other CLI Commands For Nx

pnpx nx list

Lists the currently installed Nx plugins.

pnpx nx migrate latest

Updates the packages in package.json to the latest version.

pnpx nx affected

To upgrade libraries to the latest versions, run:

pnpm update --latest

Performs the action on only the affected or modified apps.

pnpx nx serve todo-api
pnpx nx serve todo

Runs each target project separately.

pnpx nx run-many --target serve --projects todo-api,todo

Runs the target command across all projects listed.

pnpx nx dep-graph

Using LightHouse for Performance Monitoring

  • Install Lighthouse CLI
pnpm i -g lighthouse
  • Run Lighthouse audit on your Nextjs application
lighthouse http://cometbid.org/

Show the dependency graph of our application.

Learn more about Nx on CI

Install Nx Console

Nx Console is an editor extension that enriches your developer experience. It lets you run tasks, generate code, and improves code autocompletion in your IDE. It is available for VSCode and IntelliJ.

Install Nx Console »

Useful links

Learn more:

And join the Nx community: