본문 바로가기

FrontEnd

[번역] JS 번들 분할의 모든 것

반응형

원문 : https://medium.com/hackernoon/the-100-correct-way-to-split-your-chunks-with-webpack-f8a9df5b7758

 

The 100% correct way to split your chunks with Webpack

Working out the best way to serve up files to your users can be a tricky business. There’s so many different scenarios, different…

medium.com

해당 글의 주제

  • 사용자와 사이트에게 가장 적합한 파일 분할 방법을 파악하기
  • 파일 분할 방법 배우기(/w webpack4)
요즘 webpack4는 거의 사용하지 않으므로, 1번에 포인트를 맞춰 글을 읽으시면 좋습니다.

웹팩 용어집(Webpack glossary)에 따르면, 파일 분할 방법은 두 가지가 있습니다.

  • 번들 분할: 더 나은 캐싱을 위해 더 많은 더 작은 파일을 생성합니다
    • 각 네트워크 요청에서 모두 로드
  • 코드 분할: 사용자가 보고 있는 사이트 부분에 필요한 코드만 다운로드할 수 있도록 동적으로 코드를 로드합니다.

두 번째 것이 훨씬 더 매력적으로 들리지 않나요?

그리고 실제로 이 문제에 대한 많은 기사는

이것이 더 작은 JavaScript(JavaScript) 파일을 만드는 것이 항상 좋다고 생각하는 것 같습니다.


번들 분할

번들 분할의 기본 개념은 매우 간단합니다. 

하나의 거대한 파일이 있으면 코드 한 줄을 변경하는 경우 사용자는 전체 파일을 다시 다운로드해야 합니다. 

하지만 파일을 두 개로 분할하면 사용자는 변경된 파일만 다운로드하면 되고 브라우저는 캐시에서 다른 파일을 제공합니다.

 

번들 분할은 모두 캐싱에 관한 것이므로 처음 방문자에게 아무런 차이가 없다는 점은 주목할 가치가 있습니다.

  • 저는 너무 많은 성능 관련 기사들이 사이트를 처음 방문하는 것에 관한 내용만 다룬다고 생각합니다.
  • 부분적으로는 '첫인상이 중요'하기 때문일 수도 있고 부분적으로 측정하기 좋고 간단하기 때문일 수도 있습니다.

단골 방문자의 경우는 성능 향상이 미치는 영향을 정량화하는 것은 까다로울 수 있지만 정량화해야 합니다!

 

여기에는 스프레드시트가 필요하며,

각 캐싱 전략을 테스트할 수 있는 매우 특정한 케이스를 고정해야 합니다.

이전 단락에서 언급한 시나리오는 다음과 같습니다.

  • Alice는 10주 동안 일주일에 한 번 사이트를 방문합니다.
  • 우리는 일주일에 한 번 사이트를 업데이트합니다
  • 우리는 매주 '제품 목록' 페이지를 업데이트하고 있습니다.
  • 우리는 '제품 세부 정보' 페이지도 갖고 있지만, 현재 작업 중이 아닙니다.
  • 5주 차에 사이트에 새로운 npm 패키지를 추가합니다.
  • 8주 차에 기존 npm 패키지 중 하나를 업데이트합니다.

특정 유형의 사람들(나 같은)은 이 시나리오를 가능한 한 현실적으로 만들고 싶어할 것입니다. 

하지만 그럴 필요가 없습니다.

현실적이 시나리오는 중요하지 않으며 나중에 그 이유를 논의할 것입니다.


시작점(baseline)

우리의 전체 JavaScript 패키지는 400KB이고

현재 이를 main.js라는 단일 파일로 로드하고 있다고 가정해 보겠습니다.
다음과 같은 Webpack 설정이 있습니다(관련 없는 설정 항목은 생략함).

const path = require('path');

module.exports = {
  entry: path.resolve(__dirname, 'src/index.js'),
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
  },
};

캐시 버스팅을 처음 접하는 사람들을 위해:

내가 main.js라고 말할 때마다 내가 실제로 의미하는 것은 main.xMePWxHo.js와 같은 것입니다.

여기에서 요상한 문자 문자열은 파일 내용의 해시입니다. 

이것은 다른 파일 명을 의미합니다. 

애플리케이션의 코드가 변경되어 브라우저가 새 파일을 다운로드하도록 강제합니다.

 

매주 사이트에 새로운 변경 사항을 푸시할 때 이 패키지의 콘텐츠 해시가 변경됩니다. 

