How can I use dynamic Parcel 2 aliases?

18 views Asked by At

Parcel 2 supports glob aliases for simple use cases, but I can't figure out how to use it for global object properties that require some transformation.

For example, in WordPress projects, wp is a global object with many methods like wp.blocks and wp.blockEditor attached to it. I can resolve these with aliases like so in the package.json:

{
    "name": "wp-parcel",
    "version": "1.0.0",
    "description": "Parcel build tool for WordPress",
    "scripts": "...",
    "alias": {
        "@wordpress/blocks": {
            "global": "wp.blocks"
        },
        "@wordpress/block-editor": {
            "global": "wp.blockEditor"
        }
    },
    "devDependencies": {
        "parcel": "^2.9.3"
    }
}

This works great, but there are many more methods (and more may be added later), which will result in a large and growing list in my package.json.

Instead, I'm hoping for a way to dynamically resolve the aliases by converting kebab case to camel case for all @wordpress packages, something like:

{
    "name": "wp-parcel",
    "version": "1.0.0",
    "description": "Parcel build tool for WordPress",
    "scripts": "...",
    "alias": {
        "@wordpress/*": {
            "global": "wp[$1.toLowerCase().replace(/(-\w)/g, m => m.toUpperCase().substr(1))]"
        }
    },
    "devDependencies": {
        "parcel": "^2.9.3"
    }
}

Is there some way to achieve this with Parcel 2?

1

There are 1 answers

0
Tomas Mulder On BEST ANSWER

After some back-and-forth on Parcel's GitHub, here's a solution. Essentially, I needed to create a custom resolver:

In a .parcelrc file:

{
  "extends": [
    "@parcel/config-default"
  ],
  "resolvers": [
    ".parcel-resolvers.mjs",
    "..."
  ]
}

In a .parcel-resolvers.mjs file (or whatever you choose to name it):

import {Resolver} from '@parcel/plugin';
import path from 'path';

export default new Resolver({
  async resolve({ options, specifier }) {
    if (specifier.startsWith('@wordpress') && ! ['@wordpress/icons'].includes(specifier)) {
      const propertyName = specifier
        .substring(11)
        .toLowerCase()
        .replace(/(-\w)/g, (m) => m.toUpperCase().substring(1));
      return {
        filePath: path.join(
          options.projectRoot,
          `wp-${propertyName}.js`
        ),
        code: `module.exports = wp['${propertyName}'];`,
      };
    }
    return null;
  },
});