Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce environment specific configurations for Spartacus deployment on ccv2 #5772

Open
tobi-or-not-tobi opened this issue Dec 12, 2019 · 45 comments

Comments

@tobi-or-not-tobi
Copy link
Contributor

tobi-or-not-tobi commented Dec 12, 2019

For angular developers it's very common to use the environments file to distinguish different settings for different builds. This is often used for setting up different tokens for different environment. For example to target a different payment system, analytic system, tag manager, etc.

The build on Commerce Cloud is currently always using the production build. With this setup, the environment specific settings are not aligned with the build, as production build is always using the production environment settings.

Different options:

  1. We align the angular build with the build to ccv2 environments. This would result in specific builds for specific environments. This will make the builds no longer reusable cross environments.
  2. load environment settings from a file while bootstrapping the app. This would not be recommended for production builds as we introduce a blocking call before we can bootstrap the app (using config initializers)
  3. bake environment specific variables into UI, similarly to what we've done with the occ-backend-base-url. We would use backend properties, which gives the advantage of runtime configuration over build time configuration.
@neilhubertprice
Copy link
Contributor

neilhubertprice commented Dec 18, 2019

In addition to what Tobias described above, there is also currently a need for a mechanism to differentiate between local development vs deployment in CCv2. An example currently is the way that the occ-backend-base-url is used.

The options currently are: configure it in code, or use the meta injection approach. If configured in code it overrides the meta approach, but the meta approach is not available in a local development environment. It would be possible to achieve this via an environment.ts (local dev) vs environment.prod.ts (CCv2) switching approach ... if there was a standard/recommended mechanism for how to handle this in CCv2. At the moment CCv2 just uses the yarn build, taking the package.json definition (ng build vs ng build --prod) so the same environment file is used in both local/CCv2 (depending on how package.josn has been configured)

Most developers will be working in a checked-out version of the same repo used for deployment to CCv2. The current setup leaves them with only manual file alteration possibilities to make this work. For a repo that is currently working in CCv2 that means for local development, the developers must either change package.json or environment.ts/environment.prod.ts ... and to enable this, the standard app.module.ts code needs to change slightly (test whether/not the an environment configuration item for occBaseUrl exists).

It seems like some form of option 1 is required for local vs CCv2 builds, as well as perhaps option 3 for applying the CCv2 build across multiple different environments in CCv2

@aleruz
Copy link

aleruz commented Feb 5, 2020

A non trivial implementation may need different configuration properties to set for different environments, for example to connect also to other external systems or for some debugging options. Using environments is at the moment working very well for us.

@jannesaarinen
Copy link

I would vote for the option 1 from the starters three options.

In the current project we would like to set the server side rendering off for development environment, but true for test and production. Currently it seems that the only option is to create separate builds for development and test / production.

@Xymmer Xymmer added this to the needs-milestone milestone Apr 23, 2020
@Xymmer Xymmer added this to BACKLOG in Aimed 2.0 via automation Sep 2, 2020
@alvteren
Copy link
Contributor

alvteren commented Sep 3, 2020

Hi, @tobi-or-not-tobi !
How to use backend properties from Commerce Cloud?

I have disabled the properties on JS Storefront Service.
image

For other services proreperties aren't disabled

@alvteren
Copy link
Contributor

alvteren commented Sep 9, 2020

I added properties to JS Storefront Service in Portal Commerce Cloud.
image

And I added meta tag with placeholder
image

But it doesn't replace placeholder to property value

@simonkeytree
Copy link

@alvteren - for other services, the properties override back-end configuration properties - the kind of thing you can override on a server-by-server basis in hac.

Have you seen something to indicate that there is a mechanism to include properties into Spartacus? I don't get to even click the 'SAVE' button if I try this myself, so I just assumed this wasn't available.

@simonkeytree
Copy link

simonkeytree commented Sep 9, 2020

Hi @aleruz - how have you got this working in ccv2, if it's always running the production build (I assume using --prod)?

I was kind of expecting that ccv2 backend build process would be calling ng build --configuration=staging for staging, ng build --configuration=production for production, ng build --configuration=dev for development and we could use our own for local development / CI (e.g. ng build --configuration=local) and then it's easy to control config from environment to environment. Maybe even --configuration=d1 / s1 / p1 as I'm aware some customer might have more environments - e.g. s2 etc)

@hikmettuysuz
Copy link

Hi @simonkeytree - I have created environment.qa.ts and environment.prod.ts in my project also configurated property in angular.json to replace it. My question is how we can execute our builded code(ng build --configuration=qa ) in cloud?

@simonkeytree
Copy link