그래서 매주 Alice는 우리 사이트를 방문하여 새로운 400KB 파일을 다운로드해야 합니다.

 

이러한 이벤트의 섹시한 테이블을 만든다면 다음과 같이 보일 것입니다.

World’s most unnecessary total row

10주 동안 4.12MB입니다.

우리는 좀 더 최적화 할 수 있습니다.


벤더 패키지 쪼개기

패키지를 main.js 및 vendor.js 파일로 분할하겠습니다.

이것은 매우 쉽습니다.

const path = require('path');

module.exports = {
  entry: path.resolve(__dirname, 'src/index.js'),
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },
};

Webpack 4는 번들을 분할하는 방법을 정확히 알려주지 않아도 최선을 다해 이를 수행합니다.

 

많은 사람들은, 웹팩이 일을 알아서 잘한다고 생각하지만,

몇몇 사람들은 웹팩이 번들을 어떻게 처리하는지 궁금할 수 있습니다.

 

Anyhoo, optimization.splitChunks.chunks = 'all'을 추가하는 것은 

"node_modules의 모든 것을 vendors~main.js라는 파일에 넣어주세요"라고 웹팩에게 명령하는 것입니다.

 

이 기본 번들이 분할되면, Alice는 방문할 때마다 새로운 200KB main.js를 다운로드합니다.

하지만 vendors.js(200KB)는 1주차, 8주차 및 5주차(순서 아님)에만 다운로드합니다.

주 : 처음 방문 시 다운로드, 그 다음 캐싱

뜻밖에도 두 패키지 모두 정확히 200KB인 것으로 밝혀졌습니다.

총 2.64 MB 입니다.

 

36% 감소. 설정에 5줄의 코드를 추가하는 것은 나쁘지 않습니다.

이 성능 향상은 10주에 걸쳐 이루어졌기 때문에 좀 더 추상적인 것처럼 보이지만 

충성도가 높은 사용자에게 배송되는 바이트의 실제 36% 감소를 유발했으며,

우리는 우리 자신을 자랑스러워 할 수 있습니다.

하지만 우리는 더 잘할 수 있습니다.


각 npm 패키지 분할


우리의 vendors.js는 원래의 main.js 파일과 동일한 문제를 겪고 있습니다. 

즉, 한 부분이 변경되면 모든 부분을 다시 다운로드해야 합니다.

그렇다면 각 npm 패키지에 대한 별도의 파일이 없는 이유는 무엇인가요?
따라서 react, lodash, redux, moment 등을 다른 파일로 분할해 보겠습니다.

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

module.exports = {
  entry: path.resolve(__dirname, 'src/index.js'),
  plugins: [
    new webpack.HashedModuleIdsPlugin(), // so that file hashes don't change unexpectedly
  ],
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
  },
  optimization: {
    runtimeChunk: 'single',
    splitChunks: {
      chunks: 'all',
      maxInitialRequests: Infinity,
      minSize: 0,
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name(module) {
            // get the name. E.g. node_modules/packageName/not/this/part.js
            // or node_modules/packageName
            const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];

            // npm package names are URL-safe, but some servers don't like @ symbols
            return `npm.${packageName.replace('@', '')}`;
          },
        },
      },
    },
  },
};

해당 문서는 코드의 대부분을 잘 설명하고 있습니다.

하지만 어려운 부분에 대해서는 조금 설명하겠습니다.

저도 제대로 하는 데 꽤 오래 걸렸기 때문입니다.

  • Webpack에는 output 파일을 분할할 때 최대 3개의 파일과 30KB의 최소 파일 크기(모든 작은 파일이 함께 결합됨)와 같이 영리하지 않은 영리한 기본값이 있습니다.
    • 그래서 나는 이것들을 재정의했습니다.
  • cacheGroups는 Webpack이 청크를 output 파일로 그룹화하는 방법에 대한 규칙을 정의하는 곳입니다.
    • 여기에는 node_modules에서 로드되는 모든 모듈에 사용될 'vendor'라는 것이 있습니다.
      • 일반적으로 하나의 output 파일의 이름을 문자열로 정의하기만 하면 됩니다.
      • 그러나 저는 이름을 함수로 정의하고 있습니다.
        • 이 함수는 파싱된 모든 파일에 대해 호출됩니다.
        • 그런 다음 모듈 경로를 이용해 패키지 이름을 반환합니다.
        • 결과적으로 각 패키지에 대해 하나의 파일을 얻게 됩니다.
          • ex) npm.react-dom.899sadfhj4.js
  • NPM 패키지 이름이 게시되려면 URL이 안전해야 하므로(NPM package names must be URL-safe) 해당 packageName을 URI로 인코딩할 필요가 없습니다. - 이미 안전함
    • 하지만 이름에 @가 포함된 파일을 제공하지 않는 .NET 서버 문제가 있어서(범위가 지정된 패키지에서) 이를 이 스니펫에서 교체했습니다.
  • 이 전체 설정은 한번만 필요하기 때문에 훌륭합니다. 유지 관리가 필요하지 않습니다. 이름으로 패키지를 참조할 필요가 없습니다.

