Duplicate babel presets called from Shaker?
Environment
- Linaria version: 3.0.0.beta.1
Description
I have noticed that the shaker strategy loads two similar babel presets when evaluating dependencies which results in the babel plugin being loaded and executed twice for each dependency file. While the output is fine it seems this is redundant it may increase processing length but I am still learning linaria so may not have understood why both presets are required.
The root of the shaker file first calls loadBuildOptions which adds the main babel preset.
Then it calls the prepare for shake function which pre-pends the @linaria/preeval preset which adds a few (but not all) visitors from babel plugin (DetectStyledImportName and GenerateClassNames).
Is it necessary to run both presets for every dependency inside the template strings? Can we limit to the preeval preset only?
Reproducible Demo
https://github.com/callstack/linaria/blob/master/packages/babel/src/evaluators/buildOptions.ts#L29
https://github.com/callstack/linaria/blob/master/packages/shaker/src/index.ts#L26
The babel configuration in shaker is also causing me error of Duplicate plugin/preset detected. if I supply babelOptions. I used to supply all my babel options there.
Now I see that preset-env and transform-runtime are duplicated by shaker.
I'm still trying to find a way to avoid that excess transformation stage. Hopefully, I will fix it in 3.0.
For the time being i started using a custom evaluator which basically is a stripped down version of shaker/index.js:
const { transformSync } = require('@babel/core');
const generator = require('@babel/generator').default;
const { buildOptions } = require('@linaria/babel-preset');
const shake = require('@linaria/shaker/lib/shaker').default;
function prepareForShake(filename, options, code) {
const transformOptions = buildOptions(filename, options);
transformOptions.ast = true;
transformOptions.presets.unshift([
require.resolve('@linaria/preeval'),
options,
]);
const transformed = transformSync(code, transformOptions);
if (transformed === null || !transformed.ast) {
throw new Error(`${filename} cannot be transformed`);
}
return transformed.ast.program;
}
const shaker = (filename, options, text, only = null) => {
const [shaken, imports] = shake(
prepareForShake(filename, options, text),
only
);
const { code: shakenCode } = generator(shaken);
return [shakenCode, imports];
};
module.exports = shaker;
And i configurate linaria with:
{
babelOptions: ... my own babel options that already include preset-env and runtime transform,
rules: [{ action: mycustomshakercopy }],
}
It will properly work only if your babel is already targeted IE11 or you keep your styles pretty simple. Otherwise, shaker cannot build a proper dependency tree and can strip some critical code.
Anyway, I have a feeling, that it's possible to completely avoid that prepareForShake. I just need some more time :)
@Anber awesome to hear that! And yes, I'm already targetting IE11.
Anyway, much ❤️ for linaria!
I'm also getting this same error when trying to use props in styled tags. @antitoxic do you happen to have a repo link for your fix? I'm a little lost regarding which code goes in which file 😅