feat(create-turbo): apply official-starter transform
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
/** @type {import("eslint").Linter.Config} */
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["@repo/eslint-config/server.js"],
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
FROM node:18-alpine AS base
|
||||
|
||||
# The web Dockerfile is copy-pasted into our main docs at /docs/handbook/deploying-with-docker.
|
||||
# Make sure you update this Dockerfile, the Dockerfile in the web workspace and copy that over to Dockerfile in the docs.
|
||||
|
||||
FROM base AS builder
|
||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||
RUN apk update
|
||||
RUN apk add --no-cache libc6-compat
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
RUN yarn global add turbo
|
||||
COPY . .
|
||||
RUN turbo prune api --docker
|
||||
|
||||
# Add lockfile and package.json's of isolated subworkspace
|
||||
FROM base AS installer
|
||||
RUN apk update
|
||||
RUN apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
|
||||
# First install dependencies (as they change less often)
|
||||
COPY --from=builder /app/out/json/ .
|
||||
RUN yarn install
|
||||
|
||||
# Build the project and its dependencies
|
||||
COPY --from=builder /app/out/full/ .
|
||||
|
||||
# Uncomment and use build args to enable remote caching
|
||||
# ARG TURBO_TEAM
|
||||
# ENV TURBO_TEAM=$TURBO_TEAM
|
||||
|
||||
# ARG TURBO_TOKEN
|
||||
# ENV TURBO_TOKEN=$TURBO_TOKEN
|
||||
|
||||
RUN yarn turbo build
|
||||
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
|
||||
# Don't run production as root
|
||||
RUN addgroup --system --gid 1001 expressjs
|
||||
RUN adduser --system --uid 1001 expressjs
|
||||
USER expressjs
|
||||
COPY --from=installer /app .
|
||||
|
||||
CMD node apps/api/dist/index.js
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "api",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"clean": "rm -rf dist",
|
||||
"dev": "nodemon --exec \"node -r esbuild-register ./src/index.ts\" -e .ts",
|
||||
"lint": "tsc --noEmit && eslint \"src/**/*.ts*\" --max-warnings 0",
|
||||
"start": "node -r esbuild-register ./src/index.ts",
|
||||
"test": "jest --detectOpenHandles"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "@repo/jest-presets/node"
|
||||
},
|
||||
"dependencies": {
|
||||
"@repo/logger": "*",
|
||||
"body-parser": "^1.20.2",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.18.3",
|
||||
"morgan": "^1.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jest/globals": "^29.7.0",
|
||||
"@repo/eslint-config": "*",
|
||||
"@repo/jest-presets": "*",
|
||||
"@repo/typescript-config": "*",
|
||||
"@types/body-parser": "^1.19.5",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/morgan": "^1.9.9",
|
||||
"@types/node": "^20.11.24",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"esbuild": "^0.20.1",
|
||||
"esbuild-register": "^3.5.0",
|
||||
"eslint": "^8.57.0",
|
||||
"jest": "^29.7.0",
|
||||
"nodemon": "^3.1.0",
|
||||
"supertest": "^6.3.3",
|
||||
"typescript": "5.5.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import supertest from "supertest";
|
||||
import { describe, it, expect } from "@jest/globals";
|
||||
import { createServer } from "../server";
|
||||
|
||||
describe("server", () => {
|
||||
it("status check returns 200", async () => {
|
||||
await supertest(createServer())
|
||||
.get("/status")
|
||||
.expect(200)
|
||||
.then((res) => {
|
||||
expect(res.body.ok).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("message endpoint says hello", async () => {
|
||||
await supertest(createServer())
|
||||
.get("/message/jared")
|
||||
.expect(200)
|
||||
.then((res) => {
|
||||
expect(res.body.message).toBe("hello jared");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
import { createServer } from "./server";
|
||||
import { log } from "@repo/logger";
|
||||
|
||||
const port = process.env.PORT || 3001;
|
||||
const server = createServer();
|
||||
|
||||
server.listen(port, () => {
|
||||
log(`api running on ${port}`);
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import { json, urlencoded } from "body-parser";
|
||||
import express, { type Express } from "express";
|
||||
import morgan from "morgan";
|
||||
import cors from "cors";
|
||||
|
||||
export const createServer = (): Express => {
|
||||
const app = express();
|
||||
app
|
||||
.disable("x-powered-by")
|
||||
.use(morgan("dev"))
|
||||
.use(urlencoded({ extended: true }))
|
||||
.use(json())
|
||||
.use(cors())
|
||||
.get("/message/:name", (req, res) => {
|
||||
return res.json({ message: `hello ${req.params.name}` });
|
||||
})
|
||||
.get("/status", (_, res) => {
|
||||
return res.json({ ok: true });
|
||||
});
|
||||
|
||||
return app;
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "@repo/typescript-config/base.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2015"],
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"exclude": ["node_modules"],
|
||||
"include": ["src"]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/** @type {import("eslint").Linter.Config} */
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["@repo/eslint-config/next.js"],
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
project: true,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
FROM node:18-alpine AS base
|
||||
|
||||
# This Dockerfile is copy-pasted into our main docs at /docs/handbook/deploying-with-docker.
|
||||
# Make sure you update both files!
|
||||
|
||||
FROM base AS builder
|
||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||
RUN apk update
|
||||
RUN apk add --no-cache libc6-compat
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
RUN yarn global add turbo
|
||||
COPY . .
|
||||
RUN turbo prune web --docker
|
||||
|
||||
# Add lockfile and package.json's of isolated subworkspace
|
||||
FROM base AS installer
|
||||
RUN apk update
|
||||
RUN apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
|
||||
# First install the dependencies (as they change less often)
|
||||
COPY --from=builder /app/out/json/ .
|
||||
RUN yarn install
|
||||
|
||||
# Build the project
|
||||
COPY --from=builder /app/out/full/ .
|
||||
|
||||
# Uncomment and use build args to enable remote caching
|
||||
# ARG TURBO_TEAM
|
||||
# ENV TURBO_TEAM=$TURBO_TEAM
|
||||
|
||||
# ARG TURBO_TOKEN
|
||||
# ENV TURBO_TOKEN=$TURBO_TOKEN
|
||||
|
||||
RUN yarn turbo build
|
||||
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
|
||||
# Don't run production as root
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
USER nextjs
|
||||
|
||||
# Automatically leverage output traces to reduce image size
|
||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/standalone ./
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public
|
||||
|
||||
CMD node apps/web/server.js
|
||||
@@ -0,0 +1,30 @@
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
|
||||
|
||||
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
|
||||
|
||||
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn/foundations/about-nextjs) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_source=github.com&utm_medium=referral&utm_campaign=turborepo-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
@@ -0,0 +1,10 @@
|
||||
const path = require("path");
|
||||
|
||||
module.exports = {
|
||||
reactStrictMode: true,
|
||||
transpilePackages: ["@repo/ui"],
|
||||
output: "standalone",
|
||||
experimental: {
|
||||
outputFileTracingRoot: path.join(__dirname, "../../"),
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "web",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "next build",
|
||||
"dev": "next dev",
|
||||
"lint": "eslint . --max-warnings 0",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "^14.1.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"@repo/ui": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/eslint-plugin-next": "^14.1.1",
|
||||
"@types/node": "^20.11.24",
|
||||
"@types/react": "^18.2.61",
|
||||
"@types/react-dom": "^18.2.19",
|
||||
"eslint": "^8.57.0",
|
||||
"@repo/eslint-config": "*",
|
||||
"@repo/typescript-config": "*",
|
||||
"typescript": "5.5.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
This public directory can be used to store any static content, see:
|
||||
|
||||
https://nextjs.org/docs/basic-features/static-file-serving
|
||||
|
||||
To remove this directory, also remove the following line from the web `Dockerfile`:
|
||||
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public
|
||||
@@ -0,0 +1,11 @@
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState, ChangeEvent, FormEvent } from "react";
|
||||
import { Button } from "@repo/ui/button";
|
||||
|
||||
const API_HOST = process.env.NEXT_PUBLIC_API_HOST || "http://localhost:3001";
|
||||
|
||||
export default function Web() {
|
||||
const [name, setName] = useState<string>("");
|
||||
const [response, setResponse] = useState<{ message: string } | null>(null);
|
||||
const [error, setError] = useState<string | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
setResponse(null);
|
||||
setError(undefined);
|
||||
}, [name]);
|
||||
|
||||
const onChange = (e: ChangeEvent<HTMLInputElement>) =>
|
||||
setName(e.target.value);
|
||||
|
||||
const onSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
try {
|
||||
const result = await fetch(`${API_HOST}/message/${name}`);
|
||||
const response = await result.json();
|
||||
setResponse(response);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setError("Unable to fetch response");
|
||||
}
|
||||
};
|
||||
|
||||
const onReset = () => {
|
||||
setName("");
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Web</h1>
|
||||
<form onSubmit={onSubmit}>
|
||||
<label htmlFor="name">Name </label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
id="name"
|
||||
value={name}
|
||||
onChange={onChange}
|
||||
></input>
|
||||
<Button type="submit">Submit</Button>
|
||||
</form>
|
||||
{error && (
|
||||
<div>
|
||||
<h3>Error</h3>
|
||||
<p>{error}</p>
|
||||
</div>
|
||||
)}
|
||||
{response && (
|
||||
<div>
|
||||
<h3>Greeting</h3>
|
||||
<p>{response.message}</p>
|
||||
<Button onClick={onReset}>Reset</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "@repo/typescript-config/nextjs.json",
|
||||
"compilerOptions": {
|
||||
"plugins": [{ "name": "next" }]
|
||||
},
|
||||
"include": ["next-env.d.ts", "next.config.js", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user