Alice는 여전히 매주 200KB의 main.js 파일을 다시 다운로드하고 처음 방문할 때 여전히 200KB의 npm 패키지를 다운로드하지만 

동일한 패키지를 두 번 다운로드하지는 않습니다.

모든 npm 패키지는 정확히 20KB였습니다. 그럴 가능성은 얼마나 될까요?

총 2.24 MB 입니다.

 

시작점에서 44% 감소를 가져왔습니다.

블로그 게시물에서 복사/붙여넣기할 수 있는 일부 코드에 대해 매우 훌륭합니다.

 

과연 감소율이 50%를 넘을 수 있을지 궁금합니다.


애플리케이션 코드 분할하기

불쌍한 앨리스가 계속해서 다운로드하고 있는 main.js 파일을 살펴보겠습니다.

 

이전에 이 사이트에는 제품 목록과 제품 세부 정보 페이지라는 두 가지 별도 섹션이 있다고 언급했습니다. 

이러한 각 영역의 고유 코드는 25KB입니다(150KB의 공유 코드를 제외하면 - 총 200KB).

 

우리의 '제품 상세' 페이지는 완벽하게 만들었기 때문에 요즘 많이 바뀌지 않습니다. 

따라서 별도의 파일로 만들면 대부분 캐시에서 제공할 수 있습니다.

 

또한 아이콘 렌더링을 위한 거대한 인라인 SVG 파일이 있다는 사실을 알고 계셨나요?

무게는 25KB에 달하고 거의 변경되지 않습니다.

우리는 그것에 대해 뭔가를 해야 합니다.
몇 가지 진입점을 수동으로 추가하여 각 항목에 대한 파일을 생성하도록 Webpack에 지시합니다.

module.exports = {
  entry: {
    main: path.resolve(__dirname, 'src/index.js'),
    ProductList: path.resolve(__dirname, 'src/ProductList/ProductList.js'),
    ProductPage: path.resolve(__dirname, 'src/ProductPage/ProductPage.js'),
    Icon: path.resolve(__dirname, 'src/Icon/Icon.js'),
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash:8].js',
  },
  plugins: [
    new webpack.HashedModuleIdsPlugin(), // so that file hashes don't change unexpectedly
  ],
  optimization: {
    runtimeChunk: 'single',
    splitChunks: {
      chunks: 'all',
      maxInitialRequests: Infinity,
      minSize: 0,
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name(module) {
            // get the name. E.g. node_modules/packageName/not/this/part.js
            // or node_modules/packageName
            const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];

            // npm package names are URL-safe, but some servers don't like @ symbols
            return `npm.${packageName.replace('@', '')}`;
          },
        },
      },
    },
  },
};
  • SVG 인라인 ICON 분리 (거의 변경 안되는 25kb)
  • 제품 목록 컴포넌트 분리 (자주 변경)
  • 제품 상세 컴포넌트 분리 (거의 변경 안되는 25kb)
  • 메인 번들 분리 (자주 변경)

Webpack은 중복 코드를 얻지 않도록 ProductList와 ProductPage 간에 공유되는 항목에 대한 파일도 생성합니다.

이렇게 하면 대부분의 week에 Alice에게 추가 50KB의 다운로드를 절약할 수 있습니다.

6주 차에 아이콘을 수정했습니다. 기억하실 거라 확신합니다.

이제 총 1.815MB만 다운로드 합니다.

 

Alice를 위한 번들 다운로드 사이즈를 56%나 줄였으며(우리 시나리오에셔),

이 줄어든 사이즈의 효과는 세상이 멸망할 때까지 계속됩니다.

그리고 이 모든 것은 Webpack 설정의 변경으로만 수행됩니다.

애플리케이션 코드는 변경하지 않았습니다.

앞에서 테스트 중인 정확한 시나리오는 실제로 중요하지 않다고 언급했습니다. 

어떤 시나리오를 생각해내든 결론은 동일하기 때문입니다. 

