템플릿 확장성
템플릿 확장성은 PWA Kit v3에서 도입된 기능입니다. 이 기능은 템플릿을 맞춤화하여 PWA Kit 프로젝트를 보다 손쉽게 구축할 수 있도록 지원합니다. Retail React App과 같은 기존 기본 템플릿을 맞춤화하거나 자체적으로 프로젝트를 만들 수 있습니다. PWA Kit 커뮤니티의 구성원들 간에 기본 템플릿을 서로 공유해보시기 바랍니다.
템플릿 확장성은 선택한 템플릿 내의 모든 파일을 복제할 필요 없이 선택한 템플릿을 쉽게 수정할 수 있도록 해줍니다.
템플릿 확장성은 선택적 기능입니다. 단, 2023년 6월 15일 이후 생성된 새 프로젝트는 템플릿 확장성을 사용하도록 자동으로 구성됩니다.
PWA Kit v3에서 프로젝트에는 기본 템플릿과 재정의 디렉터리를 구성할 수 있으며, 둘 다 프로젝트의 package.json
파일에서 구성할 수 있습니다. 템플릿 확장성을 사용하려면 package.json
에서 ccExtensibility.extends
를 사용하여 기본 템플릿을 선언하고 ccExtensibility.overridesDir
를 사용하여 재정의 디렉터리를 선언해야 합니다. (구성에 대한 자세한 내용은 다음 섹션에서 다룹니다.)
기본 템플릿은 다른 PWA Kit 프로젝트에서 일부 파일을 재정의할 수 있도록 사전 구성된 완전한 기능을 갖춘 PWA Kit 프로젝트가 포함되어 있는 npm 모듈입니다. 기본 템플릿을 "확장 가능한 앱" 또는 "확대 가능한 앱"이라고도 합니다."
재정의 디렉터리는 프로젝트 내에서 해당 파일을 재정의하는 파일을 기본 템플릿에 저장할 수 있도록 만들어진 디렉터리입니다.
재정의 디렉터리를 이미 정의했고, Retail React App을 기본 템플릿으로 정의했다고 가정해보겠습니다. 그리고 Retail React App의 홈 페이지 구성요소를 재정의하려 한다고 가정해 보겠습니다. Retail React App에서 홈 페이지 구성요소에 대한 코드는 @salesforce/retail-react-app
패키지 내의 app/pages/home/index.jsx
에 있습니다. 해당 파일을 재정의하려면 package.json
의 ccExtensibility.overridesDir
를 통해 선언된 디렉터리에 동일한 파일을 재생성해야 합니다. 따라서 새 파일의 경로는 <ccExtensibility.overridesDir>/app/pages/home/index.jsx
입니다.
이제 index.jsx
를 @salesforce/retail-react-app
패키지 내의 파일로 가져올 때마다 재정의 디렉터리의 파일이 패키지의 파일 대신 로드됩니다. 재정의가 적용되려면 파일 이름의 기본적인 부분만 동일해야 합니다. 파일 확장명은 다를 수 있습니다.
앱을 빌드할 때 기본 템플릿의 파일을 재정의 디렉터리에 점진적으로 추가할 수 있습니다.
재정의하는 파일이 많을수록 기본 템플릿의 변경 사항을 적용하기 위한 작업량이 많아집니다.
템플릿 확장성 기능의 작동 방식을 보려면 npx @salesforce/pwa-kit-create-app@latest --outputDir <path/to/new/local/project>
를 실행하여 새로운 PWA Kit v3 프로젝트를 생성합니다.
생성된 프로젝트는 https://pwa-kit.mobify-storefront.com/의 앱과 거의 동일하게 보이는 앱을 제공하는 Retail React App 기본 템플릿을 사용합니다.
템플릿 확장성 튜토리얼에서는 사이트에 몇 가지 일반적인 맞춤화 설정을 추가하는 방법을 알아봅니다.
이 섹션의 지침에서는 기능을 활성화한 상태에서 생성되지 않은 기존 프로젝트에 대해 템플릿 확장성을 활성화한다고 가정합니다.
최신 버전의 Retail React App으로 업그레이드하려면 다음 명령을 실행합니다.
npm install @salesforce/retail-react-app@latest
해당 명령을 실행한 후 사이트를 테스트하여 정상적으로 작동하는지 확인하는 것이 좋습니다.
기본 템플릿을 정의하려면 프로젝트의 package.json
파일에 @salesforce/retail-react-app
(또는 다른 템플릿)을 npm 종속 기능으로 추가합니다.
그런 다음 package.json
에 다음 키와 값을 사용하여 ccExtensibility
키를 추가합니다.
Retail React App 이외의 기본 템플릿을 사용하는 경우 @salesforce/retail-react-app
을 다른 템플릿의 패키지 식별자로 바꾸는 것을 잊지 마십시오.
overridesDir
의 값을 맞춤형 디렉터리 이름으로 바꿀 수 있지만, 프로젝트(및 예제 코드) 간의 일관성이 유지되도록 overrides
를 사용하는 것이 좋습니다.
기본 프로젝트와 기본 템플릿 모두에 동일한 npm 종속성을 나열하지 마십시오. 프로젝트의 package.json
에 나열된 종속성이 기본 템플릿의 종속성과 다른지 확인하십시오. 이렇게 하면 @salesforce/pwa-kit-dev
가 종속성 확인에서 두 가지를 서로 구분할 수 있습니다. 구성에 설명된 대로 기본 프로젝트의 package.json
에서 기본 템플릿을 정의합니다. 기본 프로젝트는 자체에서 상속할 수 없습니다.
프로젝트와 package.json
파일에 나열된 기본 템플릿의 npm 종속 구성요소의 버전이 서로 충돌하지 않아야 합니다. 기본 템플릿이 @chakra-ui
를 사용하는 경우, 프로젝트에도 해당 종속 구성요소가 있어야 하며 버전이 동일해야 합니다. 이 예방 조치는 동일한 패키지의 버전이 충돌하여 번들이 의도치 않게 커지는 것을 방지합니다(기능적 손상이 발생할 수도 있음). 단, 지정된 종속 구성요소를 가져오는 기본 템플릿의 모든 파일에 대해 재정의를 추가한 경우는 예외로 이 규칙이 적용되지 않습니다. 이 경우, 재정의를 통해 종속 구성요소를 가져오는 모든 파일을 제거했기 때문에 프로젝트에서 기본 템플릿의 종속 구성요소 버전을 가져오는 일이 없습니다.
기본 템플릿에 사용되지 않는 npm 종속 구성요소를 추가하기만 하면 됩니다. 👌
Managed Runtime에 배포되는 모든 PWA Kit 프로젝트에는 다음 파일이 있어야 합니다.
<overridesDir>/app/main.jsx
<overridesDir>/app/ssr.js
<overridesDir>/app/routes.jsx
<overridesDir>/app/request-processor.js
config/default.js
(예외:package.json
의mobify
키를 사용하여 사이트 구성 데이터를 저장하는 경우)
프로젝트에서 동작을 맞춤화하려는 경우, 일반적으로 @salesforce/retail-react-app
의 다음 파일을 재정의합니다.
app/pages/home/index.jsx
: 거의 모든 프로젝트에서는 첫 단계로 홈 페이지에서 기본 Salesforce 마케팅 컨텐츠를 제거합니다.app/static/*
: 이 파일은 데스크톱 및 모바일 브라우저에서 사이트를 브랜딩하는 데 사용하는 아이콘을 제공하는 기본 파일입니다. 브랜드에 맞게 업데이트하십시오.app/constants.js
app/assets/svg/brand-logo.svg
: 이 파일은 생성기 프로젝트에서 재정의됩니다. 프로젝트의 다른 아이콘을 재정의하려면 다음 예를 따릅니다.
이 "파일 시스템을 API로 가져오기/내보내기" 설정은 기본 파일을 찾고 복사한 다음 동작과 로직을 맞춤화하기 위한 것입니다. 코드를 여러 하위 구성요소를 조정하는 작은 파일로 분해하면, 재정의하려는 동작만 손쉽게 대상으로 지정할 수 있습니다.
그런데 해당 파일의 일부 동작만 변경하기 위해, 파일을 재정의에 복사해야 하는 경우도 있습니다. 가능한 경우, 기본 템플릿 내보내기를 가져온 후 다시 내보내는 것이 좋습니다. 그러면 템플릿 버전을 변경할 때 확장된 프로젝트에서 코드를 수동으로 업데이트할 필요가 없습니다.
예를 들어 생성된 프로젝트의 routes.jsx
파일에서 import {routes as _routes} from '@salesforce/retail-react-app/app/routes'
를 통해 기본 경로를 가져오고, _routes
를 규칙으로 사용하여 이러한 기본 경로가 외부 종속 구성요소에 의해 관리된다는 것을 나타냅니다. routes.jsx
내보내기 경로의 맞춤형 구현인 @salesforce/retail-react-app/app/routes.jsx
파일과 마찬가지로 /
(홈) 경로를 추가합니다. React Router가 경로 배열에서 지정된 경로 이름의 첫 번째 항목을 찾기 때문에, 새 경로는 기본 경로보다 우선합니다.
템플릿 확장성을 사용하는 대부분의 프로젝트에서는 상대적 가져오기를 사용하는 것이 가장 적합합니다. 기본 템플릿(예: @salesforce/retail-react-app
)의 파일에 대한 가져오기 동작에는 재정의 디렉터리의 파일에 우선 순위를 부여하는 특수한 로직이 있습니다. 이 가져오기 로직은 재정의 디렉터리의 파일에 적용되지 않습니다. 따라서 대부분의 구현에는 상대적 가져오기를 사용하는 것이 좋습니다.
템플릿 확장성은 "심성 모형" 측면에서 생각하면 복잡할 수 있지만, 발생 가능한 예상치 못한 "문제"로는 두 개의 서로 다른 충돌하는 파일을 실수로 가져오는 것을 들 수 있습니다. PWA Kit 프로젝트는 @salesforce/pwa-kit-dev
를 통해 구축되며, 이 프로젝트는 내부적으로 Webpack를 사용합니다. @salesforce/pwa-kit-dev
에는 템플릿 확장성의 "재정의" 기능을 지원하는 플러그인이 있습니다. 이 플러그인은 모든 Webpack 파일 요청을 검사하여 다음 두 가지를 확인합니다.
- 이 파일 요청이 기본 템플릿에서 시작되었는지 여부
- 이 파일이 재정의 디렉터리에 있는지 여부
이 두 가지가 모두 그런 것으로 확인되면 빌드 시 재정의 디렉터리에 있는 파일을 가리키도록 파일 요청이 다시 작성됩니다.
재정의 디렉터리에서 발생하는 Webpack 파일 요청에는 이 로직이 적용되지 않습니다. 따라서 재정의 디렉터리와 기본 템플릿 모두에서 동일한 파일을 가져올 수 있습니다. 예를 들어 @saleforce/retail-react-app/my-file
및 <overrides directory>/my-file
을 동일한 번들에 가져오는 경우, Webpack에서 can’t find <export name> from <filename>
이라는 줄과 함께 혼란스러운 오류가 발생합니다. 번들이 번들 포함의 대상이 되는 가져오기를 알 수 없기 때문에, Webpack에서 이 오류가 발생하는 것입니다.
한 가지 주의해야 할 만한 예외를 제외하고, 재정의에 해당 파일이 있는 경우 기본 템플릿에서 파일을 가져오는 것을 피하는 것이 중요합니다. 앞서 특수 파일 섹션의 코드 예에서 설명하고 constants.js
에서 보여드린 것처럼, 기본 템플릿을 가져온 후 필요한 만큼 내보내기를 재정의하거나 추가하여 모든 내보내기를 다시 내보내는 것이 좋습니다.
app/components/_app/index.jsx
구성요소를 재정의해야 할 경우 Header
, Footer
및 DrawerMenu
와 같은 여러 글로벌 구성요소를 사용할 수 있습니다. _app/index.jsx
재정의가 실행된 후, 기본 템플릿에서 이 구성요소를 가져오려고 시도하면 파일 요청이 <ccExtensibility.overridesDir>/app/components/_app/index.jsx
로 다시 라우팅됩니다. 하지만 주의해야 할 것이 있습니다. app/components/_app/index.jsx
가 Header
및 Footer
를 가져오므로, _app/index.jsx
에서도 가져오기를 업데이트해야 합니다! 그렇지 않으면 _app/index.jsx
가 기본 템플릿에서 Header
및 Footer
를 가져옵니다.
ccExtensibility.overridesDir
를 우선으로 하여 @salesforce/pwa-kit-dev
가 여러 곳에서 해당 이름의 파일을 확인하고 우선한다는 점에서, ccExtensibility.extends
에서 시작하는 ECMAscript 가져오기는 "마법"과 같습니다.
반면 <ccExtensibility.overridesDir>/*
에서 시작하는 가져오기는 이런 마법과 같은 동작이 없으므로, 원하는 파일을 대상으로 지정해야 합니다. 따라서 다음과 같이 <ccExtensibility.overridesDir>/app/components/_app/index.jsx
에서 <ccExtensibility.overridesDir>/app/components/header/index.jsx
를 명시적으로 가져와야 합니다.
다음과 같이 패키지에서 가져오지 마십시오. 이 경우 재정의 디렉터리의 헤더를 우회하게 됩니다.
routes.jsx
는 전체 애플리케이션에 대해 Webpack 용어로 소위 "entryPoint"라는 것을 형성하는 특수 파일입니다. routes.jsx
에 잘못 설정된 내용이 있으면, pwa-kit-dev
의 경로 기반 청킹이 제대로 확인되지 않으므로 컴파일 단계에서 전체 앱이 실패합니다. 이러한 이유로 overridesDir
에 기본값 @salesforce/retail-react-app/app/routes.jsx
와 로컬 routes.jsx
로부터의 가져오기를 조합하여 경로를 적절하게 확장하는 방법의 예를 제공해 드립니다.
여기서 가져오기는 "트리의 최상단"에 있으므로 이러한 파일을 재정의한 다음 footer.jsx
를 재정의할 경우, _app/index.jsx
로 돌아와 상대적 템플릿 가져오기를 가리키도록 해당 가져오기를 수정해야 합니다.
템플릿 확장성 시스템의 알려진 제한 사항 중 하나는 마법과 같이retail-react-app/constants
등을 끌어오기 때문에, 기본 템플릿(@salesforce/retail-react-app
)이 이 파일을 가져올 때마다 동일한 값이 내보내질 것으로 예상된다는 것입니다.
해당 ECMAScript 내보내기와 동일한 ECMAScript 내보내기를 기본 템플릿으로 내보내지 못하는 재정의의 파일은 아래와 같은 예기치 않은 오류를 유발할 수 있습니다.
다음과 같이 constants.js
파일을 재정의 디렉터리에 추가하면 오류가 발생합니다.
오류 메시지 예:
이 오류의 원인은 CAT_MENU_DEFAULT_ROOT_CATEGORY
가 @salesforce/retail-react-app/components/_app/index.jsx
에서 예상되는 내보내기인데 위의 유일한 내보내기 CUSTOM_MESSAGE
로 재정의하는 과정에서 constants.js
가 내보내는 기본 "API 계약"(지정된 값(이 예의 경우 CAT_MENU_DEFAULT_ROOT_CATEGORY
)에 따라 파일이 달라지는 기능)을 위반하기 때문입니다
올바른 방법은 다음과 같습니다. 이 방법을 사용하면 예상되는 필수 내보내기로서 CAT_MENU_DEFAULT_ROOT_CATEGORY
가 누락되지 않습니다. 따라서 내보낸 API의 일관성이 유지됩니다.
이 방법은 추가적인 변경에만 적용됩니다. 다음 예에서는 기본 retail-react-app/constants.js
파일의 내보내기에 없는 CUSTOM_MESSAGE
내보내기를 추가합니다.
이 방법은 다음 시나리오에 적용됩니다. 여기서 DEFAULT_LOCALE
은 retail-react-app/constants
에 의해 내보내지고, 우리는 이 값을 변형합니다.
템플릿 후크는 이전에 npx pwa-kit-create-app
명령(지금은 npx @salesforce/pwa-kit-create-app
으로 이름 변경)을 통해 사용할 수 있었던 Retail React App 템플릿과 상호 작용하는 새로운 방법입니다.
다음 목록에 나열된 구성요소의 작은 부분 집합을 전역적으로 추가하도록 지원하는 새로운 "템플릿 후크"가 템플릿 확장성 기능의 일부로 @salesforce/retail-react-app
에 추가되었습니다. 기본적으로 이러한 각 구성요소는 null
을 반환하며, 완료된 PWA Kit 구현 프로젝트가 불필요하게 커지지 않도록 하기 위해 의도적으로 비어 있습니다. 기본 @salesforce/retail-react-app
은 이러한 구성요소에 기능을 추가하지 않습니다. 고객 구현에서 필요 이상으로 많은 파일을 덮어쓸 필요 없이 이들 위치의 템플릿에 "후크"를 통해 액세스하여 프로젝트를 맞춤화할 수 있도록, 템플릿 후크가 항상 null
을 반환합니다.
@salesforce/retail-react-app@1.0.0
을 기준으로, 다음 템플릿 후크를 사용할 수 있습니다.
app/components/_app/partials/above-header.jsx
app/pages/product-list/partials/above-page-header.jsx
PWA Kit v3 출시 당시를 기준으로, 공개적으로 제공되는 확장 가능한 기본 템플릿은 @salesforce/retail-react-app
하나뿐입니다(이후 더 많은 템플릿이 제공될 예정).
기본 템플릿으로 사용하려면 PWA Kit 프로젝트를 npm에 게시하고, 패키지 이름과 일치하는 값을 모든 ECMAscript 가져오기에 접두사로 붙여야 합니다. 예를 들어 @salesforce/retail-react-app
은 npm에 게시되고, 가져오기에는 @salesforce/retail-react-app
이 붙습니다. 이 접두사는 패키지의 루트 디렉터리에 대한 참조로, 패키지가 기본 템플릿으로 제대로 작동하는 데 필요합니다.
PWA Kit 프로젝트를 확장 가능한 기본 템플릿으로 사용하려면 모든 가져오기에 <npm package name>
을 사용해야 합니다. 예를 들어 @salesforce/retail-react-app
은 package.json
에 ccExtensibility
를 추가하여 로컬 IDE 참조(예: @salesforce/retail-react-app/app/components/_app
)가 올바르게 확인되도록 합니다.
- Retail React App 템플릿을 복사하고 편집하는 대신 템플릿 확장성을사용합니다.
- 변경할 때 프로젝트를 주기적으로 테스트하여 나타나는 문제를 식별하고 해결합니다.
- 프로덕션 환경에 배포하기 전에 비프로덕션 환경에서 맞춤화된 기능을 테스트합니다.
- 필요에 따라 재정의를 반복하여 동작을 구체화합니다.
이 섹션에서는 템플릿 확장성을 사용하는 동안 발생할 수 있는 일반적인 오류에 대해 제안된 해결 방법을 제시합니다.
프로젝트에서 파일을 변경한 후 사이트를 미리 볼 때 업데이트 내용이 표시되지 않습니다.
원인: 로컬 서버를 다시 시작하지 않았습니다.
제안된 솔루션: npm start
를 실행한 다음 사이트를 다시 미리 봅니다.
이 내용은 버전 3 이전의 PWA Kit 버전을 사용하는 경우에만 적용됩니다.
원인: package.json
파일에 필요한 ccExtensibility
구성이 없습니다.
제안된 솔루션: package.json
에서 이 구성을 완료합니다.
원인: 재정의 디렉토리(overridesDir
)의 필수 파일이 누락되었습니다.
제안된 솔루션: 프로젝트의 overrides
디렉터리에 필요한 모든 파일이 포함되어 있는지 확인합니다. 필수 프로젝트 파일을 참조하십시오.
원인: 기본 템플릿과 프로젝트 간에 충돌하는 종속성 버전이 있습니다.
제안된 솔루션: 기본 템플릿과 프로젝트 모두 동일한 버전의 공유 종속성을 사용하는지 확인합니다. 버전 충돌을 참조하십시오.