Developing Primer App

August 8, 2023 ยท View on GitHub

With Nix

We use Nix flakes to develop Primer App, so most of our developer documentation assumes you've got a working Nix installation with flakes support enabled, and that you're running any given commands in the project's nix develop shell.

Our flake supports both x86_64-linux and aarch64-darwin systems. Adding support for other common architectures should be straightforward, but we don't currently have the CI resources to support them. Please let us know if you'd like to contribute, but can't because your development platform of choice is not included in our flake.

For faster Nix builds of our project, assuming you're using one of our supported systems, you can make use of our public Cachix cache by adding the following to your Nix config:

nix.settings.substituters = [
  "https://hackworthltd.cachix.org"
];
nix.settings.trusted-public-keys = [
  "hackworthltd.cachix.org-1:0JTCI0qDo2J+tonOalrSQP3yRNleN6bQucJ05yDltRI="
];

Note that, out of an abundance of caution, we only push continuous integration (CI) build artifacts from this project to the public Cachix cache upon merges to the project's main branch. Build artifacts generated by our CI when building GitHub pull requests (PR's) are not cached in the public cache. This does mean that there may be a slight delay between when a PR is merged to main and when its build artifacts are available in the cache.

Node.js and Nix

In our experience, trying to use Nix to manage Node.js packages is not worth the hassle, so we don't bother at the moment. (This may change in the future as various Nix-based Node integrations improve.) This means that there's less benefit to using Nix for this project than you would typically expect from a Nix-based project. For example, we don't use Nix to build or cache Node packages.

Regardless, due to the dependency of this project on our primer backend project, it's still much easier to develop Primer App with Nix than without.

Without Nix

You can choose to forego Nix if you want to use your own installation of Node.js and other required tools. If you plan to use and develop this project's web application with a hosted version of the Primer language server (i.e., you don't plan to develop against a local instance of primer-service), this is probably feasible, and we should be able to provide a reasonable level of support for this development workflow, assuming your version of Node.js tracks the project's requirements.

However, if you do plan to run primer-service locally in order to develop the web application, then due to limited project resources, we may be unable to provide any support to you unless you use Nix to run the service and its required database tooling.

On Windows

Developing Primer App on Windows is more or less equivalent to developing the application without Nix, so see that section of the documentation for those caveats. You may have some success with NixOS on WSL, but we don't have the resources to provide any support for this environment.

This repo's relationship to the Primer repo

For a variety of reasons, some historical, this project and the Primer language server upon which it depends live in separate repositories. In order to keep the frontend code in sync with a particular version of the Primer backend/API, we pin the Primer backend repo to a particular git commit via a Nix flake input pin. This ensures that when we need to run a local primer-service instance), we're running the correct version of the backend for the current frontend, and we don't need to worry about keeping our local copies of these 2 repos in sync. The drawback to this approach is that if we need to make backend changes to accommodate a new frontend feature, we must first commit and publish those changes to some branch of the backend repo before we can update the local Nix flake pin. (However, we can always fall back to running the local primer-service from a local copy of the backend repo, if necessary.)

Bumping the primer pin

To bump the primer project pin, run the following commands from the top-level directory of this repo, where abcd123 is the git commit SHA of the primer repo commit you want to use:

nix run .#bump-primer abcd123
nix develop

(The nix develop step ensures that this project's API bindings are up to date with Primer's.)

Build system

We use the Vite build system to build the project, and pnpm to manage dependencies and run commands.

Interactive development

To develop interactively, enter the Nix shell via nix develop, which will install/update any necessary Node.js packages, and automatically generate the Primer API bindings.

Running a local primer-service instance

In most circumstances, while developing locally, you'll want to launch the version of primer-service that's pinned via this repo's primer Nix flake input. To do that, run the following command from this project's top-level directory:

nix run .#run-primer-sqlite

This will create (if necessary) a SQLite database in the current directory, run any necessary database migrations, and launch an instance of primer-service listening on port 8081 on all network interfaces.

Scripts

pnpm watch

This command runs the app in development mode. Open http://localhost:5173 in a browser to interact with it. You can run pnpm watch --open to automatically open a browser window. When run in this mode, the app will expect that an instance of primer-service is running on localhost port 8081.

Thanks to Vite's hot module reloading feature (HMR), the page will reload automatically whenever you make an edit to any source code or CSS files. (Changing a package's settings in a .json or .js file may require that you restart the dev server, as these changes are often not automatically picked up.)

In development mode, Vite also runs TypeScript and eslint when files change, so you'll see warnings and errors in the console where the pnpm watch command is running. There's normally a slight lag between when the browser reloads the app and the errors & warnings show up in the console, however.

pnpm format

This runs prettier --write on all source files in the project.

pnpm lint and pnpm lint:fix

Runs eslint on all source files in the project. The lint:fix variant will also attempt to fix any linting issues.

pnpm storybook

This command builds the project's Storybook, and then serves a local instance of it, which includes support for HMR. It will automatically open a browser window. This can be disabled by pnpm storybook --no-open.

pnpm build

This command builds a production version of the application, for distribution from a CDN or other static hosting service.

Once you've built the production version, you can then run pnpm serve and open http://localhost:4173 in a browser to see the production build. (Note: pnpm serve does not appear to be compatible with Safari on macOS. You may need to use Firefox or Chrome to view the production build on this platform.)

In theory, the local production version of the application should be no different than the watch HMR version, so unless you're trying to debug a production issue locally, pnpm serve is probably not what you want.

pnpm generate

This command automatically generates Primer API bindings for the frontend application. You need only run this whenever you update the primer pin.

Note that this command is run automatically every time you enter the nix develop shell, to help ensure your generated files are up-to-date with the latest API at all times.

pnpm build-storybook

This is the deployment-ready version of the component Storybook, the same as the one we deploy to Chromatic for CI builds. You probably won't ever need to run this command.

pnpm chromatic

This command performs a manual Chromatic deployment. You should never need to do this (and it probably won't work, anyway, as you likely don't have the necessary credentials to deploy to Chromatic).

Running package scripts & commands

You can use pnpm to run scripts and commands that are installed by the various packages in the repo. For example, to use tsc, the TypeScript compiler, you can run pnpm tsc.