애플리케이션을 합리적인 작은 파일로 분할하여 사용자가 더 적은 코드를 다운로드하도록 합니다.


곧 다른 타입의 파일 분할 방법인 '코드 분할'에 대해 이야기할 예정이지만

먼저 지금 딩신이 생각하고 있는 세 가지 질문에 답하고 싶습니다.

#1: 네트워크 요청이 많으면 느려지지 않나요?


이에 대한 대답은 매우 큰 목소리로 "아니오"입니다.
HTTP/1.1 시절에는 이런 경우가 있었지만, HTTP/2에서는 그렇지 않습니다.

2016년 이 게시물(this post from 2016)과 2015년 Khan Academy(Khan Academy’s post from 2015)의 게시물 모두

HTTP/2를 사용하더라도 너무 많은 파일을 다운로드하는 것이 여전히 느리다는 결론에 도달했습니다.

하지만 이 두 게시물에서 '너무 많은' 파일은 '수백여 개'을 의미합니다.

따라서 수백 개의 파일이 있는 경우 동시성 제한에 도달하기 시작할 수도 있습니다.

HTTP/2 지원은 Windows 10의 IE 11부터 시작됩니다.

하지만 저는 그보다 오래된 설정을 사용하는 모든 사람을 대상으로 철저한 설문 조사를 수행했으며 

만장일치로(unanimously) 네트워크 요청 수가 웹 사이트가 얼마나 빨리 로드되는지와 관련이 없다는 것에 동의했습니다.

#2: 각 웹팩 번들에 오버헤드/보일러플레이트 코드가 있지 않습니까?

사실입니다.

#3: 작은 파일이 여러 개 있으면 압축률이 떨어지지 않을까요?

네, 그것도 사실입니다.


정리하자면

  • 더 많은 파일 = 더 많은 Webpack 상용구를 의미합니다.
  • 더 많은 파일 = 더 적은 압축

얼마나 걱정해야 하는지 정확히 알 수 있도록 이것을 정량화해 봅시다.

 

190KB 사이트가 19개 파일로 분할되어 브라우저로 전송된 경우, 총 바이트의 약 2%가 추가되었습니다.

그래서... 우주가 끝날 때까지 처음 방문할 때 2% 더 큰 번들 사이즈를 제공하고,

두 번째 방문할 때마다 60% 더 작은 번들 사이즈를 제공합니다.

 

 

1개 파일 대 19개를 테스트하는 동안 HTTP/1.1을 포함하여 일부 다른 네트워크에서도 시도해 보았습니다.

다음은 '파일이 많을수록 좋다'는 생각을 열렬히 지지하는 표입니다.

동일한 190KB 사이트의 두 가지 버전 로드(Firebase 정적 호스팅에서)

주 : HTTP 1.1의 FIbre은 광섬유 망을 의미하는데,
모바일 네트워크에서 HTTP1.1을 사용하는 경우는 거의 없음으로 (2016년 chrome51 버전 이후 전부 적용)
이렇게 테스트한듯 함.
만약 HTTP/2를 지원하지 않는다면, 번들 스플리팅보다 이를 먼저 지원하는게 급선무 아닐까?

 

3G 및 4G에서 이 사이트는 19개의 파일이 있을 때 로드 시간이 30% 단축되었습니다.

이것은 꽤 시끄러운 데이터입니다. 

예를 들어,

run 2의 4G에서 사이트는 646ms에 로드되었고, 두 번의 실행 후에는 1,116ms가 걸렸습니다.

즉, 변경 사항 없이 73% 더 오래 걸렸습니다. 

따라서 HTTP/2가 '30% 더 빠르다'고 주장하는 것은 약간 비열한 것 같습니다.

 

나는 HTTP/2가 어떤 차이를 만들어냈는지 정량화하기 위해 이 표를 만들었지만 

실제로 내가 말할 수 있는 유일한 것은 "아마도 큰 차이가 없을 것"이라는 것입니다.

 

정말 놀라운 것은 마지막 두 행이었습니다. 

오래된 Windows와 HTTP/1.1에서는 훨씬 더 느릴 것이라고 장담했었습니다.

저는 더 느린 인터넷이 필요할 것 같습니다.

 

이것이 번들 분할에 대해 제가 말하고 싶은 전부입니다.

이 접근 방식의 유일한 단점은 작은 파일을 많이 로드해도 괜찮다고 사람들을 지속적으로 설득해야 한다는 것입니다.

 