Hi @hikmettuysuz - my question as well. I've raised a support request with SAP to see if there's any kind of workaround. I'm hoping it's not creating three builds that are duplicates of each other other than the config for each environment. Not too bad to do via CI, but a really nasty kludge.

@neilhubertprice
Copy link
Contributor

Hi @alvteren, @simonkeytree, @hikmettuysuz

This is not an official response, but my personal understanding of CCv2 is:

  • The basic concept is a single build image per release, and that applies to the Java elements of SAP Commerce as well as the Javascript elements of Spartacus when hosted in CCv2
  • For Spartacus this means the same single build is used in all 3 environments, and so it is not picking up the different config files you are talking about. I think it is probably using the prod file only (but I am not 100% sure)
  • The properties that you set in the Commerce Cloud Portal are injected into the server-side processes. At the moment I don't think there is a mechanism to inject them into the client-side code, which is what you are looking for + what Tobias and I mentioned in earlier comments.

I think all of this is at some level under review by the relevant teams, but I do not know if/how it is progressing.

@simonkeytree
Copy link

Thanks @neilhubertprice - that's my understanding at the moment. It effectively means you can't use the same build for all three environments, which seems like a big omission as Commerce Cloud officially only supports Spartacus as a SPA, and goes against the approach used for traditional Spring MVC accelerators, where the configuration is well managed through the Manifest file. But the current approach really makes an external CI pipeline essential to ensure git branches have the correct configuration per environment with a build per environment. I can't really think of another good way around it.
There doesn't seem to be any useful environment variables passed from the POD either to indicate whether it's a d1 / s1 / p1 environment, so that's not a possibility either - was a bit surprised by that.

@neilhubertprice
Copy link
Contributor

@simonkeytree My view is you should aim to keep the same single build & progress it across environments ... but that means losing out on some of the standard Angular approaches to different environment config. Elsewhere I have suggested a custom call to the backend SAP Commerce system to retrieve environment-specific configuration - that way you can treat it as data/config separate from the build.

@simonkeytree
Copy link

Hi @neilhubertprice - I was hoping to workaround it this way. I may be missing something obvious (quite likely!) but how would you know which URL to call to the SAP Commerce system for the specific environment, from the Spartacus pod? I'm looking for something that would identify the environment from within Angular (e.g. an OS environment variable, config from the manifest) but haven't been able to identify anything yet. Any ideas - I'm really hoping I've missed something obvious.

@neilhubertprice
Copy link
Contributor

@simonkeytree Each Spartacus instance is served from a particular environment & the OCC url is injected for the API endpoint of that specific environment. What I suggested above would be an additional (custom) call against that endpoint. Internal to the Commerce instance it would then have (and respond with) data specific to that environment

@simonkeytree
Copy link

simonkeytree commented Sep 14, 2020

Hi @nathanss - How is the OCC URL injected? I hadn't realized this got injected from the environment - I thought it was taken from configuration defined in the codebase (either from the meta tag or as defined in a typescript configuration file).

I guess I could take the results from the HOSTNAME environment variable and map this to the specific environment, assuming the hostname remains the same for the environment. That could then be used for using a specific set of configuration values - will give that a try.

Unfortunately, the internal HOSTNAME bears no resemblance to the externally visible hostname, so that was a dead end.

@neilhubertprice
Copy link
Contributor

Hi @simonkeytree - I guess that was meant for me rather than Nathan? Take a look at the 'Caution' box on this page: https://help.sap.com/viewer/b2f400d4c0414461a4bb7e115dccd779/v2005/en-US/63577f67a67347bf9f4765a5385ead33.html or this page in the Spartacus docs: https://sap.github.io/spartacus-docs/configuring-base-url/

@simonkeytree
Copy link

Hi @neilhubertprice - thanks. Yes apologies to Nathan there. Will give that a go. Bit of a kludge - the standard Angular approach would seem more intuitive, but I guess that's being considered by the Spartacus / Commerce Cloud teams at the moment. Cross fingers.

@simonkeytree
Copy link

Hi @tobi-or-not-tobi

What would be the problem with passing (for example)

ng build --configuration=s1 for staging, ng build --configuration=p1 for production, ng build --configuration=d1 for development so that the appropriate config files can be used?

This would seem to eliminate the need to use a meta tag, allow any config you want (per environment), and ensure there's only a single code base.

It does mean duplicating the constants per environment, but that's not the end of the world (and could potentially be worked around by including a common file in each environment .ts file)

Thanks

Simon

@janwidmer
Copy link

@simonkeytree did you figure something out to make it work via pipeline actions or did you get an answer from the SAP Support request?

