Update #2: smooch adventures?!Since I am writing adequate commit messages, I will use my git history to see what wacky stuff I've been up to!
W1. Normalized paths in console outputI thought it would be a cool idea to rewrite paths printed to the console so that they are relative to the current working directory. Since paths are different on Windows and Unix machines (Windows uses \ instead of /), my logging abstraction also normalizes this. These changes mean that my naive automated tests can check that particular paths are being correctly output! I also think it improves the readability of the logs, which is somewhat of a priority for this project.
Here's a sample:
NativeDependencies Checking that native dependencies are installed to .smooch/native-deps
NativeDependencies Native dependencies appear to be installed.
Ffmpeg Set Ffmpeg path to .smooch/native-deps/node_modules/@ffmpeg-installer/win32-x64/ffmpeg.exe
SmoochJsonWatcher Started
FsWatcher Started with subscriptions: audiCnv
FsWatcher Ignored Message #0 (Catch-up) <no events>
W2. Converting audio filesThe previous incarnation of smooch used
sox to convert audio files. This required the user to install a native dependency before running the tool. You also had to make sure that you installed the liblame thing for mp3 or whatever. It got annoying!
Apparently there are some packages on npm that seemingly abuse the "optionalDependencies" property in package.json. Examples:
https://github.com/kribblo/node-ffmpeg-installer/blob/master/package.json ,
https://github.com/parcel-bundler/watcher/blob/69f3099f009330d53abdb0e7d53e9f9204af04b3/scripts/build-npm.js (this code generates a package.json!)
They use this property to install binary packages that are installable on the user's architecture. I searched for a package like this for sox, but I couldn't find one. So I used the
@ffmpeg-installer/ffmpeg library. So, smooch now uses ffmpeg to convert audio files. I implemented this and it seems to work fine! Cool!
W3. Type hints in template programsA core component of smooch is the ability to get metadata about transformed assets and apply the metadata to a template program to generate a code file. Special context is exposed to the code file, and it's not always intuitive how to use that context without types. VS Code supports loading .d.ts (TypeScript declaration) files from within JavaScript files (our template programs are plain JavaScript files) using JSDoc. I love using TypeScript in clever ways, and don't like doing lots of manual work. So, I found a tool to generate a single .d.ts file from some types (for some reason this feature is not built into TypeScript)!! The result is some example template programs with types embedded using JSDoc!:
https://github.com/hubol/smooch/blob/973ade74ca20f731e7a44a1e9da2492b8704ee97/dist/templates/audio-convert.jsW4. Zip archiving of audio filesI got to implement this and it's looking good! At first I was exploring the possibility of keeping a cached zip file and only adding newly converted audio files to it. But on my machine it takes only ~200ms to zip the entirety of IguaRPG's sound files to a new zip file.
W5. Library bugs, version conflicts, native dependencies...I ran into an issue with one of the libraries I'm using, @parcel/watcher. I observed that when upgrading to version 2.3.0, it was possible for one of the functions exposed to me to hang infinitely. I did some digging and found this commit:
https://github.com/parcel-bundler/watcher/commit/9b7c657df8ad1c0d020541eae0dd38b921c94fb8 ...And if I upgrade to that particular version, I also experience the hanging. I tried to create a small repro so that I could report an issue, but to no avail. I am guessing they introduced a deadlock, but I have no idea how to read and/or debug C++.
@parcel/watcher is supposed to provide performant file system events. The library is even used by VS Code! I would like to use it in this project. But, I don't think it's a good idea for smooch to require a
specific version of the library...
Imagine we have this package.json in our IguaRPG 2 project:
{
...
"devDependencies": {
"smooch": "^1.0.0",
"parcel": "^9.0.0",
}
}
Both packages depend on @parcel/watcher. smooch requires a specific version 2.2.0 due to the aforementioned bug, but parcel might need something higher than that. npm will be unable to resolve this conflict!
This would be no issue if @parcel/watcher had no native dependencies. I could simply pack all of its JavaScript code into my smooch bundle, and there are now no worries about conflicting dependencies.
But because of the native dependencies, I have two choices:
1. Download specific versions of their binaries for all supported platforms, and include them in my repository and require them from my bundle
2. Install the native dependencies using npm at runtime, and place them in a special folder that only smooch is aware of
I went with 2, even though I'm pretty sure it's unorthodox AF. It actually required surprisingly little code:
https://github.com/hubol/smooch/blob/f663e32a20f9d0e7486e1150051b449f4001a462/lib/common/native/native-dependency.tsThe NativeDependencies class exposes isInstalled, install, and require methods. And I think they look pretty nice! I also did some crazy shit so that the correct API of the package is returned from the require method (-:
But yeah, now these dependencies are installed to a separate package at runtime, ensuring that the desired version is installed with the correct native dependency! I'm glad that I was able to accomplish this with very little code and by leveraging shit that already exists!