<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Posts on Robjam blog</title>
		<link>/posts/</link>
		<description>Recent content in Posts on Robjam blog</description>
		<generator>Hugo -- gohugo.io</generator>
		<language>en</language>
		<lastBuildDate>Sat, 03 May 2025 11:46:36 +0900</lastBuildDate>
		<atom:link href="/posts/index.xml" rel="self" type="application/rss+xml" />
		
		<item>
			<title>New Habits</title>
			<link>/posts/new-habits/</link>
			<pubDate>Sat, 03 May 2025 11:46:36 +0900</pubDate>
			
			<guid>/posts/new-habits/</guid>
			<description>As a parent of two small children, It is insanely challenging trying to find time and energy to do anything extra beyond parenting. I find that the quality of my free time (after they fall asleep) is so poor that all I want to do is zone out to some video until 10pm, go to bed and resent the lack of progress on things I want to do. But I think I might have unlocked something that can create some inertia and develop deliberate practice of just getting started/finishing something.</description>
			<content type="html"><![CDATA[<p>As a parent of two small children, It is insanely challenging trying to find time and energy to do anything extra beyond parenting. I find that the <em>quality</em> of my free time (after they fall asleep) is so poor that all I want to do is zone out to some video until 10pm, go to bed and resent the lack of progress on <a href="/posts/todos/">things I want to do</a>. But I think I might have unlocked something that can create some inertia and develop deliberate practice of just getting started/finishing something.</p>
<p>I made a site called: <a href="https://daily-album.club">daily-album.club</a> where I recommend an album every day with some links to where you can listen to it.</p>
<p><img src="/img/daily-album-club.png" alt="Daily Album Club"></p>
<p>This site has an intended audience of one (me), so the stakes of creating a recommendation is low stakes. After creating an album recommendation, I can usually find the energy/motivation to continue with something else. Here&rsquo;s to seeing if some deliberate practice will make me more productive overall!</p>
]]></content>
		</item>
		
		<item>
			<title>New Keyboard</title>
			<link>/posts/new-keyboard/</link>
			<pubDate>Mon, 06 Jun 2022 18:54:28 +0900</pubDate>
			
			<guid>/posts/new-keyboard/</guid>
			<description>I regularly read Hackernews to stay abreast of new tech and came across Down the mechanical keyboard rabbit hole. Having lurked on r/mechanicalkeyboards for several years, I bought a Mistel Barroco two years ago on a recommendation from a co-worker and so far it has been great! It has the typical layout layout I&amp;rsquo;m familiar with and being able to keep a more open posture while typing has (probably) helped</description>
			<content type="html"><![CDATA[<p><img src="/img/lily58/lily58-assembled.jpeg" alt="assembled">
I regularly read Hackernews to stay abreast of new tech and came across <a href="https://news.ycombinator.com/item?id=30719263"><strong>Down the mechanical keyboard rabbit hole</strong></a>. Having lurked on r/mechanicalkeyboards for several years, I bought a <a href="https://mistelkeyboard.com/products/d11cf7a73da49468e2a530b4cf18e76c">Mistel Barroco</a> two years ago on a  recommendation from a co-worker and so far it has been great! It has the typical layout layout I&rsquo;m familiar with and being able to keep a more open posture while typing has (probably) helped my shoulder soreness; although I suspect that my standing desk has had a larger impact.</p>
<p>One of the more unique keyboard layouts that has always kept my attention is a columnar ortholinear layout. The designs of these keyboards feel utilitarian and maximize proximity. Of course, learning a new keyboard layout seems like a huge productivity sink without much gain. Things finally came to a head for me reading that HN article. I was going to buy an ortho-linear keyboard. The whole process required a lot of research as pre-built keyboards are either non-existant or pretty spendy. After looking over what kits were available, I was torn between the Corne Cherry V3 and the lily58. The main difference being that the lily58 has number keys, which would soften the learning curve. I poured over the site several times making sure that I had EVERYTHING I needed and bought a lily58 kit, keycaps and switches from a company called yushakobo (遊舎工房) and it arrived the next day at 9:30am!</p>
<p>Some first thoughts when I opened everything was there&rsquo;s going to be a daunting amount of soldering components much smaller than I&rsquo;m used to. I mean, look at how tiny the diodes are!</p>
<figure class="img-md"><img src="/img/lily58/lily58-diode.jpeg"
         alt="smaller than a grain of rice!"/><figcaption>
            <p>smaller than a grain of rice!</p>
        </figcaption>
</figure>

<p>A quick rundown of tools I used that were vital:</p>
<ol>
<li>soldering iron &amp; solder: $3 from a discount store</li>
<li>tweezers: the ones with an angled tip are nice, I kind of wished I had ones that were default closed; I cannot count the number of times I dropped those tiny diodes</li>
<li>magnifying glass: I found a soldering holder for pretty cheap a few months ago</li>
<li>digital multimeter: VERY useful for confirming diode polarity</li>
<li>toothpicks: scrape away excess solder (a solder wick might work better)</li>
</ol>
<p>I managed to take care of almost all of it in about 4 hours with a $3 soldering iron. Once I got into the flow of things, I kind of lost track and soldered well past midnight.</p>
<p><img src="/img/lily58/lily58-right-side-soldered.jpeg" alt="left side almost complete"></p>
<p>It took quite a lot of getting used to working with such small components and some of the solder joints were pretty gnarly and had me worried if I had fried some diodes trying to solder them in place.</p>
<p><img src="/img/lily58/lily58-close-up.jpeg" alt="closeup of my masterful soldering"></p>
<p>The rest was such a blur I didn&rsquo;t get many pictures, but here is the assembled version:</p>
<p><img src="/img/lily58/lily58-test-fit.jpeg" alt="assembed, no pictures in-between"></p>
<p>Finally I flashed the keyboard with the default layout and am now building up some muscle memory by writing this up.</p>
<h2 id="overall-thoughts">Overall thoughts</h2>
<p>The switches I ordered (cherry-mx black-silent) are actually silent, which actually took some getting adjusting to. The amount of force is also something I&rsquo;m not in love with, but I might warm up to it. I was really surprised at how natural typing is until I need to use a key that is not in a standard keyboard&rsquo;s position. Most notably the backspace key will take some getting used to. I noticed how I have some not so great habits; My ring fingers wander outside of their lane, making my fingers leave the home row. The biggest one though is changing IME modes. I always setup my pcs to switch between Japanese and English with <code>ctrl + space</code>. It never occured to me that while I primarily type space with my left hand, the switching between English and Japanese was exlusively with my right thumb which has led to some premature mentions being thrown around in Slack and GitHub (sorry!). I am kind of excited to get used to the arrow keys being in the home row (like vim) and hopefully will help me get used to nvim in the future.</p>
<p>I have a few ideas about what kinds of layout changes I want to make in the future, but will stick it out for a week with the default.</p>
<h2 id="some-tips">Some tips</h2>
<h3 id="diodes">diodes</h3>
<p>After all the diodes are soldered, use an electrometer on the ground setting to confirm the direction of the diodes. The nice thing about the lily58 is that the diode direction is printed on both sides, making it really easy to confirm before assembling the board and removes a stressful troubleshooting step. I had put one in backwards and was very happy I found it before installing switches/keycaps.</p>
<h3 id="promicro">ProMicro</h3>
<p>The directions on the site were a little vague so I didnt solder the spring headers to the ProMicro and that lead to really spotty connections when trying to flash the firmware with QMK. after double-checking with the documents provided in the kit, I realized that as least one side needs to be soldered. The more you know.</p>
<h3 id="keycaps">keycaps</h3>
<p>I bought the standard set of keycaps and the home row key indents are pretty shallow, making htem easy to miss. I also ran into issues with finding appropriate keys for the utility keys. Its not super important, but something I would like to revisit in a few weeks and maybe order some blank caps.</p>
<h3 id="base-plate">base plate</h3>
<p>The base plate has some sharp corners to them and can easily scratch wood desktops. I&rsquo;m still thinking about how to best go about fixing this, and am currently contemplating coating the base plates in silocone. If I can get the mold just so, it would be a pretty cool non-slide coating that can also keep scratches off my desk.</p>
]]></content>
		</item>
		
		<item>
			<title>Troubleshoot Azure Devops Agents</title>
			<link>/posts/troubleshoot-azure-devops-agents/</link>
			<pubDate>Thu, 05 Sep 2019 17:07:41 +0900</pubDate>
			
			<guid>/posts/troubleshoot-azure-devops-agents/</guid>
			<description>Recently I have been automating all the things and recently had a nuxt project that would successfully build, but no artifacts! So this article is more of an outline of the things I tried to narrow the issue down.
