tooling.report

feature

Custom type

Import custom file types from JavaScript

Person in shorts with blue hair walking left

Introduction

Many applications rely on custom data types, from serialization schemes like protobuf to vendor file formats like MIDI. For many of the same reasons it's useful to allow importing other non-JavaScript resources, the ability to import custom file types as dependences allows them to be integrated into the build process. One key component of this technique is the ability to transform files at build time to "wrap" them in a specific interface.

The Test

This test tries to demonstrate the most intuitive or idiomatic means of importing a file as a custom type, which differs between each tool. For the purposes of the test, "custom type" is assumed to be some representation of a file for which there is no existing plugin or configuration available. Handling the import generally requires writing a plugin or configuration, so the result of this test takes into account how difficult it would be for a developer to write such a plugin.

import customType from 'custom-type:./binary.bin';
console.log(customType); // an instance of CustomType

The implementation details of how customType is produced differs between each test, but the result should be the same. The imported customType value must be an instance of CustomType class, which has a buffer property containing the binary data of binary.bin.

Conclusion

browserify

Browserify has a static-module plugin that lets you replace values and function calls with arbitrary script at build time. Browserify will also bundle any require calls in this replacement, so you can import helper functions once, even if they're used in multiple places.

parcel

Parcel fails on importing unknown file extension, lamenting the lack of a “transformer”. There is a plugin infrastructure for Parcel 2 that lets me write my own transformers, but at the time of writing, the documentation doesn’t really tell me how.

Issues

rollup

Rollup's plugin system is well documented. In this case, a module was generated that exports the file as a base64 string, wrapped in a function that converts base64 to an array buffer, wrapped in a custom class.

The function that does the conversion and the custom class are in a virtual module, so it isn't duplicated, and can be code-split.

webpack

Although the same approach could be taken here as in the binary test, in this case we'll write a custom loader since we want to tailor the output. The binary data passed to our loader is converted to a Base64 string to be inlined into a generated module. In the generated module, the Base64 string is passed through a function that converts it back to binary, then passed to our CustomType constructor and exported. The helper function and CustomType class are imported from a file on disk, enabling them to be inlined or deduped like any other module.