All Articles

Getting Started with NodeCG: Parcel Problems

To be completely honest, I havenā€™t been able to do a lot of NodeCG developmentā€¦ and blog-wise, I havenā€™t even started talking about how NodeCG actually works!

But in the few times that Iā€™ve been able to sit down and work, I have learned a few things about Parcel that I think are worth calling out, especially since they seem to mostly impact NodeCG development the most. Especially since I first started talking about setup.

Letā€™s start with the fix, and then explain why itā€™s needed. šŸ˜ŽšŸ‘‰šŸ‘‰

(Oh yeah, and these changes will also be reflected in my example repository)

The Fix

First, we need to install concurrently1.

npm install --save-dev concurrently

concurrently allows us to run multiple commandsā€¦ well, concurrently! Weā€™ll also need to change our scripts stanza of package.json. Previously, it looked like this:

"scripts": {
  "start": "parcel serve './src/**/*.html' --dist-dir=."
},

Weā€™ll want to change it to this:

"scripts": {
  "watch:graphics": "parcel watch 'src/graphics/*.html' --dist-dir='graphics' --public-url='.'",
  "build:graphics": "parcel build 'src/graphics/*.html' --dist-dir='graphics' --public-url='.'"
},

And lastly, instead of running npm start, weā€™ll want to run npx concurrently 'npm:watch*'.

And thatā€™s it! There are likely some changes and tweask youā€™ll want to make if you also have dashboards, and Iā€™ll probably expand on this when I start working on NodeCG extensions, but this should fix a lot of the problems I ran into after actually working in my setup.

Why?

I was really confused when I actually went to work in the previous setup. It worked fine when I had graphics, but not when I also had dashboard pages.

More specifically, when I looked at the source code in the generated HTML, the paths were not as I expected. Instead of something like this:

<script src='my-bundle.js'></script>

I was seeing this:

<script src='graphics/my-bundle.js'></script>

What was the issue then šŸ¤”šŸ’­

This lead me on a long path of learning about Parcel, specifically its plugin system and entrypoints.

When we run parcel serve './src/**/*.html' --dist-dir=., as in the initial example, that tells Parcel two things:

  1. Put the generated ā€œbundlesā€ in the root (.) directory
  2. Specify a ā€˜globā€™ of HTML files as entry points

Globs are sort of like a regular expression for files and file paths. In our case, weā€™re saying ā€œgive me all .html files in any directory under srcā€œ.

Alright, so far so good. But why did it work when there was one folder, but not when there were two folders? Why did different paths get generated in our bundles?

As I dug into the source code, I learned about a subtle behaviour that probably makes sense for other projects, but not for NodeCG.

let entryRoot =
  initialOptions.entryRoot != null
    ? path.resolve(initialOptions.entryRoot)
    : getRootDir(entries);

That snippet is from the code that decides the root path for bundles. As I scanned through the codebase, I eventually discovered that, effectively, only the getRootDir branch is ever reached.

And when digging into that code, I learned that when generating the path for bundles, it will use the root of all the entry points.

Oops šŸ™ƒ

Now, this isnā€™t a secret behaviourā€”Itā€™s technically spelled out in the Module Resolution section of the documentation. But it wasnā€™t really clear to me what was happening until I tried a whole bunch of things. In fact, Parcel has an alternative way to handle targets it just doesnā€™t work with globs yet

What that all means is that if you want to have behaviour where the root path is set to just the folder youā€™re working with, you need to explicitly pass it in:

parcel watch 'src/graphics/*.html' --dist-dir='graphics' --public-url='.'

*sigh* šŸ˜«

Anyway, I figured all this out so you donā€™t have to! I hope this helped out anyone having issues, and maybe even helped to understand Parcel a bit better.

Personally, Iā€™m hoping that I donā€™t encounter anything like this again in future development. It took up a lot of time unexpectedly, and if Iā€™m being honest, if it happens again, youā€™ll probably see a blog post about how to get NodeCG setup with something like Snowpack šŸ¤£


  1. You can also use something like npm-run-all if you want; Concurrently seemed just a bit easier for me to use.ā†©