1. Turn on diagnostics This adds a large variety of information to the output, but can help with checking environment variables, expose tasks output and current directory among others. Before this was only enable-able through environment variables but now clicking &amp;lsquo;Run pipeline&amp;rsquo; and selecting enable system diagnostics.</description>
			<content type="html"><![CDATA[<p>Recently I have been automating all the things and recently had a nuxt project that would successfully build, but no artifacts! So this article is more of an outline of the things I tried to narrow the issue down.</p>
<h2 id="1-turn-on-diagnostics">1. Turn on diagnostics</h2>
<p>This adds a large variety of information to the output, but can help with checking environment variables, expose tasks output and current directory among others. Before this was only enable-able through environment variables but now clicking &lsquo;Run pipeline&rsquo; and selecting <code>enable system diagnostics</code>.</p>
<p><img src="troubleshoot-pipelines-system-diag.png" alt="Manually run with diagnostics enabled"></p>
<h2 id="2-add-debug-bash-scripts-to-feel-out-the-issue">2. Add debug bash scripts to &lsquo;feel out&rsquo; the issue</h2>
<p>This is extremely wasteful, but can sometimes be useful.</p>
<h2 id="3-locally-debug-the-agent-via-docker">3. <del>Locally debug the agent via Docker!</del></h2>
<p>Dockeried build agents <del>are</del> were a game-changer (they have been discontinued and everything has been moved to <a href="https://github.com/microsoft/azure-pipelines-agent">azure-pipelines-agent</a>). I knew which command (<code>yarn build</code>) was failing, so being able to start an exact environment as what is running on Azure Devops made the troubleshooting trivial.</p>
<p>looking at <a href="https://hub.docker.com/_/microsoft-azure-pipelines-vsts-agent">the dockerhub repository</a> it seemed pretty straight forward to get an bash shell running with the command below:</p>
<pre tabindex="0"><code>docker run -e VSTS_ACCOUNT=TotallyFakeName \
  -e VSTS_TOKEN=TotallyInvalidToken \
  -v /var/run/docker.sock:/var/run/docker.sock \
  --mount type=bind,source=&#34;$(pwd)&#34;,target=/app \
-it mcr.microsoft.com/azure-pipelines/vsts-agent:ubuntu-16.04-docker-17.12.0-ce sh
</code></pre><p>The important parts are adding your mount to the current directory (<code>--mount type=bind,source=&quot;$(pwd)&quot;,target=/app</code>) to make debugging easier and adding bash(<code>sh</code>). Also the <code>VSTS_TOKEN</code> and <code>VSTS_ACCOUNT</code> are intentionally invalid because there is no need to have official build running on a dev pc.</p>
<p>The new agents seem great, and even have a half-baked <code>localRun</code> feature that is supposed to let you verify your build will work before failing the build serveral times greatly increasing the development cycle. Some more information is <a href="https://github.com/microsoft/azure-pipelines-agent/blob/c113d89607308107d663e3ff288be88faa66ec6b/docs/preview/outdated/yamlgettingstarted-localrun.md">here</a> and hopefully it gets fully supported in the future as I can only run it connected to a Azure Devops instance</p>
<h2 id="the-issue">The issue?</h2>
<p>One of the files was name <code>MyPascalCAseComponent.vue</code>, but the import in a parent component was <code>MyPascalCaseComponent.vue</code>. As Ubuntu treats these as seperate files, it threw an error that was swallowed by either node or yarn.</p>
]]></content>
		</item>
		
		<item>
			<title>Csrf cookies in Dotnet with axios</title>
			<link>/posts/csrf-dotnet-vue/</link>
			<pubDate>Mon, 22 Jul 2019 12:35:01 +0900</pubDate>
			
			<guid>/posts/csrf-dotnet-vue/</guid>
			<description>CSRF validation in .Net Core is a breeze when using Razor syntax or even jQuery, but how should you approach this for a front-end project that uses axios? The official documentation gets you almost all of the way, but axios has a great feature to make this as painless as possible with the axios.defaults.xsrfHeaderName and axios.defaults.xsrfCookieName with minimal changes in .Net Core land.