@Xymmer Xymmer added this to To Do in Spartacus and CCv2/Infra via automation Dec 14, 2020
@Xymmer Xymmer removed this from BACKLOG in Aimed 2.0 Dec 14, 2020
@Xymmer Xymmer modified the milestones: needs-milestone, Q1-2021 Dec 14, 2020
@Xymmer Xymmer moved this from To Do to Backlog/Stretch/Hold in Spartacus and CCv2/Infra Dec 16, 2020
@guiliguili
Copy link
Member

Hi,
Any update on this ?
This is something particularly important to be able to have different {{AuthConfig}} when using 3rd party Identity Provider with different OAuth endpoints and credentials per-environment.

@janwidmer
Copy link

@neilhubertprice the way how the deployment changes the index.html AFTER the angular build also leads to the problem, that the PWA is not working correctly because the hash of the index.html does not match anymore..

@neilhubertprice
Copy link
Contributor

@tobi-or-not-tobi were you aware of this issue around the PWA / hash? Do we have a solution?

@CarlEricLavoie
Copy link
Contributor

@simonkeytree @mpern - We've faced this issue as well while working on several projects. Overall I agree with @mpern - the application (assets) should be immutable. The way we've fixed it is as follows :

  1. Add a new OCC endpoint to expose site-specific configuration. This allows us to toggle features by environment as well as per site. For instance, GTM configuration keys can differ be site as well as per the environment.
  2. Add this new OCC call to the config initializer to ensure the information is readily available.
  3. Use it in various services to configure our features.

This change obviously relies on a backend change (OCC) but it feels like the right way to configure our immutable application as a runtime in a "headless storefront" context. It's also not tied to any hosting solution (CCV2, Onprem, etc).

@Xymmer Xymmer modified the milestones: Q1-2021, closed-without-action Jun 3, 2021
@Xymmer Xymmer closed this as completed Jun 3, 2021
@Xymmer Xymmer reopened this Jun 4, 2021
Spartacus and CCv2/Infra automation moved this from Backlog/Stretch/Hold to To Do Jun 4, 2021
@Xymmer Xymmer removed this from the closed-without-action milestone Jun 4, 2021
@Xymmer Xymmer moved this from To Do to Backlog/Stretch/Hold in Spartacus and CCv2/Infra Jun 4, 2021
@balajimohann
Copy link

Hi Team

Any information on when this may be prioritised? It would be great to just use the single build to deploy to multiple environments. Currently

Thanks,
Bala

@andreas-becker
Copy link

Any updates on this?

@sam-garland
Copy link
Contributor

This is something that would be useful in the @spartacus/epd-visualization integration library.
We had hoped that customers would be able to use a different value for the folderUsageId configuration value for each deployment environment (without creating separate builds for each environment).

@MarcelLuz
Copy link

This would be more useful if the ccv2 environment supports one of the suggestions in this ticket!
There should be a way to get the environment (d1/s1/p1) especially if you use SSR.

@sebsauer90
Copy link

It would be awesome to have the possibility to set custom NodeJS variables for build time. Or at least to have a NodeJS variable, which indicates the environment (d1/s1/p1) at build time. Looking forward for any updates on this.

@andreas-becker
Copy link

On platformServer mode (when page is generated on the server side), you can use this.windowRef.location.origin or window.location.origin to retrieve the url of the requested call and then determine the specific environment (d1, s1, p1)

@Pranavbhartia
Copy link

@simonkeytree @mpern - We've faced this issue as well while working on several projects. Overall I agree with @mpern - the application (assets) should be immutable. The way we've fixed it is as follows :

  1. Add a new OCC endpoint to expose site-specific configuration. This allows us to toggle features by environment as well as per site. For instance, GTM configuration keys can differ be site as well as per the environment.
  2. Add this new OCC call to the config initializer to ensure the information is readily available.
  3. Use it in various services to configure our features.

This change obviously relies on a backend change (OCC) but it feels like the right way to configure our immutable application as a runtime in a "headless storefront" context. It's also not tied to any hosting solution (CCV2, Onprem, etc).

How did you determine which OCC endpoint needs to be called? d1/s1/p1, etc.. Or are you sending all the config, for all the environments and then checking on UI based on window location href?

@mpern
Copy link

mpern commented Mar 1, 2022

@Pranavbhartia - the OCC endpoint is the only thing that does get automatically configured per environment.

It works by using the special placeholder OCC_BACKEND_BASE_URL_VALUE in your index.html.

Details can be found here:

@janwidmer
Copy link

