TinyMCE webpack 최적화 구현 계획 (하이브리드 방식)

Eugenius1st·5일 전

React JS

목록 보기
42/42
post-thumbnail

기존 코드에서 tinymce/tinymce-reactCDN방식으로 이용하고 있었다.

이유는,

  • 프로젝트에 파일을 포함하지 않아도 됨
  • 캐싱 활용 가능 (다른 사이트에서도 같은 CDN 사용 시)
  • 초기 설정이 간단
    ... 가장 큰 이유는 회사에서 빨리 HTML <-> 에디터 읽기쓰기 호환 기능을 가진 에디터를 도입해달라고 했기 때문.

하지만 React에서 CDN으로 불러오면 아래와 같은 단점이 있어서 npm방식으로 바꾸려 한다.

  • CDN 서버 장애 시 사용 불가
  • 버전 관리가 명확하지 않음 (URL에 버전이 있어도 관리가 어려움)
  • 보안 이슈 가능성 (외부 스크립트 실행)
  • 번들러 최적화 불가

아지만 이렇게 하다보니
예전에 써서 문제가 없던 Quill에디터는
모노리식 번들(단일번들) 이라 css만 import하면 동작하고, 모든것을 webpack이 처리해서 문제가 없었다고 한다.
TinyMCE 라는 라이브러리는 모듈러 아키텍처라 필요한 리소스를 런타임에 로드하기 때문에 React 에서 사용시 문제가 생겼다. 이 라이브러리의 유연성과 확장성 때문에 리소스 경로설정 이라는 것이 필요했다.

추가로 번들 크기가 증가할것이다 라는 문제점이 또 보였고..

결국 CRACO/webpack 설정을 하기로 했다.


TinyMCE webpack 최적화 구현 계획 (하이브리드 방식) 개요

목표

  • TinyMCE를 npm 패키지로 사용 (CDN 제거)
  • 공통 webpack 설정 + 앱별 오버라이드 구조
  • webpack으로 리소스 최적화 및 번들 크기 감소
  • seller-admin에 먼저 적용 (테스트 후 system-admin 확장)
    구현 단계

1. CRACO 설치 및 공통 설정

  • apps/seller-admin/package.json에 @craco/craco 의존성 추가
  • 루트에 공통 설정 생성: craco.base.js
  • TinyMCE 리소스 복사 설정 (CopyWebpackPlugin)
  • 공통 번들 최적화 설정 (압축, 트리쉐이킹, 코드 스플리팅)
  • apps/seller-admin/craco.config.js 생성
  • 공통 설정 import 및 seller-admin 특화 오버라이드 (필요시)
  • apps/seller-admin/package.json의 scripts를 react-scripts → craco로 변경

2. Node.js 버전 고정

  • 루트에 .nvmrc 파일 생성 (Node.js 24.6.0)
  • Jenkins 배포 시 버전 일관성 보장

3. TinyMCE 컴포넌트 수정

  • packages/ui-components/src/organisms/TinyMCEEditor.tsx 수정
  • base_url 설정 제거 (webpack이 처리)
  • tinymceScriptSrc prop 제거 (npm 패키지 사용)
  • 필요한 플러그인만 import하여 트리쉐이킹 최적화

4. 빌드 스크립트 검증

  • pnpm install 실행
  • pnpm --filter seller-admin start로 개발 서버 테스트
  • pnpm --filter seller-admin build로 프로덕션 빌드 테스트

주요 파일 변경

1. apps/seller-admin/package.json

  • @craco/craco 의존성 추가
  • scripts 수정: react-scripts → craco

2. craco.base.js (신규, 루트)

  • 공통 webpack 설정
  • TinyMCE 리소스 복사 (CopyWebpackPlugin)
  • 공통 번들 최적화 설정

3. apps/seller-admin/craco.config.js (신규)

  • 공통 설정 import
  • seller-admin 특화 설정 오버라이드 (필요시)

4. .nvmrc (신규)

  • Node.js 24.6.0 고정

5. packages/ui-components/src/organisms/TinyMCEEditor.tsx

  • base_url 제거
  • tinymceScriptSrc 제거

아키텍처

루트/
├── craco.base.js          # 공통 webpack 설정
├── .nvmrc                  # Node.js 버전 고정
└── apps/
    └── seller-admin/
        └── craco.config.js # 공통 설정 import + 오버라이드

예상 효과

  • 번들 크기: 약 20-30% 감소 (트리쉐이킹 및 최적화)
  • 로딩 속도: 개선 (로컬 파일, 번들 최적화)
  • 안정성: 향상 (외부 CDN 의존성 제거)
  • 유지보수성: 향상 (공통 설정 중앙 관리)

주의사항

Jenkins 배포 시 Node.js 24.6.0 이상 필요
빌드 메모리 사용량 증가 가능 (webpack 최적화)
seller-admin 테스트 완료 후 system-admin에도 동일 적용


코드

1. apps/system-admin/package.json 수정

script 에서
'start':'react-script start' 와 같은 것들을 아래처럼 바꾸고

  • "prestart": "node ../../scripts/copy-tinymce.js seller-admin",
  • "start": "craco start",
  • "build": "craco build",
  • "test": "craco test",

