[{"data":1,"prerenderedAt":1222},["ShallowReactive",2],{"writing-the-road-to-a-static-portfolio-website-with-a-blog":3},{"id":4,"title":5,"body":6,"category":1209,"date":1210,"description":12,"excerpt":1211,"extension":603,"image":1212,"keywords":1213,"meta":1214,"navigation":177,"path":1215,"readingTime":1216,"seo":1217,"slug":1218,"stem":1219,"tags":1220,"__hash__":1221},"blog\u002Fblog\u002Fthe-road-to-a-static-portfolio-website-with-a-blog.md","The road to a static portfolio website with a blog",{"type":7,"value":8,"toc":1202},"minimark",[9,13,16,19,24,27,30,33,37,40,48,52,94,103,109,113,116,138,154,496,503,867,878,1148,1151,1155,1158,1161,1175,1184,1187,1190,1193,1198],[10,11,12],"p",{},"The way you've built and designed your portfolio website says a lot about yourself as a developer. And why are we even building these websites? Well, I think it's a really nice and convenient way to showcase your profile and introduce yourself to the world. Many newcomers that join our developers' community are building their portfolio websites as a way to learn new technology and gain a little bit of experience in building websites. Also probably because everyone is tired of making a ToDo list.",[10,14,15],{},"I had redesigned and rebuilt my portfolio website a few times now. Since we want to showcase ourselves in the best possible way, I always listed my skills, projects I am working on, a little bit about myself and a contact form. The first version I built was built in native PHP, and it wasn't even uploaded online. After that, I wanted to experiment with Vue.js and I built the second version of my portfolio website, which at the time was a really nice looking and functional SPA (Single Page Application). However, I couldn't write any blog posts to express my thoughts on that version, so I redesigned it using Laravel and Tailwind by also adding a small dashboard for me to conveniently publish new blog posts, change the content on the website - because I really didn't want to upload a new version every time I want to change something.",[10,17,18],{},"So, everything looks perfect now. The website is live, changing stuff on it is easy, but ...",[20,21,23],"h2",{"id":22},"sometimes-we-need-to-take-a-break","Sometimes we need to take a break",[10,25,26],{},"Working on personal stuff always gives you relief and keeps you motivated because you are working for yourself, and not for someone else. Sometimes, we need to take a break from brain-intensive tasks and just work on something that isn't so demanding. Building something for yourself, even if its something that you can build for a day always kept me satisfied with the work I am doing and why I choose to become a developer in the first place. If you ever find yourself stuck in a project that seems it's going on forever and doesn't feel rewarding when you are completing tasks, take the weekend and built something for yourself.",[10,28,29],{},"Another reason why I have decided to rebuild my website is to improve its speed and usability. I also wanted it to be more blog-focused since I have experienced a big flow of visitors to some of the blog posts I have written, which means that some people like what I write.",[10,31,32],{},"So, how to improve the speed and usability of the portfolio? By building a static single page application.",[20,34,36],{"id":35},"the-new-way-of-building-static-single-page-application","The new way of building static single page application",[10,38,39],{},"A static single page application is an HTML file, with some CSS and JavaScript that doesn't require a server to load. Since we are serving static HTML pages, our visitors experience a big improvement in speed while using our website. Did you know that almost 30% of your visitors will not wait for more than 3seconds for your application to load before leaving? Sometimes, even if you optimize your web application, loading can be slower than you expected because of your server. By generating (building) a static SPA your visitors don't have to wait for the server to receive and respond to the request, all of your pages are served instantly.",[10,41,42,43,47],{},"There are tons of ways to build static SPA's (Nuxt, Gridsome, Gatsby, VuePress ...). These frameworks\u002Flibraries, give you pre-configured working environments which you can use to build your portfolio website fairly quickly. For this SPA, I am using Nuxt.js, which is a framework that gives you a boilerplate with a lot of configuration to make your development experience enjoyable. With Nuxt.js you can build universal web applications - SSR (server-side rendered) or client-side rendered. It also gives you a way to quickly generate a ",[44,45,46],"strong",{},"static single page application"," which is exactly what I wanted. And yes, since my preferred library for building UI's is Vue.js, adopting Nuxt.js in my workflow was pretty easy.",[20,49,51],{"id":50},"generating-static-pages","Generating static pages",[10,53,54,55,59,60,63,64,67,68,70,71,75,76,79,80,83,84,87,88,90,91,93],{},"Nuxt includes a command ",[56,57,58],"code",{},"nuxt generate",", that generates static pages for all ",[56,61,62],{},".vue"," files in your project's ",[56,65,66],{},"pages"," directory. Simple as that. Build your pages, run a simple command and you have a static SPA ready to be deployed. But, ",[56,69,58],{},", doesn't generate static pages for ",[72,73,74],"em",{},"dynamic"," pages. A dynamic page is a page which shows content depending on a route parameter. For example, if we want to show a blog post when a visitor navigates to ",[56,77,78],{},"blog\u002F{post}",", the ",[56,81,82],{},"{post}"," part in the URL is the ",[56,85,86],{},"post"," that we want to show to the user. But, since we can type anything we want in the ",[56,89,82],{}," parameter (therefore the page is dynamic), the ",[56,92,58],{}," command doesn't generate static pages for those routes.",[10,95,96,97,99,100,102],{},"One way we can solve this 'problem', is to explicitly tell Nuxt to generate static pages for some values of the ",[56,98,82],{}," parameter. In this case, since the blog will always have a finite number of posts, we can just get all the posts, and generate a ",[56,101,78],{}," static page that will be served to the visitor whenever he wants to visit a particular post. Great, now we even have static pages for our dynamic post page.",[10,104,105,106],{},"The next thing we need to do is to be able to write and elegantly handle blog posts. Since I don't want to use any database, every post will be stored as a single markdown file. All of the posts that I would write in the future should be handled and shown properly while also generating an appropriate static page for the new post, because doing it manually would just return me back to the previous version - and I want this one ",[44,107,108],{},"to be the last version of my portfolio I build.",[20,110,112],{"id":111},"handing-of-new-posts-and-using-markdown-to-write-content","Handing of new posts and using markdown to write content",[10,114,115],{},"My final goal is to just make a new markdown file, commit the changes, push them to a repository and they are automatically shown on the website (later in this post a bit more about the past part). But, how to parse and convert markdown and render it in JavaScript?",[10,117,118,119,122,123,122,126,129,130,133,134,137],{},"Every post has a slug in their attributes list. When a user visits a post URL, we get the slug in the URL and try to load the markdown file for that post. When the post is loaded, we get its YAML properties (post attributes) like ",[72,120,121],{},"title",", ",[72,124,125],{},"slug",[72,127,128],{},"date",", etc using the ",[56,131,132],{},"front-matter"," package. The content of the post is converted from markdown to HTML using the ",[56,135,136],{},"markdownit"," package. Before we display the content, we apply to highlight for the code snippets written in the post. That's it!",[10,139,140],{},[72,141,142,145,146,149,150,153],{},[56,143,144],{},"formatReadingTime"," and ",[56,147,148],{},"formatPostDate"," are just functions that I use to format the posts reading time and date created. ",[56,151,152],{},"markdown-it-attrs"," is a package used to parse HTML attributes added your markdown.",[155,156,161],"pre",{"className":157,"code":158,"language":159,"meta":160,"style":160},"language-js shiki shiki-themes github-light github-dark","\u002F* pages\u002Fblog\u002F_post.vue - Handling and rendering the post *\u002F\n\nimport { formatReadingTime, formatPostDate } from '~\u002Futils\u002Fformatter';\n\nconst fm = require('front-matter');\nconst md = require('markdown-it')({\n    html: true,\n    linkify: true,\n    typographer: true,\n})\n    .use(require('markdown-it-highlightjs'))\n    .use(require('markdown-it-attrs'));\n\nexport default {\n    async asyncData({ params, app: { $md } }) {\n        const result = await import(`~\u002Fposts\u002F${params.post}.md`);\n        const post = fm(result.default);\n\n        return {\n            attributes: post.attributes,\n            content: md.render(post.body),\n            readingTime: formatReadingTime(post.body),\n            date: formatPostDate(post.attributes.date),\n        };\n    },\n};\n","js","",[56,162,163,172,179,200,205,231,251,263,273,283,289,311,330,335,347,377,411,426,431,439,445,457,467,478,484,490],{"__ignoreMap":160},[164,165,168],"span",{"class":166,"line":167},"line",1,[164,169,171],{"class":170},"sJ8bj","\u002F* pages\u002Fblog\u002F_post.vue - Handling and rendering the post *\u002F\n",[164,173,175],{"class":166,"line":174},2,[164,176,178],{"emptyLinePlaceholder":177},true,"\n",[164,180,182,186,190,193,197],{"class":166,"line":181},3,[164,183,185],{"class":184},"szBVR","import",[164,187,189],{"class":188},"sVt8B"," { formatReadingTime, formatPostDate } ",[164,191,192],{"class":184},"from",[164,194,196],{"class":195},"sZZnC"," '~\u002Futils\u002Fformatter'",[164,198,199],{"class":188},";\n",[164,201,203],{"class":166,"line":202},4,[164,204,178],{"emptyLinePlaceholder":177},[164,206,208,211,215,218,222,225,228],{"class":166,"line":207},5,[164,209,210],{"class":184},"const",[164,212,214],{"class":213},"sj4cs"," fm",[164,216,217],{"class":184}," =",[164,219,221],{"class":220},"sScJk"," require",[164,223,224],{"class":188},"(",[164,226,227],{"class":195},"'front-matter'",[164,229,230],{"class":188},");\n",[164,232,234,236,239,241,243,245,248],{"class":166,"line":233},6,[164,235,210],{"class":184},[164,237,238],{"class":213}," md",[164,240,217],{"class":184},[164,242,221],{"class":220},[164,244,224],{"class":188},[164,246,247],{"class":195},"'markdown-it'",[164,249,250],{"class":188},")({\n",[164,252,254,257,260],{"class":166,"line":253},7,[164,255,256],{"class":188},"    html: ",[164,258,259],{"class":213},"true",[164,261,262],{"class":188},",\n",[164,264,266,269,271],{"class":166,"line":265},8,[164,267,268],{"class":188},"    linkify: ",[164,270,259],{"class":213},[164,272,262],{"class":188},[164,274,276,279,281],{"class":166,"line":275},9,[164,277,278],{"class":188},"    typographer: ",[164,280,259],{"class":213},[164,282,262],{"class":188},[164,284,286],{"class":166,"line":285},10,[164,287,288],{"class":188},"})\n",[164,290,292,295,298,300,303,305,308],{"class":166,"line":291},11,[164,293,294],{"class":188},"    .",[164,296,297],{"class":220},"use",[164,299,224],{"class":188},[164,301,302],{"class":220},"require",[164,304,224],{"class":188},[164,306,307],{"class":195},"'markdown-it-highlightjs'",[164,309,310],{"class":188},"))\n",[164,312,314,316,318,320,322,324,327],{"class":166,"line":313},12,[164,315,294],{"class":188},[164,317,297],{"class":220},[164,319,224],{"class":188},[164,321,302],{"class":220},[164,323,224],{"class":188},[164,325,326],{"class":195},"'markdown-it-attrs'",[164,328,329],{"class":188},"));\n",[164,331,333],{"class":166,"line":332},13,[164,334,178],{"emptyLinePlaceholder":177},[164,336,338,341,344],{"class":166,"line":337},14,[164,339,340],{"class":184},"export",[164,342,343],{"class":184}," default",[164,345,346],{"class":188}," {\n",[164,348,350,353,356,359,363,365,368,371,374],{"class":166,"line":349},15,[164,351,352],{"class":184},"    async",[164,354,355],{"class":220}," asyncData",[164,357,358],{"class":188},"({ ",[164,360,362],{"class":361},"s4XuR","params",[164,364,122],{"class":188},[164,366,367],{"class":361},"app",[164,369,370],{"class":188},": { ",[164,372,373],{"class":361},"$md",[164,375,376],{"class":188}," } }) {\n",[164,378,380,383,386,388,391,394,396,399,401,404,406,409],{"class":166,"line":379},16,[164,381,382],{"class":184},"        const",[164,384,385],{"class":213}," result",[164,387,217],{"class":184},[164,389,390],{"class":184}," await",[164,392,393],{"class":184}," import",[164,395,224],{"class":188},[164,397,398],{"class":195},"`~\u002Fposts\u002F${",[164,400,362],{"class":188},[164,402,403],{"class":195},".",[164,405,86],{"class":188},[164,407,408],{"class":195},"}.md`",[164,410,230],{"class":188},[164,412,414,416,419,421,423],{"class":166,"line":413},17,[164,415,382],{"class":184},[164,417,418],{"class":213}," post",[164,420,217],{"class":184},[164,422,214],{"class":220},[164,424,425],{"class":188},"(result.default);\n",[164,427,429],{"class":166,"line":428},18,[164,430,178],{"emptyLinePlaceholder":177},[164,432,434,437],{"class":166,"line":433},19,[164,435,436],{"class":184},"        return",[164,438,346],{"class":188},[164,440,442],{"class":166,"line":441},20,[164,443,444],{"class":188},"            attributes: post.attributes,\n",[164,446,448,451,454],{"class":166,"line":447},21,[164,449,450],{"class":188},"            content: md.",[164,452,453],{"class":220},"render",[164,455,456],{"class":188},"(post.body),\n",[164,458,460,463,465],{"class":166,"line":459},22,[164,461,462],{"class":188},"            readingTime: ",[164,464,144],{"class":220},[164,466,456],{"class":188},[164,468,470,473,475],{"class":166,"line":469},23,[164,471,472],{"class":188},"            date: ",[164,474,148],{"class":220},[164,476,477],{"class":188},"(post.attributes.date),\n",[164,479,481],{"class":166,"line":480},24,[164,482,483],{"class":188},"        };\n",[164,485,487],{"class":166,"line":486},25,[164,488,489],{"class":188},"    },\n",[164,491,493],{"class":166,"line":492},26,[164,494,495],{"class":188},"};\n",[10,497,498,499,502],{},"How about finding and browsing through all of the posts? Building the blog index page is simple. We just get all of the posts within our ",[56,500,501],{},"posts"," directory, get the needed attributes to display them on the page, sort them by creation date to show latest posts first and we are good to go. We can even add searching\u002Ffiltering of the posts using Vue.js.",[155,504,506],{"className":157,"code":505,"language":159,"meta":160,"style":160},"\u002F* blog\u002Findex.vue - Showing all posts *\u002F\n\nconst fm = require('front-matter');\nimport { formatReadingTime, formatPostDate } from '~\u002Futils\u002Fformatter';\n\nexport default {\n    async asyncData() {\n        const resolve = require.context('~\u002Fposts\u002F', true, \u002F\\.md$\u002F);\n        const posts = resolve\n            .keys()\n            .map(key => {\n                const [, name] = key.match(\u002F\\\u002F(.+)\\.md$\u002F);\n                return resolve(key);\n            })\n            .map(post => {\n                const result = fm(post.default);\n                return {\n                    ...result.attributes,\n                    readingTime: formatReadingTime(result.body),\n                    date: formatPostDate(result.attributes.date),\n                };\n            })\n            .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());\n\n        return {\n            posts,\n        };\n    };\n",[56,507,508,513,517,533,545,549,557,566,612,624,635,652,702,712,717,731,744,750,758,768,778,783,787,841,845,851,856,861],{"__ignoreMap":160},[164,509,510],{"class":166,"line":167},[164,511,512],{"class":170},"\u002F* blog\u002Findex.vue - Showing all posts *\u002F\n",[164,514,515],{"class":166,"line":174},[164,516,178],{"emptyLinePlaceholder":177},[164,518,519,521,523,525,527,529,531],{"class":166,"line":181},[164,520,210],{"class":184},[164,522,214],{"class":213},[164,524,217],{"class":184},[164,526,221],{"class":220},[164,528,224],{"class":188},[164,530,227],{"class":195},[164,532,230],{"class":188},[164,534,535,537,539,541,543],{"class":166,"line":202},[164,536,185],{"class":184},[164,538,189],{"class":188},[164,540,192],{"class":184},[164,542,196],{"class":195},[164,544,199],{"class":188},[164,546,547],{"class":166,"line":207},[164,548,178],{"emptyLinePlaceholder":177},[164,550,551,553,555],{"class":166,"line":233},[164,552,340],{"class":184},[164,554,343],{"class":184},[164,556,346],{"class":188},[164,558,559,561,563],{"class":166,"line":253},[164,560,352],{"class":184},[164,562,355],{"class":220},[164,564,565],{"class":188},"() {\n",[164,567,568,570,573,575,578,581,583,586,588,590,593,596,600,604,607,610],{"class":166,"line":265},[164,569,382],{"class":184},[164,571,572],{"class":213}," resolve",[164,574,217],{"class":184},[164,576,577],{"class":188}," require.",[164,579,580],{"class":220},"context",[164,582,224],{"class":188},[164,584,585],{"class":195},"'~\u002Fposts\u002F'",[164,587,122],{"class":188},[164,589,259],{"class":213},[164,591,592],{"class":188},",",[164,594,595],{"class":195}," \u002F",[164,597,599],{"class":598},"snhLl","\\.",[164,601,603],{"class":602},"sA_wV","md",[164,605,606],{"class":184},"$",[164,608,609],{"class":195},"\u002F",[164,611,230],{"class":188},[164,613,614,616,619,621],{"class":166,"line":275},[164,615,382],{"class":184},[164,617,618],{"class":213}," posts",[164,620,217],{"class":184},[164,622,623],{"class":188}," resolve\n",[164,625,626,629,632],{"class":166,"line":285},[164,627,628],{"class":188},"            .",[164,630,631],{"class":220},"keys",[164,633,634],{"class":188},"()\n",[164,636,637,639,642,644,647,650],{"class":166,"line":291},[164,638,628],{"class":188},[164,640,641],{"class":220},"map",[164,643,224],{"class":188},[164,645,646],{"class":361},"key",[164,648,649],{"class":184}," =>",[164,651,346],{"class":188},[164,653,654,657,660,663,666,669,672,675,677,679,682,684,686,689,692,694,696,698,700],{"class":166,"line":313},[164,655,656],{"class":184},"                const",[164,658,659],{"class":188}," [, ",[164,661,662],{"class":213},"name",[164,664,665],{"class":188},"] ",[164,667,668],{"class":184},"=",[164,670,671],{"class":188}," key.",[164,673,674],{"class":220},"match",[164,676,224],{"class":188},[164,678,609],{"class":195},[164,680,681],{"class":598},"\\\u002F",[164,683,224],{"class":602},[164,685,403],{"class":213},[164,687,688],{"class":184},"+",[164,690,691],{"class":602},")",[164,693,599],{"class":598},[164,695,603],{"class":602},[164,697,606],{"class":184},[164,699,609],{"class":195},[164,701,230],{"class":188},[164,703,704,707,709],{"class":166,"line":332},[164,705,706],{"class":184},"                return",[164,708,572],{"class":220},[164,710,711],{"class":188},"(key);\n",[164,713,714],{"class":166,"line":337},[164,715,716],{"class":188},"            })\n",[164,718,719,721,723,725,727,729],{"class":166,"line":349},[164,720,628],{"class":188},[164,722,641],{"class":220},[164,724,224],{"class":188},[164,726,86],{"class":361},[164,728,649],{"class":184},[164,730,346],{"class":188},[164,732,733,735,737,739,741],{"class":166,"line":379},[164,734,656],{"class":184},[164,736,385],{"class":213},[164,738,217],{"class":184},[164,740,214],{"class":220},[164,742,743],{"class":188},"(post.default);\n",[164,745,746,748],{"class":166,"line":413},[164,747,706],{"class":184},[164,749,346],{"class":188},[164,751,752,755],{"class":166,"line":428},[164,753,754],{"class":184},"                    ...",[164,756,757],{"class":188},"result.attributes,\n",[164,759,760,763,765],{"class":166,"line":433},[164,761,762],{"class":188},"                    readingTime: ",[164,764,144],{"class":220},[164,766,767],{"class":188},"(result.body),\n",[164,769,770,773,775],{"class":166,"line":441},[164,771,772],{"class":188},"                    date: ",[164,774,148],{"class":220},[164,776,777],{"class":188},"(result.attributes.date),\n",[164,779,780],{"class":166,"line":447},[164,781,782],{"class":188},"                };\n",[164,784,785],{"class":166,"line":459},[164,786,716],{"class":188},[164,788,789,791,794,797,800,802,805,808,811,814,817,820,823,826,829,831,833,836,838],{"class":166,"line":469},[164,790,628],{"class":188},[164,792,793],{"class":220},"sort",[164,795,796],{"class":188},"((",[164,798,799],{"class":361},"a",[164,801,122],{"class":188},[164,803,804],{"class":361},"b",[164,806,807],{"class":188},") ",[164,809,810],{"class":184},"=>",[164,812,813],{"class":184}," new",[164,815,816],{"class":220}," Date",[164,818,819],{"class":188},"(b.date).",[164,821,822],{"class":220},"getTime",[164,824,825],{"class":188},"() ",[164,827,828],{"class":184},"-",[164,830,813],{"class":184},[164,832,816],{"class":220},[164,834,835],{"class":188},"(a.date).",[164,837,822],{"class":220},[164,839,840],{"class":188},"());\n",[164,842,843],{"class":166,"line":480},[164,844,178],{"emptyLinePlaceholder":177},[164,846,847,849],{"class":166,"line":486},[164,848,436],{"class":184},[164,850,346],{"class":188},[164,852,853],{"class":166,"line":492},[164,854,855],{"class":188},"            posts,\n",[164,857,859],{"class":166,"line":858},27,[164,860,483],{"class":188},[164,862,864],{"class":166,"line":863},28,[164,865,866],{"class":188},"    };\n",[10,868,869,870,873,874,877],{},"The last step for us to do is to configure Nuxt to generate static pages for all of the posts we have. To do this, we modify the ",[56,871,872],{},"nuxt.config.js"," config by extending the ",[56,875,876],{},"generate"," key to the default exported object.",[155,879,881],{"className":157,"code":880,"language":159,"meta":160,"style":160},"\u002F** nuxt.config.js **\u002F\nconst glob = require('glob');\nconst path = require('path');\n\nconst getDynamicPaths = files => {\n    return [].concat(\n        ...Object.keys(files).map(url => {\n            var filepathGlob = files[url];\n            return glob\n                .sync(filepathGlob, { cwd: __dirname })\n                .map(filepath => `${url}\u002F${path.basename(filepath, '.md')}`);\n        }),\n    );\n};\n\nconst dynamicRoutes = getDynamicPaths({ '\u002Fblog': 'posts\u002F*.md' });\n\nexport default {\n  \u002F** ...  **\u002F\n  generate: {\n      routes: dynamicRoutes,\n      fallback: true,\n  },\n}\n",[56,882,883,888,906,924,928,944,958,982,995,1003,1014,1059,1064,1069,1073,1077,1102,1106,1114,1119,1124,1129,1138,1143],{"__ignoreMap":160},[164,884,885],{"class":166,"line":167},[164,886,887],{"class":170},"\u002F** nuxt.config.js **\u002F\n",[164,889,890,892,895,897,899,901,904],{"class":166,"line":174},[164,891,210],{"class":184},[164,893,894],{"class":213}," glob",[164,896,217],{"class":184},[164,898,221],{"class":220},[164,900,224],{"class":188},[164,902,903],{"class":195},"'glob'",[164,905,230],{"class":188},[164,907,908,910,913,915,917,919,922],{"class":166,"line":181},[164,909,210],{"class":184},[164,911,912],{"class":213}," path",[164,914,217],{"class":184},[164,916,221],{"class":220},[164,918,224],{"class":188},[164,920,921],{"class":195},"'path'",[164,923,230],{"class":188},[164,925,926],{"class":166,"line":202},[164,927,178],{"emptyLinePlaceholder":177},[164,929,930,932,935,937,940,942],{"class":166,"line":207},[164,931,210],{"class":184},[164,933,934],{"class":220}," getDynamicPaths",[164,936,217],{"class":184},[164,938,939],{"class":361}," files",[164,941,649],{"class":184},[164,943,346],{"class":188},[164,945,946,949,952,955],{"class":166,"line":233},[164,947,948],{"class":184},"    return",[164,950,951],{"class":188}," [].",[164,953,954],{"class":220},"concat",[164,956,957],{"class":188},"(\n",[164,959,960,963,966,968,971,973,975,978,980],{"class":166,"line":253},[164,961,962],{"class":184},"        ...",[164,964,965],{"class":188},"Object.",[164,967,631],{"class":220},[164,969,970],{"class":188},"(files).",[164,972,641],{"class":220},[164,974,224],{"class":188},[164,976,977],{"class":361},"url",[164,979,649],{"class":184},[164,981,346],{"class":188},[164,983,984,987,990,992],{"class":166,"line":265},[164,985,986],{"class":184},"            var",[164,988,989],{"class":188}," filepathGlob ",[164,991,668],{"class":184},[164,993,994],{"class":188}," files[url];\n",[164,996,997,1000],{"class":166,"line":275},[164,998,999],{"class":184},"            return",[164,1001,1002],{"class":188}," glob\n",[164,1004,1005,1008,1011],{"class":166,"line":285},[164,1006,1007],{"class":188},"                .",[164,1009,1010],{"class":220},"sync",[164,1012,1013],{"class":188},"(filepathGlob, { cwd: __dirname })\n",[164,1015,1016,1018,1020,1022,1025,1027,1030,1032,1035,1038,1040,1043,1045,1047,1049,1052,1054,1057],{"class":166,"line":291},[164,1017,1007],{"class":188},[164,1019,641],{"class":220},[164,1021,224],{"class":188},[164,1023,1024],{"class":361},"filepath",[164,1026,649],{"class":184},[164,1028,1029],{"class":195}," `${",[164,1031,977],{"class":188},[164,1033,1034],{"class":195},"}\u002F${",[164,1036,1037],{"class":188},"path",[164,1039,403],{"class":195},[164,1041,1042],{"class":220},"basename",[164,1044,224],{"class":195},[164,1046,1024],{"class":188},[164,1048,122],{"class":195},[164,1050,1051],{"class":195},"'.md'",[164,1053,691],{"class":195},[164,1055,1056],{"class":195},"}`",[164,1058,230],{"class":188},[164,1060,1061],{"class":166,"line":313},[164,1062,1063],{"class":188},"        }),\n",[164,1065,1066],{"class":166,"line":332},[164,1067,1068],{"class":188},"    );\n",[164,1070,1071],{"class":166,"line":337},[164,1072,495],{"class":188},[164,1074,1075],{"class":166,"line":349},[164,1076,178],{"emptyLinePlaceholder":177},[164,1078,1079,1081,1084,1086,1088,1090,1093,1096,1099],{"class":166,"line":379},[164,1080,210],{"class":184},[164,1082,1083],{"class":213}," dynamicRoutes",[164,1085,217],{"class":184},[164,1087,934],{"class":220},[164,1089,358],{"class":188},[164,1091,1092],{"class":195},"'\u002Fblog'",[164,1094,1095],{"class":188},": ",[164,1097,1098],{"class":195},"'posts\u002F*.md'",[164,1100,1101],{"class":188}," });\n",[164,1103,1104],{"class":166,"line":413},[164,1105,178],{"emptyLinePlaceholder":177},[164,1107,1108,1110,1112],{"class":166,"line":428},[164,1109,340],{"class":184},[164,1111,343],{"class":184},[164,1113,346],{"class":188},[164,1115,1116],{"class":166,"line":433},[164,1117,1118],{"class":170},"  \u002F** ...  **\u002F\n",[164,1120,1121],{"class":166,"line":441},[164,1122,1123],{"class":188},"  generate: {\n",[164,1125,1126],{"class":166,"line":447},[164,1127,1128],{"class":188},"      routes: dynamicRoutes,\n",[164,1130,1131,1134,1136],{"class":166,"line":459},[164,1132,1133],{"class":188},"      fallback: ",[164,1135,259],{"class":213},[164,1137,262],{"class":188},[164,1139,1140],{"class":166,"line":469},[164,1141,1142],{"class":188},"  },\n",[164,1144,1145],{"class":166,"line":480},[164,1146,1147],{"class":188},"}\n",[10,1149,1150],{},"Now the only thing remaining to be completed is to show the changes when we push to our repository. Netlify and it's CI\u002FCD tools are out of this world - which is why I am going to use their services to deploy any changes to my website automatically.",[20,1152,1154],{"id":1153},"netlify-is-magic","Netlify is ... magic",[10,1156,1157],{},"If you are following any trends in the developers' community, you have probably heard of Netlify. Netlify is a unified platform that automates your code to create performant, easily maintainable sites and web apps. They provide continuous deployment, an intelligent, global CDN; full DNS. automated HTTPS, asset acceleration, and much more.",[10,1159,1160],{},"Within this post, I will just explain how I use Netlify for this project specifically. There will be probably a more detailed post about Netlify in the future and its features.",[10,1162,1163,1164,1166,1167,1170,1171,1174],{},"The ",[56,1165,58],{}," command generates a ",[56,1168,1169],{},"dist"," folder that contains all of the assets we need to deploy our website. What we need to do using Netlify is to connect it to our repository and the branch we want to ",[72,1172,1173],{},"watch",". Meaning - whenever we push to that branch on our repository, Netlify will trigger the actions we told it do perform.",[10,1176,1177,1178,1180,1181],{},"So, we set up to run the ",[56,1179,58],{}," command when we push to our repository's branch and serve the dist folder as our publish directory. Everything else is handled by Netlify for us. I told ya - ",[44,1182,1183],{},"magic!",[1185,1186],"hr",{},[10,1188,1189],{},"Everything is configured now. All of the changes I make are almost instantly shown on the live version of the website. I just need to commit and that it - which is extremely easy and convenient.",[10,1191,1192],{},"As a final note - I prefer dark themes. I think they are better for your eyes and there won't be any light theme for this website. I might also open-source the project some day.",[10,1194,1195],{},[44,1196,1197],{},"Thanks for reading. I hope this post will inspire you to build your own static portfolio website 😁",[1199,1200,1201],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .snhLl, html code.shiki .snhLl{--shiki-default:#22863A;--shiki-default-font-weight:bold;--shiki-dark:#85E89D;--shiki-dark-font-weight:bold}html pre.shiki code .sA_wV, html code.shiki .sA_wV{--shiki-default:#032F62;--shiki-dark:#DBEDFF}",{"title":160,"searchDepth":174,"depth":174,"links":1203},[1204,1205,1206,1207,1208],{"id":22,"depth":174,"text":23},{"id":35,"depth":174,"text":36},{"id":50,"depth":174,"text":51},{"id":111,"depth":174,"text":112},{"id":1153,"depth":174,"text":1154},"Web Development","2019\u002F09\u002F29",null,"\u002Fimages\u002Fportfolio-final.png","nuxt, vue, static, jam stack, netlify, static blog, markdown blog, portfolio",{},"\u002Fblog\u002Fthe-road-to-a-static-portfolio-website-with-a-blog","☕️ 11 min read",{"title":5,"description":12},"the-road-to-a-static-portfolio-website-with-a-blog","blog\u002Fthe-road-to-a-static-portfolio-website-with-a-blog","web development, netlify, nuxt, vue","nX5VO1oWgjc79W6TLhF0RMMMDFr3T_S0YSts6xXMesk",1774945272381]