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 concurrently
1.
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:
- Put the generated ābundlesā in the root (
.
) directory - 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 š¤£
- You can also use something like
npm-run-all
if you want; Concurrently seemed just a bit easier for me to use.ā©