Skip to Content
Technical Articles

SAP Commerce + Wro4j : HTML in JavaScript Issue

Introduction:

In a Project, we faced the Issue that sometimes when we minimized JavaScript HTML was appended which leads to no longer valid JavaScript File and therefore browsers not evaluating JavaScript.

 

In this blog post, I want to explain the behavior and the reason for this problem, as well as how we solve this problem.

 

Behavior Explanation

Wro4j

Wro4j is configured via wro.xml see (https://wro4j.readthedocs.io/en/stable/WroFileFormat/). There the Javascript files and CSS files are defined which should be minimized. Wro4j also supports the possibility to load Resources via wildcard (https://wro4j.readthedocs.io/en/stable/WildcardSupport/)

To load the resources there are multiple Resource Locators available (https://wro4j.readthedocs.io/en/stable/ResourceTypes/). Based on conventions and definition in wro.xml.

The default behavior is to use the ServletContextUriLocator which will look for the resources via the dispatcher. If the File(s) cannot be loaded it will be tried to load them from extern with the current request context.

This is a feature of Wro4j to also provide the possibility to load external resources. For this, the UrlUriLocater will be used. In this locator, it is checked if the URL is a wildcard. Unfortunately, the check is working with a flag “enableWildcards” which is initialized with false (https://github.com/wro4j/wro4j/blob/v1.9.0/wro4j-core/src/main/java/ro/isdc/wro/model/resource/locator/wildcard/WildcardUriLocatorSupport.java#L32)

enableWildcards && super.hasWildcard(uri);

The second problem is that the Super method “hasWildcard” is working with a pattern that also returns false if “HTTP” is part of the URL (https://github.com/wro4j/wro4j/blob/b09a44747011006578d3a916fa464a39f633e860/wro4j-core/src/main/java/ro/isdc/wro/model/resource/locator/wildcard/DefaultWildcardStreamLocator.java#L52).

/**
   * Character to distinguish wildcard inside the uri. If the file name contains '*' or '?' character, it is considered
   * a wildcard.
   * <p>
   * A string is considered to contain wildcard if it doesn't start with http(s) and contains at least one of the
   * following characters: [?*].
   */
  private static final String WILDCARD_REGEX = "^(?:(?!http))(.)*[\\*\\?]+(.)*";

Therefore following URI is used for retrieving the external Resource:

https://localhost:9002/all_responsive.js/_ui/responsive/common/js/cms/*.js

Hybris

In Hybris the default Behavior for not found Pages is to display a custom 404 pages. This is necessary to display a pretty Page to the user.

The wro.xml config from Hybris OOTB looks like this:

<!--
 Copyright (c) 2019 SAP SE or an SAP affiliate company. All rights reserved.
-->
<groups xmlns="http://www.isdc.ro/wro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.isdc.ro/wro wro.xsd">
	
	<import>classpath:wro_addons.xml</import>


	<group name="alpha_responsive">
		<css>/_ui/responsive/theme-alpha/css/style.css</css>
	</group>


	<group name="lambda_responsive">
		<css>/_ui/responsive/theme-lambda/css/style.css</css>
	</group>
	
	<group name="all_responsive">
        
		<!-- jquery -->
		<js minimize="false">/_ui/responsive/common/js/jquery-3.2.1.min.js</js>
		
		<!-- plugins -->
		<js minimize="false">/_ui/responsive/common/js/enquire.min.js</js>
		<js>/_ui/responsive/common/js/Imager.min.js</js>
		<js minimize="false">/_ui/responsive/common/js/purify.min.js</js>
		<js>/_ui/responsive/common/js/jquery.blockUI-2.66.js</js>
		<js minimize="false">/_ui/responsive/common/js/jquery.colorbox-min.js</js>
		<js minimize="false">/_ui/responsive/common/js/jquery.form.min.js</js>
		<js>/_ui/responsive/common/js/jquery.hoverIntent.js</js>
		<js>/_ui/responsive/common/js/jquery.pstrength.custom-1.2.0.js</js>
		<js>/_ui/responsive/common/js/jquery.syncheight.custom.js</js>
		<js>/_ui/responsive/common/js/jquery.tabs.custom.js</js>
		<js minimize="false">/_ui/responsive/common/js/jquery-ui-1.12.1.min.js</js>
		<js>/_ui/responsive/common/js/jquery.zoom.custom.js</js>
		<js>/_ui/responsive/common/js/owl.carousel.custom.js</js>
		<js minimize="false">/_ui/responsive/common/js/jquery.tmpl-1.0.0pre.min.js</js>
		<js minimize="false">/_ui/responsive/common/js/jquery.currencies.min.js</js>
		
		<!-- Custom ACC JS -->
		<js>/_ui/responsive/common/js/acc.address.js</js>
		<js>/_ui/responsive/common/js/acc.autocomplete.js</js>
		<js>/_ui/responsive/common/js/acc.carousel.js</js>
		<js>/_ui/responsive/common/js/acc.cart.js</js>
		<js>/_ui/responsive/common/js/acc.cartitem.js</js>
		<js>/_ui/responsive/common/js/acc.checkout.js</js>
		<js>/_ui/responsive/common/js/acc.checkoutsteps.js</js>
		<js>/_ui/responsive/common/js/acc.cms.js</js>
		<js>/_ui/responsive/common/js/acc.colorbox.js</js>
		<js>/_ui/responsive/common/js/acc.common.js</js>
		<js>/_ui/responsive/common/js/acc.forgottenpassword.js</js>
		<js>/_ui/responsive/common/js/acc.global.js</js>
		<js>/_ui/responsive/common/js/acc.hopdebug.js</js>
		<js>/_ui/responsive/common/js/acc.imagegallery.js</js>
		<js>/_ui/responsive/common/js/acc.langcurrencyselector.js</js>
		<js>/_ui/responsive/common/js/acc.minicart.js</js>
		<js>/_ui/responsive/common/js/acc.navigation.js</js>
		<js>/_ui/responsive/common/js/acc.order.js</js>
		<js>/_ui/responsive/common/js/acc.paginationsort.js</js>
		<js>/_ui/responsive/common/js/acc.payment.js</js>
		<js>/_ui/responsive/common/js/acc.paymentDetails.js</js>
		<js>/_ui/responsive/common/js/acc.pickupinstore.js</js>
		<js>/_ui/responsive/common/js/acc.product.js</js>
		<js>/_ui/responsive/common/js/acc.productDetail.js</js>
		<js>/_ui/responsive/common/js/acc.quickview.js</js>
		<js>/_ui/responsive/common/js/acc.quote.js</js>
		<js>/_ui/responsive/common/js/acc.consent.js</js>
		<js>/_ui/responsive/common/js/acc.cookienotification.js</js>
		<js>/_ui/responsive/common/js/acc.closeaccount.js</js>
		<js>/_ui/responsive/common/js/acc.ratingstars.js</js>
		<js>/_ui/responsive/common/js/acc.refinements.js</js>
		<js>/_ui/responsive/common/js/acc.sanitizer.js</js>
		<js>/_ui/responsive/common/js/acc.silentorderpost.js</js>
		<js>/_ui/responsive/common/js/acc.tabs.js</js>
		<js>/_ui/responsive/common/js/acc.termsandconditions.js</js>
		<js>/_ui/responsive/common/js/acc.track.js</js>
		<js>/_ui/responsive/common/js/acc.storefinder.js</js>
		<js>/_ui/responsive/common/js/acc.futurelink.js</js>
		<js>/_ui/responsive/common/js/acc.productorderform.js</js>
		<js>/_ui/responsive/common/js/acc.savedcarts.js</js>
		<js>/_ui/responsive/common/js/acc.multidgrid.js</js>
		<js>/_ui/responsive/common/js/acc.quickorder.js</js>
		<js>/_ui/responsive/common/js/acc.csv-import.js</js>
		<js>/_ui/responsive/common/js/_autoload.js</js>
		
		<!-- Cms Action JavaScript files -->
        <js>/_ui/responsive/common/js/cms/*.js</js>
    </group>
   
</groups>       

The Wildcard line

<js>/_ui/responsive/common/js/cms/*.js</js>

is necessary to load additional JavaScripts from Components and/or other Storefront addons and therefore is part of how the Storefront customization works.

The Problem

In the wro.xml the following wildcard is defined:

<js>/_ui/responsive/common/js/cms/*.js</js>

If no files exist in the cms folder it will be tried to load them via external locator, which results in a URI like this:

https://localhost:9002/all_responsive.js/_ui/responsive/common/js/cms/*.js

Unfortunately, if a page is called that does not exist in hybris, the custom 404 Page is returned with code 200 (OK) instead of HTTP Status 404 (NOT FOUND). (see de.hybris.platform.yacceleratorstorefront.controllers.pages.DefaultPageController.java#get)

This leads to wro4j to use the response (in form of the 404 page HTML) and append them to the minimized JavaScript.

 

Possible Solutions

  1. Add the prefix “classpath” to the resources URLs
    <js>classpath:_ui/responsive/common/js/cms/*.js</js>​

    to indicate that this line should only be interpreted by the ClasspathUriLocator.
    This solution is the quickest but not the longest one, as the problem could reoccur if resources cannot be found locally (maybe deleted as they are no longer necessary or were refactored).

  1. Modify web.xml to prevent javascript and css files going through DispatcherServlet
    <filter-mapping>
     <filter-name>resourceFilter</filter-name>
     <url-pattern>/_ui/*</url-pattern>
     <url-pattern>*.js</url-pattern>
     <url-pattern>*.css</url-pattern>
    </filter-mapping>
    ..
    <serverl-mapping>
     <servlet-name>DefaultServletAdapter</servlet-name>
     ...
     <url-pattern>*.js</url-pattern>
     <url-pattern>*.css</url-pattern>
    </servlet-mapping>​
  1. Change the Storefront Implementation so that the custom 404 Page also returns the HTTP Status Code 404.

 

Be the first to leave a comment
You must be Logged on to comment or reply to a post.