Skip to content

Commit

Permalink
Extract logic to monorepo packages: UI package, "client-hints" packag…
Browse files Browse the repository at this point in the history
…e, and config (tsconfig, eslint) packages. (#3)

With this commit we begin to extract some logic from the epic-stack app into their own packages.

* Add @epic-stack-monorepo/ui package containing Components and utilities that were present in the APP before. This package also contains the icons build step. This package has a tsup build step but we are actually exporting ts source files directly, Remix will compile it.
* Add @epic-stack-monorepo/client-hints package containing the logic of client hints that was previously in the utils folder.
* Add config packages for eslint and tsconfig.
  • Loading branch information
PhilDL committed Sep 23, 2023
1 parent a824868 commit 33997f9
Show file tree
Hide file tree
Showing 126 changed files with 3,219 additions and 661 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,7 @@ jobs:
deploy:
name: 🚀 Deploy
runs-on: ubuntu-latest
# needs: [lint, typecheck, vitest, playwright, build]
needs: [lint, typecheck, vitest, build]
needs: [lint, typecheck, vitest, playwright, build]
# only build/deploy main branch on pushes
if:
${{ (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev') &&
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
node_modules
.DS_store

/packages/**/build
/packages/**/dist

/apps/**/build
/apps/**/public/build
/apps/**/server-build
Expand Down
107 changes: 102 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,35 @@
</p>
</div>

## Epic Stack Monorepo Example

This monorepo was created with `pnpm` for space efficiency and more convienence
in monorepos than `npm`.
in monorepos than `npm`. On top of that package manager the monorepo pipeline
tool of choice is turborepo (feel free to switch it for NX).

- `apps` Folder containing the applications
- [`epic-app`](https://github.com/PhilDL/epic-stack-monorepo/tree/main/apps/epic-app):
the [Remix.run](https://remix.run) Epic Stack app.
- `packages` Folder containing examples

- [`ui`](https://github.com/PhilDL/epic-stack-monorepo/tree/main/packages/ui):
this UI package contains the [shadcn/ui](https://ui.shadcn.com/) Component
previously in the Epic Stack App. It also exposes a Tailwind config
"epic-stack" preset, that you consume from the Remix app.
- [`client-hints`](https://github.com/PhilDL/epic-stack-monorepo/tree/main/packages/client-hints):
is an example package that takes the original functions and hooks handling
client-hints in the `utils` folder of the original app, and put that into
their own package.
[`The hooks`](https://github.com/PhilDL/epic-stack-monorepo/tree/main/packages/client-hints/src/client-hints.tsx):
were refactored to take "loader" as generics (typically the root loader).
- Some config packages:
- eslint containing some common eslint configs.
- tsconfig presets.

## Local development

All the following commands are run from the root of the monorepo.
> **Warning** All the following commands should be launched from the **monorepo
> root directory**
### Install dependencies

Expand All @@ -26,14 +49,88 @@ pnpm i

Given the name of our app in `package.json` is `@epic-stack-monorepo/epic-app`:

Turborepo is used here to have pipeline between packages. The setup here is
basic, and you can see turbo as just a way to run the same `pnpm` command in all
packages, for example:

### Build all packages

```bash
pnpm run --filter @epic-stack-monorepo/epic-app build
pnpm build
```

### Dev all packages

```bash
pnpm dev
```

All turborepo // pnpm commands can be filtered to a specific package with the
`--filter` flag. For example:

### To Work on the Remix Epic Stack app

```bash
pnpm dev --filter=@epic-stack-monorepo/epic-app
```

### Dev epic-stack app
You could also use `...` to run dev also on all the workspace packages deps:

```bash
pnpm dev --filter=@epic-stack-monorepo/epic-app...
```

(This will also run the dev command on `@epic-stack-monorepo/client-hints` and
`@epic-stack-monorepo/ui`).

## Install package in a specific package

```bash
pnpm run --filter @epic-stack-monorepo/epic-app dev
pnpm add -D chokidar --filter=@epic-stack-monorepo/ui
```

This will install `chokidar` in the `@epic-stack-monorepo/ui` package.

# Original documentation

```sh
npx create-remix@latest --install --init --git-init --template epicweb-dev/epic-stack
```

[![The Epic Stack](https://github-production-user-asset-6210df.s3.amazonaws.com/1500684/246885449-1b00286c-aa3d-44b2-9ef2-04f694eb3592.png)](https://www.epicweb.dev/epic-stack)

[The Epic Stack](https://www.epicweb.dev/epic-stack)

<hr />

## Watch Kent's Introduction to The Epic Stack

[![screenshot of a YouTube video](https://github-production-user-asset-6210df.s3.amazonaws.com/1500684/242088051-6beafa78-41c6-47e1-b999-08d3d3e5cb57.png)](https://www.youtube.com/watch?v=yMK5SVRASxM)

["The Epic Stack" by Kent C. Dodds at #RemixConf 2023 💿](https://www.youtube.com/watch?v=yMK5SVRASxM)

## Docs

[Read the docs](https://github.com/epicweb-dev/epic-stack/blob/main/docs)
(please 🙏).

## Support

- 🆘 Join the
[discussion on GitHub](https://github.com/epicweb-dev/epic-stack/discussions)
and the [KCD Community on Discord](https://kcd.im/discord).
- 💡 Create an
[idea discussion](https://github.com/epicweb-dev/epic-stack/discussions/new?category=ideas)
for suggestions.
- 🐛 Open a [GitHub issue](https://github.com/epicweb-dev/epic-stack/issues) to
report a bug.

## Branding

Want to talk about the Epic Stack in a blog post or talk? Great! Here are some
assets you can use in your material:
[EpicWeb.dev/brand](https://epicweb.dev/brand)

## Thanks

You rock 🪨
86 changes: 1 addition & 85 deletions apps/epic-app/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,85 +1 @@
const vitestFiles = ['app/**/__tests__/**/*', 'app/**/*.{spec,test}.*']
const testFiles = ['**/tests/**', ...vitestFiles]
const appFiles = ['app/**']

/** @type {import('@types/eslint').Linter.BaseConfig} */
module.exports = {
extends: [
'@remix-run/eslint-config',
'@remix-run/eslint-config/node',
'prettier',
],
rules: {
// playwright requires destructuring in fixtures even if you don't use anything 🤷‍♂️
'no-empty-pattern': 'off',
'@typescript-eslint/consistent-type-imports': [
'warn',
{
prefer: 'type-imports',
disallowTypeAnnotations: true,
fixStyle: 'inline-type-imports',
},
],
'import/no-duplicates': ['warn', { 'prefer-inline': true }],
'import/consistent-type-specifier-style': ['warn', 'prefer-inline'],
'import/order': [
'warn',
{
alphabetize: { order: 'asc', caseInsensitive: true },
groups: [
'builtin',
'external',
'internal',
'parent',
'sibling',
'index',
],
},
],
},
overrides: [
{
plugins: ['remix-react-routes'],
files: appFiles,
excludedFiles: testFiles,
rules: {
'remix-react-routes/use-link-for-routes': 'error',
'remix-react-routes/require-valid-paths': 'error',
// disable this one because it doesn't appear to work with our
// route convention. Someone should dig deeper into this...
'remix-react-routes/no-relative-paths': [
'off',
{ allowLinksToSelf: true },
],
'remix-react-routes/no-urls': 'error',
'no-restricted-imports': [
'error',
{
patterns: [
{
group: testFiles,
message: 'Do not import test files in app files',
},
],
},
],
},
},
{
extends: ['@remix-run/eslint-config/jest-testing-library'],
files: vitestFiles,
rules: {
'testing-library/no-await-sync-events': 'off',
'jest-dom/prefer-in-document': 'off',
},
// 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,
},
},
},
],
}
module.exports = require('@epic-stack-monorepo/eslint-config/remix.cjs')
2 changes: 1 addition & 1 deletion apps/epic-app/app/components/error-boundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function GeneralErrorBoundary({
}

return (
<div className="container flex items-center justify-center p-20 text-h2">
<div className="text-h2 container flex items-center justify-center p-20">
{isRouteErrorResponse(error)
? (statusHandlers?.[error.status] ?? defaultStatusHandler)({
error,
Expand Down
12 changes: 6 additions & 6 deletions apps/epic-app/app/components/forms.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useInputEvent } from '@conform-to/react'
import { Checkbox, type CheckboxProps } from '@epic-stack-monorepo/ui/checkbox'
import { Input } from '@epic-stack-monorepo/ui/input'
import { Label } from '@epic-stack-monorepo/ui/label'
import { Textarea } from '@epic-stack-monorepo/ui/textarea'
import React, { useId, useRef } from 'react'
import { Checkbox, type CheckboxProps } from './ui/checkbox.tsx'
import { Input } from './ui/input.tsx'
import { Label } from './ui/label.tsx'
import { Textarea } from './ui/textarea.tsx'

export type ListOfErrors = Array<string | null | undefined> | null | undefined

Expand All @@ -19,7 +19,7 @@ export function ErrorList({
return (
<ul id={id} className="flex flex-col gap-1">
{errorsToRender.map(e => (
<li key={e} className="text-[10px] text-foreground-danger">
<li key={e} className="text-foreground-danger text-[10px]">
{e}
</li>
))}
Expand Down Expand Up @@ -137,7 +137,7 @@ export function CheckboxField({
<label
htmlFor={id}
{...labelProps}
className="self-center text-body-xs text-muted-foreground"
className="text-body-xs text-muted-foreground self-center"
/>
</div>
<div className="px-4 pb-3 pt-1">
Expand Down
8 changes: 4 additions & 4 deletions apps/epic-app/app/components/search-bar.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Icon } from '@epic-stack-monorepo/ui/icon'
import { Input } from '@epic-stack-monorepo/ui/input'
import { Label } from '@epic-stack-monorepo/ui/label'
import { StatusButton } from '@epic-stack-monorepo/ui/status-button'
import { Form, useSearchParams, useSubmit } from '@remix-run/react'
import { useDebounce, useIsPending } from '#app/utils/misc.tsx'
import { Icon } from './ui/icon.tsx'
import { Input } from './ui/input.tsx'
import { Label } from './ui/label.tsx'
import { StatusButton } from './ui/status-button.tsx'

export function SearchBar({
status,
Expand Down
30 changes: 0 additions & 30 deletions apps/epic-app/app/components/ui/icons/name.d.ts

This file was deleted.

25 changes: 0 additions & 25 deletions apps/epic-app/app/components/ui/input.tsx

This file was deleted.

0 comments on commit 33997f9

Please sign in to comment.