惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

人人都是产品经理
人人都是产品经理
MyScale Blog
MyScale Blog
Y
Y Combinator Blog
罗磊的独立博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
P
Proofpoint News Feed
Google DeepMind News
Google DeepMind News
V
Vulnerabilities – Threatpost
T
The Blog of Author Tim Ferriss
云风的 BLOG
云风的 BLOG
Recorded Future
Recorded Future
N
News and Events Feed by Topic
B
Blog RSS Feed
阮一峰的网络日志
阮一峰的网络日志
博客园_首页
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园 - 【当耐特】
N
Netflix TechBlog - Medium
博客园 - 叶小钗
B
Blog
Vercel News
Vercel News
T
Tenable Blog
T
The Exploit Database - CXSecurity.com
Spread Privacy
Spread Privacy
T
Threat Research - Cisco Blogs
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Last Week in AI
Last Week in AI
F
Fortinet All Blogs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Microsoft Security Blog
Microsoft Security Blog
S
Securelist
Microsoft Azure Blog
Microsoft Azure Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Palo Alto Networks Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
D
DataBreaches.Net
Cyberwarzone
Cyberwarzone
Engineering at Meta
Engineering at Meta
Martin Fowler
Martin Fowler
G
GRAHAM CLULEY
Project Zero
Project Zero
Cisco Talos Blog
Cisco Talos Blog
A
Arctic Wolf
C
CERT Recently Published Vulnerability Notes
L
LangChain Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
C
Check Point Blog
A
About on SuperTechFans
W
WeLiveSecurity
The GitHub Blog
The GitHub Blog

Nx Blog

