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?
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;
},
});