TypeForm이 Next와 함께 작동하도록 합니다.js 및 타자 스크립트

나는 새로운Next를 세우고 있다.js 응용 프로그램(Nextuth를 사용하여 SSO)을 실행하고 TypeORM을 데이터베이스 영구층으로 사용하기로 결정했습니다.다음.js는 트림과 TypeORM이 없는 TypeScript 코드를 실행할 때 매우 뛰어나다. 비록 나에게는 초보이지만 미니멀리즘은 전도가 유망한 것 같다.하지만 함께 놀기 위해 중요한 오류 메시지와 버그를 만났습니다.비록 대다수의 답안은 이미 인터넷상에서 다른 선량한 사람들에게 발견되었지만, 나는 한참이 걸려서야 답을 찾았고, 하나의 해결 방안으로 결합되었다.
다음과 같은 세 가지 핵심 영역이 필요합니다.
  • Next에서 TypeScript 형식의 엔티티를 가져옵니다.js 및 CLI 컨텍스트
  • Next에서 TypeORM의 decorator 구문 +reflect-metadata를 지원합니다.js 파이프 건설
  • 개발 실행 시 핫 모듈 재로드(HMR) 클래스 인스턴스 혼동 방지

  • 엔티티 및 연결 구성 가져오기
    일반적으로 TypeORM은 일반 노드에서 실행됩니다.js 환경, 이것은 미리 컴파일되지 않은 상황에서 TypeScript 파일 (예를 들어 실체 클래스 정의) 을 사용할 수 없다는 것을 의미합니다.예를 들어, TypeORM config의 entities 경로가 TS 소스 파일(즉 src/entity/*.ts을 참조할 때 자주 발생하는 오류가 발생합니다.
    Error during schema synchronization:
    /project/path/src/entity/User.ts:1
    import {
    ^^^^^^
    
    SyntaxError: Cannot use import statement outside a module
        at wrapSafe (internal/modules/cjs/loader.js:979:16)
    ...
    
    다음.js와 TypeScript에 대한 내장 지원은 예상치 못했지만, 결국 위의 오류 메시지를 만났습니다.
    왜냐하면 TypeORM이 새 연결을 만들 때 경로 어댑터에 따라 모든 실체 클래스 파일을 동적으로 불러오려고 합니다.이 과정은 전체 다음 과정을 돌았다.js Babel bundling 파이프를 사용하여 노드로 돌아갑니다.js의 내장 모듈 캐리어입니다.그러니까 내 다음에도js 서버 코드는 실체 클래스인 TS 파일을 가져오고 실행할 수 있습니다. TypeORM 연결 초기 값 설정 항목은 '병렬 세계' 에서 생활하고 있습니다. 0부터 불러오려고 천진난만하게 시도한 후에 실패했습니다.
    TS 모듈이 TypeORM을 통해 로드될 때 ts-node를 사용하여 동적으로 컴파일하려고 했지만 다른 오류가 발생했습니다.
    RepositoryNotFoundError: No repository for "User" was found. Looks like this entity is not registered in current "default" connection?
    
    이 장면에서 모든 실체 클래스의 두 개의 복제는 메모리에 공존한다. 하나는 TypeORM+ts-node로 불러오고 실례화되며, 다른 하나는 Next로 귀속된다.js 파이프와 기타 서버 코드.이로 인해 유인용이 혼동되었다.
    대신 다음 그림과 같이 모든 엔티티 파일을 명명하고 가져오는 방법entities 와일드카드를 사용하지 않습니다.
    import { User } from './entity/User';
    import { Account } from './entity/Account';
    // etc
    
    그런 다음 명시적 옵션 객체를 createConnection()에 전달하고 솔리드 클래스는 다음과 같이 직접 참조합니다.
    createConnection({
      entities: [
        User,
        Account,
        // etc
      ]
    })
    
    이에 따라 나는 더 이상의 충돌을 피하기 위해 ormconfig.js 파일을 삭제했다.
    CLI 모드 동기화 및 마이그레이션에만 사용되는 별도의 ormconfig.cli.js 파일을 보유하고 있습니다.이를 위해 ts-node를 설치하고 require('ts-node/register')를 구성 파일의 맨 위에 추가하여 TS 엔티티 정의를 쉽게 로드할 수 있습니다.명령줄 스크립트는 다음과 같습니다.
    typeorm --config ormconfig.cli.js schema:sync
    

    Decorator 구문 및 reflect-metadata.js
    TypeORM 실체 클래스 정의는 decorator 문법(예를 들어 @Entity(), @Column() 등을 사용한다.또한, TypeORM이 string 등 TypeScript 필드 유형을 읽고 varchar 등 데이터베이스 열 유형을 추정할 수 있도록 특수한 파이프라인이 있어야 한다.상기 기능을 실현하기 위해 TypeORM 문서는 reflect-metadata라는 패키지를 설치하고 tsconfig.jsonemitDecoratorMetadataexperimentalDecoratorstrue로 조정해야 한다.
    하지만 그 다음은.js는 TSC (최초의 TypeScript 컴파일러) 를 사용하지 않고 Babel의 @babel/preset-typescript 패키지에 의존합니다.따라서 이런 조정tsconfig.json은 아무런 효과가 없다.
    대신 나는 다음 글에 맞춤형 바베타 설정을 추가했다.js 프로젝트, 바베타의 등효 옵션 (((this issue about decorator supportthis issue about metadata 을 포함).이것은 생성된 .babelrc 파일의 내용입니다.
    {
      "presets": [
        [
          "next/babel",
          {
            "class-properties": {
              "loose": true
            }
          }
        ]
      ],
      "plugins": [
        "babel-plugin-transform-typescript-metadata",
        ["@babel/plugin-proposal-decorators", { "legacy": true }]
      ]
    }
    
    설치해야 하는 추가 패키지class-properties 플러그인이 Next에 이미 포함되어 있습니다.js:@babel/plugin-proposal-decorators babel-plugin-transform-typescript-metadata @babel/core.
    참고: 데이터베이스 열 유형을 명시적으로 지정하면 설치reflect-metadatababel-plugin-transform-typescript-metadata를 생략할 수 있습니다.그러면 TypeORM은 TS 유형에서 어떤 것도 추정할 필요가 없습니다.일부 사람들에게는 안정성 차원에서 더 바람직할 수도 있지만 그 대가는 더 지루하다.

    다음.js HMR 및 TypeORM 솔리드 클래스
    핫 모듈 리로드(HMR)는 또 하나의 활동 스패너를 가져왔다.
    개발 과정에서 매번 다음을 편집한다.js 페이지, API 루트, 또는 다른 파일 (예를 들어 실체 클래스) 은 최종적으로 코드를 다시 컴파일하고 다시 불러옵니다.TypeORM 연결 관리자가 실체 클래스의 재로드를 모르기 때문에 연결 대상은 곧 동기화를 잃고 더 이상 쓸모가 없습니다.
    예를 들어 사용자 실체 클래스가 있다면 다음 단계입니다.js에서 클래스 인용을 불러오고 만들 것입니다. "User v1"이라고 합니다.이 인용은 createConnection 로 전달되었고, 물론 코드의 나머지 부분도 그것을 사용했다.이제, 이 종류의 파일을 편집하면, 다음에.js는 열을 다시 불러옵니다. 현재 실행할 때 메모리에 두 개의 다른 클래스 인용이 있습니다.하나는 원시적인 '사용자 v1' 이고, 다른 하나는 새로 컴파일된 '사용자 v2' 이다.라우팅 코드에 User v2 클래스 참조가 사용되고 있지만 연결된 알려진 엔티티 목록에 User v1이 남아 있습니다.코드에서 getRepository(User)를 호출하려고 하면 TypeORM과 같은 클래스 참조가 전달되지 않으므로 이 오류가 다시 발생합니다.
    RepositoryNotFoundError: No repository for "User" was found. Looks like this entity is not registered in current "default" connection?
    
    나는 몇몇 GitHub 문제가 해결 방안을 토론하고 있는 것을 보았다. (예: this workaround나에게 있어서, 최종 답은 이전의 연결을 간단하게 얻고, 새로운 연결을 열기 전에 닫는 것이다.
    다음은 예시 코드 세션이다.나는 그것을 공유된 중심 파일에 두었다. 예를 들어 src/db.ts:
    let connectionReadyPromise: Promise<void> | null = null;
    
    function prepareConnection() {
      if (!connectionReadyPromise) {
        connectionReadyPromise = (async () => {
          // clean up old connection that references outdated hot-reload classes
          try {
            const staleConnection = getConnection();
            await staleConnection.close();
          } catch (error) {
            // no stale connection to clean up
          }
    
          // wait for new default connection
          await createConnection({
            // connection options go here
          });
        })();
      }
    
      return connectionReadyPromise;
    }
    
    그런 다음 TypeORM을 호출하는 모든 함수에서 데이터베이스 작업을 수행하기 전에 다음을 추가합니다.
    await prepareConnection();
    
    많은 곳에서 이 점을 포함하는 것은 좀 무거운 것 같지만, 어쨌든 데이터베이스 사용은 준비가 다 될 때까지 어떤 기다림이 있어야 하기 때문에 최종적으로 확실한 목적을 달성했다.

    결론
    저는 TypeORM 문서에 최종적으로 Babel의 특정한 설정 방법과 HMR의 우호적인'연결 리셋'조수가 포함되기를 바랍니다. 위에서 말한 바와 같이.또한 엔티티의 동적 와일드카드 로더가 이상적일 경우 Next와 같은 바인더 파이프에 삽입할 수 있습니다.js의. 그러나 현재 이런 조합의 설정은 매우 잘 작동하고 있습니다. 그것도 당신을 도울 수 있기를 바랍니다!

    좋은 웹페이지 즐겨찾기