A first exploration of Nuxt.js

Prologue

Yesterday, an idea about a Single-Page Application (SPA) that does some data analysis with MusicKit JS (Apple Music’s JavaScript API) occurred to me, and I started looking for frameworks (or a technology stack) to be used to construct the app. As I was trying to refrain from using Express.js, which seemed too heavy for the task, I decided to look into Nuxt.js, a cousin of Vue.js that had only recently come across my sight. Specifically, I needed a lightweight Node.js framework that serves an SPA with Oauth JWT support, and I also needed to protect my signing key for MusicKit, as it can only be generated from Apple’s paid developer membership.

I spent almost a whole day on getting the fundamentals set-up right, as the documentation was somewhat vague compared to Vue’s or those of other frameworks. Apart from that, I discovered that for the part of signing credential tokens with a private key, I probably had to rely on a separate back-end (or utilize npm packages such as DOTENV, not to be confused with the dotenv-module from Nuxt), as by design (aiming at optimized Server-Side Rendering, or SSR) Nuxt does not seem to have server-side-exclusive information. This was to the best of my knowledge at this point, so I may have been mistaken.

Eventually, I decided that Nuxt.js probably isn’t the most appropriate cookware for my groceries given its oversized shipment meanwhile missing some key parts I needed.

Getting Started

So, installation first. I was using macOS Mojave here, and since I had had node 10.15.1 and npm 6.13.4 (so npx was also present) installed already, I jumped over to Nuxt.js’ installation guide. I first tried their create-nuxt-app method, which prompted me with a bunch of options regarding what to include in first-run. I selected none for wherever possible, and was then instantly overwhelmed by the massive amount of node modules that this command pulled (almost 10,000). The whole process took over 3 minutes to complete. Upon first running npm run dev (which under the hood got executed as npx nuxt), whoa, almost 150 megabytes of memory was consumed! Even though this was the development mode (and people say that this is already better than most other frameworks), and a second try of npx nuxt build; npx nuxt start reduced the instant memory consumption to around 20 megabytes, I was still annoyed that I had to start with such a colossal initial environment.

Second trial. I noticed that the Nuxt team has put a second method on their website, “Starting from scratch”. This looks more friendly, and it seems to me that I have more control over what I want installed. I remove the previous folder, and with the example packages.json provided on Nuxt.js’ getting started guide, I ran npm install --save nuxt. Still, it was a few thousand packages, but better than what I got from my first attempt.

Subsequently, I needed to figure out the configurations, which was not too hard with Nuxt.js’ guide. I created an src directory to store all Nuxt-related files, and set it as the value for srcDir in nuxt.config.js.

Routing

I have to say that Nuxt provides a really intuitive and handy way of creating routes for requests: basically, all that a developer using Nuxt needs to do is to create request-handling files in a series of sub-directories inside the pages folder. A normally-named folder represents a layer of static request path, and an underscore-prefixed folder represents a layer of dynamic request path, capable of holding variables. This saves developers from the trouble of defining routes explicitly in some form of routing middlewares.

Structuring Content

Then came the catch: to decide where contents should be placed. Nuxt provides three folders for structuring its webpages (“views”), a pages folder, a layouts folder, and a components folder. A structural graph is available to illustrate the relationship between these parts:

It was a little bit confusing to me that layout is actually a super part of page in Nuxt, as I understood layout as a form of theming for pages. However, it still makes sense to have pages wrapped by layouts, similar to how every Activity is rendered inside a Layout in Android.

Here I also noticed a bug which happened to me in development mode only: regardless of inclusion, CSS codes (either direct or built from pre-processing codes) from every file inside the layouts folder was included in the preview of the generated index.html, even though I used the scoped keyword for <style> tags. According to this thread on GitHub, this problem has been present since v1.4.2 of Nuxt.js, and still has not been fixed to date. As it happens, the scoped keyword did help with specifying from which file should styles be retrieved to apply to an element on a page, so apparently, Nuxt was just loading redundant content in development mode. When I looked at the built version, there was no inclusion of styling codes from irrelevant layouts. This is nevertheless a trivial bug that hopefully gets fixed.

Securing Private Key?

I then started looking for best practices to secure my signing credential obtained from Apple’s developer website for generating valid JSON Web Tokens (JWTs) for OAuth purposes. Ideally, this Nuxt app that I was trying to create should only obtain and exposed signed JWTs to its clients, without leaking the original private key in any form. I looked into axios proxies, and Nuxt’s dotenv-module, and several threads (1, 2) suggested that this was not quite possible without a secondary back-end or using DOTENV from the start, that is, outside the scope of Nuxt.

Notice here that I am not talking about a protected api route or protected resources that will be accessible to a user once they are verified, which can be achieved by serverMiddlewares or axios proxies, but an key that should only be available to the server-side (i.e., back-end), similar to SECRET_KEY in Django. Since JWTs are usually short-lived, and best practice suggests that session access tokens be generated as frequently as every usage, I needed a mechanism to spontaneously generate valid signed JWTs on the server-side. The best solution I could come up with was setting up a separate process that binds only to the server’s localhost (or 127.0.0.1), responsible for signing and delivering JWTs for the Nuxt app in the topic. Eventually, this was the practice I decided to implement.

Pros and Cons

I have come to the following incomplete summary of my first impression on Nuxt.js.

Pros of Nuxt.js:

  • Easy and one-step setup
  • Clear structuring of content and routes
  • Server-Side Rendering

Cons of Nuxt.js:

  • A heavily dependent initial setup process
  • Lacking of server-side-access only information storage/management

Epilogue

This exploration narration ends here as the idea of trying out Nuxt was instantaneous (i.e., emerging a day before this article). With the power of Vue under the hood, Nuxt does seem to leverage the scalability and modularization of web application development. It is just more powerful than, meanwhile not as powerful as, what I needed.