diff --git a/examples/with-firebase/.firebaserc b/examples/with-firebase/.firebaserc new file mode 100644 index 0000000000000..a4ab0f4157211 --- /dev/null +++ b/examples/with-firebase/.firebaserc @@ -0,0 +1,5 @@ +{ + "projects": { + "default": "turborepo-firebase-example" + } +} diff --git a/examples/with-firebase/README.md b/examples/with-firebase/README.md new file mode 100644 index 0000000000000..7545e96d04bfc --- /dev/null +++ b/examples/with-firebase/README.md @@ -0,0 +1,37 @@ +# `Turborepo` Vite starter + +This is an official starter Turborepo. + +## What's inside? + +This Turborepo includes the following packages and apps: + +### Apps and Packages + +- `api`: a firebase clould function using express, built with rollup +- `web`: a vanilla [vite](https://vitejs.dev) ts app +- `config`: eslint shared config +- `shared`: shared util lib that you share code with various apps +- `tsconfig`: `tsconfig.json`s used throughout the monorepo + +Each package and app is 100% [TypeScript](https://www.typescriptlang.org/). + +### Utilities + +This Turborepo has some additional tools already setup for you: + +- [TypeScript](https://www.typescriptlang.org/) for static type checking +- [ESLint](https://eslint.org/) for code linting +- [Jest](https://jestjs.io) test runner for all things JavaScript +- [Prettier](https://prettier.io) for code formatting + +## Using this example + +Run the following command: + +```sh +npx degit vercel/turborepo/examples/with-firebase with-firebase +cd with-firebase +yarn +git init . && git add . && git commit -m "Init" +``` diff --git a/examples/with-firebase/apps/api/.gitignore b/examples/with-firebase/apps/api/.gitignore new file mode 100644 index 0000000000000..ffab5d12e9070 --- /dev/null +++ b/examples/with-firebase/apps/api/.gitignore @@ -0,0 +1,3 @@ +*.log +.runtimeconfig.json +dist/ \ No newline at end of file diff --git a/examples/with-firebase/apps/api/jest.config.ts b/examples/with-firebase/apps/api/jest.config.ts new file mode 100644 index 0000000000000..b5865bcc90db0 --- /dev/null +++ b/examples/with-firebase/apps/api/jest.config.ts @@ -0,0 +1,15 @@ +import type { Config } from "@jest/types"; + +// Sync object +const config: Config.InitialOptions = { + verbose: true, + transform: { + "^.+\\.(ts|tsx)$": "ts-jest", + }, + globals: { + "ts-jest": { + tsconfig: "tsconfig.json", + }, + }, +}; +export default config; diff --git a/examples/with-firebase/apps/api/package.json b/examples/with-firebase/apps/api/package.json new file mode 100644 index 0000000000000..037577ce11c18 --- /dev/null +++ b/examples/with-firebase/apps/api/package.json @@ -0,0 +1,29 @@ +{ + "name": "api", + "scripts": { + "dev": "rollup -w -c rollup.config.js", + "build": "rimraf ./dist/**/* && rollup -c rollup.config.js", + "deploy": "firebase deploy --only functions" + }, + "engines": { + "node": "16" + }, + "type": "module", + "main": "dist/index.js", + "dependencies": { + "express": "^4.17.3", + "firebase-admin": "^10.1.0", + "firebase-functions": "^3.20.1", + "rollup": "^2.70.2", + "shared": "*" + }, + "devDependencies": { + "@rollup/plugin-node-resolve": "^13.2.1", + "@rollup/plugin-typescript": "^8.3.2", + "eslint": "^8.11.0", + "rimraf": "^3.0.2", + "ts-node": "^10.7.0", + "typescript": "^4.6.3" + }, + "private": true +} diff --git a/examples/with-firebase/apps/api/rollup.config.js b/examples/with-firebase/apps/api/rollup.config.js new file mode 100644 index 0000000000000..36da9ee3df4b8 --- /dev/null +++ b/examples/with-firebase/apps/api/rollup.config.js @@ -0,0 +1,17 @@ +import typescript from "@rollup/plugin-typescript"; +import nodeResolve from "@rollup/plugin-node-resolve"; +import pkg from "./package.json"; + +export default { + input: "src/index.ts", + external: [...Object.keys(pkg.dependencies)], + plugins: [typescript(), nodeResolve()], + onwarn: () => { + return; + }, + output: { + file: "dist/index.js", + format: "es", + sourcemap: true, + }, +}; diff --git a/examples/with-firebase/apps/api/src/index.ts b/examples/with-firebase/apps/api/src/index.ts new file mode 100644 index 0000000000000..bb28d25f80881 --- /dev/null +++ b/examples/with-firebase/apps/api/src/index.ts @@ -0,0 +1,11 @@ +import express from "express"; +import * as functions from "firebase-functions"; +import { exampleConfigFromShared } from "shared/util"; + +const app = express(); + +app.get("*", (req, res) => { + res.send(exampleConfigFromShared); +}); + +export const server = functions.https.onRequest(app); diff --git a/examples/with-firebase/apps/api/tsconfig.json b/examples/with-firebase/apps/api/tsconfig.json new file mode 100644 index 0000000000000..76e5bfd005931 --- /dev/null +++ b/examples/with-firebase/apps/api/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "lib": ["ES2021"], + "module": "ES2020", + "moduleResolution": "node", + "target": "ES2021", + "outDir": "dist", + "sourceMap": true, + "rootDir": "../../", + "typeRoots": ["node_modules/@types"], + "allowSyntheticDefaultImports": true, + "esModuleInterop": true + }, + "include": ["../../packages/shared/**/*.ts", "src"] +} diff --git a/examples/with-firebase/apps/web/.gitignore b/examples/with-firebase/apps/web/.gitignore new file mode 100644 index 0000000000000..a547bf36d8d11 --- /dev/null +++ b/examples/with-firebase/apps/web/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/examples/with-firebase/apps/web/index.html b/examples/with-firebase/apps/web/index.html new file mode 100644 index 0000000000000..0710cc2399bf6 --- /dev/null +++ b/examples/with-firebase/apps/web/index.html @@ -0,0 +1,13 @@ + + + + + + + Firebase + Turborepo + + +
+ + + diff --git a/examples/with-firebase/apps/web/package.json b/examples/with-firebase/apps/web/package.json new file mode 100644 index 0000000000000..8a9d73d447c72 --- /dev/null +++ b/examples/with-firebase/apps/web/package.json @@ -0,0 +1,23 @@ +{ + "name": "web", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "deploy": "firebase deploy --only hosting" + }, + "dependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0", + "shared": "*" + }, + "devDependencies": { + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@vitejs/plugin-react": "^1.3.0", + "typescript": "^4.6.3", + "vite": "^2.9.7" + } +} diff --git a/examples/with-firebase/apps/web/src/App.css b/examples/with-firebase/apps/web/src/App.css new file mode 100644 index 0000000000000..2ae6bc987166b --- /dev/null +++ b/examples/with-firebase/apps/web/src/App.css @@ -0,0 +1,11 @@ +.App { + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; + padding: 80px; +} diff --git a/examples/with-firebase/apps/web/src/App.tsx b/examples/with-firebase/apps/web/src/App.tsx new file mode 100644 index 0000000000000..abe94ad783b03 --- /dev/null +++ b/examples/with-firebase/apps/web/src/App.tsx @@ -0,0 +1,22 @@ +import { useEffect, useState } from "react"; +import { exampleConfigFromShared } from "shared/util"; + +import "./App.css"; + +function App() { + const [data, setData] = useState({}); + useEffect(() => { + fetch("/api/test") + .then((res) => res.json()) + .then((res) => setData(res)); + }, []); + + return ( +
+
API: {JSON.stringify(data)}
+
Shared: {JSON.stringify(exampleConfigFromShared)}
+
+ ); +} + +export default App; diff --git a/examples/with-firebase/apps/web/src/favicon.svg b/examples/with-firebase/apps/web/src/favicon.svg new file mode 100644 index 0000000000000..de4aeddc12bdf --- /dev/null +++ b/examples/with-firebase/apps/web/src/favicon.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/examples/with-firebase/apps/web/src/index.css b/examples/with-firebase/apps/web/src/index.css new file mode 100644 index 0000000000000..e8c77d2921d3f --- /dev/null +++ b/examples/with-firebase/apps/web/src/index.css @@ -0,0 +1,14 @@ +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; + background-color: #282c34; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/examples/with-firebase/apps/web/src/logo.svg b/examples/with-firebase/apps/web/src/logo.svg new file mode 100644 index 0000000000000..6b60c1042f58d --- /dev/null +++ b/examples/with-firebase/apps/web/src/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/examples/with-firebase/apps/web/src/main.tsx b/examples/with-firebase/apps/web/src/main.tsx new file mode 100644 index 0000000000000..9b67590a06915 --- /dev/null +++ b/examples/with-firebase/apps/web/src/main.tsx @@ -0,0 +1,10 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; +import "./index.css"; + +ReactDOM.createRoot(document.getElementById("root")!).render( + + + +); diff --git a/examples/with-firebase/apps/web/src/vite-env.d.ts b/examples/with-firebase/apps/web/src/vite-env.d.ts new file mode 100644 index 0000000000000..11f02fe2a0061 --- /dev/null +++ b/examples/with-firebase/apps/web/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/with-firebase/apps/web/tsconfig.json b/examples/with-firebase/apps/web/tsconfig.json new file mode 100644 index 0000000000000..3d0a51a86e202 --- /dev/null +++ b/examples/with-firebase/apps/web/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/examples/with-firebase/apps/web/tsconfig.node.json b/examples/with-firebase/apps/web/tsconfig.node.json new file mode 100644 index 0000000000000..e993792cb12c9 --- /dev/null +++ b/examples/with-firebase/apps/web/tsconfig.node.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "composite": true, + "module": "esnext", + "moduleResolution": "node" + }, + "include": ["vite.config.ts"] +} diff --git a/examples/with-firebase/apps/web/vite.config.ts b/examples/with-firebase/apps/web/vite.config.ts new file mode 100644 index 0000000000000..5e8d581e89ac7 --- /dev/null +++ b/examples/with-firebase/apps/web/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + server: { + proxy: { + "/api": { + target: "http://localhost:5000", + changeOrigin: true, + }, + }, + }, +}); diff --git a/examples/with-firebase/firebase.json b/examples/with-firebase/firebase.json new file mode 100644 index 0000000000000..5c603e2f5e5d0 --- /dev/null +++ b/examples/with-firebase/firebase.json @@ -0,0 +1,31 @@ +{ + "functions": { + "source": "apps/api" + }, + "hosting": { + "public": "apps/web/dist", + "ignore": ["firebase.json", "**/.*", "**/node_modules/**"], + "rewrites": [ + { + "source": "/api/**", + "function": "server" + }, + { + "source": "**", + "destination": "/index.html" + } + ] + }, + "emulators": { + "ui": { + "enabled": true + }, + "functions": { + "port": 5001 + }, + "hosting": { + "enabled": true, + "port": 5000 + } + } +} diff --git a/examples/with-firebase/package.json b/examples/with-firebase/package.json new file mode 100644 index 0000000000000..5a80eed40a4ea --- /dev/null +++ b/examples/with-firebase/package.json @@ -0,0 +1,29 @@ +{ + "name": "turborepo-firebase", + "version": "0.0.0", + "private": true, + "workspaces": [ + "apps/*", + "packages/*" + ], + "scripts": { + "start": "concurrently npm:dev npm:emulators", + "dev": "turbo run dev --parallel", + "build": "turbo run build", + "emulators": "firebase emulators:start", + "deploy": "turbo run build --parallel && turbo run deploy --filter=web --filter=api", + "lint": "turbo run lint", + "format": "prettier --write \"**/*.{ts,tsx,md}\"" + }, + "devDependencies": { + "concurrently": "^7.1.0", + "firebase-tools": "^11.9.0", + "prettier": "latest", + "turbo": "latest" + }, + "engines": { + "npm": ">=7.0.0", + "node": ">=14.0.0" + }, + "packageManager": "npm@7.24.0" +} diff --git a/examples/with-firebase/packages/config/eslint-preset.js b/examples/with-firebase/packages/config/eslint-preset.js new file mode 100644 index 0000000000000..cedc38df2ccfc --- /dev/null +++ b/examples/with-firebase/packages/config/eslint-preset.js @@ -0,0 +1,12 @@ +module.exports = { + extends: ["next", "prettier"], + settings: { + next: { + rootDir: ["apps/*/", "packages/*/"], + }, + }, + rules: { + "@next/next/no-html-link-for-pages": "off", + "react/jsx-key": "off", + }, +}; diff --git a/examples/with-firebase/packages/config/package.json b/examples/with-firebase/packages/config/package.json new file mode 100644 index 0000000000000..cdcaeea47ae35 --- /dev/null +++ b/examples/with-firebase/packages/config/package.json @@ -0,0 +1,14 @@ +{ + "name": "config", + "version": "0.0.0", + "main": "index.js", + "license": "MIT", + "files": [ + "eslint-preset.js" + ], + "dependencies": { + "eslint-config-next": "^12.0.8", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-react": "7.28.0" + } +} diff --git a/examples/with-firebase/packages/shared/package.json b/examples/with-firebase/packages/shared/package.json new file mode 100644 index 0000000000000..f16d73c13b7a9 --- /dev/null +++ b/examples/with-firebase/packages/shared/package.json @@ -0,0 +1,8 @@ +{ + "name": "shared", + "version": "0.0.0", + "private": true, + "files": [ + "*" + ] +} \ No newline at end of file diff --git a/examples/with-firebase/packages/shared/util.ts b/examples/with-firebase/packages/shared/util.ts new file mode 100644 index 0000000000000..734462ade2409 --- /dev/null +++ b/examples/with-firebase/packages/shared/util.ts @@ -0,0 +1,3 @@ +export const exampleConfigFromShared = { + turbo: "blazingly fastâ„¢" +}; diff --git a/examples/with-firebase/packages/tsconfig/README.md b/examples/with-firebase/packages/tsconfig/README.md new file mode 100644 index 0000000000000..0da79cf231837 --- /dev/null +++ b/examples/with-firebase/packages/tsconfig/README.md @@ -0,0 +1,3 @@ +# `tsconfig` + +These are base shared `tsconfig.json`s from which all other `tsconfig.json`'s inherit from. diff --git a/examples/with-firebase/packages/tsconfig/base.json b/examples/with-firebase/packages/tsconfig/base.json new file mode 100644 index 0000000000000..d72a9f3a27835 --- /dev/null +++ b/examples/with-firebase/packages/tsconfig/base.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Default", + "compilerOptions": { + "composite": false, + "declaration": true, + "declarationMap": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "inlineSources": false, + "isolatedModules": true, + "moduleResolution": "node", + "noUnusedLocals": false, + "noUnusedParameters": false, + "preserveWatchOutput": true, + "skipLibCheck": true, + "strict": true + }, + "exclude": ["node_modules"] +} diff --git a/examples/with-firebase/packages/tsconfig/package.json b/examples/with-firebase/packages/tsconfig/package.json new file mode 100644 index 0000000000000..d49a4c6ee807e --- /dev/null +++ b/examples/with-firebase/packages/tsconfig/package.json @@ -0,0 +1,11 @@ +{ + "name": "tsconfig", + "version": "0.0.0", + "private": true, + "main": "index.js", + "files": [ + "base.json", + "nextjs.json", + "react-library.json" + ] +} diff --git a/examples/with-firebase/turbo.json b/examples/with-firebase/turbo.json new file mode 100644 index 0000000000000..3782e77314aec --- /dev/null +++ b/examples/with-firebase/turbo.json @@ -0,0 +1,18 @@ +{ + "pipeline": { + "build": { + "dependsOn": ["^build"], + "outputs": ["dist/**"] + }, + "deploy": { + "dependsOn": ["^build"], + "outputs": [] + }, + "lint": { + "outputs": [] + }, + "dev": { + "cache": false + } + } +}