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 page
s. However, it still makes sense to have page
s wrapped by layout
s, 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 (JWT
s) for OAuth purposes. Ideally, this Nuxt app that I was trying to create should only obtain and exposed signed JWT
s 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 serverMiddleware
s 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 JWT
s 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 JWT
s 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 JWT
s 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.