Code splitting (불필요한 코드 다운받지 않기)

이 특정 접근 방식은 일부 사이트에서만 의미가 있을 것 같습니다.

 

제가 방금 만든 20/20 규칙을 설명드리겠습니다.

  • 사이트에서 사용자의 20%만 방문하는 부분이 있고
  • 사이트 자바스크립트의 20%보다 크면
  • 해당 코드만 스플리팅 합니다.

20 수치는 입맛에 따라 변경할 수 있고,

분명 이보다 복잡한 시나리오가 존재할 것입니다.

요점은 코드 분할이 사이트에 적합한지 결정하는 균형점이 존재한다는 것입니다.

 

어떻게 결정하나요?

쇼핑 사이트가 있으며 

현재 방문자의 30%만이 방문하기 때문에 '체크아웃' 코드를 분리해야 하는지 궁금하다고 가정해 보겠습니다. 

요점은 코드 분할이 사이트에 적합하지 않은 케이스가 있다는 것입니다.

더 중요한 것은 더 좋은 물건을 파는것입니다.

 

두 번째는 얼마나 많은 코드가 체크아웃에 완전히 고유한지 알아내는 것입니다. 

항상 '코드 분할'을 하기 전에 '번들 분할'을 해야 하므로 

코드의 이 부분이 얼마나 큰지 이미 알고 있을 것입니다.

 

해당 번들 크기가 생각보다 작을 수 있으므로 흥분하기 전에 합계를 먼저 확인하세요. 

예를 들어 React 사이트가 있는 경우 스토어, 리듀서, 라우터, 액션 등이 전체 사이트에서 모두 공유됩니다. 

고유한 부분은 대부분 컴포넌트의 헬퍼 함수힙니다.

 

따라서 결제 페이지에 완전히 고유한 코드는 7KB입니다. 

나머지 사이트는 300KB입니다. 

저는 이것을 보고 다음과 같은 몇 가지 이유로 귀찮게 코드 분할을 하지 않겠다고 말할 것입니다.

 

  • 미리 로드하는 것이 더 느리지 않습니다.
    • 이 모든 파일을 병렬로 로드하고 있음을 떠올리세요.
    • 300KB와 307KB 사이의 로드 시간 차이가 큰 의미가 있을까요?
  • 나중에 이 코드를 로드하면 사용자는 'TAKE MY MONEY'를 클릭한 후 해당 파일을 기다려야 합니다.
    • 이는 인터랙션 중간의 매우 중요한 시점입니다.
  • 코드를 분할하려면 애플리케이션 코드를 변경해야 합니다. 
    • 이전에는 동기식 논리만 있었던 곳에 비동기식 논리를 도입합니다. 
    • 로켓 과학 정도로 복잡한 것은 아니지만 사용자 경험에 대한 인식 가능한 개선을 위해 정당화되어야 한다고 생각하는 복잡성입니다.

 

좋은 코드 분할의 두 가지 예를 살펴보겠습니다.


폴리필

대부분의 사이트에 적용되고 간단하게 코드 분할을 소개하기 좋은 예제입니다.
저는 제 사이트에서 여러 멋진 기능을 사용하고 있으므로 필요한 모든 폴리필을 가져오는 파일이 있습니다.

여기에는 다음 여덟 줄이 포함됩니다.

require('whatwg-fetch');
require('intl');
require('url-polyfill');
require('core-js/web/dom-collections');
require('core-js/es6/map');
require('core-js/es6/string');
require('core-js/es6/array');
require('core-js/es6/object');

진입점인 index.js의 맨 위에 이 파일을 가져옵니다.

import './polyfills';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App/App';
import './index.css';

const render = () => {
  ReactDOM.render(<App />, document.getElementById('root'));
}

render(); // yes I am pointless, for now

번들 분할 섹션의 Webpack 설정을 사용하면

여기에 4개의 npm 패키지가 있으므로 폴리필이 자동으로 4개의 다른 파일로 분할됩니다. 

 

모두 약 25KB이며 브라우저의 90%는 해당 폴리필이 필요하지 않으므로 동적으로 로드할 가치가 있습니다.

 

Webpack 4와 import() 구문(import 구문과 혼동하지 말 것)을 사용하면 폴리필을 조건부로 로드하는 것이 매우 쉽습니다.

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App/App';
import './index.css';

const render = () => {
  ReactDOM.render(<App />, document.getElementById('root'));
}

