babel-plugin-optimize-objstr
v1.0.0
Published
Babel plugin to optimize `obj-str` calls.
Downloads
622
Maintainers
Readme
babel-plugin-optimize-obj-str
Babel plugin to optimize
obj-str
calls by replacing them with an equivalent unrolled expression.
Even though the obj-str
function is negligible in size over-the-wire, the motivation for this plugin is that transformed expressions execute almost twice as fast as equivalent calls.
import objstr from 'obj-str';
objstr({
'my-classname': true,
'another-one': maybe,
'third': a && b,
});
// Transformed:
'my-classname' + (maybe ? ' another-one' : '') + (a && b ? ' third' : '');
Install
npm install --save-dev babel-plugin-optimize-obj-str
Usage
Via babel.config.js (recommended):
// babel.config.js
module.exports = {
plugins: ['optimize-obj-str'],
};
Via CLI:
babel --plugins optimize-obj-str script.js
Options
// babel.config.js
module.exports = {
plugins: [
['optimize-obj-str', {
strict: false,
}],
],
};
options.strict
Type: boolean
Default: false
Allow Babel to throw errors when encountering obj-str
calls that cannot be optimized.
We can only optimize function calls whose single argument is an object literal containing only keyed properties.
objstr({
'optimizable': true,
[classes.myClass]: maybe,
});
// Transformed:
'optimizable' + (maybe ? ' ' + classes.myClass : '');
By default, calls that cannot be optimized are preserved.
objstr({ optimizable: true });
objstr(cannotOptimizeIdentifierArg);
objstr({ ...cannotOptimizeSpread });
// Transformed:
('optimizable');
objstr(cannotOptimizeIdentifierArg);
objstr({ ...cannotOptimizeSpread });
Preserved calls force the resulting bundle to contain the objstr()
function, which could otherwise be dead-code-eliminated.
Instead, when setting the option { strict: true }
the plugin errors out to prevent this.
Caveats
Performance
The purpose of this transform is to improve execution performance. This benchmark results in a ~1.8x speedup on desktop Chrome (88) (obj-str
calls are about 45% slower).
You should not expect this transform should to reduce bundle size. Depending on the amount of object properties and plugin configuration, it might actually output slightly larger code. A rough estimate is that using less than ~100 different conditional properties should not increase the size of a bundle.
Leading Space
Direct results from objstr()
always omit a leading space. This is not the case when using this transform:
objstr({
a: false,
foo: true
});
// transformed:
(' foo');
You must ensure that your expression consumers ignore this leading space. A classname should work just fine.
Inconsistent Duplicates
Object literals may contain duplicate property names, in which case the lastly defined value is preserved.
objstr({
dupe: one,
dupe: two
});
// Transformed:
'' + (two ? 'dupe' : '');
The example above is transformed properly since the duplicate property names are literal and constant. The plugin does its best to override duplicates by comparing property name expressions, but it's unable to compare equal computed results whose expressions vary:
objstr({
good: one,
'good': two,
['good']: three,
});
objstr({
bad: one,
'bad': two,
['ba' + 'd']: three,
});
// Transformed:
'' + (three ? 'good' : '');
'' + (two ? 'bad' : '') + (three ? ' bad' : '');
It's therefore recommended to reserve the use of computed property names for identifiers to unique values, and to avoid complex expressions. This reduces the likelihood of mismatched dupes.
// These computed names are likely ok:
objstr({ [FOO]: true });
objstr({ [myConstants.BAR]: true });
// More complex computed names are at a higher risk of duping:
objstr({
[FOO + 'bar']: true,
[FOO + possiblyBar]: false,
});
License
MIT