- Monorepo Structure: Managed with Lerna, containing multiple packages:
packages/api: GraphQL API server using PostGraphile.packages/client: React SPA built with Create React App.packages/infra: AWS CDK app defining production infrastructure.- There are several other packages to support different "tasks" using AWS lambda and cloudflare workers, as well as extra modules used by one or more of the main api and client projects.
- TypeScript: Primary language across the codebase.
- React: Functional components with Hooks.
- GraphQL: All data is sent to/from the client using GraphQL
- Styling: Tailwind CSS
- Naming:
- Variables and functions:
camelCase. - Classes and components:
PascalCase.
- Variables and functions:
- Imports:
- Use absolute imports where possible.
- Components:
- Prefer functional components with Hooks.
- Use default exports, prefering a single component per file. If there are groups of related components, create a directory to organize them.
- Where possible, reuse components in
packages/client/src/components/. Particularly the modal component. When 3rd party components are needed, prefer Radix UI. - Icons - Use Radix icons where available, and fall back to heroicons. Both are already installed.
- Code Style
- Follow the conventions defined in
packages/client/.eslintrc.js, and.vscode/settings.json.
- Follow the conventions defined in
- i18n
- Client code eslint rules disallow untranslated strings. Readable content should be wrapped in a Trans component with an appropriate namespace, or use a component-level translate function. Trans tags are better for string content mixed with html tags. For quoted strings that don't need to be translated, use a special comment to disable the rule for that line (// eslint-disable-next-line i18next/no-literal-string)
- Don't ever modify json files in packages/client/src/lang/ -- Those are automatically generated!
- Typescript features
- Our graphql codegen process uses an older babel system to parse code and extract gql strings. Don't use
import typesyntax anywhere in the client, or in code that is imported by it or there will be trouble. Check theGraphQL:codegenterminal task for errors caused by usage of this syntax.
- Our graphql codegen process uses an older babel system to parse code and extract gql strings. Don't use
// packages/client/src/components/MyComponent.tsx
import React from "react";
import { Trans, useTranslation } from "react-i18next";
interface MyComponentProps {
title: string;
}
export const MyComponent: React.FC<MyComponentProps> = ({ title }) => {
const { t } = useTranslation("homepage");
return (
<div>
<h1>{title}</h1>
<button>{t("Go Back")}</button>
<p>
<Trans ns="homepage">
Visit the <a href="https://www.seasketch.org">SeaSketch Homepage</a>
</Trans>
</p>
</div>
);
};- The capabilities of the GraphQL API are defined in
packages/api/generated-schema.gql. - When a new query or mutation is necessary, create it in
packages/api/migrations/current.sql, following the guidance of the PostGraphile documentation at https://www.graphile.org/postgraphile/introduction/. Never create a migration file inpackages/api/migrations/committeddirectly. If a mutation or query is particularly complex, it can be implemented as a plugin underpackages/api/src/plugins. - Never directly edit client/src/generated/* files! If you need to modify queries and related auto-generated types, edit .graphql files and run the
graphql:codegennpm script to regenerate these files.
- Whenever making changes to the client, run
npm run lintfrompackages/clientto ensure there are no linter errors that will break the build.
When implementing Report Widgets (and spatial analysis features generally), refer to packages/client/reports/widgets/README.md file for details on the architecture, user interface, and implementation conventions.