Overview: Scaffold new MVC project Follow official docs + extend Add an Antiforgery enabled endpoint to test Add axios make axios call the endpoint with AntiforgeryValidation Scaffold new Mvc project first scaffold a new MVC project in dotnet core:</description>
			<content type="html"><![CDATA[<p>CSRF validation in .Net Core is a breeze when using Razor syntax or even jQuery, but how should you approach this for a front-end project that uses axios? The <a href="https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-2.2">official documentation</a> gets you <em>almost</em> all of the way, but axios has a great feature to make this as painless as possible with the <code>axios.defaults.xsrfHeaderName</code> and <code>axios.defaults.xsrfCookieName</code> with minimal changes in .Net Core land.</p>
<h2 id="overview">Overview:</h2>
<ol>
<li>Scaffold new MVC project</li>
<li>Follow official docs + extend</li>
<li>Add an Antiforgery enabled endpoint to test</li>
<li>Add axios</li>
<li>make axios call the endpoint with AntiforgeryValidation</li>
</ol>
<h2 id="scaffold-new-mvc-project">Scaffold new Mvc project</h2>
<p>first scaffold a new MVC project in dotnet core:</p>
<pre tabindex="0"><code>dotnet new mvc --name Csrf.Sample 
</code></pre><h2 id="follow-official-docs--extend">Follow official docs + extend</h2>
<p>First configure <code>Starup.cs</code> while referencing the <a href="https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-2.2#antiforgery-options">Starup.ConfigureServices docs</a> and the extra annotations in comments below:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="c1">// Startup.cs</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// ...</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">void</span> <span class="n">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// ...</span>
</span></span><span class="line"><span class="cl">        <span class="n">services</span><span class="p">.</span><span class="n">AddAntiforgery</span><span class="p">(</span><span class="n">options</span> <span class="p">=&gt;</span> <span class="p">{</span>    
</span></span><span class="line"><span class="cl">            <span class="n">options</span><span class="p">.</span><span class="n">HeaderName</span> <span class="p">=</span> <span class="s">&#34;X-XSRF-TOKEN&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="n">services</span><span class="p">.</span><span class="n">Configure</span><span class="p">&lt;</span><span class="n">CookiePolicyOptions</span><span class="p">&gt;(</span><span class="n">options</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// All unessential cookies (including anti-csrf) will not be allowed until consent is granted by default.</span>
</span></span><span class="line"><span class="cl">            <span class="n">options</span><span class="p">.</span><span class="n">CheckConsentNeeded</span> <span class="p">=</span> <span class="n">context</span> <span class="p">=&gt;</span> <span class="k">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// ...</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">void</span> <span class="n">Configure</span><span class="p">(</span><span class="n">IApplicationBuilder</span> <span class="n">app</span><span class="p">,</span> <span class="n">IAntiforgery</span> <span class="n">antiforgery</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// ...</span>
</span></span><span class="line"><span class="cl">        <span class="n">app</span><span class="p">.</span><span class="n">Use</span><span class="p">(</span><span class="n">next</span> <span class="p">=&gt;</span> <span class="n">context</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="kt">string</span> <span class="n">path</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">Request</span><span class="p">.</span><span class="n">Path</span><span class="p">.</span><span class="n">Value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">                <span class="c1">// You can modify what gets a csrf token here</span>
</span></span><span class="line"><span class="cl">                <span class="kt">string</span><span class="p">.</span><span class="n">Equals</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s">&#34;/&#34;</span><span class="p">,</span> <span class="n">StringComparison</span><span class="p">.</span><span class="n">OrdinalIgnoreCase</span><span class="p">)</span> <span class="p">||</span>
</span></span><span class="line"><span class="cl">                <span class="kt">string</span><span class="p">.</span><span class="n">Equals</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s">&#34;/index.html&#34;</span><span class="p">,</span> <span class="n">StringComparison</span><span class="p">.</span><span class="n">OrdinalIgnoreCase</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="kt">var</span> <span class="n">tokens</span> <span class="p">=</span> <span class="n">antiforgery</span><span class="p">.</span><span class="n">GetAndStoreTokens</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                <span class="c1">// IF using CookiePolicyOptions IsEssential needs to be true</span>
</span></span><span class="line"><span class="cl">                <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="n">Cookies</span><span class="p">.</span><span class="n">Append</span><span class="p">(</span><span class="s">&#34;XSRF-TOKEN&#34;</span><span class="p">,</span> <span class="n">tokens</span><span class="p">.</span><span class="n">RequestToken</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">                    <span class="k">new</span> <span class="n">CookieOptions</span><span class="p">()</span> <span class="p">{</span> <span class="n">HttpOnly</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span> <span class="n">IsEssential</span> <span class="p">=</span> <span class="k">true</span> <span class="p">});</span> 
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">next</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// ...</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></div><p>Some important points:</p>
<ul>
<li>if <code>options.HeaderName</code> is null, it will only work for form data (<a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.antiforgery.antiforgeryoptions.headername?view=aspnetcore-2.2">ref</a>).</li>
<li><code>options.Cookie.Name</code> must not match the <code>context.Response.Cookies.Append</code> token name.</li>
<li>if using <code>CookiePolicyOptions</code>, the <code>context.Response.Cookies.Append</code> CookieOptions needs <code>IsEssential</code> to add to the client before consent.</li>
</ul>
<p>Start the application (<code>dotnet run</code>), go to the homepage (<code>https://localhost:5001</code>) and open up the developer tools. Confirm that the client code can read the <code>XSRf-COOKIE</code> in the network tab as well as <code>document.cookie</code> in the console section like the picture below:</p>
<p><img src="/img/dotnet-csrf-ff-devtools.png" alt="confimring the cookie is accessible from the client"></p>
<h2 id="add-an-antiforgery-enabled-endpoint-to-test">Add an Antiforgery enabled endpoint to test</h2>
<p>In <code>Controllers/HomeController.cs</code> add the following route:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="na">[ValidateAntiforgeryToken]</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span> <span class="n">IActionResult</span> <span class="n">WelcomeMessage</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">Ok</span><span class="p">(</span><span class="s">&#34;Great!&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Next, to test this with axios.</p>
<h2 id="add-axios">Add Axios</h2>
<p>First the Axios libary is needed. For brevity and ease-of-use, use the CDN version In <code>Views/Shared/_Layout.cshtml</code> add the following parts below the annotation <code>&lt;!-- Added here</code>:</p>
<pre tabindex="0"><code>// _Layout.cshtml
&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;!-- ... omitted for brevity --&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;!-- ... omitted for brevity --&gt;
&lt;footer class=&#34;border-top footer text-muted&#34;&gt;
    &lt;div class=&#34;container&#34;&gt;
        &amp;copy; 2019 - Csrf.Sample - &lt;a asp-area=&#34;&#34; asp-controller=&#34;Home&#34; asp-action=&#34;Privacy&#34;&gt;Privacy&lt;/a&gt;
    &lt;/div&gt;
&lt;/footer&gt;

&lt;environment include=&#34;Development&#34;&gt;
    &lt;script src=&#34;~/lib/jquery/dist/jquery.js&#34;&gt;&lt;/script&gt;
    &lt;script src=&#34;~/lib/bootstrap/dist/js/bootstrap.bundle.js&#34;&gt;&lt;/script&gt;

    &lt;!-- Added here for development --&gt;
    &lt;script src=&#34;https://unpkg.com/axios/dist/axios.min.js&#34;&gt;&lt;/script&gt;
&lt;/environment&gt;
&lt;environment exclude=&#34;Development&#34;&gt;
    &lt;script src=&#34;https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js&#34;
            asp-fallback-src=&#34;~/lib/jquery/dist/jquery.min.js&#34;
            asp-fallback-test=&#34;window.jQuery&#34;
            crossorigin=&#34;anonymous&#34;
            integrity=&#34;sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=&#34;&gt;
    &lt;/script&gt;
    &lt;script src=&#34;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js&#34;
            asp-fallback-src=&#34;~/lib/bootstrap/dist/js/bootstrap.bundle.min.js&#34;
            asp-fallback-test=&#34;window.jQuery &amp;&amp; window.jQuery.fn &amp;&amp; window.jQuery.fn.modal&#34;
            crossorigin=&#34;anonymous&#34;
            integrity=&#34;sha384-xrRywqdh3PHs8keKZN+8zzc5TX0GRTLCcmivcbNJWm2rs5C8PRhcEn3czEjhAO9o&#34;&gt;

    &lt;/script&gt;
    &lt;!-- added here for production --&gt;
    &lt;script src=&#34;https://unpkg.com/axios/dist/axios.min.js&#34;&gt;&lt;/script&gt;
&lt;/environment&gt;
&lt;script src=&#34;~/js/site.js&#34; asp-append-version=&#34;true&#34;&gt;&lt;/script&gt;

@RenderSection(&#34;Scripts&#34;, required: false)
&lt;/body&gt;
&lt;/html&gt;
</code></pre><p>After the axios library is added, axios can now call the endpoint from <code>Home.cshtml</code>. In <code>Views/Home/Index.cshtml</code> add the following snippet to the end:</p>
<pre tabindex="0"><code>@section scripts {
    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            window.axios.get(&#39;/home/WelcomeMessage&#39;).then((response) =&gt; {
                alert(response.data);
            }).catch((err) =&gt; {
                console.log(err);
            })
        });
    &lt;/script&gt;
}
</code></pre><h3 id="wheres-the-magic">Where&rsquo;s the magic?</h3>
<p>Axios has a default setting for CSRF cookies halfway down the <a href="https://github.com/axios/axios#request-config">Request Config section</a> that will explains it.</p>
<pre tabindex="0"><code>// `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
xsrfCookieName: &#39;XSRF-TOKEN&#39;, // default

// `xsrfHeaderName` is the name of the http header that carries the xsrf token value
xsrfHeaderName: &#39;X-XSRF-TOKEN&#39;, // default
</code></pre><p>The defaults in axios are what we set in the <code>Startup.cs</code>. Whenever axios makes a request, it will check the <code>document.cookie</code> for a value called <code>XSRF-TOKEN</code> and add it as a header <code>X-XSRF-TOKEN</code>.</p>
<p>Some considerations:</p>
<p>This will not provide a new token for every request. If there is interest, I may look into it. Additionally, this integration works just as well for Vue/Nuxt/React apps that use axios as it is the default behavior.</p>
]]></content>
		</item>
		
		<item>
			<title>Vue Multi Pages in Dotnet Core</title>
			<link>/posts/vue-multi-page-dotnet-core/</link>
			<pubDate>Thu, 09 May 2019 22:04:21 +0900</pubDate>
			
			<guid>/posts/vue-multi-page-dotnet-core/</guid>
			<description>One of the nice things about Vue is the balance between bare framework and opinionated spa, or even multiple pages as seperate applications are easily configurable. They can also be integrated into ASP.Net Core&amp;rsquo;s MVC pages when Razor isn&amp;rsquo;t enough. This post will go into integrating two Vue apps (with/without routing) served by ASP.Net Core MVC.
Prerequirements:
yarn @vue/cli ASP.Net Core 2.2 VS Code Start by creating an MVC Project:</description>
			<content type="html"><![CDATA[<p>One of the nice things about Vue is the balance between bare framework and opinionated spa, or even multiple pages as seperate applications are easily configurable. They can also be integrated into ASP.Net Core&rsquo;s MVC pages when Razor isn&rsquo;t enough. This post will go into integrating two Vue apps (with/without routing) served by ASP.Net Core MVC.</p>
<p>Prerequirements:</p>
<ul>
<li>yarn</li>
<li>@vue/cli</li>
<li>ASP.Net Core 2.2</li>
<li>VS Code</li>
</ul>
<p>Start by creating an MVC Project:</p>
<pre tabindex="0"><code>mkdir DotnetVues
dotnet new mvc --name DotnetVues.Web -o src/DotnetVues.Web
</code></pre><p>Create a solution and add the project:</p>
<pre tabindex="0"><code>dotnet new sln DotnetVues
dotnet sln DotnetVues.sln add src/DotnetVues.Web/
</code></pre><p>Next create a new Vue app:</p>
<pre tabindex="0"><code>vue create client-app
</code></pre><p>Manually select the below features:</p>
<pre tabindex="0"><code>? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, TS, Router, CSS Pre-processors, Linter, Unit
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript for auto-detected polyfills? Yes
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass)
? Pick a linter / formatter config: Prettier
? Pick additional lint features: (Press &lt;space&gt; to select, &lt;a&gt; to toggle all, &lt;i&gt; to invert selection)Lint on save
? Pick a unit testing solution: Jest
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
</code></pre><p>Add Buefy:</p>
<pre tabindex="0"><code>vue add buefy
</code></pre><p>select the below choices</p>
<pre tabindex="0"><code>? Add Buefy style? scss
? Include Material Design Icons? Yes
? Include Font Awesome Icons? No
</code></pre><p><em>NOTE: this will change the dart-sass dependency to node-sass</em></p>
<h2 id="configure-vue-for-multi-page-output">Configure Vue for multi-page output</h2>
<p>Create a <code>vue.config.js</code> file and add the following to add support for <a href="https://cli.vuejs.org/config/#pages">pages</a> and change the built files directory to the MVC project&rsquo;s <code>wwwroot</code>:</p>
<pre tabindex="0"><code>module.exports = {
  pages: {
    spa: &#34;src/pages/spa/main.ts&#34;,
    singleDashboard: &#34;src/pages/singleDashboard/main.ts&#34;
  },
  outputDir: &#34;../src/DotnetVues.Web/wwwroot/&#34;,
  filenameHashing: false,
};
</code></pre><p>The <code>pages</code> will identify the two entrypoints (next step).
<code>filenameHashing</code> should be turned off to allow for easy reference in the Razor Views.</p>
<p>Add the following directories to <code>client-app/src</code> of the Vue app:</p>
<pre tabindex="0"><code>.
└── pages
    ├── singleDashboard
    └── spa
</code></pre><p>Copy the App.vue and main.ts into each of the folders:</p>
<pre tabindex="0"><code>.
├── App.vue
├── main.ts
├── router.ts
├── pages
│   ├── singleDashboard
│   │   ├── App.vue
│   │   └── main.ts
│   └── spa
│       ├── App.vue
│       └── main.ts
</code></pre><p>Move the <code>views/*</code> to <code>pages/spa/</code>
Move <code>router.ts</code> to <code>pages/spa/</code></p>
<p>Update the <code>pages/spa/router.ts</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Vue</span> <span class="kr">from</span> <span class="s2">&#34;vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Router</span> <span class="kr">from</span> <span class="s2">&#34;vue-router&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Home</span> <span class="kr">from</span> <span class="s2">&#34;@/pages/spa/views/Home.vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">Vue</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">Router</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="k">new</span> <span class="nx">Router</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">mode</span><span class="o">:</span> <span class="s2">&#34;history&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">base</span><span class="o">:</span> <span class="s2">&#34;/Spa&#34;</span><span class="p">,</span> <span class="c1">// This is going to be accessed from the &#39;spa&#39; controller
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">routes</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">path</span><span class="o">:</span> <span class="s2">&#34;/&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;home&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">component</span>: <span class="kt">Home</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">path</span><span class="o">:</span> <span class="s2">&#34;/about&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;about&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// this will split the route to a seperate chunk to keep the browser more responsive
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;@/pages/spa/views/About.vue&#34;</span><span class="p">),</span> 
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span> <span class="nx">path</span><span class="o">:</span> <span class="s2">&#34;*&#34;</span><span class="p">,</span> <span class="nx">redirect</span><span class="o">:</span> <span class="s2">&#34;/&#34;</span> <span class="p">}</span> <span class="c1">// fallback to home component if route is not found
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Then delete <code>client-app/src/App.vue</code> as well as <code>client-app/src/main.ts</code>.</p>
<p>the Vue app should look like this:</p>
<pre tabindex="0"><code>.
├── README.md
├── babel.config.js
├── jest.config.js
├── package.json
├── postcss.config.js
├── public
│   ├── favicon.ico
│   └── index.html
├── src
│   ├── assets
│   │   ├── logo.png
│   │   └── scss
│   │       ├── _variables.scss
│   │       └── app.scss
│   ├── components
│   │   └── HelloWorld.vue
│   ├── pages
│   │   ├── singleDashboard
│   │   │   ├── App.vue
│   │   │   └── main.ts
│   │   └── spa
│   │       ├── App.vue
│   │       ├── main.ts
│   │       ├── router.ts
│   │       └── views
│   │           ├── About.vue
│   │           └── Home.vue
│   ├── shims-tsx.d.ts
│   └── shims-vue.d.ts
├── tests
│   └── unit
│       └── example.spec.ts
├── tsconfig.json
└── yarn.lock
</code></pre><p>Next remove routing from the singleDasboard project <code>pages/singleDashboard/main.ts</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Vue</span> <span class="kr">from</span> <span class="s1">&#39;vue&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">App</span> <span class="kr">from</span> <span class="s1">&#39;./App.vue&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Buefy</span> <span class="kr">from</span> <span class="s1">&#39;buefy&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// import router from &#39;./router.ts; // delete
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">import</span> <span class="s1">&#39;./assets/scss/app.scss&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">Vue</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">Buefy</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">Vue</span><span class="p">.</span><span class="nx">config</span><span class="p">.</span><span class="nx">productionTip</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">Vue</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// router, // delete
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">render</span>: <span class="kt">h</span> <span class="o">=&gt;</span> <span class="nx">h</span><span class="p">(</span><span class="nx">App</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}).</span><span class="nx">$mount</span><span class="p">(</span><span class="s2">&#34;#singleDashboard&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>And in <code>pages/singleDashboard/App.vue</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;app&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;section&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        SPA-less multi-page sample
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;scss&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Building the project will delete the wwwroot folder of the MVC project! (we will replace it all with Buefy/Bulma):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">yarn build
</span></span></code></pre></div><h2 id="prepare-the-mvc-project-for-the-two-vue-apps">Prepare the MVC Project for the two Vue apps</h2>
<p>Now that we have built two seperate vue apps, let&rsquo;s look at the MVC side. As the build process deleted all the bootstrap styles and JQuery, start by deleting all of those resources.</p>
<p>In: <code>Views/Shared/_Layout.cshml</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="cp">&lt;!DOCTYPE html&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;utf-8&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;viewport&#34;</span> <span class="na">content</span><span class="o">=</span><span class="s">&#34;width=device-width, initial-scale=1.0&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>@ViewData[&#34;Title&#34;] - DotnetVues.Web<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c">&lt;!-- TODO Add common-css --&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="c">&lt;!-- &lt;environment include=&#34;Development&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">        &lt;link rel=&#34;stylesheet&#34; href=&#34;~/lib/bootstrap/dist/css/bootstrap.css&#34; /&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">    &lt;/environment&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">    &lt;environment exclude=&#34;Development&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">        &lt;link rel=&#34;stylesheet&#34; href=&#34;https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">              asp-fallback-href=&#34;~/lib/bootstrap/dist/css/bootstrap.min.css&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">              asp-fallback-test-class=&#34;sr-only&#34; asp-fallback-test-property=&#34;position&#34; asp-fallback-test-value=&#34;absolute&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">              crossorigin=&#34;anonymous&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">              integrity=&#34;sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE=&#34;/&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">    &lt;/environment&gt; --&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="c">&lt;!-- &lt;link rel=&#34;stylesheet&#34; href=&#34;~/css/site.css&#34; /&gt; --&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="c">&lt;!-- Delete this and replace later wit ha bulma-based navbar --&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="c">&lt;!-- &lt;nav class=&#34;navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">            &lt;div class=&#34;container&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">                &lt;a class=&#34;navbar-brand&#34; asp-area=&#34;&#34; asp-controller=&#34;Home&#34; asp-action=&#34;Index&#34;&gt;DotnetVues.Web&lt;/a&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">                &lt;button class=&#34;navbar-toggler&#34; type=&#34;button&#34; data-toggle=&#34;collapse&#34; data-target=&#34;.navbar-collapse&#34; aria-controls=&#34;navbarSupportedContent&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">                        aria-expanded=&#34;false&#34; aria-label=&#34;Toggle navigation&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">                    &lt;span class=&#34;navbar-toggler-icon&#34;&gt;&lt;/span&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">                &lt;/button&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">                &lt;div class=&#34;navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">                    &lt;ul class=&#34;navbar-nav flex-grow-1&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">                        &lt;li class=&#34;nav-item&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">                            &lt;a class=&#34;nav-link text-dark&#34; asp-area=&#34;&#34; asp-controller=&#34;Home&#34; asp-action=&#34;Index&#34;&gt;Home&lt;/a&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">                        &lt;/li&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">                        &lt;li class=&#34;nav-item&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">                            &lt;a class=&#34;nav-link text-dark&#34; asp-area=&#34;&#34; asp-controller=&#34;Home&#34; asp-action=&#34;Privacy&#34;&gt;Privacy&lt;/a&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">                        &lt;/li&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">                    &lt;/ul&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">                &lt;/div&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">            &lt;/div&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">        &lt;/nav&gt; --&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">partial</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;_CookieConsentPartial&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">main</span> <span class="na">role</span><span class="o">=</span><span class="s">&#34;main&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;pb-3&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            @RenderBody()
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;border-top footer text-muted&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="ni">&amp;copy;</span> 2019 - DotnetVues.Web - <span class="p">&lt;</span><span class="nt">a</span> <span class="na">asp-area</span><span class="o">=</span><span class="s">&#34;&#34;</span> <span class="na">asp-controller</span><span class="o">=</span><span class="s">&#34;Home&#34;</span> <span class="na">asp-action</span><span class="o">=</span><span class="s">&#34;Privacy&#34;</span><span class="p">&gt;</span>Privacy<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c">&lt;!-- TODO Add webpack vendor chunks here --&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="c">&lt;!-- &lt;environment include=&#34;Development&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">        &lt;script src=&#34;~/lib/jquery/dist/jquery.js&#34;&gt;&lt;/script&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">        &lt;script src=&#34;~/lib/bootstrap/dist/js/bootstrap.bundle.js&#34;&gt;&lt;/script&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">    &lt;/environment&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">    &lt;environment exclude=&#34;Development&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">        &lt;script src=&#34;https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">                asp-fallback-src=&#34;~/lib/jquery/dist/jquery.min.js&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">                asp-fallback-test=&#34;window.jQuery&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">                crossorigin=&#34;anonymous&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">                integrity=&#34;sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">        &lt;/script&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">        &lt;script src=&#34;https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.min.js&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">                asp-fallback-src=&#34;~/lib/bootstrap/dist/js/bootstrap.bundle.min.js&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">                asp-fallback-test=&#34;window.jQuery &amp;&amp; window.jQuery.fn &amp;&amp; window.jQuery.fn.modal&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">                crossorigin=&#34;anonymous&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">                integrity=&#34;sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4=&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">        &lt;/script&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">    &lt;/environment&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">    &lt;script src=&#34;~/js/site.js&#34; asp-append-version=&#34;true&#34;&gt;&lt;/script&gt; --&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    @RenderSection(&#34;Scripts&#34;, required: false)
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Add the common dependencies to the MVC Projec:</p>
<p>When Vue is built, the dependencies are added to the <code>wwwroot</code> directory like:</p>
<pre tabindex="0"><code>.
├── css
│   ├── chunk-common.css
│   └── spa.css
├── favicon.ico
├── img
│   └── logo.png
├── index.html
├── js
│   ├── chunk-common.js
│   ├── chunk-common.js.map
│   ├── chunk-vendors.js
│   ├── chunk-vendors.js.map
│   ├── singleDashboard.js
│   ├── singleDashboard.js.map
│   ├── spa.js
│   └── spa.js.map
├── singleDashboard.html
└── spa.html
</code></pre><p><em>NOTE: the build process also outputs unneeded html that can probably be omitted from the build process</em></p>
<p>Add the common js/css to MVC <code>_Layout.cshtml</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="cp">&lt;!DOCTYPE html&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;utf-8&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;viewport&#34;</span> <span class="na">content</span><span class="o">=</span><span class="s">&#34;width=device-width, initial-scale=1.0&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>@ViewData[&#34;Title&#34;] - DotnetVues.Web<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c">&lt;!-- Because the version handled by ASP.Net Core, this should be for all environments --&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">environment</span> <span class="na">exclude</span><span class="o">=</span><span class="s">&#34;Development,Staging,Production&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;~/css/chunk-common.css&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">environment</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    @RenderSection(&#34;Styles&#34;, required: false)
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="c">&lt;!-- Change the navbar to ba buefy-styled one --&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">nav</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;navbar&#34;</span> <span class="na">role</span><span class="o">=</span><span class="s">&#34;navigation&#34;</span> <span class="na">aria-label</span><span class="o">=</span><span class="s">&#34;main navigation&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;navbar-brand&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;navbar-item brand-text&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/&#34;</span><span class="p">&gt;</span>DotnetVues<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">span</span> <span class="na">aria-hidden</span><span class="o">=</span><span class="s">&#34;true&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">span</span> <span class="na">aria-hidden</span><span class="o">=</span><span class="s">&#34;true&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">span</span> <span class="na">aria-hidden</span><span class="o">=</span><span class="s">&#34;true&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;navbar-menu&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;navbar-end&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">a</span> <span class="na">asp-controller</span><span class="o">=</span><span class="s">&#34;SingleDashboard&#34;</span>
</span></span><span class="line"><span class="cl">                    <span class="na">asp-action</span><span class="o">=</span><span class="s">&#34;Index&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;navbar-item&#34;</span><span class="p">&gt;</span>SingleDashboard<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">a</span> <span class="na">asp-controller</span><span class="o">=</span><span class="s">&#34;Spa&#34;</span>
</span></span><span class="line"><span class="cl">                    <span class="na">asp-action</span><span class="o">=</span><span class="s">&#34;Index&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;navbar-item&#34;</span><span class="p">&gt;</span>Spa<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">partial</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;_CookieConsentPartial&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">main</span> <span class="na">role</span><span class="o">=</span><span class="s">&#34;main&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;section&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            @RenderBody()
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;footer&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="ni">&amp;copy;</span> 2019 - DotnetVues.Web - <span class="p">&lt;</span><span class="nt">a</span> <span class="na">asp-area</span><span class="o">=</span><span class="s">&#34;&#34;</span> <span class="na">asp-controller</span><span class="o">=</span><span class="s">&#34;Home&#34;</span> <span class="na">asp-action</span><span class="o">=</span><span class="s">&#34;Privacy&#34;</span><span class="p">&gt;</span>Privacy<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c">&lt;!-- Add the common js portions here --&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">environment</span> <span class="na">include</span><span class="o">=</span><span class="s">&#34;Development,Staging,Production&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;~/js/chunk-common.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;~/js/chunk-vendors.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">environment</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    @RenderSection(&#34;Scripts&#34;, required: false)
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Add routes/views to MVC:</p>
<p>In the navbar there are two controllers that don&rsquo;t acutally exist (<code>SingleDashboard</code> and <code>Spa</code>) so we will need to add them. MVC has a directory structure to adhere to, which defaults to:</p>
<pre tabindex="0"><code>.
├── Controllers
│   └── MyViewA.cs // has an action of Index
└── Views
    └── MyViewA
        └── Index.cshtml
</code></pre><p>Add the <code>Controllers/SingleDashboard.cs</code> route:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cs" data-lang="cs"><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Collections.Generic</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Diagnostics</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Linq</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Threading.Tasks</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">Microsoft.AspNetCore.Mvc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">DotnetVues.Web.Models</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nn">DotnetVues.Web.Controllers</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">class</span> <span class="nc">SingleDashboardController</span> <span class="p">:</span> <span class="n">Controller</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">public</span> <span class="n">IActionResult</span> <span class="n">Index</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">View</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Add the <code>Views/SingleDashboard/Index.cshtml</code> view:</p>
<pre tabindex="0"><code>@{
    ViewData[&#34;Title&#34;] = &#34;Vue-based SPA-less single dasboard&#34;;
}

@section scripts {
    &lt;environment include=&#34;Development,Production,Staging&#34;&gt;
        &lt;script src=&#34;~/js/singleDashboard.js&#34; asp-append-version=&#34;true&#34;&gt;&lt;/script&gt;
    &lt;/environment&gt;
}

&lt;div id=&#34;singleDashboard&#34;&gt;&lt;/div&gt;
</code></pre><p>Add the <code>Controllers/Spa.cs</code> Route:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cs" data-lang="cs"><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Collections.Generic</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Diagnostics</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Linq</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Threading.Tasks</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">Microsoft.AspNetCore.Mvc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">DotnetVues.Web.Models</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nn">DotnetVues.Web.Controllers</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">class</span> <span class="nc">SpaController</span> <span class="p">:</span> <span class="n">Controller</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">public</span> <span class="n">IActionResult</span> <span class="n">Index</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">View</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Add the <code>Views/Spa/Index.cshtml</code> View:</p>
<pre tabindex="0"><code>@{
    ViewData[&#34;Title&#34;] = &#34;Vue SPA&#34;;
}

@section scripts {
    &lt;environment include=&#34;Development,Production,Staging&#34;&gt;
        &lt;script src=&#34;~/js/spa.js&#34; asp-append-version=&#34;true&#34;&gt;&lt;/script&gt;
    &lt;/environment&gt;
}

@section styles {
    &lt;environment include=&#34;Development,Production,Staging&#34;&gt;
        &lt;script src=&#34;~/css/spa.css&#34; asp-append-version=&#34;true&#34;&gt;&lt;/script&gt;
    &lt;/environment&gt;
}

&lt;div id=&#34;spa&#34;&gt;&lt;/div&gt;
</code></pre><p><em>NOTE: code-chunking is applied to css as well, creating a need to manage all assets per app</em></p>
<p>Navigating around we can see the singleDashboard URI loads the app and the SPA URI loads the app with routing to <code>Home</code> and <code>About</code>.</p>
<p>What happens when we enter the spa route directly though? It 404&rsquo;s with a blank page, yikes. For requests to the <code>/spa</code> url only, we need to provide a fallback routing in MVC be compatible with <code>vue-router</code>&rsquo;s history mode.</p>
<p>MVC&rsquo;s routing rules are located in <code>Startup.cs</code> under <code>public void Configure(IApplicationBuilder app, IHostingEnvironment env)</code> method inside of the <code>app.UseMvc</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cs" data-lang="cs"><span class="line"><span class="cl"><span class="k">public</span> <span class="k">void</span> <span class="n">Configure</span><span class="p">(</span><span class="n">IApplicationBuilder</span> <span class="n">app</span><span class="p">,</span> <span class="n">IHostingEnvironment</span> <span class="n">env</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">env</span><span class="p">.</span><span class="n">IsDevelopment</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">app</span><span class="p">.</span><span class="n">UseDeveloperExceptionPage</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">app</span><span class="p">.</span><span class="n">UseExceptionHandler</span><span class="p">(</span><span class="s">&#34;/Home/Error&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.</span>
</span></span><span class="line"><span class="cl">        <span class="n">app</span><span class="p">.</span><span class="n">UseHsts</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">app</span><span class="p">.</span><span class="n">UseHttpsRedirection</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="n">app</span><span class="p">.</span><span class="n">UseStaticFiles</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="n">app</span><span class="p">.</span><span class="n">UseCookiePolicy</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">app</span><span class="p">.</span><span class="n">UseMvc</span><span class="p">(</span><span class="n">routes</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">routes</span><span class="p">.</span><span class="n">MapRoute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">name</span><span class="p">:</span> <span class="s">&#34;default&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">template</span><span class="p">:</span> <span class="s">&#34;{controller=Home}/{action=Index}/{id?}&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">        <span class="c1">// Whenever a request to the Spa Controller doesnt match a defined Action, return the Index.cshtml and let the front-end handle it</span>
</span></span><span class="line"><span class="cl">        <span class="n">routes</span><span class="p">.</span><span class="n">MapRoute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">name</span><span class="p">:</span> <span class="s">&#34;spa-route&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">template</span><span class="p">:</span> <span class="s">&#34;{controller=Spa}/{*anything=Index}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">defaults</span><span class="p">:</span> <span class="k">new</span> <span class="p">{</span> <span class="n">action</span> <span class="p">=</span> <span class="s">&#34;Index&#34;</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Debug again and the MVC Router returns index for unknown routes for only the <code>SpaController</code>.</p>
<h2 id="conclusion">Conclusion</h2>
<p>While this is certainly not exhaustive, here are some more things I would like to explore more deeply:</p>
<ul>
<li>Support development builds - VueDevTools can then be enabled</li>
<li>Setup Reverse proxy for Vue  - route calls to MVC instance (local or hosted) during <code>yarn serve</code></li>
<li>Disable CSS Code-chunking - the amount of custom css should be minimal enough to not justify chunking the code, also avoiding a maintenance nightmare</li>
<li>Create a MVC View Component (or tag-helper?) to help cut down on boiler code for the Razor Views</li>
</ul>
<p>The finished product will look like:</p>
<pre tabindex="0"><code>.
├── DotnetVues.sln
├── client-app // Vue App
│   ├── README.md
│   ├── babel.config.js
│   ├── jest.config.js
│   ├── package.json
│   ├── postcss.config.js
│   ├── public
│   │   ├── favicon.ico
│   │   └── index.html
│   ├── src
│   │   ├── assets
│   │   │   ├── logo.png
│   │   │   └── scss
│   │   │       ├── _variables.scss
│   │   │       └── app.scss
│   │   ├── components
│   │   │   └── HelloWorld.vue
│   │   ├── pages
│   │   │   ├── singleDashboard
│   │   │   │   ├── App.vue
│   │   │   │   └── main.ts
│   │   │   └── spa
│   │   │       ├── App.vue
│   │   │       ├── main.ts
│   │   │       ├── router.ts
│   │   │       └── views
│   │   │           ├── About.vue
│   │   │           └── Home.vue
│   │   ├── shims-tsx.d.ts
│   │   └── shims-vue.d.ts
│   ├── tests
│   │   └── unit
│   │       └── example.spec.ts
│   ├── tsconfig.json
│   ├── vue.config.js
│   └── yarn.lock
└── src // ASP.Net Core MVC Project
    └── DotnetVue.Web
        ├── Controllers
        │   ├── HomeController.cs
        │   ├── SingleDashboard.cs
        │   └── Spa.cs
        ├── DotnetVues.Web.csproj
        ├── Models
        │   └── ErrorViewModel.cs
        ├── Program.cs
        ├── Properties
        │   └── launchSettings.json
        ├── Startup.cs
        ├── Views
        │   ├── Home
        │   │   ├── Index.cshtml
        │   │   └── Privacy.cshtml
        │   ├── Shared
        │   │   ├── Error.cshtml
        │   │   ├── _CookieConsentPartial.cshtml
        │   │   ├── _Layout.cshtml
        │   │   └── _ValidationScriptsPartial.cshtml
        │   ├── SingleDashboard
        │   │   └── Index.cshtml
        │   ├── Spa
        │   │   └── Index.cshtml
        │   ├── _ViewImports.cshtml
        │   └── _ViewStart.cshtml
        ├── appsettings.Development.json
        ├── appsettings.json
        └── wwwroot
            ├── css
            │   ├── chunk-common.css
            │   └── spa.css
            ├── favicon.ico
            ├── img
            │   └── logo.png
            ├── index.html
            ├── js
            │   ├── chunk-2d0b23f4.js
            │   ├── chunk-2d0b23f4.js.map
            │   ├── chunk-common.js
            │   ├── chunk-common.js.map
            │   ├── chunk-vendors.js
            │   ├── chunk-vendors.js.map
            │   ├── singleDashboard.js
            │   ├── singleDashboard.js.map
            │   ├── spa.js
            │   └── spa.js.map
            ├── singleDashboard.html
            └── spa.html
</code></pre>]]></content>
		</item>
		
		<item>
			<title>Convert existing Nuxt app to Typescript part 1</title>
			<link>/posts/convert-exisiting-nuxt-app-to-typescript-1/</link>
			<pubDate>Sat, 02 Mar 2019 12:07:40 +0900</pubDate>
			
			<guid>/posts/convert-exisiting-nuxt-app-to-typescript-1/</guid>
			<description>Nuxt-ts was announced recently and I was really excited as I was working on a nuxt app with a ASP.NET Core backend. As I have already spent a bit of time working on this, I felt it would be easier/more educational to convert the project manually rather than re-scaffold and copy contents over.
This will be an ongoing project chronicling my adventure into Nuxt with Typescript. First we will create a nuxt app and then convert it to a typescript app.</description>
			<content type="html"><![CDATA[<p>Nuxt-ts was announced recently and I was really excited as I was working on a nuxt app with a ASP.NET Core backend. As I have already spent a bit of time working on this, I felt it would be easier/more educational to convert the project manually rather than re-scaffold and copy contents over.</p>
<p>This will be an ongoing project chronicling my adventure into Nuxt with Typescript. First we will create a nuxt app and then convert it to a typescript app. This will reference the <a href="https://github.com/nuxt-community/hackernews-nuxt-ts">hackernews-nuxt-typescript</a> repository as well as the Vue-cli typescript scaffolding to find a happy medium that works best with VSCode.</p>
<p>Before getting started, install the below dependencies:</p>
<ul>
<li>Yarn</li>
</ul>
<h1 id="in-this-part">In this part:</h1>
<ol>
<li>Scaffold a new Nuxt app</li>
<li>Change dependencies to typescript versions</li>
<li>Update package.json scripts to the new dependencies</li>
<li>Port configuration to typescript</li>
<li>Port Single File Components to Typescript</li>
</ol>
<hr>
<h3 id="scaffold-a-new-nuxt-app">Scaffold a new Nuxt app</h3>
<p>run <code>npx create-nuxt-app my-typescript app</code></p>
<table>
<thead>
<tr>
<th>section</th>
<th>values</th>
</tr>
</thead>
<tbody>
<tr>
<td>serverside framework</td>
<td>None</td>
</tr>
<tr>
<td>features</td>
<td>linter/formatter<!-- raw HTML omitted -->axios<!-- raw HTML omitted -->prettier</td>
</tr>
<tr>
<td>UI framework</td>
<td>Buefy</td>
</tr>
<tr>
<td>test</td>
<td>Jest</td>
</tr>
<tr>
<td>package manager</td>
<td>yarn</td>
</tr>
</tbody>
</table>
<p>lets install the dependencies and run this to make sure: <code>yarn &amp;&amp; yarn dev</code></p>
<p><img src="/img/nuxt-buefy-landing.png" alt="nuxt-buefy default page"></p>
<hr>
<h2 id="change-dependencies-to-typescript-versions">Change dependencies to typescript versions</h2>
<p>first add <code>vue-property-decorator</code> to the app via yarn: <code>yarn add vue-property-decorator</code></p>
<p>open <code>package.json</code> and change the entry from <code>&quot;nuxt&quot;: &quot;^2.X.X&quot;</code> to <code>&quot;nuxt-ts&quot;: &quot;latest&quot;</code></p>
<p>next, add the prettier linter to the <code>devDependencies</code> below:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl">   <span class="s2">&#34;tslint-config-prettier&#34;</span><span class="o">:</span> <span class="s2">&#34;1.18.0&#34;</span>
</span></span></code></pre></div><p>NOTE: This will work, but some items will not lint before compile errors.</p>
<hr>
<h2 id="update-packagejson-scripts-to-the-new-dependencies">Update package.json scripts to the new dependencies</h2>
<p>replace:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;dev&#34;</span><span class="o">:</span> <span class="s2">&#34;nuxt&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;build&#34;</span><span class="o">:</span> <span class="s2">&#34;nuxt build&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;start&#34;</span><span class="o">:</span> <span class="s2">&#34;nuxt start&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;generate&#34;</span><span class="o">:</span> <span class="s2">&#34;nuxt generate&#34;</span><span class="p">,</span>
</span></span></code></pre></div><p>with:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;dev&#34;</span><span class="o">:</span> <span class="s2">&#34;nuxt-ts&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;build&#34;</span><span class="o">:</span> <span class="s2">&#34;nuxt-ts build&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;start&#34;</span><span class="o">:</span> <span class="s2">&#34;nuxt-ts start&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;generate&#34;</span><span class="o">:</span> <span class="s2">&#34;nuxt-ts generate&#34;</span><span class="p">,</span>
</span></span></code></pre></div><p>lets run this and see the progress <code>yarn dev</code></p>
<p>There should be a prompt to create a <code>tsconfig.json</code> as it is missing; press yes.</p>
<p><img src="/img/nuxt-ts-debug-server.png" alt="nuxt server is also being built"></p>
<p>The serverside framework was set to <code>None</code> when the Nuxt app was created&hellip; but there is a server being built.</p>
<p>looking at the page we will find missing css and errors saying:</p>
<p><code>[Vue warn]: Unknown custom element: &lt;b-icon&gt; - did you register the component correctly? For recursive components, make sure to provide the &quot;name&quot; option.</code></p>
<p><img src="/img/nuxt-buefy-ts-landing-1.png" alt="default page after changing to ts"></p>
<p>The server being built is a hint; <code>nuxt.config.js</code> is not being loaded and a default is executed in place. Because the default doesn&rsquo;t use Buefy, the <code>b-icon</code> is also not resolved and a warning is thrown. This is fixed in the next step.</p>
<hr>
<h2 id="port-configuration-to-typescript">Port configuration to typescript</h2>
<p>Change the name of <code>nuxt.config.js</code> to <code>nuxt.config.ts</code></p>
<p>Then change the <code>module.exports = </code> to <code>export default</code></p>
<p>The default page should be showing with Buefy again.</p>
<p><img src="/img/nuxt-buefy-landing.png" alt="nuxt-buefy default page"></p>
<hr>
<h2 id="port-single-file-components-to-typescript">Port Single File Components to Typescript</h2>
<p>NOTE: This section has a variety of pitfalls, so lets go through the common ones as the show up.</p>
<p>First convert <code>layouts/default.vue</code> to the <code>vue-property-decorator</code>:</p>
<ol>
<li>change the script language to ts and add the component decorators</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="p">...</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ts&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span><span class="nx">Vue</span><span class="p">,</span> <span class="nx">Component</span><span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;vue-property-decorator&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">@Component</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">App</span> <span class="kr">extends</span> <span class="nx">Vue</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="p">...</span>
</span></span></code></pre></div><p>There should be an error similar to the one below:
<img src="/img/default.vue-tsconfig-error.png" alt="tsConfig error"></p>
<p>This is caused by property decorators being an experimental typescript feature. Enable them by adding the below to <code>tsconfig.json</code> <code>compilerOptions</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl">  <span class="s2">&#34;compilerOptions&#34;</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;baseUrl&#34;</span><span class="o">:</span> <span class="s2">&#34;.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;types&#34;</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;@types/node&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;@nuxt/vue-app&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;experimentalDecorators&#34;</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="c1">// add this
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="p">}</span>
</span></span></code></pre></div><p>NOTE: this may require a restart for VSCode to understand the tsconfig changes</p>
<p>Next, do the same for <code>pages/index.vue</code></p>
<p>in the <code>script</code> section change:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Card</span> <span class="kr">from</span> <span class="s1">&#39;~/components/Card&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;HomePage&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">components</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">Card</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>to:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ts&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">Vue</span><span class="p">,</span> <span class="nx">Component</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;vue-property-decorator&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Card</span> <span class="kr">from</span> <span class="s1">&#39;~/components/Card&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">@Component</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">components</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">Card</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kr">class</span> <span class="nx">HomePage</span> <span class="kr">extends</span> <span class="nx">Vue</span> <span class="p">{}</span>
</span></span></code></pre></div><p>There should be another error here:</p>
<p><img src="/img/nuxt-ts-vue-sfc-import.png" alt="cannot import .vue files"></p>
<p>This one is trickier and has some <a href="https://github.com/vuejs/vue/issues/5298">history</a>(spoilers it&rsquo;s really long). Typescript, by default, will only look for files with extension <code>.ts</code> and there seems to be two methods of fixing this. One is to modify the webpack config and the other is to extend the typing definitions with a shim as it is easier than extending webpack (personal opinion only, don&rsquo;t @me).</p>
<p>Add a <code>shims.d.ts</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">declare</span> <span class="nx">module</span> <span class="s1">&#39;*.vue&#39;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="nx">Vue</span> <span class="kr">from</span> <span class="s1">&#39;vue&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">export</span> <span class="k">default</span> <span class="nx">Vue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>NOTE: A VSCode restart may be required to pickup the changes</p>
<p>Next change <code>components/Card.vue</code> from:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">props</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">title</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">required</span>: <span class="kt">true</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">icon</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">required</span>: <span class="kt">true</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>to:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ts&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span><span class="nx">Vue</span><span class="p">,</span> <span class="nx">Component</span><span class="p">,</span> <span class="nx">Prop</span><span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;vue-property-decorator&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">@Component</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kr">class</span> <span class="nx">Card</span> <span class="kr">extends</span> <span class="nx">Vue</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">@Prop</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="nx">required</span>: <span class="kt">true</span>
</span></span><span class="line"><span class="cl">    <span class="p">})</span>
</span></span><span class="line"><span class="cl">    <span class="nx">title</span><span class="o">!:</span> <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">@Prop</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="nx">required</span>: <span class="kt">true</span>
</span></span><span class="line"><span class="cl">    <span class="p">})</span>
</span></span><span class="line"><span class="cl">    <span class="nx">icon</span><span class="o">!:</span> <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Some brief tips:</p>
<ul>
<li>The <code>@Prop</code> decorator takes on all the definitions property definitions that typescript is not built for (namely if the property is required and the default value).</li>
<li>The <code>!</code> after the property name is to declare that the property can be unintialized (the <code>@Prop</code> makes it reactive) because it is set during the vue lifecycle.</li>
</ul>
<p>Extras: tweaking the linter/formatter</p>
<p>For the most part, the prettier formatter works well. Coming from a C# background however, I would like a couple of changes. namely semicolons at the end of statements.
<a href="https://prettier.io/docs/en/options.html#semicolons">Official docs</a> says that adding <code>&quot;semi&quot;: true&quot;</code> to <code>.prettierrc</code> should work.</p>
<p>Next, increase the max line length by setting <code>&quot;printWidth&quot;: 120</code> in the <code>.prettierrc</code> file.</p>
<p>Lastly, add commas to everything! <code>&quot;trailingComma&quot;: &quot;all&quot;</code></p>
<p>This will conclude part 1. Any corrections can be sent via Twitter DM</p>
]]></content>
		</item>
		
		<item>
			<title>About this blog (a tour)</title>
			<link>/posts/making-a-blog/</link>
			<pubDate>Wed, 27 Feb 2019 15:53:12 +0900</pubDate>
			
			<guid>/posts/making-a-blog/</guid>
			<description>After many false-starts, my blog has finally been published! This will serve as a place for me to talk about what I have learned to remind myself/help others. Until now, I had looked at several blogging platforms and was continually disappointed by something or another: self-hosted - I want to own my data as much as possible multi-language - I would like to improve my Japanese writing ability static tags</description>
			<content type="html"><![CDATA[<p>After many false-starts, my blog has finally been published! This will serve as a place for me to talk about what I have learned to remind myself/help others. Until now, I had looked at several blogging platforms and was continually disappointed by something or another:</p>
<ul>
<li>self-hosted - I want to own my data as much as possible</li>
<li>multi-language - I would like to improve my Japanese writing ability</li>
<li>static</li>
<li>tags</li>
<li>continuous - essentialy, make a new file <code>git-push</code> and its done, no need for anything more complicated</li>
</ul>
<p>want, but not needed:</p>
<ul>
<li>analytics (access count, unique users)</li>
<li>feedback (NOT comments)</li>
</ul>
<p>First up was Metalsmith and after a decent amount of fiddling with things, most of everything on the wishlist was covered. Except multi-lang. There&rsquo;s a plugin, but was an extremely frustrating experience.</p>
<p>Next attempt was Vuepress, which is a wonderful framework that supports i18n out of the box and can publish easily to a variety of hosts. But the framework is still in a lot of flux. I may look at it again in the future as Vue&rsquo;s component-based model is excellent.</p>
<p>Finally, I settled on Hugo as I can integrate with CICD, deploy anywhere and create truly multi-lang static sites with tags as well as an rss feed! Additionaly, themes are added as git submodules.</p>
<h1 id="note-the-below-architecture-taught-me-alot-about-aws-but-i-moved-to-netlify">NOTE: The below architecture taught me alot about AWS, but I moved to Netlify!</h1>
<p>CICD now looks like:</p>
<p>Git Push/Create PR =&gt; Netlify builds via hugo =&gt; Netlify deploys the site =&gt; DONE!</p>
<p>This is great because they also support SSL via Let&rsquo;s Encrypt for free. It also only took 10min to migrate.</p>
<p><img src="/img/NetlifyDashboard.png" alt=""></p>
<hr>
<h1 id="a-tour-of-this-blog-from-post-to-deployment">A tour of this blog (from post to deployment):</h1>
<p>This makes use of three services:</p>
<ul>
<li>GitHub.com (source host/workflow management)</li>
<li>Azure DevOps (CICD)</li>
<li>AWS (Hosting Platform)</li>
</ul>
<p>The general flow looks like the below diagram (thanks to <a href="draw.io">draw.io</a>):</p>
<p><img src="/img/blog-tour-flow.png" alt="blog flow diagram"></p>
<p>The source is saved on GitHub.com in a private repository. This makes for collaboration (TODO) and proof-reading much easier. For every post a new branch is made (e.g. <code>posts/my-blog-tour</code>) locally. Using Hugo, a new article is made with the command <code>hugo new posts/my-blog-tour.md</code>. This has the advantage of automatically creating the front-matter template. After writing and making a Japanese copy, the changes are pushed to GitHub. From here I create a PR, and assign <a href="/ja/about/#%E8%A8%80%E8%AA%9E%E7%B7%A8%E9%9B%86%E4%BA%A4%E6%8F%9B">reviewers</a>. After revisions are completed, The PR is merged to the master branch. Any changes to the master branch will trigger a build and deployment by Azure DevOps. The CICD process is roughly:</p>
<h3 id="build">BUILD</h3>
<ul>
<li>clone repository from GitHub</li>
<li>clone submodules—for out theme</li>
<li>download and extract Hugo</li>
<li>use Hugo to build the site with the destination being the artifacts directory</li>
</ul>
<h3 id="release">Release</h3>
<ul>
<li>copy files from artifacts</li>
<li>upload to AWS S3.</li>
</ul>
<p>That is the tour for now, I would like to be able to support feedback (NOT comments) via github issues to make corrections and updates easier for everyone (I presonally dislike sites that have outdated information that become misleading lies given enough time). So if there is something in this blog that is incorrect/outdated or just weird, create an issue (there will be a link at the bottom of each page soon-ish) and let&rsquo;s improve it.</p>
]]></content>
		</item>
		
		<item>
			<title>Things I want to do</title>
			<link>/posts/todos/</link>
			<pubDate>Tue, 26 Feb 2019 09:00:00 +0900</pubDate>
			
			<guid>/posts/todos/</guid>
			<description> Create a blog Blog fairly often Write an article about my ideal serverless architecture Create a custom keyboard </description>
			<content type="html"><![CDATA[<ul>
<li><input checked="" disabled="" type="checkbox"> Create a blog</li>
<li><input disabled="" type="checkbox"> Blog fairly often
<ul>
<li><input disabled="" type="checkbox"> Write an article about my ideal serverless architecture</li>
</ul>
</li>
<li><input checked="" disabled="" type="checkbox"> Create a custom keyboard</li>
</ul>
]]></content>
		</item>
		
	</channel>
</rss>
