diff --git a/.eslintrc.cjs b/.eslintrc.cjs
new file mode 100644
index 00000000..67a6f3a2
--- /dev/null
+++ b/.eslintrc.cjs
@@ -0,0 +1,136 @@
+/**
+ * This is intended to be a basic starting point for linting in the Indie Stack.
+ * It relies on recommended configs out of the box for simplicity, but you can
+ * and should modify this configuration to best suit your team's needs.
+ */
+
+/** @type {import('eslint').Linter.Config} */
+module.exports = {
+ root: true,
+ parserOptions: {
+ ecmaVersion: "latest",
+ sourceType: "module",
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+ env: {
+ browser: true,
+ commonjs: true,
+ es6: true,
+ },
+
+ // Base config
+ extends: ["eslint:recommended"],
+
+ overrides: [
+ // React
+ {
+ files: ["**/*.{js,jsx,ts,tsx}"],
+ plugins: ["react", "jsx-a11y"],
+ extends: [
+ "plugin:react/recommended",
+ "plugin:react/jsx-runtime",
+ "plugin:react-hooks/recommended",
+ "plugin:jsx-a11y/recommended",
+ "prettier",
+ ],
+ settings: {
+ react: {
+ version: "detect",
+ },
+ formComponents: ["Form"],
+ linkComponents: [
+ { name: "Link", linkAttribute: "to" },
+ { name: "NavLink", linkAttribute: "to" },
+ ],
+ },
+ rules: {
+ "react/jsx-no-leaked-render": [
+ "warn",
+ { validStrategies: ["ternary"] },
+ ],
+ },
+ },
+
+ // Typescript
+ {
+ files: ["**/*.{ts,tsx}"],
+ plugins: ["@typescript-eslint", "import"],
+ parser: "@typescript-eslint/parser",
+ settings: {
+ "import/internal-regex": "^~/",
+ "import/resolver": {
+ node: {
+ extensions: [".ts", ".tsx"],
+ },
+ typescript: {
+ alwaysTryTypes: true,
+ },
+ },
+ },
+ extends: [
+ "plugin:@typescript-eslint/recommended",
+ "plugin:@typescript-eslint/stylistic",
+ "plugin:import/recommended",
+ "plugin:import/typescript",
+ "prettier",
+ ],
+ rules: {
+ "import/order": [
+ "error",
+ {
+ alphabetize: { caseInsensitive: true, order: "asc" },
+ groups: ["builtin", "external", "internal", "parent", "sibling"],
+ "newlines-between": "always",
+ },
+ ],
+ },
+ },
+
+ // Markdown
+ {
+ files: ["**/*.md"],
+ plugins: ["markdown"],
+ extends: ["plugin:markdown/recommended-legacy", "prettier"],
+ },
+
+ // Jest/Vitest
+ {
+ files: ["**/*.test.{js,jsx,ts,tsx}"],
+ plugins: ["jest", "jest-dom", "testing-library"],
+ extends: [
+ "plugin:jest/recommended",
+ "plugin:jest-dom/recommended",
+ "plugin:testing-library/react",
+ "prettier",
+ ],
+ env: {
+ "jest/globals": true,
+ },
+ settings: {
+ jest: {
+ // We're using vitest which has a very similar API to jest
+ // (so the linting plugins work nicely), but it means we
+ // have to set the jest version explicitly.
+ version: 28,
+ },
+ },
+ },
+
+ // Cypress
+ {
+ files: ["cypress/**/*.ts"],
+ plugins: ["cypress"],
+ extends: ["plugin:cypress/recommended", "prettier"],
+ },
+
+ // Node
+ {
+ files: [".eslintrc.js", "mocks/**/*.js"],
+ env: {
+ node: true,
+ },
+ },
+ ],
+};
diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index 8ab077d6..00000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/** @type {import('@types/eslint').Linter.BaseConfig} */
-module.exports = {
- extends: [
- "@remix-run/eslint-config",
- "@remix-run/eslint-config/node",
- "@remix-run/eslint-config/jest-testing-library",
- "prettier",
- ],
- env: {
- "cypress/globals": true,
- },
- plugins: ["cypress"],
- // we're using vitest which has a very similar API to jest
- // (so the linting plugins work nicely), but it means we have to explicitly
- // set the jest version.
- settings: {
- jest: {
- version: 28,
- },
- },
-};
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index c78eb1b6..8f7ec3ce 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -1,10 +1,15 @@
name: đ Deploy
+
on:
push:
branches:
- main
- dev
- pull_request: {}
+ pull_request:
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
permissions:
actions: write
@@ -15,21 +20,18 @@ jobs:
name: ⏣ ESLint
runs-on: ubuntu-latest
steps:
- - name: đ Cancel Previous Runs
- uses: styfle/cancel-workflow-action@0.10.0
-
- name: âŹď¸ Checkout repo
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: â Setup node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: 16
+ cache: npm
+ cache-dependency-path: ./package.json
+ node-version: 18
- - name: đĽ Download deps
- uses: bahmutov/npm-install@v1
- with:
- useLockFile: false
+ - name: đĽ Install deps
+ run: npm install
- name: đŹ Lint
run: npm run lint
@@ -38,21 +40,18 @@ jobs:
name: ĘŚ TypeScript
runs-on: ubuntu-latest
steps:
- - name: đ Cancel Previous Runs
- uses: styfle/cancel-workflow-action@0.10.0
-
- name: âŹď¸ Checkout repo
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: â Setup node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: 16
+ cache: npm
+ cache-dependency-path: ./package.json
+ node-version: 18
- - name: đĽ Download deps
- uses: bahmutov/npm-install@v1
- with:
- useLockFile: false
+ - name: đĽ Install deps
+ run: npm install
- name: đ Type check
run: npm run typecheck --if-present
@@ -61,21 +60,18 @@ jobs:
name: ⥠Vitest
runs-on: ubuntu-latest
steps:
- - name: đ Cancel Previous Runs
- uses: styfle/cancel-workflow-action@0.10.0
-
- name: âŹď¸ Checkout repo
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: â Setup node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: 16
+ cache: npm
+ cache-dependency-path: ./package.json
+ node-version: 18
- - name: đĽ Download deps
- uses: bahmutov/npm-install@v1
- with:
- useLockFile: false
+ - name: đĽ Install deps
+ run: npm install
- name: ⥠Run vitest
run: npm run test -- --coverage
@@ -84,24 +80,21 @@ jobs:
name: âŤď¸ Cypress
runs-on: ubuntu-latest
steps:
- - name: đ Cancel Previous Runs
- uses: styfle/cancel-workflow-action@0.10.0
-
- name: âŹď¸ Checkout repo
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: đ Copy test env vars
run: cp .env.example .env
- name: â Setup node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: 16
+ cache: npm
+ cache-dependency-path: ./package.json
+ node-version: 18
- - name: đĽ Download deps
- uses: bahmutov/npm-install@v1
- with:
- useLockFile: false
+ - name: đĽ Install deps
+ run: npm install
- name: đ Setup Database
run: npx prisma migrate reset --force
@@ -110,105 +103,42 @@ jobs:
run: npm run build
- name: đł Cypress run
- uses: cypress-io/github-action@v4
+ uses: cypress-io/github-action@v6
with:
start: npm run start:mocks
- wait-on: "http://localhost:8811"
+ wait-on: http://localhost:8811
env:
- PORT: "8811"
-
- build:
- name: đł Build
- # only build/deploy main branch on pushes
- if: ${{ (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev') && github.event_name == 'push' }}
- runs-on: ubuntu-latest
- steps:
- - name: đ Cancel Previous Runs
- uses: styfle/cancel-workflow-action@0.10.0
-
- - name: âŹď¸ Checkout repo
- uses: actions/checkout@v3
-
- - name: đ Read app name
- uses: SebRollen/toml-action@v1.0.0
- id: app_name
- with:
- file: "fly.toml"
- field: "app"
-
- - name: đł Set up Docker Buildx
- uses: docker/setup-buildx-action@v2
-
- # Setup cache
- - name: âĄď¸ Cache Docker layers
- uses: actions/cache@v3
- with:
- path: /tmp/.buildx-cache
- key: ${{ runner.os }}-buildx-${{ github.sha }}
- restore-keys: |
- ${{ runner.os }}-buildx-
-
- - name: đ Fly Registry Auth
- uses: docker/login-action@v2
- with:
- registry: registry.fly.io
- username: x
- password: ${{ secrets.FLY_API_TOKEN }}
-
- - name: đł Docker build
- uses: docker/build-push-action@v3
- with:
- context: .
- push: true
- tags: registry.fly.io/${{ steps.app_name.outputs.value }}:${{ github.ref_name }}-${{ github.sha }}
- build-args: |
- COMMIT_SHA=${{ github.sha }}
- cache-from: type=local,src=/tmp/.buildx-cache
- cache-to: type=local,mode=max,dest=/tmp/.buildx-cache-new
-
- # This ugly bit is necessary if you don't want your cache to grow forever
- # till it hits GitHub's limit of 5GB.
- # Temp fix
- # https://github.com/docker/build-push-action/issues/252
- # https://github.com/moby/buildkit/issues/1896
- - name: đ Move cache
- run: |
- rm -rf /tmp/.buildx-cache
- mv /tmp/.buildx-cache-new /tmp/.buildx-cache
+ PORT: 8811
deploy:
name: đ Deploy
runs-on: ubuntu-latest
- needs: [lint, typecheck, vitest, cypress, build]
- # only build/deploy main branch on pushes
+ needs: [lint, typecheck, vitest, cypress]
+ # only deploy main/dev branch on pushes
if: ${{ (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev') && github.event_name == 'push' }}
steps:
- - name: đ Cancel Previous Runs
- uses: styfle/cancel-workflow-action@0.10.0
-
- name: âŹď¸ Checkout repo
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: đ Read app name
- uses: SebRollen/toml-action@v1.0.0
+ uses: SebRollen/toml-action@v1.2.0
id: app_name
with:
- file: "fly.toml"
- field: "app"
+ file: fly.toml
+ field: app
+
+ - name: đ Setup Fly
+ uses: superfly/flyctl-actions/setup-flyctl@v1
- name: đ Deploy Staging
if: ${{ github.ref == 'refs/heads/dev' }}
- uses: superfly/flyctl-actions@1.3
- with:
- args: "deploy --app ${{ steps.app_name.outputs.value }}-staging --image registry.fly.io/${{ steps.app_name.outputs.value }}:${{ github.ref_name }}-${{ github.sha }}"
+ run: flyctl deploy --remote-only --build-arg COMMIT_SHA=${{ github.sha }} --app ${{ steps.app_name.outputs.value }}-staging
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
- name: đ Deploy Production
if: ${{ github.ref == 'refs/heads/main' }}
- uses: superfly/flyctl-actions@1.3
- with:
- args: "deploy --image registry.fly.io/${{ steps.app_name.outputs.value }}:${{ github.ref_name }}-${{ github.sha }}"
+ run: flyctl deploy --remote-only --build-arg COMMIT_SHA=${{ github.sha }} --app ${{ steps.app_name.outputs.value }}
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
diff --git a/.github/workflows/format-repo.yml b/.github/workflows/format-repo.yml
new file mode 100644
index 00000000..240b0ecc
--- /dev/null
+++ b/.github/workflows/format-repo.yml
@@ -0,0 +1,46 @@
+name: đ Format
+
+on:
+ push:
+ branches:
+ - main
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ format:
+ if: github.repository == 'remix-run/indie-stack'
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: âŹď¸ Checkout repo
+ uses: actions/checkout@v4
+
+ - name: â Setup node
+ uses: actions/setup-node@v4
+ with:
+ cache: npm
+ cache-dependency-path: ./package.json
+ node-version: 18
+
+ - name: đĽ Install deps
+ run: npm install
+
+ - name: đ Format
+ run: npm run format:repo
+
+ - name: đŞ Commit
+ run: |
+ git config --local user.email "github-actions[bot]@users.noreply.github.com"
+ git config --local user.name "github-actions[bot]"
+
+ git add .
+ if [ -z "$(git status --porcelain)" ]; then
+ echo "đż no formatting changed"
+ exit 0
+ fi
+ git commit -m "chore: format"
+ git push
+ echo "đż pushed formatting changes https://github.com/$GITHUB_REPOSITORY/commit/$(git rev-parse HEAD)"
diff --git a/.github/workflows/lint-repo.yml b/.github/workflows/lint-repo.yml
new file mode 100644
index 00000000..b2d38564
--- /dev/null
+++ b/.github/workflows/lint-repo.yml
@@ -0,0 +1,33 @@
+name: ⏣ Lint repository
+
+on:
+ push:
+ branches:
+ - main
+ - dev
+ pull_request:
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ lint:
+ name: ⏣ Lint repo
+ runs-on: ubuntu-latest
+ steps:
+ - name: âŹď¸ Checkout repo
+ uses: actions/checkout@v4
+
+ - name: â Setup node
+ uses: actions/setup-node@v4
+ with:
+ cache: npm
+ cache-dependency-path: ./package.json
+ node-version: 18
+
+ - name: đĽ Install deps
+ run: npm install
+
+ - name: đŹ Lint
+ run: npm run lint
diff --git a/.github/workflows/no-response.yml b/.github/workflows/no-response.yml
new file mode 100644
index 00000000..96426f67
--- /dev/null
+++ b/.github/workflows/no-response.yml
@@ -0,0 +1,34 @@
+name: 𼺠No Response
+
+on:
+ schedule:
+ # Schedule for five minutes after the hour, every hour
+ - cron: "5 * * * *"
+
+permissions:
+ issues: write
+ pull-requests: write
+
+jobs:
+ stale:
+ if: github.repository == 'remix-run/indie-stack'
+ runs-on: ubuntu-latest
+ steps:
+ - name: 𼺠Handle Ghosting
+ uses: actions/stale@v9
+ with:
+ days-before-close: 10
+ close-issue-message: >
+ This issue has been automatically closed because we haven't received a
+ response from the original author đ. This automation helps keep the issue
+ tracker clean from issues that are unactionable. Please reach out if you
+ have more information for us! đ
+ close-pr-message: >
+ This PR has been automatically closed because we haven't received a
+ response from the original author đ. This automation helps keep the issue
+ tracker clean from PRs that are unactionable. Please reach out if you
+ have more information for us! đ
+ # don't automatically mark issues/PRs as stale
+ days-before-stale: -1
+ stale-issue-label: needs-response
+ stale-pr-label: needs-response
diff --git a/.gitignore b/.gitignore
index ca3adffb..d5f63bb4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,10 @@
# We don't want lockfiles in stacks, as people could use a different package manager
# This part will be removed by `remix.init`
+bun.lockb
package-lock.json
-yarn.lock
pnpm-lock.yaml
pnpm-lock.yml
+yarn.lock
node_modules
@@ -15,5 +16,3 @@ node_modules
/cypress/videos
/prisma/data.db
/prisma/data.db-journal
-
-/app/styles/tailwind.css
diff --git a/Dockerfile b/Dockerfile
index db9ea014..093ace78 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
# base node image
-FROM node:16-bullseye-slim as base
+FROM node:18-bullseye-slim as base
# set for base and all layer that inherit from it
ENV NODE_ENV production
@@ -13,7 +13,7 @@ FROM base as deps
WORKDIR /myapp
ADD package.json .npmrc ./
-RUN npm install --production=false
+RUN npm install --include=dev
# Setup production node_modules
FROM base as production-deps
@@ -22,7 +22,7 @@ WORKDIR /myapp
COPY --from=deps /myapp/node_modules /myapp/node_modules
ADD package.json .npmrc ./
-RUN npm prune --production
+RUN npm prune --omit=dev
# Build the app
FROM base as build
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 00000000..8ed8d952
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,22 @@
+MIT License
+
+Copyright (c) Remix Software Inc. 2021
+Copyright (c) Shopify Inc. 2022-2023
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index b4196bd9..8687ded0 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,17 @@
+> [!NOTE]
+> This repo has been archived. Please refer instead to:
+> - The official [React Router templates](https://github.com/remix-run/react-router-templates/) for simple templates to get started with
+> - [The Epic Stack](https://github.com/epicweb-dev/epic-stack) for a more comprehensive, batteries-included option
+> - [Remix Discord](https://rmx.as/discord) to ask and share community templates
+
# Remix Indie Stack

Learn more about [Remix Stacks](https://remix.run/stacks).
-```
-npx create-remix --template remix-run/indie-stack
+```sh
+npx create-remix@latest --template remix-run/indie-stack
```
## What's in the stack
@@ -14,7 +20,7 @@ npx create-remix --template remix-run/indie-stack
- Production-ready [SQLite Database](https://sqlite.org)
- Healthcheck endpoint for [Fly backups region fallbacks](https://fly.io/docs/reference/configuration/#services-http_checks)
- [GitHub Actions](https://github.com/features/actions) for deploy on merge to production and staging environments
-- Email/Password Authentication with [cookie-based sessions](https://remix.run/docs/en/v1/api/remix#createcookiesessionstorage)
+- Email/Password Authentication with [cookie-based sessions](https://remix.run/utils/sessions#md-createcookiesessionstorage)
- Database ORM with [Prisma](https://prisma.io)
- Styling with [Tailwind](https://tailwindcss.com/)
- End-to-end testing with [Cypress](https://cypress.io)
@@ -30,17 +36,20 @@ Not a fan of bits of the stack? Fork it, change it, and use `npx create-remix --
Click this button to create a [Gitpod](https://gitpod.io) workspace with the project set up and Fly pre-installed
-[](https://gitpod.io/from-referrer/)
+[](https://gitpod.io/#https://github.com/remix-run/indie-stack/tree/main)
## Development
-- This step only applies if you've opted out of having the CLI install dependencies for you:
-
+- First run this stack's `remix.init` script and commit the changes it makes to your project.
+
```sh
npx remix init
+ git init # if you haven't already
+ git add .
+ git commit -m "Initialize project"
```
-- Initial setup: _If you just generated this project, this step has been done for you._
+- Initial setup:
```sh
npm run setup
@@ -89,6 +98,7 @@ Prior to your first deployment, you'll need to do a few things:
fly apps create indie-stack-template
fly apps create indie-stack-template-staging
```
+
> **Note:** Make sure this name matches the `app` set in your `fly.toml` file. Otherwise, you will not be able to deploy.
- Initialize Git.
@@ -112,7 +122,7 @@ Prior to your first deployment, you'll need to do a few things:
fly secrets set SESSION_SECRET=$(openssl rand -hex 32) --app indie-stack-template-staging
```
- If you don't have openssl installed, you can also use [1password](https://1password.com/password-generator/) to generate a random secret, just replace `$(openssl rand -hex 32)` with the generated secret.
+ If you don't have openssl installed, you can also use [1Password](https://1password.com/password-generator) to generate a random secret, just replace `$(openssl rand -hex 32)` with the generated secret.
- Create a persistent volume for the sqlite database for both your staging and production environments. Run the following:
@@ -172,7 +182,7 @@ This project uses TypeScript. It's recommended to get TypeScript set up for your
### Linting
-This project uses ESLint for linting. That is configured in `.eslintrc.js`.
+This project uses ESLint for linting. That is configured in `.eslintrc.cjs`.
### Formatting
diff --git a/app/db.server.ts b/app/db.server.ts
index 843cc97e..ac5701fa 100644
--- a/app/db.server.ts
+++ b/app/db.server.ts
@@ -1,23 +1,9 @@
import { PrismaClient } from "@prisma/client";
-let prisma: PrismaClient;
+import { singleton } from "./singleton.server";
-declare global {
- var __db__: PrismaClient;
-}
-
-// this is needed because in development we don't want to restart
-// the server with every change, but we want to make sure we don't
-// create a new connection to the DB with every change either.
-// in production we'll have a single connection to the DB.
-if (process.env.NODE_ENV === "production") {
- prisma = new PrismaClient();
-} else {
- if (!global.__db__) {
- global.__db__ = new PrismaClient();
- }
- prisma = global.__db__;
- prisma.$connect();
-}
+// Hard-code a unique key, so we can look up the client when this module gets re-imported
+const prisma = singleton("prisma", () => new PrismaClient());
+prisma.$connect();
export { prisma };
diff --git a/app/entry.client.tsx b/app/entry.client.tsx
index 1d4ba68d..186cd934 100644
--- a/app/entry.client.tsx
+++ b/app/entry.client.tsx
@@ -1,22 +1,18 @@
+/**
+ * By default, Remix will handle hydrating your app on the client for you.
+ * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` â¨
+ * For more information, see https://remix.run/docs/en/main/file-conventions/entry.client
+ */
+
import { RemixBrowser } from "@remix-run/react";
import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
-const hydrate = () => {
- startTransition(() => {
- hydrateRoot(
- document,
-