@Pranavbhartia you should be able to access the OCC endpoint in your code by using this.config.backend?.occ?.baseUrl. With that, you can then do the OCC Backend call to get the environment specific properties as described by @CarlEricLavoie

@Pranavbhartia
Copy link

Pranavbhartia commented Mar 3, 2022

@janwidmer and @mpern, thanks for that. I am a bit stuck though. I am a Backend dev trying to resolve this, and not very good with Angular concepts. I have reached to a point where I am able to read the property, but I am just not able to set it to the properties inside the ngModule. Could you please help me out. Please find the code attached. The conf variable inside the constructor has a value and is printing the full config object that I need. On the other hand, the object before the ngModule has an undefined value and hence it takes the undefined value where I need to provide it with the base url and base site. Instead of going with a backend API, I am using a config file per environment here, so then all the control is within the Spartacus code itself.

This might not be the best forum for this, but though would help others in my situation as well.
spartacus.configuration.module.txt

Edit : Putting the Stackoverflow link for anyone who might be in the same position as me.
https://stackoverflow.com/questions/71343648/spartacus-access-occ-url-on-the-ngmodule-inside-spartacus-configuration-module

@janwidmer
Copy link

@Pranavbhartia could you maybe create a stackoverflow question with your code, then the community can help there..

@Xymmer Xymmer added the infrastructure Infrastructure tasks label Apr 25, 2022
@Xymmer Xymmer added this to the validate-before-moving-to-jira milestone Apr 25, 2022
@Xymmer Xymmer removed this from Backlog/Stretch/Hold in Spartacus and CCv2/Infra Apr 25, 2022
@timoblume
Copy link

@tobi-or-not-tobi Is there any hope a solution to this issue will be provided in the future? We are running into the issue of trying to pass environment specific google tag manager Ids in app.module. We still have not found way to get this working. Any help would be great

@Pranavbhartia
Copy link

Hi @timoblume,
The only way we could solve it for now was to have separate branches for each environment. We have environment-prod.ts files setup in those branches specific to the environments. I created stackoverflow questions, SAP tickets, spent weeks at trying everything, but nothing really helped. Hopefully there would be a proper solution soon for it, but till then I think that would be the easiest and quickest way to do it.
Hopefully this helps.

@sebsauer90
Copy link

sebsauer90 commented May 19, 2022

Hey, I see there's a lot of frustration about this topic, so I want to share our solution to separate between stages on server side. It's not the nicest way, but the only way we found. We are using a custom storefront, based on express and react, but this also works for spartacus.

So, the only indicator to get information about the stage we found at runtime, is the occ-backend-base-url meta tag in dist/custom-storefront/index.html. If you put <meta name="occ-backend-base-url" content="OCC_BACKEND_BASE_URL_VALUE" /> in your index.html, the commerce cloud will set it during the build/deployment. So each stage has a separated occ url.

We built a service, which read this meta tag information from the index.html file on server side, to get the current stage. This service is only called once at startup of our nodejs (express) app. After we got the stage, we import asynchronously the corresponding stage configuration.

@bechte
Copy link

bechte commented Jun 16, 2023

Hey guys,

because SAP doesn't really seem to provide an update on this topic and also no solution for one of the fundamental missing features in Spartacus / Composable Storefront, I thought it would be great to provide an easy-to-integrate solution to the SAP Commerce Cloud community and especially for every project, in which one is force to have different configuration provided, e.g. for single-sign-on with OAuth, etc.

The solution can be summarized as follows:

  • Enhance the Spartacus with a custom configProviderFactory that override the local configuration of the SPA
  • Introduction of a new OCC endpoint that provides the frontend configuration in form of a serialized JSON object
  • Let the configProviderFactory fetch the configuration from the associate (environment specific) OCC API

As I don't like to do things several times, you can jump-on a open-source extension provided at SAP CX Tools:
https://github.com/sapcxtools/workspace/tree/develop/core-customize/hybris/bin/custom/sapcxtools/sapcxenvconfig

Steps to integrate

  • Download the latest release (4.1.2) at https://github.com/sapcxtools/workspace/releases/tag/v.4.1.2
  • Copy over the sapcxenvconfig Extension to your project, ideally into your bin/custom/sapcxtools folder
  • Within the frontend, create the sapcxenvconfig.ts file from the template within the README.md of the extension
  • Add the securedConfigChunkFromBackend config factory to your custom module
  • Add the defaultBaseSite configuration to your environment.ts file
  • Add your sapcxenvconfig.frontend.* properties to your local.properties or environment specific secured configuration as needed

With this solution in place, I think this topic can be marked as solved. Even though it would be great to have the solution provided by SAP... Have fun.

Bechte

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests