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.