monorepository에서 React 사용하기

19258 단어 architecturereact
TL;DRJump straight to code.Monorepository는 공유 도구 (eslint, 웹 팩,prettier) 설정의 장점을 이용하여react 프로젝트, 격리 및 테스트 구성 요소/연결/기타 응용 프로그램 부분을 구성할 수 있도록 합니다.
주의: 본고는 전단 저장소만 소개합니다.

왜?


디자인 시스템과 그에 의존하는react 응용 프로그램이 몇 개 있다고 가정하십시오.monorepo가 없는 경우:
  • 디자인 시스템을 단독으로 개발하고react 구성 요소가 있는 npm 라이브러리로 발표 - 스토리북, 웹 패키지, eslint, 디자인 시스템의 기타 도구 설정 설정
  • 응용 프로그램에 새 저장소를 만듭니다. 이 저장소는 응용 프로그램의 디자인 시스템, 스토리북, 웹 패키지, eslint 및 기타 도구 설정에 따라 달라집니다(새 응용 프로그램이 필요할 때마다 이 절차를 반복합니다)
  • 설계 시스템 및 모든 어플리케이션 지원 - 프로젝트별 모든 도구 및 종속성 업데이트
  • 새로운 개발자를 고용하고 응용 프로그램당 단독 설명
  • 프로그램이 있을 때는 좋지만, 여러 프로그램을 사용하기 시작하면 진정한 복사 붙여넣기 지옥이 됩니다.
    Monorepository에서 다음을 수행할 수 있습니다.
  • 모든 중복 논리를 한 위치로 유지하고 모든 응용 프로그램과 패키지 간에 공유
  • 한 저장소에서 모든 관련 프로젝트를 관리합니다. 이 경우 팀에 합류한 새 개발자가 모든 프로젝트에 완전히 액세스할 수 있습니다
  • 모든 패키지
  • 에서 개발 도구(webpack,eslint,jest 등) 설정 재사용
  • 더 큰 코드 재사용 실현 - 디자인 시스템의 예시를 제외하고 갈고리 라이브러리를 추출하여 패키지를 분리할 수 있습니다
  • 템플릿 코드를 설정하지 않고 새 응용 프로그램과 패키지를 만듭니다
  • 모든 응용 프로그램과 디자인 시스템 업데이트를 동기화하며 의존 항목을 업데이트할 필요가 없음
  • 어떻게


    전체 예는 react-monorepo-starter 에서 확인할 수 있습니다.

    프로젝트 구조


    공유 도구 설정이 있는 최소 프로젝트 구조 - 스크립트, 스토리북, 패키지 폴더는 모든 응용 프로그램과 패키지에 사용되는 모든 공유 논리를 포함합니다.
    .
    ├── scripts/
    │   ├── build-package.js
    │   └── start-app-dev-server.js
    ├── storybook/
    │   ├── main.js
    │   └── start.js
    ├── webpack/
    │   ├── .babelrc.js
    │   ├── get-app-config.js
    │   ├── get-package-config.js
    │   └── loaders.js
    ├── src/
    │   ├── packages/
    │   │   └── ui/ –> @monorepo/ui
    │   │       ├── src/
    │   │       │   ├── index.js
    │   │       │   └── Button/
    │   │       │       └── Button.jsx
    │   │       ├── package.json
    │   │       └── webpack.config.js
    │   └── apps/
    │       └── hello-world/ -> @monorepo/hello-world
    │           ├── src/
    │           │   └── index.jsx
    │           ├── package.json
    │           └── webpack.config.js
    ├── .eslintrc.js
    ├── .prettierrc.js
    └── package.json
    

    패키지 생성 설정


    웹 패키지를 설정하려면, 우리는 심상치 않은 조정 - 자동 별명 생성 - 소프트웨어 패키지와 응용 프로그램 src 디렉터리를 해결할 수 있습니다.
    예를 들어 @monorepo/hello-world 응용 프로그램의 경우 @monorepo/uisrc/packages/ui 별명을 가리켜야 합니다.
    이것은 쉽게 할 수 있다. 너는 모든 논리를 찾을 수 있다here
    두 개의 독립된 웹 패키지 설정이 필요합니다. 첫 번째는 패키지이고, 두 번째는 응용 프로그램에 사용됩니다.그들은 같은 불러오는 프로그램을 공유하기 때문에 두 가지 설정에서 파일을 다시 사용할 수 있도록 추출 loaders 을 해야 합니다.
    // loaders.js
    // babel loader example
    const path = require('path');
    const babelrc = require('./.babelrc');
    
    const babel = () => ({
      test: /\.(js|jsx)$/,
      exclude: /node_modules/,
      include: path.join(__dirname, '../src'),
      use: {
        loader: 'babel-loader',
        options: babelrc, // babelrc is loaded directly with webpack
      },
    });
    
    패키지 구성의 모든 다른 부분은 다른 항목과 같지만 조금 다르다. 우리는 함수로 모든 내용을 포장하여 모든 응용 프로그램과 패키지를 패키지 구성으로 만들어야 한다.
    // get-pacakge-config.js
    const fs = require('fs-extra');
    const path = require('path');
    const webpack = require('webpack');
    const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
    const TerserJSPlugin = require('terser-webpack-plugin');
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const loaders = require('./loaders');
    const getPackageAlias = require('../scripts/utils/get-package-alias');
    
    module.exports = function getPackageConfig({ base, publicPath = '/' } = {}) {
      const { name } = fs.readJsonSync(path.join(base, './package.json'));
    
      return {
        mode: 'production',
        devtool: false,
        entry: path.join(base, './src/index'),
    
        optimization: {
          minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
        },
    
        resolve: {
          extensions: ['.js', '.jsx'],
          alias: {
            ...getPackageAlias(name),
          },
        },
    
        module: {
          rules: [loaders.babel(), loaders.less({ mode: 'production', publicPath }), loaders.file()],
        },
    
        plugins: [
          new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }),
          new MiniCssExtractPlugin(),
        ],
      };
    };
    
    그리고 우리는 reuse webpack configuration 한 줄로 포장할 수 있다.
    // @monorepo/ui package -> src/packages/ui
    const path = require('path');
    const getPackageConfig = require('../../../webpack/get-package-config');
    
    module.exports = getPackageConfig({ base: path.join(__dirname, './') });
    

    공유된 이야기책


    나는 storybook를 사용하여 ui 개발을 진행하기 때문에, 우리는 이를monorepository와 함께 사용하도록 설정해야 한다.
    한 가지 도전은 모노포가 성장할 때 대형 이야기책이 점점 느려지기 때문에 현재 개발되지 않은 이야기를 삭제해야 한다는 것이다.이를 실현하기 위해서는 편집을 계획하는 패키지와 응용 프로그램부터 이야기책을 작성해야 한다.예를 들어, 두 개의 패키지를 사용하여 스토리북 실행 – npm run storybook @package/first @package/second이를 위해서는 패키지 디렉터리를 분석하고 사용하지 않은 것을 제거해야 한다. (웹 패키지 별명과 거의 같다.)전체 논리 here 를 찾을 수 있습니다.
    필터 패키지의 핵심 논리:
    // storybook/main.js
    const DEFAULT_STORIES = ['../src/**/*.story.@(jsx|mdx)'];
    const packages = argv._;
    let stories = DEFAULT_STORIES;
    
    if (packages.length !== 0) {
      stories = [];
    
      packages.forEach(packageName => {
        const packagePath = getPackagePath(packageName);
        if (packagePath) {
          stories.push(path.join(packagePath, 'src/**/*.story.@(jsx|mdx)'));
        } else {
          process.stdout.write(chalk.yellow(`Warning: Unable to resolve ${packageName}, skipping\n`));
        }
      });
    }
    

    생성 및 시작 스크립트 공유


    템플릿 코드를 줄이기 위해서는 공유 구축 및 시작 스크립트를 만들어서 저장소 루트 디렉터리에서 패키지를 구축하고 시작할 수 있도록 해야 합니다.위와 같이, 이것은 src 디렉터리 해석을 통해 완성된 것이다.전체 코드를 찾을 수 있습니다 here
    이 스크립트를 사용하면 다음과 같은 응용 프로그램을 구축하고 시작할 수 있습니다.
  • npm start @application/name – 애플리케이션 시작
  • npm run build @package/name – 단일 패키지 구성
  • npm run build @package/first @package/second – 패키지 목록 생성
  • 발전을 위해 준비를 하다



    현재, 우리는 이미 개발을 위해 충분한 준비를 마쳤다. 우리는 storybook을 사용하여 가방에 구성 요소를 개발하고, 웹 패키지 별명을 가진 응용 프로그램에서 그것을 사용할 수 있다.Example :
    // example with included @monorepo/hello-world app
    import React from 'react';
    import { Text } from '@monorepo/typography';
    import Button from '@monorepo/ui/Button/Button';
    
    export default function App() {
      return (
        <div>
          <Text style={{ marginBottom: 20 }}>Welcome to monorepo starter</Text>
          <Button>Hello</Button>
        </div>
      );
    }
    

    좋은 웹페이지 즐겨찾기