devDependencies에서 아래와 같은 것들을 설치

  • "@craco/craco": "^7.1.0",
  • "copy-webpack-plugin": "^12.0.2",

2. apps/system-admin/craco.config.js 생성

const baseConfig = require('../../craco.base.js');

module.exports = {
  ...baseConfig,
  // system-admin 특화 설정이 필요한 경우 여기에 추가
  // 예: 특정 플러그인, 로더 설정 등
};

3. 루트 스크립트에 copy-tinymce.js 생성

const fs = require('fs');
const path = require('path');

// 루트 디렉토리 찾기 (craco.base.js와 동일한 기준)
const rootDir = path.resolve(__dirname, '../../..');

// 여러 가능한 경로 시도
const possibleSources = [
  // 1. 루트의 node_modules (craco.base.js와 동일한 방식)
  path.resolve(rootDir, 'node_modules/tinymce'),
  // 2. pnpm의 .pnpm 디렉토리에서 찾기
  (() => {
    try {
      const pnpmStore = path.resolve(rootDir, 'node_modules/.pnpm');
      if (fs.existsSync(pnpmStore)) {
        // tinymce@로 시작하는 디렉토리 찾기
        const entries = fs.readdirSync(pnpmStore);
        for (const entry of entries) {
          if (entry.startsWith('tinymce@')) {
            const entryPath = path.join(pnpmStore, entry);
            if (fs.statSync(entryPath).isDirectory()) {
              const tinymcePath = path.join(entryPath, 'node_modules/tinymce');
              if (fs.existsSync(tinymcePath)) {
                return tinymcePath;
              }
            }
          }
        }
      }
      return null;
    } catch (e) {
      return null;
    }
  })(),
  // 3. ui-components의 node_modules
  path.resolve(rootDir, 'packages/ui-components/node_modules/tinymce'),
  // 4. system-admin의 node_modules
  path.resolve(__dirname, '../node_modules/tinymce'),
];

// 존재하는 소스 경로 찾기
let source = null;
for (const possibleSource of possibleSources) {
  if (possibleSource && fs.existsSync(possibleSource)) {
    source = possibleSource;
    break;
  }
}

if (!source) {
  console.error('❌ TinyMCE not found in node_modules');
  console.error('   Tried paths:');
  possibleSources.forEach((p, i) => {
    if (p) {
      const exists = fs.existsSync(p) ? '✓' : '✗';
      console.error(`   ${i + 1}. ${exists} ${p}`);
    } else {
      console.error(`   ${i + 1}. (skipped)`);
    }
  });
  console.error('\n   Please ensure TinyMCE is installed:');
  console.error('   pnpm install');
  console.error('\n   Or check if TinyMCE is in packages/ui-components:');
  console.error('   ls packages/ui-components/node_modules/tinymce');
  process.exit(1);
}

const dest = path.resolve(__dirname, '../public/tinymce');
const checkFile = path.resolve(dest, 'plugins/help/js/i18n/keynav/en.js');

// 파일이 없을 때만 복사 (빠름)
if (!fs.existsSync(checkFile)) {
  console.log('📦 Copying TinyMCE files (first time only)...');
  console.log(`   From: ${source}`);
  console.log(`   To: ${dest}`);
  
  const { execSync } = require('child_process');
  
  if (fs.existsSync(dest)) {
    fs.rmSync(dest, { recursive: true, force: true });
  }
  
  const isWindows = process.platform === 'win32';
  if (isWindows) {
    execSync(`xcopy /E /I /Y "${source}" "${dest}"`, { stdio: 'inherit' });
  } else {
    execSync(`cp -R "${source}" "${dest}"`, { stdio: 'inherit' });
  }
  console.log('✅ Done');
} else {
  console.log('⚡ TinyMCE files already exist');
}

파일별 용도 설명

1. craco.base.js - Webpack 설정 파일

  • 용도: CRACO를 통한 webpack 설정
  • 역할:
    개발/프로덕션 모드에서 webpack이 실행될 때 동작
    CopyWebpackPlugin으로 TinyMCE 리소스를 빌드 출력에 복사
    프로덕션 빌드 최적화 (코드 스플리팅, 트리쉐이킹, 압축)
  • 작동 시점:
  • craco start 실행 시 (개발 모드)
  • craco build 실행 시 (프로덕션 빌드)
  • 🔴 문제점:
    개발 모드에서 CopyWebpackPlugin이 초기 복사를 보장하지 않을 수 있음
    개발 서버 시작 시 파일이 없으면 에러 발생 가능!!!

2. scripts/copy-tinymce.js - 파일 복사 스크립트

  • 용도: 개발 서버/빌드 시작 전에 TinyMCE 파일을 수동 복사
  • 역할:
    prestart, prebuild 훅에서 실행
    TinyMCE 파일이 없을 때만 복사 (조건부)
    개발 모드에서 리소스 누락 방지
  • 작동 시점:
    pnpm start 실행 전 (prestart 훅)
    pnpm build 실행 전 (prebuild 훅)
  • 장점:
    개발 서버 시작 전에 파일 존재 보장
    파일이 있으면 스킵하여 빠른 시작
    에러 메시지로 문제 진단 용이
profile
최강 프론트엔드 개발자가 되고싶은 안유진 입니다

0개의 댓글