diff --git a/README.md b/README.md index 4a522a048..88d94affc 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,8 @@ Maven template that creates a minimal, best-practices-based Adobe Experience Man * **Responsive Layout:** On templates or individual pages, [define how the elements reflow](https://docs.adobe.com/content/help/en/experience-manager-65/authoring/siteandpage/responsive-layout.html) for the defined breakpoints. * **Header and Footer:** Assemble and localize them without code, using the [localization features of the components](https://docs.adobe.com/content/help/en/experience-manager-core-components/using/get-started/localization.html). * **Style System:** Avoid building custom components by allowing authors to [apply different styles](https://docs.adobe.com/content/help/en/experience-manager-learn/getting-started-wknd-tutorial-develop/style-system.html) to them. -* **Front-End Build:** Front-end devs can [mock AEM pages](https://docs.adobe.com/content/help/en/experience-manager-core-components/using/developing/archetype/uifrontend.html#webpack-dev-server) and [build client libraries](https://docs.adobe.com/content/help/en/experience-manager-core-components/using/developing/archetype/uifrontend.html) with Webpack, TypeScript, and SASS. +* **Front-End Build:** Front-end devs can [mock AEM pages](https://docs.adobe.com/content/help/en/experience-manager-core-components/using/developing/archetype/uifrontend.html#webpack-dev-server) and [build client libraries](https://docs.adobe.com/content/help/en/experience-manager-core-components/using/developing/archetype/uifrontend.html) with Webpack, TypeScript, and SASS. +* **Decoupled Front-End:** When chosing the frontend module to be decoupled, the project is preconfigured to use the [AEMaaCS Frontend Pipeline](https://experienceleague.adobe.com/docs/experience-manager-cloud-service/content/sites/administering/site-creation/enable-front-end-pipeline.html). See [the AEM React SPA](https://github.com/adobe/aem-react-spa) template for more details how to get started with a decoupled frontend module using React. * **WebApp-Ready:** For sites using [React](https://docs.adobe.com/content/help/en/experience-manager-core-components/using/developing/archetype/uifrontend-react.html) or [Angular](https://docs.adobe.com/content/help/en/experience-manager-core-components/using/developing/archetype/uifrontend-angular.html), use the [SPA SDK](https://docs.adobe.com/content/help/en/experience-manager-64/developing/headless/spas/spa-architecture.html) to retain [in-context authoring of the app](https://docs.adobe.com/content/help/en/experience-manager-learn/sites/spa-editor/spa-editor-framework-feature-video-use.html). * **Commerce Enabled:** For projects that want to use Commerce Integration Framework ([CIF](https://github.com/adobe/aem-core-cif-components)) to integrate with commerce solutions like Magento. * **Forms Enabled:** For projects that want to use ([Forms](https://github.com/adobe/aem-core-forms-components)). @@ -76,7 +77,7 @@ Name | Default | Description `aemVersion` | `cloud` | Target AEM version (can be `cloud` for [AEM as a Cloud Service](https://docs.adobe.com/content/help/en/experience-manager-cloud-service/landing/home.html); or `6.5.5` for [Adobe Managed Services](https://github.com/adobe/aem-project-archetype/tree/master/src/main/archetype/dispatcher.ams) or on-premise). `sdkVersion` | `latest` | When `aemVersion=cloud` an [SDK](https://docs.adobe.com/content/help/en/experience-manager-cloud-service/implementing/developing/aem-as-a-cloud-service-sdk.html) version can be specified (e.g. `2020.02.2265.20200217T222518Z-200130`). `includeDispatcherConfig` | `y` | Includes a dispatcher configuration either for cloud or for AMS/on-premise, depending of the value of `aemVersion` (can be `y` or `n`). -`frontendModule` | `general` | Includes a Webpack frontend build module that generates the client libraries (can be `general` or `none` for regular sites; can be `angular` or `react` for a Single Page App that implements the [SPA Editor](https://docs.adobe.com/content/help/en/experience-manager-65/developing/headless/spas/spa-overview.html)). +`frontendModule` | `general` | Includes a Webpack frontend build module that generates the client libraries (can be `general` or `none` for regular sites; can be `angular`, `react` or `decoupled` for a Single Page App that implements the [SPA Editor](https://docs.adobe.com/content/help/en/experience-manager-65/developing/headless/spas/spa-overview.html). In the later case the project will be preconfigured to use the [AEM as a Cloud Service Frontend Pipeline](https://experienceleague.adobe.com/docs/experience-manager-cloud-service/content/sites/administering/site-creation/enable-front-end-pipeline.html)). `language` | `en` | Language code (ISO 639-1) to create the content structure from (e.g. `en`, `deu`). `country` | `us` | Country code (ISO 3166-1) to create the content structure from (e.g. `US`). `singleCountry` | `y` | Includes a language-master content structure (can be `y`, or `n`). diff --git a/src/main/archetype/pom.xml b/src/main/archetype/pom.xml index 05d173a46..5017088ec 100644 --- a/src/main/archetype/pom.xml +++ b/src/main/archetype/pom.xml @@ -24,7 +24,7 @@ #set( $symbol_escape = '\' ) #set( $startbrace = "{" ) #set( $endbrace = "}" ) -#set( $isSpaProject = $frontendModule == "angular" || $frontendModule == "react" ) +#set( $isSpaProject = $frontendModule == "angular" || $frontendModule == "react" || $frontendModule == "decoupled" ) #set( $includeClassifierOnUberJar = $aemVersion.matches("6\.5\.[0-5]") ) 4.0.0 @@ -38,7 +38,7 @@ all core -#if ( $frontendModule != "none" ) +#if ( $frontendModule != "none" && $frontendModule != "decoupled" ) ui.frontend #end #if ( $includeFormsheadless == "y" ) @@ -89,7 +89,7 @@ UTF-8 UTF-8 #if ( $isSpaProject ) - 1.3.12 + 1.3.16 #end #if ( $frontendModule == "angular" ) +#if ( $frontendModule != "decoupled" ) - +#end + + diff --git a/src/main/archetype/ui.apps/src/main/content/jcr_root/apps/__appId__/components/xfpage/customheaderlibs.html b/src/main/archetype/ui.apps/src/main/content/jcr_root/apps/__appId__/components/xfpage/customheaderlibs.html index ded265079..e45510b38 100644 --- a/src/main/archetype/ui.apps/src/main/content/jcr_root/apps/__appId__/components/xfpage/customheaderlibs.html +++ b/src/main/archetype/ui.apps/src/main/content/jcr_root/apps/__appId__/components/xfpage/customheaderlibs.html @@ -31,8 +31,16 @@ +#if ( $frontentModule != "decoupled" ) +#end + + + + #else @@ -45,4 +53,12 @@ -#end \ No newline at end of file + + + + +#end + diff --git a/src/main/archetype/ui.content/src/main/content/jcr_root/conf/__appId__/_sling_configs/.content.xml b/src/main/archetype/ui.content/src/main/content/jcr_root/conf/__appId__/_sling_configs/.content.xml index dc27b4f7b..47db4c560 100644 --- a/src/main/archetype/ui.content/src/main/content/jcr_root/conf/__appId__/_sling_configs/.content.xml +++ b/src/main/archetype/ui.content/src/main/content/jcr_root/conf/__appId__/_sling_configs/.content.xml @@ -1,5 +1,5 @@ - +#if ( $frontendModule == 'decoupled') + + + + + + + + + + + + +
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
+
+
+#end
\ No newline at end of file diff --git a/src/main/archetype/ui.content/src/main/content/jcr_root/conf/__appId__/settings/wcm/policies/.content.xml b/src/main/archetype/ui.content/src/main/content/jcr_root/conf/__appId__/settings/wcm/policies/.content.xml index 8305357e3..d43e4110b 100644 --- a/src/main/archetype/ui.content/src/main/content/jcr_root/conf/__appId__/settings/wcm/policies/.content.xml +++ b/src/main/archetype/ui.content/src/main/content/jcr_root/conf/__appId__/settings/wcm/policies/.content.xml @@ -423,8 +423,10 @@ +#if ( $frontendModule != "decoupled" ) + clientlibs="[${appId}.${frontendModule}]" +#end + sling:resourceType="wcm/core/components/policy/policy"> #end @@ -435,7 +437,9 @@ jcr:primaryType="nt:unstructured" jcr:title="${appTitle} App Policy" sling:resourceType="wcm/core/components/policy/policy" +#if ( $frontendModule != "decoupled" ) clientlibs="[${appId}.${frontendModule}]" +#end isRoot="{Boolean}true" structureDepth="3" /> @@ -611,7 +615,7 @@ jcr:primaryType="nt:unstructured" jcr:title="SPA Content" sling:resourceType="wcm/core/components/policy/policy" - components="[/libs/wcm/foundation/components/responsivegrid,/apps/${appId}/components/text]"> + components="[group:${appTitle} - Content]"> #if ( ($includeForms == "y" or $includeFormsenrollment == "y" or $includeFormscommunications == "y") and $aemVersion == "cloud") diff --git a/src/main/archetype/ui.content/src/main/content/jcr_root/content/__appId__/.content.xml b/src/main/archetype/ui.content/src/main/content/jcr_root/content/__appId__/.content.xml index c8c86a961..111178b55 100644 --- a/src/main/archetype/ui.content/src/main/content/jcr_root/content/__appId__/.content.xml +++ b/src/main/archetype/ui.content/src/main/content/jcr_root/content/__appId__/.content.xml @@ -4,10 +4,11 @@ + + + + + + + + + + + diff --git a/src/main/resources/META-INF/archetype-post-generate.groovy b/src/main/resources/META-INF/archetype-post-generate.groovy index f49678753..749110c91 100644 --- a/src/main/resources/META-INF/archetype-post-generate.groovy +++ b/src/main/resources/META-INF/archetype-post-generate.groovy @@ -86,13 +86,15 @@ if (aemVersion == "cloud") { buildContentSkeleton(uiContentPackage, uiAppsPackage, singleCountry, appId, language, country) cleanUpFrontendModule(frontendModules, frontendModule, rootPom, rootDir, appsFolder, confFolder, configFolder, contentFolder,enableSSR, includeCommerce) -if ( includeDispatcherConfig == "n"){ +if (includeDispatcherConfig == "n") { // remove the unneeded config file + def rrfConfig; if (aemVersion.startsWith("6.4")) { - assert new File("$configFolder/config.publish/org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl.config").delete() + rrfConfig = new File("$configFolder/config.publish/org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl.config") } else { - assert new File("$configFolder/config.publish/org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl.cfg.json").delete() + rrfConfig = new File("$configFolder/config.publish/org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl.cfg.json") } + assert !rrfConfig.exists() || rrfConfig.delete(); } else { def source; if (aemVersion == 'cloud') { @@ -275,12 +277,12 @@ def cleanUpFrontendModule(frontendModules, optionFrontendModule, rootPom, rootDi } // Rename selected frontend module (e.g. "ui.frontend.angular" -> "ui.frontend") - if (optionFrontendModule != "none") { + if (optionFrontendModule != "none" && optionFrontendModule != "decoupled") { assert new File(rootDir, "ui.frontend.$optionFrontendModule").renameTo(new File(rootDir, "ui.frontend")) } // Not generating SPA: Delete SPA-specific files - if (optionFrontendModule != "angular" && optionFrontendModule != "react") { + if (optionFrontendModule != "angular" && optionFrontendModule != "react" && optionFrontendModule != "decoupled") { // Delete app component assert new File("$appsFolder/components/structure/spa").deleteDir() assert new File("$appsFolder/components/xfpage/body.html").delete() @@ -298,6 +300,7 @@ def cleanUpFrontendModule(frontendModules, optionFrontendModule, rootPom, rootDi assert new File("$confFolder/settings/wcm/template-types/remote-page").deleteDir() // Delete SPA content + assert new File("$contentFolder/language-masters/en/home").deleteDir() assert new File("$contentFolder/us/en/home").deleteDir() }else{ @@ -312,13 +315,21 @@ def cleanUpFrontendModule(frontendModules, optionFrontendModule, rootPom, rootDi } // Generating SPA: Delete non-SPA specific files - if (optionFrontendModule == "angular" || optionFrontendModule == "react") { + if (optionFrontendModule == "angular" || optionFrontendModule == "react" || optionFrontendModule == "decoupled") { assert new File("$confFolder/settings/wcm/templates/page-content").deleteDir() assert new File("$confFolder/settings/wcm/template-types/page").deleteDir() - if(enableSSR == "n"){ + // remove JcrResourceResolverFactoryImpl configuration as Sling Mappings do not work with SPA yet + for (def rrfConfig in [ + new File("$configFolder/config.publish/org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl.cfg.json"), + new File("$configFolder/config.publish/org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl.config") + ]) { + assert !rrfConfig.exists() || rrfConfig.delete() + } + + if (enableSSR == "n") { - if(optionFrontendModule == "react"){ + if (optionFrontendModule == "react") { //cleanup IO runtime related files from react module assert new File(rootDir, "ui.frontend/webpack.config.express.js").delete(); assert new File(rootDir, "ui.frontend/webpack.config.adobeio.js").delete(); @@ -326,7 +337,7 @@ def cleanUpFrontendModule(frontendModules, optionFrontendModule, rootPom, rootDi assert new File(rootDir, "ui.frontend/src/server").deleteDir(); assert new File(rootDir, "ui.frontend/actions").deleteDir(); assert new File(rootDir, "ui.frontend/scripts").deleteDir(); - }else if(optionFrontendModule == "angular"){ + } else if (optionFrontendModule == "angular") { assert new File(rootDir, "ui.frontend/server.ts").delete(); assert new File(rootDir, "ui.frontend/serverless.ts").delete(); assert new File(rootDir, "ui.frontend/manifest.yml").delete(); @@ -337,6 +348,11 @@ def cleanUpFrontendModule(frontendModules, optionFrontendModule, rootPom, rootDi } } + + if (optionFrontendModule == "decoupled") { + // remove clientlibs for decoupled frontend + assert new File("$appsFolder/clientlibs").deleteDir(); + } } } diff --git a/src/test/resources/projects/frontend-decoupled/archetype.properties b/src/test/resources/projects/frontend-decoupled/archetype.properties new file mode 100644 index 000000000..284959929 --- /dev/null +++ b/src/test/resources/projects/frontend-decoupled/archetype.properties @@ -0,0 +1,27 @@ +groupId=archetype.it +artifactId=testing-frontend-decoupled +appId=testing-frontend-decoupled +package=it.pkg +version=0.1-SNAPSHOT +appTitle=Test General Decoupled Project +aemVersion=cloud +sdkVersion=latest +language=en +country=us +singleCountry=n +frontendModule=decoupled +includeExamples=n +includeErrorHandler=n +includeDispatcherConfig=n +includeCommerce=n +commerceEndpoint=https://hostname.com/grapql +includeForms=n +includeFormsenrollment=n +includeFormscommunications=n +sdkFormsVersion=latest +datalayer=${datalayer} +amp=${amp} +enableDynamicMedia=y +enableSSR=n +precompiledScripts=n +includeFormsheadless=n \ No newline at end of file diff --git a/src/test/resources/projects/frontend-decoupled/goal.txt b/src/test/resources/projects/frontend-decoupled/goal.txt new file mode 100644 index 000000000..7c32f5598 --- /dev/null +++ b/src/test/resources/projects/frontend-decoupled/goal.txt @@ -0,0 +1 @@ +install