Sharing Tailwind CSS Styles Across Apps in a Monorepo | Nx Blog How SiriusXM Stays Competitive by Iterating and Getting to Market Fast | Nx Blog Agentic Experience Is the New Developer Experience | Nx Blog Nx Joins the Linux Foundation and the Agentic AI Foundation | Nx Blog A Monorepo Is NOT a Monolith | Nx Blog Why we deleted (most of) our MCP tools | Nx Blog Teach Your AI Agent How to Work in a Monorepo | Nx Blog How Broadcom stays efficient and nimble with monorepos | Nx Blog Why Monorepos are King in the Age of AI | Nx Blog Nx 2026 Roadmap: Expanding Agent Autonomy, Improving Performance, Better Polyglot and More | Nx Blog End to End Autonomous AI Agent Workflows with Nx | Nx Blog Autonomous Agents at Scale | Nx Blog Scaling 700+ Projects: How Nx Became a 'No-Brainer' for Caseware | Nx Blog Configure Tailwind v4 with Angular in an Nx Monorepo | Nx Blog The Missing Multiplier for AI Agent Productivity | Nx Blog A Year of Nx Webinars | Nx Blog Wrapping Up 2025 | Nx Blog Nx 22.3 Release: Angular 21 Support, tsgo Compiler, and Prettier v3 | Nx Blog Nx Cloud Release: Agent Resource Usage | Nx Blog Nx Platform Outperforms DIY Cache by 5x | Nx Blog An Nx Carol: Past, Present, and Future of Your Monorepo | Nx Blog Nx 22.1 Release: Terminal UI on Windows, Storybook 10, Vitest 4, and more! | Nx Blog The Compounding Effect: How Nx Features Multiply Performance Gains | Nx Blog 10 Monorepo Myths Debunked: Separating Fact from Fiction | Nx Blog Nx Cloud Release: Enterprise Task Analytics | Nx Blog Watch and Rebuild Storybook Dependencies with Nx | Nx Blog Book - React for Enterprise: Timeless Architecture for Enterprise Apps | Nx Blog Beyond Remote Cache: Unlock 70% More CI Performance | Nx Blog Nx 22 Release: Expanding the build platform | Nx Blog What's the Point of Generating All This Code If You Can't Merge It? | Nx Blog What's New in Nx Self-Healing CI | Nx Blog Nx Highlights: Smarter AI integration, all-new graph UI, and big new versions of your favorite tools | Nx Blog Making the Case for Smarter Monorepos, and How to Not Get Fooled by Myths | Nx Blog Integrating Biome in 20 Minutes | Nx Blog S1ngularity - What Happened, How We Responded, What We Learned | Nx Blog Stop Babysitting Your PRs: Self-Healing CI Cuts Time to Green by 50% | Nx Blog UKG Unifies Their Codebase and Eliminates CI Overhead to Focus on Customer Value | Nx Blog How Git Worktrees Changed My AI Agent Workflow | Nx Blog Nx Cloud Workspace Graph: See Your Organization's Code Structure Like Never Before | Nx Blog Seamless Java Deployment in Nx Using Docker | Nx Blog Getting Mobile Into Your Monorepo: Android + Nx | Nx Blog Polyglot Projects Made Easy: Integrating Spring Boot into an Nx Workspace | Nx Blog The Journey of the Nx Plugin for Gradle: From Prototype to Production | Nx Blog Combining Predictability and Intelligence With Nx Generators and AI | Nx Blog A New UI For The Humble Terminal | Nx Blog Continuous tasks are a huge DX improvement | Nx Blog New and Improved Module Federation Experience with Nx | Nx Blog A New UI for Nx Migration | Nx Blog Custom Task Runners and Self-Hosted Caching Changes | Nx Blog Enterprise Angular Monorepo Patterns | Nx Blog Using Rspack with Angular | Nx Blog Angular Architecture Guide To Building Maintainable Applications at Scale | Nx Blog Modern Angular Testing with Nx | Nx Blog Nx Update: 20.5 | Nx Blog Are Monorepos the Answer to Better AI-Assisted Development? | Nx Blog Making Cursor Smarter with an MCP Server For Nx Monorepos | Nx Blog React Development for 2025 | Nx Blog Angular State Management for 2025 | Nx Blog Tailoring Nx for Your Organization | Nx Blog Nx Cloud Pipelines Come To Nx Console | Nx Blog Define the relationship with monorepos | Nx Blog See your affected project graph in Nx Cloud | Nx Blog Handling CORS In Your Workspace | Nx Blog Improve your architecture and CI pipeline times with Nx projects | Nx Blog Announcing Nx 20 | Nx Blog Introducing Nx Powerpack | Nx Blog Nx 19.5 is here! Stackblitz, Bun, Incremental Builds for Vite, Gradle Test Atomizer | Nx Blog Introducing Explain with AI | Nx Blog Nx Enterprise Podcast Episode 2: Tine Kondo | Nx Blog Monorepos and CI can be a Mess - Here's How Nx and Nx Cloud Fixed It | Nx Blog Nx Enterprise Podcast Episode 1: Hicham El Hammouchi | Nx Blog Nx 19.0 Release!! | Nx Blog Manage Your Gradle Project using Nx | Nx Blog Making the Argument for Monorepos | Nx Blog Reliable CI. A new execution model fixing both flakiness and slowness | Nx Blog Monorepos - Why Speed Matters | Nx Blog Nx Agents Walkthrough: Effortlessly Fast CI Built for Monorepos | Nx Blog Launch Nx Week Recap | Nx Blog Versioning and Releasing Packages in a Monorepo | Nx Blog Fast, Effortless CI | Nx Blog Introducing @nx/nuxt Enhanced Nuxt.js Support in Nx | Nx Blog What if Nx Plugins Were More Like VSCode Extensions | Nx Blog Monorepos: the Benefits, Challenges, and Importance of Tooling Support | Nx Blog Nx — Highlights of 2023 | Nx Blog Nx 17.2 Update | Nx Blog Unit Testing Expo Apps With Jest | Nx Blog Nx Docs AI Assistant | Nx Blog State Management Nx React Native/Expo Apps with TanStack Query and Redux | Nx Blog Nx 17 has Landed | Nx Blog Nx Conf 2023 — Recap | Nx Blog Nx Raises $16M Series A | Nx Blog Introducing Playwright Support for Nx | Nx Blog Nx 16.8 Release!!! | Nx Blog Step-by-Step Guide to Creating an Expo Monorepo with Nx | Nx Blog Qwikify your Development with Nx | Nx Blog Create Your Own create-react-app CLI | Nx Blog Storybook Interaction Tests in Nx | Nx Blog Evergreen Tooling — More than Just CodeMods | Nx Blog Nx 16.5 Release!!! | Nx Blog A Practical Guide on Effective AI Use - AI as Your Peer Programmer | Nx Blog
Using Apollo GraphQL in an Nx Workspace | Nx Blog
Philip Fulcher · 2025-02-22 · via Nx Blog

