Skip to content

Commit df7cd17

Browse files
committed
fix: use transform-tagged-template-literal plugin explicitly (#609)
1 parent 8abb51d commit df7cd17

File tree

12 files changed

+94
-49
lines changed

12 files changed

+94
-49
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
9696
"@babel/plugin-transform-modules-commonjs": "^7.9.0",
9797
"@babel/plugin-transform-runtime": "^7.9.0",
98+
"@babel/plugin-transform-template-literals": "^7.8.3",
9899
"@babel/register": "^7.9.0",
99100
"@babel/template": "^7.8.6",
100101
"@babel/traverse": "^7.9.0",
@@ -138,4 +139,4 @@
138139
"<rootDir>/jest/resolveTypescript.js"
139140
]
140141
}
141-
}
142+
}

src/__tests__/__snapshots__/preval.test.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ CSS:
525525
;
526526
}
527527
528-
Dependencies: @babel/runtime/helpers/interopRequireDefault, @babel/runtime/helpers/taggedTemplateLiteralLoose
528+
Dependencies: @babel/runtime/helpers/interopRequireDefault, @babel/runtime/helpers/taggedTemplateLiteral
529529
530530
`;
531531

src/babel/evaluators/buildOptions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* This file handles preparing babel config for Linaria babel plugin.
2+
* This file handles preparing babel config for Linaria preevaluation.
33
*/
44

55
import { PluginItem, TransformOptions } from '@babel/core';

src/babel/evaluators/extractor/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ const extractor: Evaluator = (filename, options, text, only = null) => {
5151
{ useESModules: false },
5252
]);
5353

54+
// We made a mistake somewhen, and linaria preval was dependent on `plugin-transform-template-literals`
55+
// Usually it was loaded into preval, because user was using `@babel/preset-env` preset which included that plugin. Internally we used this preset for tests (and previously for everything) - thats why we implemented behavior based on existing of that plugin
56+
// The ordering is very important here, that's why it is added as a preset, not just as a plugin. It makes this plugin run *AFTER* linaria preset, which is required to make have the current behavior.
57+
// In preval we have 2 visitors, one for Call Expressions and second for TaggedTemplateLiterals. Babel process TaggedTemplates first for some reason, and we grab only the css`` statements, we skip styled statements at this stage.
58+
// Then it process TaggedTemplateLiterals with mentioned plugin, which transforms them to CallExpressions (babel seems to apply thw whole set of plugins for particular visitor, then for the next visitor and so on).
59+
// Then Linaria can identify all `styled` as call expressions, including `styled.h1`, `styled.p` and others.
60+
61+
// Presets ordering is from last to first, so we add the plugin at the beginning of the list, which persist the order that was established with formerly used `@babel/preset-env`.
62+
63+
transformOptions.presets!.unshift({
64+
plugins: ['@babel/plugin-transform-template-literals'],
65+
});
5466
// Expressions will be extracted only for __linariaPreval.
5567
// In all other cases a code will be returned as is.
5668
let { code } = transformSync(text, transformOptions)!;

src/babel/evaluators/preeval.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
import { NodePath } from '@babel/traverse';
66
import { types } from '@babel/core';
77
import GenerateClassNames from '../visitors/GenerateClassNames';
8-
import JSXElement from '../visitors/JSXElement';
9-
import CallExpression from '../visitors/CallExpression';
8+
import DetectStyledImportName from '../visitors/DetectStyledImportName';
9+
import JSXElement from './visitors/JSXElement';
10+
import ProcessStyled from './visitors/ProcessStyled';
11+
import ProcessCSS from './visitors/ProcessCSS';
1012
import { State, StrictOptions } from '../types';
11-
import CSSTemplateExpression from '../visitors/CSSTemplateExpression';
12-
import ImportDeclaration from '../visitors/ImportDeclaration';
1313

1414
function preeval(_babel: any, options: StrictOptions) {
1515
return {
@@ -26,16 +26,15 @@ function preeval(_babel: any, options: StrictOptions) {
2626
// We need our transforms to run before anything else
2727
// So we traverse here instead of a in a visitor
2828
path.traverse({
29-
ImportDeclaration: p => ImportDeclaration(p, state),
29+
ImportDeclaration: p => DetectStyledImportName(p, state),
3030
TaggedTemplateExpression: p =>
3131
GenerateClassNames(p, state, options),
32-
3332
JSXElement,
3433
});
3534
},
3635
},
37-
CallExpression,
38-
TaggedTemplateExpression: CSSTemplateExpression,
36+
CallExpression: ProcessStyled,
37+
TaggedTemplateExpression: ProcessCSS, // TaggedTemplateExpression is processed before CallExpression
3938
},
4039
};
4140
}

src/babel/evaluators/shaker/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ function prepareForShake(
1515
transformOptions.ast = true;
1616
transformOptions.presets!.unshift([
1717
'@babel/preset-env',
18-
{ targets: 'ie 11' },
18+
{
19+
targets: 'ie 11',
20+
// we need this plugin so we list it explicitly, explanation in `evaluators/extractor/index`
21+
include: ['@babel/plugin-transform-template-literals'],
22+
},
1923
]);
2024
transformOptions.presets!.unshift([require.resolve('../preeval'), options]);
2125
transformOptions.plugins!.unshift('transform-react-remove-prop-types');
File renamed without changes.

src/babel/visitors/CSSTemplateExpression.ts renamed to src/babel/evaluators/visitors/ProcessCSS.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
/**
2+
* This visitor replaces css tag with the generated className
3+
*
4+
*/
5+
16
import { NodePath } from '@babel/traverse';
27
import { types as t } from '@babel/core';
3-
import getLinariaComment from '../utils/getLinariaComment';
8+
import getLinariaComment from '../../utils/getLinariaComment';
49

5-
export default function CSSTemplateExpression(
6-
path: NodePath<t.TaggedTemplateExpression>
7-
) {
10+
export default function ProcessCSS(path: NodePath<t.TaggedTemplateExpression>) {
811
if (t.isIdentifier(path.node.tag) && path.node.tag.name === 'css') {
912
const [, , className] = getLinariaComment(path);
1013
if (!className) {

src/babel/visitors/CallExpression.ts renamed to src/babel/evaluators/visitors/ProcessStyled.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1+
/**
2+
* This visitor replaces styled components with metadata about them.
3+
* CallExpression should be used to match styled components.
4+
* Works out of the box for styled that wraps other component,
5+
* styled.tagName are transformed to call expressions using @babel/plugin-transform-template-literals
6+
* @babel/plugin-transform-template-literals is loaded as a prest, to force proper ordering. It has to run just after linaria.
7+
* It is used explicitly in extractor, and loaded as a part of `prest-env` in shaker
8+
*/
9+
110
import { NodePath } from '@babel/traverse';
211
import { types } from '@babel/core';
3-
import getLinariaComment from '../utils/getLinariaComment';
12+
import getLinariaComment from '../../utils/getLinariaComment';
413
import { expression } from '@babel/template';
514

615
const linariaComponentTpl = expression(
@@ -13,7 +22,7 @@ const linariaComponentTpl = expression(
1322
}`
1423
);
1524

