Contribution and Coding Guidelines
Use Volta
Because the deployment lambda utilizes specific versions of node and npm, it's best to mirror those in your local environment. The root package.json
specifies these as
"volta": {
"node": "16.18.1",
"npm": "8.19.2"
},
After installing Volta (and restarting your session!), your terminal will automatically switch to the correct node and npm versions specified.
Use npm Workspaces
The Helium
repo makes use of npm workspaces to link dependencies and facilitate the use of non-published packages within the repo. The majority of npm commands (such as adding or removing package dependencies) will take place in the root directory. After cloning the repository, running npm install will install all necessary dependencies as well as link any local dependencies.
When installing/uninstalling a dependency within a specific component, you can specify which package the dependency should be installed to by utilizing the -w
flag during install (Note: command should be run from root directory):
$ npm install example-dependency -w ./packages/example-component
When adding a new component you'll want to define a new workspace with npm init
(Note: command should be run from root directory):
$ npm init -w ./packages/new-example-component
This Header component is a helpful reference for the basic building blocks we'll need for each component.
Note:
- UI packages should be developed under the
/packages/
directory. - The package's
package.json.name
should be prefixed with@thoughtindustries/
and license should beMIT
. Note themain
andfiles
properties from existing packages as well: https://github.com/thoughtindustries/helium/blob/df3547c2a69dde9cf590f35cc3caae9e060098c8/packages/content/package.json#L8
Directory structure
For easier readability/navigating, graphql queries/mutations, hooks and rendering components should live in a separate directories. Example ideal structure: https://github.com/thoughtindustries/helium/tree/staging/packages/cart/src/core
Use GraphQL Codegen to generate hooks for queries and mutations
Prerequisites
We point to the remote URL for the Graphql endpoint to introspect the schema, which requires the endpoint to allow introspection.
Step 1: Install dependencies for Graphql Codegen toolings
Note: this is already setup in the root of Helium repo to support existing workspaces. Dependencies:
@graphql-codegen/cli
: GraphQL Code Generator CLI
@graphql-codegen/typescript-operations
: plugin to generate TypeScript types based on your GraphQLSchema and your GraphQL operations and fragments.
@graphql-codegen/near-operation-file-preset
: preset to generate a file per each GraphQL operation file. This preset works alongside @graphql-codegen/typescript-operations
.
@graphql-codegen/typescript-react-apollo
: plugin to generate React Apollo components with TypeScript typings.
@thoughtindustries/graphql-codegen-plugin
: plugin which extends the existing plugin @graphql-codegen/typescript
to generate only the object types used in operations, which is useful when working with a large Graphql schema since we don't want to expose all the typings. There is not yet a public plugin available to support this.
Step 2: Prepare codegen configuration file Note: this will be setup at the Helium workspace level.
Sample Configuration File:
# file located at <path_to_workspace>/codegen.yml
overwrite: true
schema: "https://home.thoughtindustries.com/helium?apiKey=***"
# # use the local copy of schema introspected from remote schema
# schema: "graphql.schema.json"
documents: "src/**/*.graphql"
config:
avoidOptionals: false
maybeValue: T
inlineFragmentTypes: 'combine'
scalars:
Slug: 'string'
Date: 'string'
JSON: 'any'
AbsoluteOrRelativeURL: 'string'
HexColor: 'string'
RelativeURL: 'string'
URL: 'string'
strictScalars: true
omitObjectTypes: false
preResolveTypes: true
generates:
# use this to re-generate global types from schema
src/graphql/global-types.ts:
plugins:
- "@thoughtindustries/graphql-codegen-plugin"
src/:
preset: near-operation-file
presetConfig:
# use a reduced global types scoped for content
baseTypesPath: graphql/global-types.ts
extension: .generated.tsx
plugins:
- "typescript-operations"
- "typescript-react-apollo"
# # use this to re-generate schema from remote schema
# ./graphql.schema.json:
# plugins:
# - "introspection"
Step 3: Prepare Graphql operation file Note: this will be setup at the Helium workspace level.
Sample File:
# file located at <path_to_workspace>/src/graphql/queries/RssItems.graphql
query RssItems($feedUrl: String!) {
RssItems(feedUrl: $feedUrl) {
title
link
}
}
Step 4: Run Graphql code generation
First, add the following script to the package.json
file at the Helium workspace level.
"scripts": {
"generate": "graphql-codegen --config codegen.yml"
},
Then, run the script at the Helium root level.
npm run generate -w ./<path_to_workspace>
Step 5: Verify generated files Note: the generated files will be located at the Helium workspace level.
According to the codegen configurations, the generated files would include:
a file with global typings, usually located at <path_to_workspace>/src/graphql/global-types.ts
next to each operation file. For example, if you have an operation file located at <path_to_workspace>/src/graphql/queries/RssItems.graphql
, the generated file will reside in the same directory named RssItems.generated.tsx
.
Include Readme and Storybook demonstrating use of component
Each package should include a Readme.md
demonstrating use of the component, as well as a Storybook story. Storybook can be run from the root with:
$ npm run storybook
Once running, the Storybook will be visible at localhost:6006
.
Beyond local development, the Storybook is also intended as a way for external users to preview the component library. Whenever component additions/changes are merged into main the Storybook is re-built and published here: https://thoughtindustries.github.io/helium.
Finally, tests! Because these tools and components are intended for external consumption, it's imperative that each is accompanied with a test suite. These are straightforward enough to set up, and simple to run with the command jest --watch
(Note: as with npm workspace commands, this should be run from root as well).
Note: Both Storybook and Jest are configured to find the necessary stories/tests
under /packages/*/stories/*.stories.tsx
and /packages/*/__tests__/*.test.tsx
, so no need to register them with either service.
Coding Guidelines
Names
- Use PascalCase for Component and Context/Provider functions, type names, and enum values.
- Use PascalCase for enum values.
- Use UPPER_SNAKE_CASE for constants used in the file scope.
- Use camelCase for property names and local variables.
- Use whole words in names when possible.
Components
- Use lowercase-hyphenated for filenames.
- Files with
.generated.*
suffix are auto-generated; do not hand-edit.
Types
- Do not export types/functions unless needed across multiple components.
- Shared types should be defined in
types.ts
. - Type definitions should come first in a file (after imports).
Comments
- Use JSDoc style comments when necessary.
Strings
- Use double quotes for strings.
- Where possible,
react-i18n
should be used for localization.
General
- Use
.forEach()
,.map()
,.filter()
, and other assorted array methods instead of loops when not strongly inconvenient. - Components are designed to be used in projects hosted on Cloudflare Workers. It is worth reviewing Node.js compatibility when implementing functionality that relies on the Node.js runtime.
Style
- Use arrow functions over anonymous function expressions.
- Surround arrow function parameters only when necessary.
- Use a single declaration per variable statement.
- Use 2 spaces per indentation.