Because of the Nx's robust support for a diverse ecosystem of JavaScript development, it enables you to build your entire full-stack application in a single repo. This allows you to share code and interfaces between your frontend and backend and acts as a multiplier on your development velocity.

GraphQL is a query language for your API. Because of its typed schema definition, it’s a great candidate for defining the contract between your API and its consumers. By using smart tools to generate code based on that schema, you can save yourself a lot of time and enforce better cooperation between your frontend and backend.

In this article, you will build a simple GraphQL API that tracks some information about Lego sets. You’ll create this API using Apollo Server, and it will be consumed by a React application. You’ll have this all inside of an Nx Workspace in a single repository.

In this article, you’ll learn how to:

  • Create an Nx workspace for both frontend and backend applications
  • Create a GraphQL API using Apollo Server
  • Generate frontend code and backend resolver types based on your GraphQL schema using GraphQL Codegen
  • Create a React application to consume your GraphQL API

Minimal configuration

When given the option to enable another tool, like linting or testing, we're going to decline. This keeps this article focussed on GraphQL instead of having lint and test configs in the example. As you progress, feel free to enable these additional options if you'd like, especially if you're adding to an existing workspace that has those tools enabled.

An example repo with all the work you’ll be doing here can be found in our Nx Recipes repo

Create a new workspace

Start by creating an Nx workspace:

npx create-nx-workspace@latest --preset=node-monorepo nx-apollo

When prompted, answer the prompts as follows:

❯ npx create-nx-workspace@latest --preset node nx-apollo

 NX   Let's create a new workspace [https://nx.dev/getting-started/intro]

