linaria icon indicating copy to clipboard operation
linaria copied to clipboard

CSS not generated inside `var a = function a() {...}`

Open yume-chan opened this issue 2 years ago • 2 comments

Environment

  • Linaria version: 4.5.4
  • Bundler (+ version): Vite 4.4.7, Webpack 5.75.0
  • Node.js version: v18.17.0
  • OS: Windows

Description

a.js:

import {css} from '@linaria/atomic'

export const a = function a() {
    return css`
        background-color: red;
    `
}

b.js:

import { a } from "./a";

export default function App() {
  return <div className={a()}>Hello World!</div>;
}

css template string in a() will be replaced with names, but the CSS rules won't be generated.

https://github.com/callstack/linaria/blob/79557248f51f21663729add3a0564a830d8d4c87/packages/babel/src/utils/getTagProcessor.ts#L394-L421

parent is the const a node, but path.scope.getBinding(id.node.name) returns the function a() node. function a() node has no references so CSS extraction was skipped.

This code is simplified from an output of Solid.js babel plugin, so it can't change.

Reproducible Demo

https://codesandbox.io/p/sandbox/interesting-brook-vn8dgp

yume-chan avatar Aug 02 '23 09:08 yume-chan

The actual code given to Linaria is:

Expand
import { template as _$template } from "solid-js/web";
import { className as _$className } from "solid-js/web";
import { getNextMarker as _$getNextMarker } from "solid-js/web";
import { createComponent as _$createComponent } from "solid-js/web";
import { getNextElement as _$getNextElement } from "solid-js/web";
import { insert as _$insert } from "solid-js/web";
import { effect as _$effect } from "solid-js/web";
import { setAttribute as _$setAttribute } from "solid-js/web";
import { $$component as _$$component } from "solid-refresh";
import { $$refresh as _$$refresh } from "solid-refresh";
import { $$registry as _$$registry } from "solid-refresh";
const _REGISTRY = _$$registry();
const _tmpl$ = /*#__PURE__*/_$template(`<option disabled hidden selected>`),
  _tmpl$2 = /*#__PURE__*/_$template(`<label><!#><!/><div><select><!#><!/><!#><!/></select><!#><!/>`);
import { css, cx } from "@linaria/atomic";
import { Show, createUniqueId } from "solid-js";
import { rem, theme } from "~/utils/theme";
import { AddClassList, FluentChevronDown16Regular } from "./icons";
export const Select = _$$component(_REGISTRY, "Select", function Select(props) {
  const id = createUniqueId();
  return (() => {
    const _el$ = _$getNextElement(_tmpl$2),
      _el$11 = _el$.firstChild,
      [_el$12, _co$4] = _$getNextMarker(_el$11.nextSibling),
      _el$2 = _el$12.nextSibling,
      _el$3 = _el$2.firstChild,
      _el$5 = _el$3.firstChild,
      [_el$6, _co$] = _$getNextMarker(_el$5.nextSibling),
      _el$7 = _el$6.nextSibling,
      [_el$8, _co$2] = _$getNextMarker(_el$7.nextSibling),
      _el$9 = _el$3.nextSibling,
      [_el$10, _co$3] = _$getNextMarker(_el$9.nextSibling);
    _$setAttribute(_el$, "for", id);
    _$insert(_el$, () => props.label, _el$12, _co$4);
    _el$3.addEventListener("change", e => props.onChange(e.currentTarget.value));
    _$setAttribute(_el$3, "id", id);
    _$insert(_el$3, _$createComponent(Show, {
      get when() {
        return props.placeholder;
      },
      get children() {
        const _el$4 = _$getNextElement(_tmpl$);
        _$insert(_el$4, () => props.placeholder);
        return _el$4;
      }
    }), _el$6, _co$);
    _$insert(_el$3, _$createComponent(AddClassList, {
      get ["class"]() {
        return css`
              background-color: var(${theme.background});
              color: var(${theme.foreground});
            `;
      },
      get children() {
        return props.children;
      }
    }), _el$8, _co$2);
    _$insert(_el$2, _$createComponent(FluentChevronDown16Regular, {
      get ["class"]() {
        return css`
            position: absolute;
            top: 50%;
            right: ${rem(8)};
            transform: translateY(-50%);
            font-size: ${rem(16)};
            pointer-events: none;
          `;
      }
    }), _el$10, _co$3);
    _$effect(_p$ => {
      const _v$ = cx(css`
          color: var(${theme.foreground});
        `, props.class),
        _v$2 = css`
          position: relative;
          margin-top: ${rem(8)};
        `,
        _v$3 = css`
            appearance: none;
            display: block;
            width: 100%;
            height: ${rem(40)};
            background-color: transparent;
            border-width: 1px;
            border-style: solid;
            border-color: var(${theme.foreground3});
            padding-left: ${rem(12)};
            padding-right: ${rem(12)};
            color: inherit;
            border-radius: 5px;
          `;
      _v$ !== _p$._v$ && _$className(_el$, _p$._v$ = _v$);
      _v$2 !== _p$._v$2 && _$className(_el$2, _p$._v$2 = _v$2);
      _v$3 !== _p$._v$3 && _$className(_el$3, _p$._v$3 = _v$3);
      return _p$;
    }, {
      _v$: undefined,
      _v$2: undefined,
      _v$3: undefined
    });
    _$effect(() => _el$3.value = props.value);
    return _el$;
  })();
}, {
  location: "src\\components\\select.tsx:15:7"
});
if (import.meta.hot) {
  _$$refresh("vite", import.meta.hot, _REGISTRY);
  import.meta.hot.accept();
}

Two styles in get ["class"]() functions are not extracted. Styles in _$effect function are extracted correctly.

I can't share the whole project.

yume-chan avatar Aug 02 '23 09:08 yume-chan

This issue is still reproducible with Linaria v5 (@linaria/[email protected]).

Updated demo: https://codesandbox.io/p/sandbox/elastic-water-4wwgmy

yume-chan avatar Sep 28 '23 07:09 yume-chan