다음단일 Express 응용 프로그램의 js, Apollo 클라이언트 및 서버

본고는 두 가지 일을 묘사하였다.
  • api를 어떻게 전방Next.jsApollo Clientapi를 단일Apollo Server 응용 프로그램에 결합시킬 수 있습니까?또 다른 중요한 요구 사항은 GraphQL 지원을 얻는 것이다.그것에 대한 정보가 많지 않기 때문에, 이것은 이 안내서의 주요 목적이다.
  • 어떻게 모든 내용을 Express SSR yarn workspaces 에 잘 구성하고 하나의 무료 계획 응용 프로그램으로 배치할 수 있습니까?너는 그것에 관한 많은 내용을 발견할 수 있지만, 나는 여기서 그것을 내가 진행하고 있는 프로젝트 과정의 일부분으로 삼는다.
  • 통상적으로 모든 내용을 함께 놓고 싶지 않을 수도 있고 호스트가 같은 서버에 있을 수도 있습니다.하지만 창고 전체가 빠른 속도로 같은 환매를 보여줘야 합니다.나는 또 상금으로 monorepo 을 쓰고 싶다.

    검수 기준

  • 다음.js React 프런트엔드
  • GraphQL api
  • 단일 포털/호스트/서버
  • 단일 저장소
  • 아직 결합되지 않은 패키지: 클라이언트,api, 서버...후기 기타 서비스
  • SSR 지원
  • 여기저기 타자
  • 모든 항목 다시 로드
  • heroku
  • 에 배치
  • 테스트 버전 시작 및 실행
  • 1시간을 초과하면 안 됨

    너무 길어서 읽을 수가 없어요.


    소스 코드 here

    단계

  • design
  • monorepo
  • graphql api
  • client app
  • server
  • connecting everything together
  • setting up heroku
  • deploying
  • 1. 디자인

    Here is how you would usually want to use graphql - as a API Gateway between client app and back end services:


    우리는 기본적으로 같은 일을 하고 있지만, 우리의 서버 루트는 다음과 같이 보인다.

    이것은 우리의 주요 소프트웨어 패키지의 의존 관계도입니다.

    2. 주문서 반품

    We want every service in a single repo, but at the same time decoupled - Heroku . We can do it seamlessly with the help of TypeScript .

    Folder structure:

    root
     |- packages
     |   |- client
     |   |- graphql
     |   |- server
     |- package.json
     |- yarn.lock
    

    monorepo :

    {
     "name": "monorepo",
     ...
      "scripts": {
        "build": "yarn workspace @monorepo/client run build",
        "start": "yarn workspace @monorepo/server run start",
        "dev": "export $(cat .env | xargs) && yarn workspace @monorepo/server run dev"
      },
      "private": true,
      "workspaces": ["packages/*"],
      "engines": {
        "node": "13.x"
      }
    }
    

    No dependencies here. yarn workspaces is required by yarn workspaces. package.json declares where our packages live. Each script executes yarn command in specified workspace. In private": true script we read local development environment variables from "workspaces": [...] file before starting dev server. (If it does not work on your OS, replace with what works for you)

    dev :

    NODE_ENV=development
    PORT=3000
    GRAPHQL_URI=http://localhost:3000/graphql
    

    Let's agree on the naming convention for our packages: .env .


    3. GraphQL API 설정

    This one is the easiest.

    .env :

    {
      "name": "@monorepo/graphql",
      ...
      "dependencies": {
        "apollo-server-express": "2.12.0"
      }
    }
    

    @monorepo/package-name :

    import { ApolloServer, gql } from 'apollo-server-express';
    
    const typeDefs = gql`
      type Query {
        hello: String
      }
    `;
    
    const resolvers = {
      Query: {
        hello: () => 'Hello world!',
      },
    };
    
    const server = new ApolloServer({ typeDefs, resolvers });
    
    export default server;
    

    Everything super simple: schema, reducer. At the end we create Apollo Server, export it, but do not start it right away.


    4. 클라이언트 응용 프로그램 설정

    This one is trickier. We need to make Next js use Apollo Client for fetching the data and make sure SSR is supported.

    To bootstrap the Next.js app, I followed this quick start guide .js 응용 프로그램.하지만 우리는 약간의 수정이 필요하다.packages/graphql/package.json :
    {
      "name": "@monorepo/client",
      ...
      "scripts": {
        "dev": "next",
        "build": "next build",
        "start": "next start"
      },
      "dependencies": {
        ...
      }
    }
    
    별거 아니에요.
    이제 packages/graphql/index.ts 설정 packages/client/package.json 을 사용하여 next.js/examples/with-apollo 에서 Apollo ClientSSR 을 복사합니다.
    우리는 약간의 수정이 필요하다/apolloClient.js:
    ...
    
    export default function createApolloClient(initialState, ctx) {
      return new ApolloClient({
        ssrMode: Boolean(ctx),
        link: new HttpLink({
          uri: process.env.GRAPHQL_URI, // must be absolute for SSR to work
          credentials: 'same-origin',
          fetch,
        }),
        cache: new InMemoryCache().restore(initialState),
      });
    }
    
    우리는 링크를 가리킬 것이다./lib/apollo.js 환경 변수를 기반으로 로컬 dev 서버나heroku 호스트의 URL을 가리킵니다.기본적으로, URL은 apolloClient.js 이지만, SSR을 작동하기 위해서는 절대 경로를 거기에 두어야 합니다.왜냐고 묻지 마.
    우리는 두 개의 페이지가 있는데, 하나는 SSR이 있고, 다른 하나는 없다.GRAPHQL_URI :
    import React from 'react';
    import { useQuery } from '@apollo/react-hooks';
    import Layout from '../components/Layout';
    import gql from 'graphql-tag';
    import { withApollo } from '../apollo/apollo';
    
    const QUERY = gql`
      query GetHello {
        hello
      }
    `;
    
    const NOSSR = () => {
      const { data, loading, error, refetch } = useQuery(QUERY);
    
      if (loading) return <p>Loading...</p>;
      if (error) return <p>Error: {error.message}</p>;
    
      return (
        <Layout>
          <h1>This should be rendered on client side</h1>
          <pre>Data: {data.hello}</pre>
          <button onClick={() => refetch()}>Refetch</button>
        </Layout>
      );
    };
    
    export default withApollo({ ssr: false })(NOSSR);
    
    /graphql이 얼마나 간결한지 주의하세요.미녀아래쪽에 있는 페이지를 packages/client/pages/index.ts 에 포장하여 SSR을 사용/비활성화하기만 하면 됩니다.우리는 거의 같은 페이지가 하나 더 있을 것이다. useQuery, 그러나 withApollo({ ssr: false })(NOSSR) 있다.
    마지막으로 packages/client/pages/ssr.ts:
    import next from 'next';
    
    const nextApp = next({
      dev: process.env.NODE_ENV !== 'production',
      dir: __dirname,
    });
    
    export default nextApp;
    
    우리는 다음 것을 만들고 있습니다.js 프로그램을 내보내서 나중에 express에서 사용할 수 있도록 합니다.

    5. express 서버 설정

    Alright, its time to stitch everything together.

    ssr: true :

    {
      "name": "@monorepo/server",
      ...
      "scripts": {
        "start": "ts-node index.ts",
        "dev": "nodemon index.ts"
      },
      "dependencies": {
        "express": "4.17.1",
        "ts-node": "8.8.2",
        "typescript": "3.8.3"
      },
      "devDependencies": {
        "nodemon": "2.0.3",
        "@types/node": "13.11.1"
      }
    }
    

    We'll use packages/client/index.ts to run our TypeScript app on production, it will compile it and keep the build in cache. We'll use packages/server/package.json for the hot reload. Latest versions have built in TypeScript support, no need to do anything other than ts-node . Magic!

    And the epxress server itself nodemon :

    import express from 'express';
    
    import nextApp from '@monorepo/client';
    import apolloServer from '@monorepo/graphql';
    
    const { PORT } = process.env;
    
    async function main() {
      const app = express();
    
      await bootstrapApolloServer(app);
      await bootstrapClientApp(app);
    
      app.listen(PORT, (err) => {
        if (err) throw err;
        console.log(`[ server ] ready on port ${PORT}`);
      });
    }
    
    async function bootstrapClientApp(expressApp) {
      await nextApp.prepare();
      expressApp.get('*', nextApp.getRequestHandler());
    }
    
    async function bootstrapApolloServer(expressApp) {
      apolloServer.applyMiddleware({ app: expressApp });
    }
    
    main();
    

    Notice how we import nodemon index.ts and packages/server/index.ts packages. That's possible thanks to yarn workspaces simlinking.

    Next.js and Apollo Server have different express APIs. Next creates request handler that can be used as express middleware:

    await nextApp.prepare();
    expressApp.get('*', nextApp.getRequestHandler());
    

    Apollo Server does the same thing, but inside client method:

    apolloServer.applyMiddleware({ app: expressApp });
    

    6. dev 서버 실행

    Now that we have all the source code ready, from root run:

    yarn install
    

    This will instal all the dependencies and do the simlinking between our packages. If you inspect the content of root graphql in eg VS Code editor, you'll notice something like this:


    루트 node_ 모듈에 monorepo 패키지가 추가된 것처럼 보이지만 화살표 아이콘은 파일 시스템의 상응하는 위치를 가리키는 간단한 링크일 뿐임을 나타냅니다.괜찮은데!
    이제 루트에서 계속 실행합니다.
    yarn dev
    

    응용 프로그램을 엽니다applyMiddleware.

    네트워크 로그에서 볼 수 있듯이 페이지를 표시한 후 node_modules에 대한 XHR 요청이 있습니다.http://localhost:3000 를 클릭하거나 링크가 있는 /graphql 페이지로 이동하면 추가 요청이 전송되지 않습니다.데이터가 Apollo 클라이언트 캐시에 이미 존재하고 명확한 지시 없이 다시 추출되지 않기 때문이다.또 마술이 됐어!
    현재, 만약에 우리가 refetch 페이지를 다시 불러온다면, 우리는 페이지가 표시된 후에 XHR 요청이 없다는 것을 알아차릴 것이다. 만약에 우리가 페이지 원본 코드를 검사한다면, 우리는 SSR 텍스트가 이미 존재하는 것을 볼 수 있을 것이다.SSR은 예상대로 작동합니다.
    마지막으로 SSR로 이동합니다.개발 모드에서는 Apollo grapqhl 놀이공원 화면을 볼 수 있습니다.

    7. heroku 응용 프로그램 설정

    I wont describe much about the process of setting up new account and creating the app, but its pretty straight forward and should not take longer than 5 minutes.

    • Go to Data: Hello world! , crete a free plan account.
    • Do to your dashboard http://localhost:3000/graphql
    • Click https://www.heroku.com/ -> https://dashboard.heroku.com/apps , choose app name, region, and click New .

    You will land on the page with instructions of how to Create new app and deploy your app.

    One more thing you have to do is to set up Create app env var. Go to install heroku cli tab in heroku dashboard. In GRAPHQL_URI section you will find text Settings . Copy that url, scroll up to the Domains section and create new env var with key Your app can be found at https://your-app-name.herokuapp.com/ and value Config Vars :


    8. 배포

    heroku login
    git init
    git add .
    git commit -am "make it better"
    git push heroku master
    

    This will initiate the deployment process. Now here is the last Magical part. Heroku will recognize that your app is NodeJS based, you don't have to configure anything yourself. Moreover, Heroku will figure out that you use GRAPHQL_URI as a package manager and will run https://your-app-name.herokuapp.com/graphql after it fetches the source files. Then it will investigate your root package.json, find yarn script and run it. Finally it will look for the yarn install script and use it to start the app by default. Awesome. All the set up literally take about 15 minutes if you don't have an existing account.


    네, 당신의 heroku 응용 프로그램 URL로 내비게이션해 주세요. 저희가 다 설정했습니다.

    좋은 웹페이지 즐겨찾기