✔ Application name · api
✔ What framework should be used? · none
✔ Would you like to generate a Dockerfile? [https://docs.docker.com/] · No
✔ Which CI provider would you like to use? · skip
✔ Would you like remote caching to make your build faster? · skip

Create GraphQL schema and project

We want to generate model types from our schema that can be used by other projects in our workspace, so we'll start by creating a new project:

npx nx g @nx/js:library --directory=libs/models-graphql models-graphql

When prompted, answer the prompts as follows:

❯ npx nx g @nx/js:library --directory=libs/models-graphql models-graphql

 NX  Generating @nx/js:library

✔ Which bundler would you like to use to build the library? Choose 'none' to skip build setup. · none
✔ Which linter would you like to use? · none
✔ Which unit test runner would you like to use? · none

Why do I need a separate project?

When you have your GraphQL schema and generated models in a separate project, other projects can depend on it. This ensures that all projects are using the same version of the schema and models. This exemplifies the "modulith" structure for monorepos. Read more

You need a GraphQL schema to create the API, so write a very simple one with a single query and a single mutation. Create a file named schema.graphql in the new models-graphql project:

libs/models-graphql/src/lib/schema.graphql

type Set {
  id: Int!
  name: String
  year: Int
  numParts: Int
}

type Query {
  allSets: [Set]
}

type Mutation {
  addSet(name: String, year: String, numParts: Int): Set
}

To start generating our models from this schema, we'll use GraphQl Codegen. Install the packages needed:

npm install -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-resolvers @graphql-codegen/typescript-react-apollo

GraphQL Codegen is controlled by a configuration file named codegen.ts in each project that needs it. Create one for models-graphql:

libs/models-graphql/codegen.ts

import type { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
  schema: 'libs/models-graphql/src/lib/schema.graphql',
  generates: {
    'libs/models-graphql/src/lib/__generated__/models.ts': {
      plugins: ['typescript'],
      config: {
        avoidOptionals: true,
      },
    },
  },
};
export default config;

To run GraphqlQL Codegen, we need a target added to our project. Add this to the project.json for models-graphql:

libs/models-graphql/project.json

"targets": {
    "codegen": {
      "command": "npx graphql-codegen --config {projectRoot}/codegen.ts"
    }
}

Run the codegen task to generate our new models:

npx nx codegen models-graphql

You should see the new models created in the __generated__ directory in models-graphql. To use them outside the project, export them from the index.ts:

libs/models-graphql/src/index.ts

export * from './lib/__generated__/models';

Create GraphQL API

Use Apollo Server to create your GraphQL api. Start by installing the GraphQL modules needed for Apollo

npm install @apollo/server graphql

The workspace was generated with a Node application for us, but we need to make some small changes to support ESM for Apollo Server. First, change these compiler options in tsconfig.app.json:

apps/api/tsconfig.app.json

  "compilerOptions": {
    "lib": ["es2020"],
    "target": "es2020",
    "module": "esnext",
    "moduleResolution": "node",
    "esModuleInterop": true,
    ...
  }

And change the build target config in project.json:

apps/api/project.json

"targets": {
  "build": {
    ...
    "options": {
      ...
      "format": ["esm"]
    }
  }
}

GraphQl Codegen has already created our models for our GraphQL schema, but it can also generate the resolver types we'll want to implement in Apollo Server. Like before, create a codegen.ts in the api application:

apps/api/codegen.ts

import type { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
  schema: 'libs/models-graphql/src/lib/schema.graphql',
  generates: {
    'apps/api/src/__generated__/resolvers.ts': {
      plugins: ['add', 'typescript-resolvers'],
      config: {
        useIndexSignature: true,
        content: 'import * as types from "@nx-apollo/models-graphql"',
        namespacedImportName: 'types',
      },
    },
  },
};
export default config;

And add the task to our targets:

apps/api/project.json

  "targets": {
    "codegen": {
      "command": "npx graphql-codegen --config {projectRoot}/codegen.ts"
    }
}

And run the task:

npx nx codegen api

And now there should be resolver types in the __generated__ directory. We're ready to put create our Apollo Server application. Replace the contents of main.ts with this:

apps/api/src/main.ts

import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import { Set } from '@nx-apollo/models-graphql';
import { readFileSync } from 'fs';
import { join } from 'path';
import { Resolvers } from './__generated__/resolvers';

// Note: this uses a path relative to the project's
// root directory, which is the current working directory
// if the server is executed using `npm run`.
const typeDefs = readFileSync(
  join('libs/models-graphql/src/lib', 'schema.graphql'),
  { encoding: 'utf-8' }
);

const sets: Set[] = [
  {
    id: 1,
    name: 'Voltron',
    numParts: 2300,
    year: '2019',
  },
  {
    id: 2,
    name: 'Ship in a Bottle',
    numParts: 900,
    year: '2019',
  },
];

// Resolvers define how to fetch the types defined in your schema.
// This resolver retrieves books from the "books" array above.
const resolvers: Resolvers = {
  Query: {
    allSets: () => sets,
  },
  Mutation: {
    addSet: (parent, args) => {
      const newSet = {
        id: sets.length + 1,
        name: args.name,
        year: args.year,
        numParts: +args.numParts,
      };

      sets.push(newSet);

      return newSet;
    },
  },
};

// The ApolloServer constructor requires two parameters: your schema
// definition and your set of resolvers.
const server = new ApolloServer({
  typeDefs,
  resolvers,
});

// Passing an ApolloServer instance to the `startStandaloneServer` function:
//  1. creates an Express app
//  2. installs your ApolloServer instance as middleware
//  3. prepares your app to handle incoming requests
const { url } = await startStandaloneServer(server, {
  listen: { port: 4000 },
});

console.log(`🚀  Server ready at: ${url}`);

This is already enough to see some progress when you run the api application.

npx nx serve api

When the application is running, bring up the GraphQL Playground in your browser at http://localhost:4000/

Here you can inspect your GraphQL schema as well as submit queries and mutations.

This is a very simple resolver that holds data in memory. It returns the current contents of the sets array for the allSets query and allows users to add a new set using the addSet mutation. Add this resolver to the providers array in your app module:

Go back to your GraphQL Playground and see if your queries return any data now. Try a query and a mutation:

query allSets {
  allSets {
    id
    name
    numParts
  }
}

mutation addSet {
  addSet(name: "My New Set", numParts: 200, year: "2020") {
    id
  }
}

Now that the API is working, you’re ready to build a frontend to access this.

Add React frontend

Start by adding a React app to your workspace using the @nx/react plugin:

npx nx add @nx/react

Create the React app using the generator:

npx nx g @nx/react:app --directory=apps/frontend frontend

When prompted, answer the prompts as follows:

❯ npx nx g @nx/react:app --directory=apps/frontend frontend

 NX  Generating @nx/react:application

✔ Which stylesheet format would you like to use? · tailwind
✔ Would you like to add React Router to this application? (y/N) · false
✔ Which bundler do you want to use to build the application? · vite
✔ Which linter would you like to use? · none
✔ What unit test runner should be used? · none
✔ Which E2E test runner would you like to use? · none

We use Tailwind styles here for convenience. It will allow us to add some simple styles to our app without adding CSS files and importing them.

The Apollo client makes it easy to consume your GraphQL API. Install the client:

npm install @apollo/client

Modify your app.tsx to provide the Apollo Client:

apps/frontend/src/main.tsx

import { StrictMode } from 'react';
import * as ReactDOM from 'react-dom/client';
import App from './app/app';
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

const client = new ApolloClient({
  uri: 'http://localhost:4000/graphql',
  cache: new InMemoryCache(),
});

root.render(
  <StrictMode>
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  </StrictMode>
);

Create React library

Nx helps you break down your code into well-organized libraries for consumption by apps, so create a couple of React libraries to organize your work. Create a data-access library that handles communication with the backend and a feature-sets library that includes container components for displaying the Lego set data. In a real app, you might also create a ui library that includes reusable presentational components, but that is not part of this example. For more information on how to organize your React monorepo using Nx, read our book Effective React Development with Nx by registering here

To create the described project, run this command:

npx nx g @nx/react:lib --directory=libs/feature-sets feature-sets

When prompted, answer the prompts as follows:

npx nx g @nx/react:lib --directory=libs/feature-sets feature-sets

 NX  Generating @nx/react:library

✔ Which bundler would you like to use to build the library? Choose 'none' to skip build setup. · none
✔ What unit test runner should be used? · none

Setup React Code Generation

A tool called GraphQL Codegen makes the development of your feature library faster.

You need to create some GraphQL queries and mutations for the frontend to consume. Create a file named operations.graphql in the projects:

libs/feature-sets/src/lib/operations.graphql

mutation addSet($name: String!, $year: String!, $numParts: Int!) {
  addSet(name: $name, year: $year, numParts: $numParts) {
    id
    name
    numParts
    year
  }
}

query setList {
  allSets {
    id
    name
    numParts
    year
  }
}

Once again create a codegen.ts for the project:

libs/feature-sets/codegen.ts

import { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
  schema: 'libs/models-graphql/src/lib/schema.graphql',
  documents: ['libs/feature-sets/src/**/*.graphql'],
  generates: {
    'libs/feature-sets/src/lib/__generated__/operations.ts': {
      plugins: ['add', 'typescript-operations', 'typescript-react-apollo'],
      config: {
        useIndexSignature: true,
        content: 'import * as types from "@nx-apollo/models-graphql"',
        namespacedImportName: 'types',
      },
    },
  },
  ignoreNoDocuments: true,
};

export default config;

This configuration grabs all of your GraphQL files and generates all the needed types and services to consume the API.

Add a new task in project.json to run this code generator:

libs/feature-sets/project.json

  "targets": {
    "codegen": {
      "command": "npx graphql-codegen --config {projectRoot}/codegen.ts"
    }
}

Now you can run that task using the Nx CLI:

npx nx codegen feature-sets

You should now have a folder called __generated__ in your feature-sets library with a file named operations.ts. It contains typing information about the GraphQL schema and the operations you defined. It even has some hooks that make consuming this API superfast.

Create React components

You now have everything needed to start building your React components. Create two components: a list of Lego sets and a form to add a Lego set. Use Nx generators to scaffold these:

npx nx generate @nx/react:component libs/feature-sets/src/lib/add-set-form
npx nx generate @nx/react:component libs/feature-sets/src/lib/set-list

When prompted, answer the prompts as follows:

❯ npx nx generate @nx/react:component libs/feature-sets/src/lib/add-set-form

 NX  Generating @nx/react:component

✔ Should this component be exported in the project? (y/N) · false

In the SetList component, add the following:

libs/feature-sets/src/lib/set-list.tsx

import { useSetListQuery } from './__generated__/operations';

export function SetList() {
  const { loading, data } = useSetListQuery();

  return loading ? (
    <p>Loading ...</p>
  ) : (
    <ul className="mx-6 w-full list-none">
      {data &&
        data.allSets?.map(({ id, name, numParts, year }) => (
          <li className="p-2 even:bg-slate-200">
            {year} - <strong>{name}</strong> ({numParts} parts)
          </li>
        ))}
    </ul>
  );
}

export default SetList;

Notice how useSetListQuery is imported from the data-access library. This is a hook generated by GraphQL Codegen that provides the results of the SetList query. This entire pipeline is type-safe, using the types generated by GraphQL Codegen.

In the AddSetForm component, add the following:

libs/feature-sets/src/lib/add-set-form.tsx

import { useRef } from 'react';
import { useAddSetMutation } from './__generated__/operations';

export function AddSetForm() {
  const formRef = useRef<HTMLFormElement>(null);
  const [addSet] = useAddSetMutation({
    refetchQueries: ['setList'],
  });

  const handleSubmit = (formData: FormData) => {
    const name = formData.get('name')?.toString();
    const year = formData.get('year')?.toString();
    const numParts = parseInt(formData.get('numParts')?.toString() || '0', 10);

    if (name && year && numParts > 0) {
      addSet({ variables: { name, year, numParts } });
    }
    formRef.current?.reset();
  };

  return (
    <form
      ref={formRef}
      action={handleSubmit}
      className="mx-6 max-w-60 border border-slate-200 p-6"
    >
      <label
        htmlFor="name"
        className="block text-sm/6 font-medium text-gray-900"
      >
        Name
      </label>
      <div className="mt-2">
        <input
          id="name"
          name="name"
          type="text"
          className="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6"
        />
      </div>

      <label
        htmlFor="name"
        className="mt-2 block text-sm/6 font-medium text-gray-900"
      >
        Year
      </label>
      <div className="mt-2">
        <input
          id="year"
          name="year"
          type="text"
          className="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6"
        />
      </div>

      <label
        htmlFor="name"
        className="mt-2 block text-sm/6 font-medium text-gray-900"
      >
        Number of Parts
      </label>
      <div className="mt-2">
        <input
          id="numParts"
          name="numParts"
          type="number"
          className="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6"
        />
      </div>

      <button
        type="submit"
        className="mt-6 rounded-md bg-indigo-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
      >
        Create new set
      </button>
    </form>
  );
}

export default AddSetForm;

Again, notice that the component imports hooks, queries, and typing information from our generated code to accomplish this.

Integrate components into the app

Final step: bring those new components into FeatureSets component:

libs/feature-sets/src/lib/feature-sets.tsx

import AddSetForm from './add-set-form';
import SetList from './set-list';

export function FeatureSets() {
  return (
    <div className="flex">
      <AddSetForm></AddSetForm>
      <SetList></SetList>
    </div>
  );
}

export default FeatureSets;

And bring that component into your app:

apps/frontend/src/app/app.tsx

import { FeatureSets } from '@nx-apollo/feature-sets';

export function App() {
  return (
    <div>
      <h1 className="my-6 text-center text-2xl font-bold">My Lego Sets</h1>
      <FeatureSets></FeatureSets>
    </div>
  );
}

export default App;

If your API isn’t running already, go ahead and start it:

npx nx serve api

And now start your React app in a separate terminal:

npx nx serve frontend

Browse to http://localhost:4200 and see the results of your work!

Extend codegen configuration

The configuration for the codegen targets is a good start, but it's currently lacking two things:

  1. Caching
  2. Dependent tasks

Without caching enabled, codegen tasks will be run every time, regardless if they need to be or not. And without dependent tasks configured, we can't be sure that codegen is run any time our generated code depends on the generated code in another project. IOn our example, the generated code in both api and feature-sets rely on the models generated in models-graphql. If we make changes to the schema in models-graph and then run codegen on api, our models will be out-of-sync and lead to errors.

Let's fix both of these problems with a target default for codegen. In nx.json, add this:

nx.json

  "targetDefaults": {
  ...
  "codegen": {
      "cache": true,
      "outputs": ["{projectRoot}/src/__generated__"],
      "inputs": ["{workspaceRoot}/libs/models-graphql/src/lib/schema.graphql","{projectRoot}/**/*.graphql"],
      "dependsOn": ["^codegen"]
    }
  }

Now try running codegen for api to see that codegen for models-graphql is run first:

❯ npx nx codegen api

   ✔  1/1 dependent project tasks succeeded [0 read from cache]

   Hint: you can run the command with --verbose to see the full dependent project outputs

—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————


> nx run api:codegen

> npx graphql-codegen --config apps/api/codegen.ts

✔ Parse Configuration
✔ Generate outputs

—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

 NX   Successfully ran target codegen for project api and 1 task it depends on (2s)

Try running the command again, and you'll see that the results are pulled from the cache, and the task ends immediately.

Further Reading