├── .gitignore ├── .npmrc.example ├── .nvmrc ├── README.md ├── app ├── entry.client.tsx ├── entry.server.tsx ├── root.tsx ├── routes │ ├── 404.tsx │ └── index.tsx ├── styles │ ├── global.css │ └── index.css └── tsconfig.json ├── index.js ├── package.json ├── public └── favicon.ico ├── remix.config.js └── vercel.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | package-lock.json 3 | 4 | /.cache/ 5 | /build/ 6 | /public/build/ 7 | 8 | .vercel 9 | -------------------------------------------------------------------------------- /.npmrc.example: -------------------------------------------------------------------------------- 1 | # Swap out "" below with the key you get from logging in 2 | # to https://remix.run. If this is a public repo, you'll want to move this 3 | # line into ~/.npmrc to keep it private. 4 | //npm.remix.run/:_authToken= 5 | 6 | # This line tells npm where to find @remix-run packages. 7 | @remix-run:registry=https://npm.remix.run 8 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 14 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Please Don't Use 2 | 3 | > Please use `npm init remix` instead of this starter repo to create a new Remix app. 4 | > This repository was archived on April 29, 2021. 5 | 6 | # Remix Starter for Vercel 7 | 8 | Welcome to Remix! 9 | 10 | This is a starter repo for using [Remix](https://remix.run) with [Vercel](http://vercel.com/). 11 | 12 | ## Development 13 | 14 | After cloning the repo, rename `.npmrc.example` to `.npmrc` and insert the license key you get from [logging in to your dashboard at remix.run](https://remix.run). 15 | 16 | > Note: if this is a public repo, you'll probably want to move the line with your key into `~/.npmrc` to keep it private. 17 | 18 | Then, install all dependencies using `npm`: 19 | 20 | ```sh 21 | $ npm install 22 | ``` 23 | 24 | Your `@remix-run/*` dependencies will come from the Remix package registry. 25 | 26 | ### First Run 27 | 28 | Before you can run the app in development you need link the project to a new vercel project on your account. 29 | 30 | ```sh 31 | $ vercel link 32 | ``` 33 | 34 | Follow the prompts, and when its done you should be able to get started: 35 | 36 | ```sh 37 | $ npm start 38 | ``` 39 | 40 | This will start the Remix's build watcher and the vercel development server. 41 | 42 | ## Deploying to Production 43 | 44 | You will need to add your npmrc with your Remix token inside it to your environments: 45 | 46 | ```bash 47 | $ vercel env add plain NPM_RC development < .npmrc 48 | $ vercel env add plain NPM_RC preview < .npmrc 49 | $ vercel env add plain NPM_RC production < .npmrc 50 | ``` 51 | 52 | Once that's done you can deploy! 53 | 54 | ```sh 55 | $ npm run build 56 | $ vercel 57 | ``` 58 | 59 | ## Documentation 60 | 61 | Detailed documentation for Remix [is available at remix.run](https://remix.run/dashboard/docs). 62 | -------------------------------------------------------------------------------- /app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | import ReactDOM from "react-dom"; 2 | import { RemixBrowser as Remix } from "@remix-run/react"; 3 | 4 | ReactDOM.hydrate( 5 | // @types/react-dom says the 2nd argument to ReactDOM.hydrate() must be a 6 | // `Element | DocumentFragment | null` but React 16 allows you to pass the 7 | // `document` object as well. This is a bug in @types/react-dom that we can 8 | // safely ignore for now. 9 | // @ts-ignore 10 | , 11 | document 12 | ); 13 | -------------------------------------------------------------------------------- /app/entry.server.tsx: -------------------------------------------------------------------------------- 1 | import ReactDOMServer from "react-dom/server"; 2 | import { RemixServer as Remix } from "@remix-run/react"; 3 | import type { EntryContext } from "@remix-run/node"; 4 | 5 | export default function handleRequest( 6 | request: Request, 7 | responseStatusCode: number, 8 | responseHeaders: Headers, 9 | remixContext: EntryContext 10 | ) { 11 | let markup = ReactDOMServer.renderToString( 12 | 13 | ); 14 | 15 | return new Response("" + markup, { 16 | status: responseStatusCode, 17 | headers: { 18 | ...Object.fromEntries(responseHeaders), 19 | "Content-Type": "text/html" 20 | } 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /app/root.tsx: -------------------------------------------------------------------------------- 1 | import type { LinksFunction, LoaderFunction } from "@remix-run/react"; 2 | import { Meta, Links, Scripts, useRouteData } from "@remix-run/react"; 3 | import { Outlet } from "react-router-dom"; 4 | 5 | import stylesUrl from "./styles/global.css"; 6 | 7 | export let links: LinksFunction = () => { 8 | return [{ rel: "stylesheet", href: stylesUrl }]; 9 | }; 10 | 11 | export let loader: LoaderFunction = () => { 12 | return { date: new Date() }; 13 | }; 14 | 15 | export default function App() { 16 | let data = useRouteData(); 17 | 18 | return ( 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |

This page was rendered at {data.date.toLocaleString()}

30 |
31 | 32 | 33 | 34 | ); 35 | } 36 | 37 | export function ErrorBoundary({ error }: { error: Error }) { 38 | return ( 39 | 40 | 41 | 42 | Oops! 43 | 44 | 45 |
46 |

App Error

47 |
{error.message}
48 |

49 | Replace this UI with what you want users to see when your app throws 50 | uncaught errors. The file is at app/App.tsx. 51 |

52 |
53 | 54 | 55 | 56 | 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /app/routes/404.tsx: -------------------------------------------------------------------------------- 1 | import type { MetaFunction } from "@remix-run/node"; 2 | 3 | export let meta: MetaFunction = () => { 4 | return { title: "Ain't nothing here" }; 5 | }; 6 | 7 | export default function FourOhFour() { 8 | return ( 9 |
10 |

404

11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /app/routes/index.tsx: -------------------------------------------------------------------------------- 1 | import type { 2 | MetaFunction, 3 | LinksFunction, 4 | LoaderFunction 5 | } from "@remix-run/react"; 6 | import { useRouteData } from "@remix-run/react"; 7 | 8 | import stylesUrl from "../styles/index.css"; 9 | 10 | export let meta: MetaFunction = () => { 11 | return { 12 | title: "Remix Starter", 13 | description: "Welcome to remix!" 14 | }; 15 | }; 16 | 17 | export let links: LinksFunction = () => { 18 | return [{ rel: "stylesheet", href: stylesUrl }]; 19 | }; 20 | 21 | export let loader: LoaderFunction = () => { 22 | return { message: "this is awesome 😎" }; 23 | }; 24 | 25 | export default function Index() { 26 | let data = useRouteData(); 27 | 28 | return ( 29 |
30 |

Welcome to Remix!

31 |

32 | Check out the docs to get 33 | started. 34 |

35 |

Message from the loader: {data.message}

36 |
37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /app/styles/global.css: -------------------------------------------------------------------------------- 1 | :focus:not(:focus-visible) { 2 | outline: none; 3 | } 4 | 5 | body { 6 | font-family: sans-serif; 7 | } 8 | 9 | footer { 10 | text-align: center; 11 | color: #ccc; 12 | padding-top: 80px; 13 | } 14 | -------------------------------------------------------------------------------- /app/styles/index.css: -------------------------------------------------------------------------------- 1 | /* 2 | * when the user visits this page, this style will apply, when they leave, it 3 | * will get unloaded, so don't worry so much about conflicting styles between 4 | * pages! 5 | */ 6 | -------------------------------------------------------------------------------- /app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "jsx": "react-jsx", 5 | "moduleResolution": "node", 6 | "target": "es2019", 7 | "strict": true, 8 | "skipLibCheck": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { createRequestHandler } = require("@remix-run/vercel"); 2 | module.exports = createRequestHandler({ 3 | build: require("./build") 4 | }); 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remix-starter-vercel", 3 | "private": true, 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "remix build2", 7 | "start": "concurrently \"remix run2\" \"vercel dev\"", 8 | "deploy": "vercel" 9 | }, 10 | "dependencies": { 11 | "@remix-run/node": "^0.15.1", 12 | "@remix-run/react": "^0.15.1", 13 | "@remix-run/vercel": "^0.15.1", 14 | "@vercel/node": "1.8.3", 15 | "react": "^17.0.1", 16 | "react-dom": "^17.0.1", 17 | "react-router-dom": "^6.0.0-beta.0" 18 | }, 19 | "devDependencies": { 20 | "@babel/core": "^7.11.6", 21 | "@babel/preset-env": "^7.13.10", 22 | "@babel/preset-react": "^7.12.13", 23 | "@babel/preset-typescript": "^7.13.0", 24 | "@remix-run/dev": "^0.15.1", 25 | "@types/react": "^17.0.0", 26 | "@types/react-dom": "^17.0.0", 27 | "concurrently": "^5.3.0", 28 | "typescript": "^4.1.2", 29 | "vercel": "^21.2.2" 30 | }, 31 | "engines": { 32 | "node": "14.x" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/starter-vercel/4487688282597d445ec04758ac4934fbb52d25d3/public/favicon.ico -------------------------------------------------------------------------------- /remix.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | /** 3 | * The path to the `app` directory, relative to remix.config.js. Defaults to 4 | * "app". All code in this directory is part of your app and will be compiled 5 | * by Remix. 6 | * 7 | * We prevent vercel from building when it deploys because it chokes on the 8 | * typescript files that Remix already built. 9 | */ 10 | appDirectory: "app", 11 | 12 | /** 13 | * A hook for defining custom routes based on your own file conventions. This 14 | * is not required, but may be useful if you have custom/advanced routing 15 | * requirements. 16 | */ 17 | // routes(defineRoutes) { 18 | // return defineRoutes(route => { 19 | // route( 20 | // // The URL path for this route. 21 | // "/pages/one", 22 | // // The path to this route's module file, relative to `appDirectory`. 23 | // "pages/one", 24 | // // Options: 25 | // { 26 | // // The path to this route's styles file, relative to `appDirectory`. 27 | // styles: "..." 28 | // } 29 | // ); 30 | // }); 31 | // }, 32 | 33 | /** 34 | * The path to the browser build, relative to remix.config.js. Defaults to 35 | * `public/build`. The browser build contains all public JavaScript and CSS 36 | * files that are created when building your routes. 37 | */ 38 | browserBuildDirectory: "public/build", 39 | 40 | /** 41 | * The URL prefix of the browser build with a trailing slash. Defaults to 42 | * `/build/`. 43 | */ 44 | publicPath: "/build/", 45 | 46 | /** 47 | * The path to the server build directory, relative to remix.config.js. 48 | * Defaults to `build`. The server build is a collection of JavaScript modules 49 | * that are created from building your routes. They are used on the server to 50 | * generate HTML. 51 | */ 52 | serverBuildDirectory: "build", 53 | 54 | /** 55 | * The port to use when running `remix run`. Defaults to 8002. 56 | */ 57 | devServerPort: 8002, 58 | }; 59 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "builds": [ 3 | { 4 | "src": "public/**/*", 5 | "use": "@vercel/static" 6 | }, 7 | { 8 | "src": "index.js", 9 | "use": "@vercel/node" 10 | } 11 | ], 12 | "rewrites": [ 13 | { 14 | "source": "/(.*)", 15 | "destination": "/public/$1" 16 | }, 17 | { 18 | "source": "/(.*)", 19 | "destination": "/" 20 | } 21 | ], 22 | "headers": [ 23 | { 24 | "source": "/build/(.*)", 25 | "headers": [ 26 | { 27 | "key": "Cache-Control", 28 | "value": "public, max-age=31536000" 29 | } 30 | ] 31 | } 32 | ] 33 | } 34 | --------------------------------------------------------------------------------