How imports are handled in Pundle

July 09, 2018

This post is a part of the series "An Intro to Pundle".

Imports are a way of sharing bindings between modules. Imports help keep the code modular and maintainable as the size of the codebase grows as well as sharing it with other people trying to solve similar problems (think npmjs).

In Javascript runtimes like V8 (heart of Chrome browser and Node.js) you can import JS files into JS files but you cannot for example import CSS files into JS files. Being able to import CSS into JS would help modularize the code further and help avoid any conflicts on the global css namespace.

Interoperability between asset types as different as JS and CSS (compared to say JS and WASM) requires a lot of decisions that are better done by the bundler instead of runtime. For example, whether to use the contents of the asset or export a path pointing at it because the size of the asset is too big (think 150kb+ of blob, wouldn't make sense in a JS bundle).

While other module bundlers try to hard-code how the bridges work between types in the core, Pundle takes a different approach. Pundle's file resolver allows users to specify completely arbitrary "format"s to use for each extension. Pundle enforces "chunk"s to have the same format throughout so when you import a css file or a golang file or any other non-js format file, It'll be force loaded as js as to allow the transformers to provide "bridge" code.

While providing the bridge code the transformers can add the import as a chunk dependency and return path to it or return it as base64 blob etc. For css this lets us do interesting things like return the css modules object to the requiring module or insert css into a JSON blob that accepts HMR during development.

For example, here's what happens when your import ./index.js imports an ./index.css

  • Resolve ./index.js relative to project root
  • Resolved to project/index.js with format js
  • Process project/index.js as js and scan for imports
  • Resolve ./index.css relative to ./index.js
  • Resolved to project/index.css with format css
  • Process project/index.css as js and scan for imports (notice how we're processing as js)
    • If the file contains with .module before its extension like (.module.css), return its module mapping back to JS
    • If HMR and Development are turned on, put the raw contents as blob to create a style tag to be replaced on HMR later
      • Otherwise add project/index.css with format css as an external dependency of the file

This process depending on your configuration would either embed the css in JS file or add it as an external dependency (while also resolving its imports and adding them as dependencies recursively). This allows Pundle to maintain multiple versions of the same file with different formats. Handling imports like this allows for an unprecedented level of customizable interoperability between different formats.

Profile picture

Written by Anees Iqbal who likes writing code and racing cars. @steelbrain on Github / @realsteelbrain on Twitter / X.

© 2023, all code on this blog is licensed under MIT License. An RSS Feed is available.