if (
  'fetch' in window &&
  'Intl' in window &&
  'URL' in window &&
  'Map' in window &&
  'forEach' in NodeList.prototype &&
  'startsWith' in String.prototype &&
  'endsWith' in String.prototype &&
  'includes' in String.prototype &&
  'includes' in Array.prototype &&
  'assign' in Object &&
  'entries' in Object &&
  'keys' in Object
) {
  render();
} else {
  import('./polyfills').then(render);
}

 

이해되시죠?

  • 모든 항목이 지원되는 경우 페이지를 렌더링합니다.
    • 그렇지 않으면 폴리필을 가져온 다음 페이지를 렌더링합니다.
  • 이 코드가 브라우저에서 실행될 때 Webpack의 런타임은 4개의 npm 패키지 로드를 처리합니다.
    • 다운로드 및 구문 분석이 완료되면 render()를 호출하고 작업이 계속됩니다.
      • import()를 사용하려면 Babel의 동적 임포트 플러그인이 필요합니다.
      • 또한 Webpack 문서에서 설명하는 것처럼 import()는 Promise을 사용하므로 다른 폴리필과 별도로 폴리필해야 합니다.

쉽죠? 여기 좀 까다로운 것이 있습니다…


경로 기반 동적 로딩(React 특정)

앨리스의 예로 돌아가서 이제 사이트에 'admin' 섹션이 있다고 가정해 보겠습니다.

여기서 제품 판매자는 로그인하여 판매용 물건을 관리할 수 있습니다.

이 섹션에는 npm의 멋진 기능, 많은 차트 및 크고 뚱뚱한 차트 라이브러리가 있습니다. 

이미 번들 분할을 수행 중이었기 때문에 모두 100KB가 넘는 음영임을 알 수 있었습니다.

(주 - 초기 페이지 로드 시 이미 다운로드 된 번들들임)

현재 사용자가 /admin URL을 볼 때 <AdminPage>를 렌더링하는 라우팅 설정이 있습니다. 

Webpack이 초기 번들링 시, 즉 모든 파일을 묶을 때

import AdminPage from './AdminPage.js'를 찾고 "이봐, 초기 페이로드에 이것을 포함시켜야 해"라고 말할 것입니다.

그러나 우리는 그것을 원하지 않습니다. 

Webpack이 이를 동적으로 로드할 수 있도록 

import('./AdminPage.js')와 같은 동적 가져오기 내부에 관리자 페이지에 대한 참조를 넣어야 합니다.

꽤 멋지고 설정이 전혀 필요하지 않습니다.

따라서 AdminPage를 직접 참조하는 대신 

사용자가 /admin URL로 이동할 때 렌더링될 다른 구성 요소를 만들 수 있습니다. 

다음과 같이 보일 수 있습니다.

import React from 'react';

class AdminPageLoader extends React.PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      AdminPage: null,
    }
  }

  componentDidMount() {
    import('./AdminPage').then(module => {
      this.setState({ AdminPage: module.default });
    });
  }

  render() {
    const { AdminPage } = this.state;

    return AdminPage
      ? <AdminPage {...this.props} />
      : <div>Loading...</div>;
  }
}

export default AdminPageLoader;

개념이 상당히 직관적이죠? 

이 컴포넌트가 마운트되면(사용자가 /admin URL에 있음을 의미).

/AdminPage.js를 동적으로 로드한 다음 해당 컴포넌트에 대한 참조를 상태로 저장합니다.

render 메서드에서 

  • <AdminPage>가 로드되기를 기다리는 동안 <div>Loading...</div>을 렌더링하거나
  • <AdminPage>가 로드된 후 상태에 저장되면 렌더링합니다.

이는 설명을 위한 용도로, 현실에서는 React 공식 문서에서 설명된 대로 구현하면 됩니다.

 


저는 위에 언급한 내용이 번들 분할의 전부라고 생각합니다.

 

  • 사람들이 사이트를 두 번 이상 방문하는 경우 코드를 여러 개의 작은 파일로 분할합니다.
  • 대부분의 사용자가 방문하지 않는 사이트의 많은 부분이 있는 경우 해당 코드를 동적으로 로드합니다.
    • 20/20의 법칙
      • 사이트 자바스크립트 크기의 20% 이상
      • 사용자의 20% 이상만 방문

읽어주셔서 감사합니다. 최고의 하루 보내세요!
...젠장 CSS를 언급하는 것을 잊었습니다!

 

주 : CSS 번들 크기를 줄이는 방법
1. tailwind와 같은 utility css 사용
2. 위의 리액트처럼 경로 기반 분할 
반응형