Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: architecture notes regarding deps #1079

Merged
merged 3 commits into from
Jun 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,45 @@ what follows is a stub
- typescript not hooked into module extensions
- plugins are imported for tree-shaking

## Dependency Philosophy
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First draft, we have a base to edit and improve upon.


Nexus takes a different perspective on the arguably mainstream approach of Node dependency management. In Node it is common practice to write and share tiny reusable modules. Then, users build their applications by assembling these many smaller packages how they need to.

Nexus takes a batteries included approach. Aside from being featureful, it also means bundling things that would typically be peer dependencies in other systems: `graphql` and `@nexus/schema` for Nexus itself, and for prisma plugin `@prisma/cli`, `@prisma/sdk`, and `@prisma/client`. There are numerous benefits to this.

1. Setting up dependency automation tools like renovate lead to simpler experiences.

For example when `graphql` 0.15 was released, bothering `nexus` users to upgrade it wouldn't have made sense since `@nexus/schema` didn't support it yet.

2. Integration bugs are owned by the core team

For example when TypeScript 3.9 was released `nexus-prisma` was incompatible with it. The types it generated led to static errors that were previously not there due to a change in how TS dealt with `any` as a type generic default.

3. Simpler upgrade paths for you

It is easier to piece together an upgrade path from one dep to another than a combination of `n` deps to another combination of `n` deps. In pratice what happens is the migration guide is written with a discrete set of `n` rather than all possible `n`.

4. More "honest" than peer dependenies

Peer dependencies in a nutshell are a loose contract encoding thus: "I, author of lib A, declare that A supports a _range_ of lib B that, you, user, will bring to the party". This sounds great, but how is this claim enforced? Its very likely not, at least rigorously. Trust in semver and a test suite against one version of `B` is probably how the majority of situations go. And so of course a not insubstantial burden falls onto users' laps.

