title: Get rid of hard-coding the context path of web apps in external JavaScript files
body: <p>I have several WebSockets endpoints such as,</p>
  
  <pre class="lang-none prettyprint-override"><code>wss://localhost:8181/ContextPath/Push
  </code></pre>
  
  <p>All of such endpoint URLs are hard-coded in separate, external JavaScript files (<code>.js</code>). These JavaScript files are included in respective XHTML files as and when required. The host name and the context path should be evaluated programmatically instead of hard-coding all over the place where they are required.</p>
  
  <p>The host name (<code>localhost:8181</code>) can be obtained in JavaScript using <code>document.location.host</code> but there is no standard/canonical way in JavaScript to obtain a context path where the application runs.</p>
  
  <hr>
  
  <p>I am doing something like the following.</p>
  
  <p>A global JavaScript variable is declared on the master template as follows.</p>
  
  <pre><code>&lt;f:view locale="#{bean.locale}" encoding="UTF-8" contentType="text/html"&gt;
          &lt;f:loadBundle basename="messages.ResourceBundle" var="messages"/&gt;
  
          &lt;ui:param name="contextPath" value="#{request.contextPath}"/&gt;
          &lt;ui:insert name="metaData"&gt;&lt;/ui:insert&gt;
  
          &lt;h:head&gt;
              &lt;script type="text/javascript"&gt;var contextPath = "#{contextPath}";&lt;/script&gt;
          &lt;/h:head&gt;
  
          &lt;h:body id="body"&gt;
  
          &lt;/h:body&gt;
      &lt;/f:view&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>The JavaScript files in which the host name and the context path are hard-coded are included in respective template clients or any of sections of the template north, south, east and west as follows.</p>
  
  <pre><code>&lt;html lang="#{bean.language}"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:h="http://xmlns.jcp.org/jsf/html"&gt;
  
      &lt;h:form&gt;
          &lt;h:outputScript library="default" name="js/websockets.js" target="head"/&gt;
      &lt;/h:form&gt;
  </code></pre>
  
  <p>For the sake of viewpoint only, <code>websockets.js</code> looks like the following (you can simply ignore it).</p>
  
  <pre class="lang-javascript prettyprint-override"><code>if (window.WebSocket) {
      // The global variable "contextPath" is unavailable here
      // because it is declared afterwards in the generated HTML.
      var ws = new WebSocket("wss://"+document.location.host + contextPath + "/Push");
      ws.onmessage = function (event) {
          // This handler is invoked, when a message is received through a WebSockets channel.
      };
  
      $(window).on('beforeunload', function () {
          ws.close();
      });
  } else {}
  </code></pre>
  
  <p>Now, the global JavaScript variable <code>contextPath</code> declared in the master template is expected to be available in the included JavaScript file namely <code>websockets.js</code>. This is however untrue.</p>
  
  <p>What happens is that the included JavaScript file namely <code>websockets.js</code> where the global variable <code>contextPath</code> is attempted to be accessed, is placed <strong>before</strong> the hard-coded <code>&lt;script&gt;</code> tag in the generated HTML <code>&lt;head&gt;</code> tag in the master template.</p>
  
  <p>In other words, the global JavaScript variable <code>contextPath</code> is actually attempted to use in the included file <code>websockets.js</code> before being declared.</p>
  
  <p>Anyway, how to get rid of hard-coding the context path in external JavaScript files?</p>
  
  <p><sub>The sole purpose of doing this is that unlike CSS files, EL isn't evaluated in external JavaScript files. Therefore, <code>#{}</code> thing will not work unless it is placed in an XHTML file.</sub></p>