{"id":286,"date":"2018-05-21T15:34:00","date_gmt":"2018-05-21T13:34:00","guid":{"rendered":"https:\/\/celilsemi.erkiner.com\/blog\/?p=286"},"modified":"2020-05-28T16:34:43","modified_gmt":"2020-05-28T14:34:43","slug":"static-angular-deployment-to-a-subfolder","status":"publish","type":"post","link":"https:\/\/celilsemi.erkiner.com\/blog\/static-angular-deployment-to-a-subfolder\/","title":{"rendered":"Static Angular Deployment to a Subfolder"},"content":{"rendered":"\n<p>If you ever try to deploy an Angular app to a subfolder in your server, you will see that your app will end up with a white screen of death on your main root.<\/p>\n\n\n\n<p>There are 2 main issues; The&nbsp;base&nbsp;tag and LocationStrategy. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"basic-deployment-to-a-remote-server\">First part of the fix: The&nbsp;<code>base<\/code>&nbsp;tag<\/h3>\n\n\n\n<p>The HTML&nbsp;<a href=\"https:\/\/angular.io\/guide\/router\"><em>&lt;base href=&#8221;&#8230;&#8221;\/&gt;<\/em><\/a>&nbsp;specifies a base path for resolving relative URLs to assets such as images, scripts, and style sheets. For example, given the&nbsp;<code>&lt;base href=\"\/my\/app\/\"&gt;<\/code>, the browser resolves a URL such as&nbsp;<code>some\/place\/foo.jpg<\/code>&nbsp;into a server request for&nbsp;<code>my\/app\/some\/place\/foo.jpg<\/code>. During navigation, the Angular router uses the&nbsp;<em>base href<\/em>&nbsp;as the base path to the component, template, and module files.<\/p>\n\n\n\n<p>In development, you typically start the server in the folder that holds&nbsp;<code>index.html<\/code>. That&#8217;s the root folder and you&#8217;d add&nbsp;<code>&lt;base href=\"\/\"&gt;<\/code>&nbsp;near the top of&nbsp;<code>index.html<\/code>&nbsp;because&nbsp;<code>\/<\/code>&nbsp;is the root of the app. Furthermore  Angular defaults to <code>&lt;base href=\"\/\"&gt;<\/code> because it is a common configuration  for most deployments .<\/p>\n\n\n\n<p>When the&nbsp;<code>base<\/code>&nbsp;tag is mis-configured, the app fails to load and the browser console displays&nbsp;<code>404 - Not Found<\/code>&nbsp;errors for the missing files. Look at where it&nbsp;<em>tried<\/em>&nbsp;to find those files and adjust the base tag appropriately.<\/p>\n\n\n\n<p>On subfolder structured production server, you might configure this to prevent errors. For example, when the URL to load the app is something like&nbsp;<code>http:\/\/www.example.com\/my\/app\/<\/code>, the subfolder is&nbsp;<code>my\/app\/<\/code>&nbsp;and you should add&nbsp;<code>&lt;base href=\"\/my\/app\/\"&gt;<\/code>&nbsp;to the server version of the&nbsp;<code>index.html<\/code>.<\/p>\n\n\n\n<p>You can configure while building like this;<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:false,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;null&quot;,&quot;mime&quot;:&quot;text\/plain&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Plain Text&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;text&quot;}\">ng build --prod --output-path docs --base-href \/my\/app\/<\/pre><\/div>\n\n\n\n<p>You can also configure in angular.json;<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:false,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;javascript&quot;,&quot;mime&quot;:&quot;application\/json&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;JSON&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;json&quot;}\">{\n  \/\/...\n  &quot;projects&quot;: {\n    &quot;app&quot;: {\n      \/\/...\n      &quot;architect&quot;: {\n        &quot;build&quot;: {\n          \/\/...\n          &quot;configurations&quot;: {\n            &quot;production&quot;: {\n              &quot;baseHref&quot;: &quot;\/my\/app\/&quot;,\n              \/\/...\n            }\n          }<\/pre><\/div>\n\n\n\n<p>It is possible to set <code>base-href<\/code> to <code>.<\/code> to achieve a generic app which works in all all subfolders by relative paths but all used asset should follow a relative  path within the app to comply.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"basic-deployment-to-a-remote-server\">Second part of the fix: <code>LocationStrategy<\/code><\/h3>\n\n\n\n<p>In a single-page application, there is only one path to the entry file. After bootstrapping the application, instead of going to the server to get a new page, you change what the user sees by showing or hiding parts of the screen that correspond to certain components. As users perform application tasks, they need to switch between the different views you define. In this case, the server needs to redirect all traffic to index.html so Angular can take over to handle path on UI.<\/p>\n\n\n\n<p>This otherwise brilliant solution, overly complicates server management, especially when having applications in subfolders. When the location strategy is misconfigured, the app fails to load any sub-routes and the browser console displays\u00a0<code>404 - Not Found<\/code>.\u00a0 HashLocationStrategy is another strategy which is immune to this subfolder &#8211; subroute mismatch.<\/p>\n\n\n\n<p>HashLocationStrategy is a&nbsp;<a href=\"https:\/\/angular.io\/api\/common\/LocationStrategy\"><code>LocationStrategy<\/code><\/a>&nbsp;used to configure the&nbsp;<a href=\"https:\/\/angular.io\/api\/common\/Location\"><code>Location<\/code><\/a>&nbsp;service to represent its state in the&nbsp;<a href=\"https:\/\/en.wikipedia.org\/wiki\/Uniform_Resource_Locator#Syntax\">hash fragment<\/a>&nbsp;of the browser&#8217;s URL.<\/p>\n\n\n\n<p>To&nbsp;enable&nbsp;<code>HashLocationStrategy<\/code>&nbsp;in&nbsp;an Angular application we pass&nbsp;<code>{useHash: true}<\/code>&nbsp;when we are providing our routes with&nbsp;<code>RouterModule<\/code>, like so:TypeScript<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:false,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;javascript&quot;,&quot;mime&quot;:&quot;application\/typescript&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;TypeScript&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;typescript&quot;}\">RouterModule.forRoot(routes, {useHash: true})<\/pre><\/div>\n\n\n\n<p>URL&nbsp;can contain some data prepended with a&nbsp;<code>#<\/code>&nbsp;character. The&nbsp;<code>#<\/code>&nbsp;part of&nbsp;the&nbsp;URL&nbsp;is called the&nbsp;<em>hash fragment<\/em>. However, it has another very important characteristic in&nbsp;that anything past the&nbsp;<code>#<\/code>&nbsp;in&nbsp;a&nbsp;URL&nbsp;<em>never gets sent to&nbsp;the server<\/em>.  It\u2019s, therefore, an&nbsp;ideal solution for&nbsp;implementing&nbsp;client-side routing:-<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>It\u2019s part of&nbsp;the&nbsp;URL&nbsp;so can be bookmarked and&nbsp;sent to&nbsp;other people.<\/li><li>It won\u2019t confuse the&nbsp;server side since the&nbsp;hash fragment is never sent to&nbsp;the server.<\/li><li>It can be programmatically changed via JavaScript.<\/li><\/ul>\n\n\n\n<p>And&nbsp;that\u2019s exactly why, for&nbsp;a number of&nbsp;years, the&nbsp;primary way of&nbsp;implementing client-side routing was via hash fragments.<\/p>\n\n\n\n<p>HashLocationStrategy simplifies the server management when an angular app is running from a subfolder.  <\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>With this strategy and base href set properly, you can simply deploy in 2 steps;<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Start with the production build<\/li><li>Copy&nbsp;<em>everything<\/em>&nbsp;within the output folder (<code>dist\/<\/code>&nbsp;by default) to the subfolder on the server.<\/li><\/ol>\n\n\n\n<p>This is the simplest way to deploy your application as a static file bundle in a subfolder. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you ever try to deploy an Angular app to a subfolder in your server, you will see that your app will end up with a white screen of death on your main root. There are 2 main issues; The&nbsp;base&nbsp;tag and LocationStrategy. First part of the fix: The&nbsp;base&nbsp;tag The HTML&nbsp;&lt;base href=&#8221;&#8230;&#8221;\/&gt;&nbsp;specifies a base path for [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"default","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"default","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[8,7],"tags":[22,23,47,16],"class_list":["post-286","post","type-post","status-publish","format-standard","hentry","category-back-end","category-front-end","tag-angular","tag-apache","tag-nodejs","tag-server"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/celilsemi.erkiner.com\/blog\/wp-json\/wp\/v2\/posts\/286","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/celilsemi.erkiner.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/celilsemi.erkiner.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/celilsemi.erkiner.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/celilsemi.erkiner.com\/blog\/wp-json\/wp\/v2\/comments?post=286"}],"version-history":[{"count":7,"href":"https:\/\/celilsemi.erkiner.com\/blog\/wp-json\/wp\/v2\/posts\/286\/revisions"}],"predecessor-version":[{"id":293,"href":"https:\/\/celilsemi.erkiner.com\/blog\/wp-json\/wp\/v2\/posts\/286\/revisions\/293"}],"wp:attachment":[{"href":"https:\/\/celilsemi.erkiner.com\/blog\/wp-json\/wp\/v2\/media?parent=286"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/celilsemi.erkiner.com\/blog\/wp-json\/wp\/v2\/categories?post=286"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/celilsemi.erkiner.com\/blog\/wp-json\/wp\/v2\/tags?post=286"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}