nexus-future v0.0.0-pr.439.3.caf1a2e
Documentation
Internal Development
Code Architecture
Overview
Roughly speaking we have three distinct levels of code:
src/{cli, framework}Top level modules coded directly against their respective domain.src/utils/*Mid level modules that might provide some conveniences or encapsulate concerns shared acrossframeworkandcli.src/lib/*Discrete modules that stand alone conceptually and technically.
Each level builds on the one below it.
One can think of code as evolving from level 1 down toward level 3.
Of course the natural place for some code is level 1. On the other hand we often don't know at first what a generic solution looks like. So level 3 tends to be grown into, rather than started from.
You could see a level 4 here as npm registry, where we fully extract a library. That is not an explicit goal, just a tip for the mental model.
Overall status of the codebase is in a state of refactoring.
utils,watcher, and more are undergoing source restructuring in the near future.
Layout Overview
/docs -- The website
/test -- Integration tests
/src
/cli -- CLI codebase
/framework -- Runtime codebase
/utils -- Non-discrete modules (may have state, tight coupling)
/lib -- Discrete moduleslib
The layout of a typical lib module looks like so:
/lib
/<module-name>
/index.ts -- Export-only module, the public interface
/index.spec.ts -- Tests against the public interface. Integration in the sense
that it is agnostic to the unit or units making up the lib.
/*.ts -- The modules making up the lib
/*.spec.ts -- Optional tests. Please prioritize `index.spec.ts`Be careful about lib modules depending upon one another excessively. The more complex the dependency graph the harder it can become to reason about the modules. But if there is non-trivial re-use to be had and/or just a simple/clean and logical dependency then go for it.
The built-in exception to this heuristic is lib/utils which can be thought of as a bespoke lodash for our lib components. Use it for small utilities, which might be shared, are very generic, and are not numerous enough to justify their own dedicated lib module. For example there is a utility to make text span a given length using given pad character.
Testing
We use GitHub Actions.
Unit
yarn test:unit
yarn dev:test # watch modeLive under
/srcseparated by and colocated with the respective module they test.Unit tests run in CI against every commit.
System
yarn test:systemLive under
/test/systemAlmost like E2E but they work with the local package code (whereas E2E would work with an actually published package).
These are useful because they provide many of the functional checks of E2E with a lower barrier to running, namely needing a published package. For example pull-requests made by community members cannot trigger E2E tests because that would require publishing and GitHub actions has no way for PRs from forks to access secrets.
You must run
yarn buildright before running these tests.These tests run by having the local package installed via folder-reference into the test project. This disables package hoisting. This in turn breaks typegen because its import of
@nexus/schemawill be unresolvable (it looks fornode_modules/@nexus/schemabut actually needs to look atnode_modules/nexus-future/node_modules/@nexus/schema). The system tests encode a solution to this. You should only have to think about this when actually devloping the system tests.
The solution to this problem is an env hook exposed by nexus-future called NEXUS_TYPEGEN_NEXUS_SCHEMA_IMPORT_PATH. when set it will cause the typegen file node_modules/@types/nexus-typegen/index.d.ts to have the import from-value rewritten to whatever the env var value is. This env hook lives inside the typegen component but is leveraged by the system tests suite.
E2E
yarn test:e2eLive under
/test/e2eE2E tests run in CI against every commit after the package has been published. These are preview and pr releases so its acceptable, and doing it this way provides a true smoke test of if the real user journey works end to end.
E2E tests can be run on your machine. They default to working with
latestdist-tag. UseE2E_NEXUS_VERSIONenv var to set the desired version to test against.
Continuous Delivery
We use
dripipto make releases.Every PR commit results in:
Pre-Release of pattern:
0.0.0-pr.<pr-num>.<build-num>.<short-sha>`Update to an npm dist tag of pattern
pr.<pr-num>`
Every trunk commit results in a
Pre-Release of pattern:
<next-version>-next.<build-num>Update to an npm dist tag of pattern
next
Stable releases are cut manually.
Any release type can be run manually:
yarn release:preview yarn release:stable yarn release:pr
Website
- We use docsifyjs/docsify.
- There is no build step
- Commits to master will trigger deployment (via
gh-pages, no ci/cd on our part) - Navigation is manually managed in
_sidebar.md - Cover page is managed in
_coverpage.md - Configuration and significant styling customizations are kept in
index.html
Getting started
Install
docsify-cliThere is currently a bug with
docsify-clirequiring the following manual fix after installation. To make this less painful, install globally so you should only have to do this once.yarn global add docsifyvim /usr/local/bin/docsify :se ff=unix :wqBoot docs dev to preview your changes locally
yarn docs:dev
Workflow Tips
Working With Example Apps via Linking
Refer to https://github.com/prisma-labs/nexus-future-examples
Working with create command
In any example you can use this workflow:
rm -rf test-create && mcd test-create && ../node_modules/.bin/nexus createHacks
Shebang / TS use strict / experimental-worker mess
- We use workers to speed up extraction of context type from user's app
- These are experimental in Node 10.x and thus require flag
--experimental-worker - We support Node 10.x
- Node only allows opting in via cli flag (e.g. no config file being read optionally)
- Nexus is a node CLI and has a shebang so os knows to use Node to interpret the contents
- It is not possible to pass flags to node here
- Except with a weird shebang hack
The shebang hack is broken by the output of
use strictby TS strict modeNeeds to be:
#!/bin/sh ':' //; exec node --experimental-worker "$0" "$@"Actually:
#!/bin/sh "use strict" ':' //; exec node --experimental-worker "$0" "$@"So we use
noImplicitUseStrictoption to remove it from our emit- This fails because
strictaddsalwaysStrictand that is incompatible withnoImplicitUseStrict - So we explor
strictinto all its parts except the one we want to remove,alwaysStrict - sigh
- ...
- UDPATE
- ...
We discovered that TS also emits
;which breaks things:Needs to be:
#!/bin/sh ':' //; exec node --experimental-worker "$0" "$@"Actually:
#!/bin/sh ':'; //; exec node --experimental-worker "$0" "$@"Went back on the no-strict-emit and now resoted to
sedoperations after build...- ...
- UDPATE
- ...
- We discovered that
npxgets broken by the weird shebang - reverted
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago