Typescript 및 Clean Architecture를 사용하여 템플릿 스캐폴딩 CLI 유틸리티 개발

소개



코드 작성에 관련된 모든 사람은 때때로 복사 및 붙여넣기를 처리합니다. 단일 파일, 특정 구조를 가진 관련 파일의 작은 폴더 또는 프로젝트 상용구일 수 있습니다.

React 개발자로서 나는 이것을 많이 사용했습니다. 새 구성 요소를 만들 때는 일반적으로 이미 만든 구성 요소의 폴더를 복사합니다.
Title 구성 요소를 만들고 싶다고 가정해 보겠습니다. 가장 가까운Button 구성 요소를 복사하여 시작합니다.

|____Button
| |____Button.module.scss
| |____Button.stories.mdx
| |____Button.tsx
| |____index.ts
| |____README.md

그런 다음 다음을 수행해야 합니다.
  • 폴더 및 파일 이름 변경
  • 소스 코드
  • 에서 Button의 모든 항목을 찾아서 바꿉니다.
  • 중복 제거 제거 props , import s 등
  • 🤦



  • 그래서 약간의 연구 끝에 짧은npx 명령을 제공하여 시간을 절약할 수 있는 간단한 CLI 도구를 만들기로 결정했습니다. 같은 것
    npx mycooltool rfc ./components
    여기서 rfc는 템플릿(React 기능 구성 요소)의 이름이고 ./components는 템플릿을 넣을 경로입니다.

    기사의 나머지 부분은 위의 CLI 유틸리티의 개발 프로세스를 안내하지만 앞으로 코드로 바로 이동하려는 경우 다음과 같이 생각했습니다.


    스트렛츠 / 바이스트로


    스캐폴딩 코드 템플릿 및 상용구용 CLI 유틸리티 라이브러리입니다.





    바이스트로


    스캐폴딩 코드 템플릿 및 상용구용 CLI 유틸리티 라이브러리
    때로는 일부 구성 요소(예: React 구성 요소)를 나타내는 파일의 전체 폴더를 복사하여 붙여 넣은 다음 필요에 따라 파일 이름, 변수 등의 이름을 바꿀 수 있습니다. Bystro는 이 프로세스를 자동화하도록 도와줍니다.




    설치


    $ npm install -D bystro

    용법

    $ bystro <template_name> <path>

    Note: You can alternatively run npx bystro <template_name> <path> without install step.

    Arguments

    <template_name> - Name of the template you want to scaffold.
    <path>- Path to scaffold template in.

    List of available templates can be found here

    템플릿 만들기

    To create a local template start by making a .bystro directory in the current working directory:

    $ mkdir .bystro

    After that you can add templates:

    $ mkdir .bystro/my_template
    $ mkdir .bystro/my_template/__Name__
    $ echo 'import "./__Name__.css";' > .bystro/my_template/__Name__.js
    $ echo '// hello from __Name__'

    계획

    Before writing any code I found it reasonable to put together some small description of the algorithm that I expect from my CLI tool to implement:

    1. Obtain user input (<template_name> and <path_to_clone_into>) from the command line.

    2. Get template data by <template_name> by checking custom templates folder created by user and if not found fetch it from predefined templates folder inside of the package itself.

    3. If template was found prompt user to fill the variables required in the template.

    4. Interpolate template filenames and contents according to users input.

    5. Write result template files into <path_to_clone_into>

    건축물

    For now it is totally fine to store shared templates inside of package source code but the bigger it gets the slower npx will execute it.

    Later we could implement templates search using github api or something. That is why we need our code to be loosely coupled to easily switch between template repository implementations.

    Clean architecture to the rescue. I won't go in much details explaining it here, there are a lot of great official resources to read. Just take a look at the diagram which describes the main idea:

    CA states that source code dependencies can only point inwards, the inner circles must be unaware of the outer ones and that they should communicate by passing simple Data Transfer objects. Let's take all the about literally and start writing some code.

    비즈니스 규칙

    If we take a closer look at the algorithm we've defined at planning phase it seems like it's a perfect example of a use case. So let's implement right away:

    import Template from "entities/Template"
    
    export default class ScaffoldTemplateIntoPath {
      constructor(
        private templatesRepository: ITemplatesRepository,
        private fs: IFileSystemAdapter,
        private io: IInputOutputAdapter,
      ) {}
    
      public exec = async (path: string, name: string) => {
        if (!name) throw new Error("Template name is required");
    
        // 2. Get template data by <template_name>
        const dto = this.templatesRepository.getTemplateByName(name);
        if (!dto) throw new Error(`Template "${name}" was not found`);
    
        // 3. If template was found prompt user to fill the variable
        const template = Template.make(dto).setPath(path);
        const variables = await this.io.promptInput(template.getRequiredVariables());
    
        // 4. Interpolate template filenames and contents
        const files = template.interpolateFiles(values);
    
        // 5. Write modified files
        return this.fs.createFiles(files);
      };
    }
    

    보시다시피 TemplateITemplatesRepository , IFileSystemAdapterIInputOutputAdapter가 주입(반전)되는 동안 유일한 직접 종속성이므로 종속성 규칙을 위반하지 않습니다. 이러한 사실은 가능한 변경 사항이 사용 사례에 영향을 미치지 않고ScaffoldTemplateIntoPath 테스트 환경에서 쉽게 목업화할 수 있기 때문에 많은 유연성을 제공합니다.

    이제 Template 엔터티를 구현해 보겠습니다.

    class Template implements ITemplateInstance {
      constructor(private dto: ITemplate) {
        this.dto = { ...dto };
      }
    
      public getPath = () => {
        return this.dto.path;
      };
    
      public getRequiredVariables = () => {
        return this.dto.config.variables;
      };
    
      public getFiles = () => {
        return this.dto.files;
      };
    
      public interpolateFiles = (variables: Record<string, string>) => {
        return this.dto.files.map((file) => {
          // private methods
          file = this.interpolateFile(file, variables); 
          file.path = this.toFullPath(file.path);
          return file;
        });
      };
    
      public setPath = (newPath: string) => {
        this.dto.path = newPath;
        return this;
      };
    
      public toDTO = () => {
        return this.dto;
      };
    
      // ...
    }
    

    이를 통해 기본적으로 모든 자바스크립트 환경에서 사용할 수 있는 기본 비즈니스 규칙이 이미 준비되어 있습니다. CLI 도구, REST API, 프런트엔드 앱, 브라우저 확장 등이 될 수 있습니다.

    외부 레이어 구현에 대한 소스 코드를 자유롭게 확인하십시오.


    스트렛츠 / 바이스트로


    스캐폴딩 코드 템플릿 및 상용구용 CLI 유틸리티 라이브러리입니다.





    npm에 게시



    프로젝트를 실행 가능한 패키지npm로 전역에서 사용할 수 있도록 하려면 package.json에서 다음을 수행해야 합니다.

    {
      "name": "bystro",
      "version": "0.1.0",
      "bin": "./dist/index.js", // compiled code
      // ...
    }
    

    bin 필드npm를 설정하면 설치 시 bystro라는 심볼릭 링크를 ./node_modules/.bin에 넣어 프로젝트를 실행 파일로 취급해야 합니다.

    마지막으로 .ts 코드를 컴파일한 후 np 패키지를 사용하여 패키지를 효율적으로 게시할 수 있습니다.

    "scripts": {
      "build": "tsc -p .",
      "release": "yarn build && np", 
      // ...
    }
    

    npm run release 또는 yarn release를 실행하면 파일을 확인하고, 테스트를 실행하고, 버전을 범프하고, 마지막으로 프로젝트를 npm 레지스트리에 게시해야 합니다.

    🎉🎉🎉

    아웃트로



    클린 아키텍처를 내 프로젝트에 도입하게 되어 매우 기쁩니다. 하지만 제가 말하는 모든 것을 당연하게 여기지 않으셨으면 합니다. 나도 배우는 중이므로 일부 CA 개념을 이해하는 데 잘못되었을 수 있으며 피드백을 듣고 싶습니다.

    BTW 이것은 나의 첫 번째 기사이자 첫 번째 오픈 소스 프로젝트이며 커뮤니티에서 소식을 듣게 되어 기쁩니다. 모든 피드백, 풀 요청, 공개 문제가 좋습니다. 당신이 무슨 생각을하는지 제게 알려주세요.

    읽어주셔서 감사합니다 🙏

    좋은 웹페이지 즐겨찾기