16-
export default function CallExpression(path: NodePath<types.CallExpression>) {
25+
export default function ProcessStyled(path: NodePath<types.CallExpression>) {
1726
const [, displayName, className] = getLinariaComment(path);
1827
if (!className) {
1928
return;

src/babel/extract.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ import {
2626
ValueCache,
2727
} from './types';
2828
import CollectDependencies from './visitors/CollectDependencies';
29-
import ImportDeclaration from './visitors/ImportDeclaration';
30-
import { debug } from './utils/logger';
29+
import DetectStyledImportName from './visitors/DetectStyledImportName';
3130
import GenerateClassNames from './visitors/GenerateClassNames';
31+
import { debug } from './utils/logger';
3232

3333
function isLazyValue(v: ExpressionValue): v is LazyValue {
3434
return v.kind === ValueType.LAZY;
@@ -113,7 +113,7 @@ export default function extract(_babel: any, options: StrictOptions) {
113113
// We need our transforms to run before anything else
114114
// So we traverse here instead of a in a visitor
115115
path.traverse({
116-
ImportDeclaration: p => ImportDeclaration(p, state),
116+
ImportDeclaration: p => DetectStyledImportName(p, state),
117117
TaggedTemplateExpression: p => {
118118
GenerateClassNames(p, state, options);
119119
CollectDependencies(p, state, options);
@@ -186,13 +186,11 @@ export default function extract(_babel: any, options: StrictOptions) {
186186
},
187187
exit(_: any, state: State) {
188188
if (Object.keys(state.rules).length) {
189-
// Store the result as the file metadata
190-
state.file.metadata = {
191-
linaria: {
192-
rules: state.rules,
193-
replacements: state.replacements,
194-
dependencies: state.dependencies,
195-
},
189+
// Store the result as the file metadata under linaria key
190+
state.file.metadata.linaria = {
191+
rules: state.rules,
192+
replacements: state.replacements,
193+
dependencies: state.dependencies,
196194
};
197195
}
198196

0 commit comments

Comments
 (0)