Pre-evaluate code at build-time

npm install parcel-transformer-preval@0.1.3



Pre-evaluate code at build-time

The problem

You need to do some dynamic stuff, but don’t want to do it at runtime. Or maybe you want to do stuff like read the file system to get a list of files and you can’t do that in the browser.

Table of Contents


As this package will be used during the build process with Parcel, it needs to live in your devDependencies:

npm install --save-dev parcel-transformer-preval
# or
yarn add -D parcel-transformer-preval


Important notes:

  1. This is a Parcel plugin.
  2. All code run by preval is not run in a sandboxed environment.
  3. All code must run synchronously.
  4. Code that is run by preval is not transpiled so it must run natively in the version of node you’re running. (cannot use ES Modules).
  5. All exported values need to be serializable as JSON for better interop between node environment and the runtime.

Parcel config

In your .parcelrc file, you need enable the preval transformer on *.preval.js files (it needs to be the 1st one in the list):

  "extends": "@parcel/config-default",
  "transformers": {
    "*.preval.js": ["parcel-transformer-preval", "..."]

And now, you’re ready to use it.

Simple example

Every file imported that ends in .preval.js will be evaluated by Parcel at build time:

// file.preval.js
module.exports = 1 + 3;
// other-file.js
import result from "./file.preval.js";

//      ↓ ↓ ↓ ↓ ↓ ↓

// other-file.js
const result = 4;


As mentioned in the important notes, preval uses JSON serialization. So it can only handle:

  • numbers
  • strings
  • arrays
  • simple objects

But not:

  • sets
  • maps
  • functions
  • classes
  • in general complex “objects”
// Not supported
module.exports = new Set();
module.exports = new Map();
module.exports = new Date();
module.exports = class A {};
module.exports = () => {};
module.exports = function () {};

How is this different from babel-plugin-preval?

This plugin is heavily inspired by babel-plugin-preval. We could even say that this plugin is a port of the babel plugin for Parcel with a few differences:

This plugin doesn’t support:

  • template tags: preval`module.exports = …`;
  • import comments: import x from /* preval */ './something'
  • preval.requires: preval.require('./something')
  • preval file comments: // @preval
  • exporting a function.

The reason behind the first 4 differences is: when using preval in bigger projects, we wanted to easily understand in which environment each file/line of code would run. And so we decided to only be able to run preval on whole files, based on their filename (the env is collocated with the file itself in its name, instead of being set in another file's imports).

So instead of having to tell mention from another file that the file we’re importing needs to be prevaled (the import comments and preval.require), we found that the file name was a better indicator to reviewers. As the transformer is now only based on the file name, there is no need for @preval comments.

Only using the file name allows you to be able to easily configure:

  • ESLint
  • TypeScript
  • Parcel
  • and others