If Nexus, especially with Prisma plugin, were going to leverage peer dependencies (implying a range of lib support or what's the point?) doing it honestly would mean a test suite running against a matrix of the combinations of the supported ranges of peer deps. Nexus already runs a matrix of Node versions and OSs. Adding peer deps to the mix would further strain an already strained test setup. Then, of course, there would be the actual burden of supporting whatever idiosyncracies exist along the ranges. Our internal implementations would complexify, more tests would be needed, more room for bugs.

5. Yarn `resolutions` to the rescue

_But what if I **really** need an older or newer version of X transient dep!?_

If the bundled versions of deps in Nexus or Prisma plugin aren't meeting your needs and there is an urgent issue you can use the [yarn resolutions](https://classic.yarnpkg.com/en/docs/selective-version-resolutions) option. If you aren't using `yarn` or a package manager with similar capability, and you aren't willing to, then you probably don't havev an urgent issue.

Of course by doing this you're going outside what a given version of Nexus officially supports, so, YMMV "your mileage may vary"! But its not like if Nexus were using peer dep ranges that this caveat would magically go away.

In conclusion, from both a DX and engineering resource perspective we believe the best dep strategy for Nexus is not peer deps but internalized deps. Recapping the tradeoffs:

- **Cost:** Giving you less flexibility to tailor the packages you use
...but even then _not really_. You _can_ have final say via Yarn's `resolutions` setting.

- **Benefit:** For us, lowering our implementation complexity, tests, and test infrastructure; The number of bugs which we in turn have to spend more time triaging, reproducting, and investigating. For you, less things to install, think about; More confidence that integration works; More overhead around dep management, changelog consumption, upgrade paths, and, invariably, bug reporting.

## Glossary

### Assembly
Expand Down
4 changes: 3 additions & 1 deletion docs/plugins/prisma.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ Prisma is a next-generation developer-centric toolkit focused on making the data
npm add nexus-plugin-prisma
```

> Note: `nexus-plugin-prisma` bundles the Prisma CLI. You can invoke it using `npm run prisma` or `yarn prisma`.
<div class="NextIs Warn"></div>

> All Prisma deps are bundled, so do _not_ install e.g. `@prisma/cli` or `@prisma/client`. If you are wondering _why_ you can read through [Nexus' philosophy on dependency management](/architecture?id=dependency-philosophy). You can still find the the prisma CLI by running `npm run prisma` or `yarn prisma`. In an emergency you can still control the version of prisma deps with Yarn [`"resolutions"`](https://classic.yarnpkg.com/en/docs/selective-version-resolutions).

**2. Enable the plugin**

Expand Down
4 changes: 4 additions & 0 deletions docs/tutorial/chapter-1-setup-and-first-query.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ npm add nexus

Nexus comes out of the box with a CLI. You'll use it often while working on your app. While you can access the CLI of your local nexus via `yarn` or npm scripts or `npx` but there's an even easier way. Install `nexus` globally. Then you can access the CLI from anywhere. Nexus is smart enough to delegate all invocations to the _local_ nexus. This is the idiomatic way to work with Nexus, but you aren't forced to do this.

<div class="NextIs Note"></div>

> The simplicity of the dependencies you need is no accident. We're not hiding complexity to kick off this tutorial only for it to pounce upon you later. This is it. If you're curious about Nexus' philosophy on dependency management [we've written about it here](/meta/architecture#dependency-philosophy).

```markdown
npm add --global nexus
```
Expand Down
4 changes: 4 additions & 0 deletions docs/tutorial/chapter-5-persisting-data-via-prisma.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ like so:
npm add nexus-plugin-prisma
```

<div class="NextIs Note"></div>

> Like we mentioned in Chapter 1, the simplicity of the dependency story here is no accident. Nexus Prisma plugin bundles deps like `@prisma/client` for you. If you're curious about Nexus' philosophy on dependency management [we've written about it here](/meta/architecture#dependency-philosophy).

```ts
// api/app.ts

Expand Down
52 changes: 29 additions & 23 deletions scripts/postinstall-message.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,39 @@ const green = '\u001b[32;1m'
const purple = '\u001b[35;1m'
const CR = '\u001b[31;1m'
const blue = '\u001b[36;1m'
const red = '\u001b[1;31m'
const yellow = '\u001b[33;1m'
const gray = '\u001b[30;1m'

let message = `
┌─────────────────────────────────────────────────────────────┐
│ │
│ ${yellow}Nexus has become a framework!${reset} │
│ ${yellow}Nexus has become a framework!${reset} │
│ ${yellow}Nexus has become a framework!${reset} │
│ │
│ Starting from 0.20.0 the nexus package is a framework. │
│ │
│ ${boldWhite}Learn more about the transition:${reset} │
│ https://nxs.li/schema-to-framework/about │
│ │
│ ${boldWhite}Learn more about the framework:${reset} │
│ https://nexusjs.org │
│ │
│ ${boldWhite}Migrate to the framework:${reset} │
│ https://nxs.li/schema-to-framework/migrate │
│ │
│ ${boldWhite}Were you looking for the old Nexus?${reset} │
│ ${purple}@nexus/schema${reset} │
│ │
│ │
│ ${gray}This post-install notice will be removed on July 1 2020${reset} │
└─────────────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────────────┐
│ │
│ ${purple}nexus-prisma has migrated!${reset} │
│ ${purple}nexus-prisma has migrated!${reset} │
│ ${purple}nexus-prisma has migrated!${reset} │
│ │
│ ${boldWhite}Please change your dependencies:${reset} │
│ │
│ npm remove nexus-prisma @prisma/client @prisma/cli │
│ npm add nexus-plugin-prisma │
│ │
│ ${boldWhite}Please change your imports:${reset} │
│ │
│ import { nexusPluginPrisma } from ${red}'nexus-prisma'${reset} │
│ import { nexusPluginPrisma } from ${green}'nexus-plugin-prisma/schema'${reset} │
│ │
│-------------------------------------------------------------------│
│ │
│ ${boldWhite}Learn about the transition:${reset} │
│ https://nxs.li/nexus-prisma-to-nexus-plugin-prisma/about │
│ │
│ ${boldWhite}Learn about the framework plugin:${reset} │
│ https://nxs.li/plugins/prisma │
│ │
│ ${boldWhite}Learn how to migrate to the framework:${reset} │
│ https://nxs.li/schema-to-framework/migrate │
│ │
└───────────────────────────────────────────────────────────────────┘

`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ like so:
npm add nexus-plugin-prisma
```

> Note: Like we mentioned in Chapter 1, the simplicity of the dependency story here is no accident. Nexus Prisma plugin bundles deps like `@prisma/client` for you. If you're curious about Nexus' philosophy on dependency management [we've written about it here](/meta/architecture#dependency-philosophy).

```ts
// api/app.ts

Expand Down
3 changes: 2 additions & 1 deletion website/content/03-plugins/01-prisma.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ Prisma is a next-generation developer-centric toolkit focused on making the data
npm add nexus-plugin-prisma
```

> Note: `nexus-plugin-prisma` bundles the Prisma CLI. You can invoke it using `npm run prisma` or `yarn prisma`.

> Warning: All Prisma deps are bundled, so do _not_ install e.g. `@prisma/cli` or `@prisma/client`. If you are wondering _why_ you can read through [Nexus' philosophy on dependency management](/meta/architecture#dependency-philosophy). You can still find the the prisma CLI by running `npm run prisma` or `yarn prisma`. In an emergency you can still control version of prisma deps with Yarn [`"resolutions"`](https://classic.yarnpkg.com/en/docs/selective-version-resolutions).

**2. Enable the plugin**

Expand Down
39 changes: 39 additions & 0 deletions website/content/05-meta/04-architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,45 @@ t
- typescript not hooked into module extensions
- plugins are imported for tree-shaking

## Dependency Philosophy

Nexus takes a different perspective on the arguably mainstream approach of Node dependency management. In Node it is common practice to write and share tiny reusable modules. Then, users build their applications by assembling these many smaller packages how they need to.

Nexus takes a batteries included approach. Aside from being featureful, it also means bundling things that would typically be peer dependencies in other systems: `graphql` and `@nexus/schema` for Nexus itself, and for prisma plugin `@prisma/cli`, `@prisma/sdk`, and `@prisma/client`. There are numerous benefits to this.

1. Setting up dependency automation tools like renovate lead to simpler experiences.

For example when `graphql` 0.15 was released, bothering `nexus` users to upgrade it wouldn't have made sense since `@nexus/schema` didn't support it yet.

2. Integration bugs are owned by the core team

For example when TypeScript 3.9 was released `nexus-prisma` was incompatible with it. The types it generated led to static errors that were previously not there due to a change in how TS dealt with `any` as a type generic default.

3. Simpler upgrade paths for you

It is easier to piece together an upgrade path from one dep to another than a combination of `n` deps to another combination of `n` deps. In pratice what happens is the migration guide is written with a discrete set of `n` rather than all possible `n`.

4. More "honest" than peer dependenies

Peer dependencies in a nutshell are a loose contract encoding thus: "I, author of lib A, declare that A supports a _range_ of lib B that, you, user, will bring to the party". This sounds great, but how is this claim enforced? Its very likely not, at least rigorously. Trust in semver and a test suite against one version of `B` is probably how the majority of situations go. And so of course a not insubstantial burden falls onto users' laps.

If Nexus, especially with Prisma plugin, were going to leverage peer dependencies (implying a range of lib support or what's the point?) doing it honestly would mean a test suite running against a matrix of the combinations of the supported ranges of peer deps. Nexus already runs a matrix of Node versions and OSs. Adding peer deps to the mix would further strain an already strained test setup. Then, of course, there would be the actual burden of supporting whatever idiosyncracies exist along the ranges. Our internal implementations would complexify, more tests would be needed, more room for bugs.

5. Yarn `resolutions` to the rescue

_But what if I **really** need an older or newer version of X transient dep!?_

If the bundled versions of deps in Nexus or Prisma plugin aren't meeting your needs and there is an urgent issue you can use the [yarn resolutions](https://classic.yarnpkg.com/en/docs/selective-version-resolutions) option. If you aren't using `yarn` or a package manager with similar capability, and you aren't willing to, then you probably don't havev an urgent issue.

Of course by doing this you're going outside what a given version of Nexus officially supports, so, YMMV "your mileage may vary"! But its not like if Nexus were using peer dep ranges that this caveat would magically go away.

In conclusion, from both a DX and engineering resource perspective we believe the best dep strategy for Nexus is not peer deps but internalized deps. Recapping the tradeoffs:

- **Cost:** Giving you less flexibility to tailor the packages you use
...but even then _not really_. You _can_ have final say via Yarn's `resolutions` setting.

- **Benefit:** For us, lowering our implementation complexity, tests, and test infrastructure; The number of bugs which we in turn have to spend more time triaging, reproducting, and investigating. For you, less things to install, think about; More confidence that integration works; More overhead around dep management, changelog consumption, upgrade paths, and, invariably, bug reporting.

## Glossary

### Assembly
Expand Down