plugins icon indicating copy to clipboard operation
plugins copied to clipboard

Emotion css prop using object styles produces no sourceMaps

Open soconnor-affinity opened this issue 2 years ago • 7 comments

The Emotion swc plugin doesn't produce a sourceMappingURL comment when using the css prop with the object styles syntax.

I found existing tests for the Emotion plugin that handle the css prop w/ the css JS template literal syntax I could not find any tests for the css prop w/ object styles.

Examples

Creates sourceMappingURL

<div css={css`color: red`}>Hello</div>

Missing sourceMappingURL

<div css={{ color: 'red' }}>Hello</div>

soconnor-affinity avatar Mar 19 '23 21:03 soconnor-affinity

Are you still finding this to be the case?

When transpiling:

import { css } from "@emotion/react";
import { PureComponent } from "react";

export class SimpleComponent extends PureComponent {
  render() {
    return (
      <div
        css={css`
          color: red;
        `}
      >
        Hello
      </div>
    );
  }
}

swc emits:

import { jsx as _jsx } from "react/jsx-runtime";
import { css } from "@emotion/react";
import { PureComponent } from "react";
export class SimpleComponent extends PureComponent {
    render() {
        return /*#__PURE__*/ _jsx("div", {
            css: /*#__PURE__*/ css("color:red;", "SimpleComponent", "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3JjL2luZGV4LnRzeCIsInNvdXJjZXMiOlsic3JjL2luZGV4LnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjc3MgfSBmcm9tIFwiQGVtb3Rpb24vcmVhY3RcIjtcbmltcG9ydCB7IFB1cmVDb21wb25lbnQgfSBmcm9tIFwicmVhY3RcIjtcblxuZXhwb3J0IGNsYXNzIFNpbXBsZUNvbXBvbmVudCBleHRlbmRzIFB1cmVDb21wb25lbnQge1xuICByZW5kZXIoKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIDxkaXZcbiAgICAgICAgY3NzPXtjc3NgXG4gICAgICAgICAgY29sb3I6IHJlZDtcbiAgICAgICAgYH1cbiAgICAgID5cbiAgICAgICAgSGVsbG9cbiAgICAgIDwvZGl2PlxuICAgICk7XG4gIH1cbn1cbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFPYSJ9 */"),
            children: "Hello"
        });
    }
}

Which contains the sourceMappingURL 🤔

Codex- avatar Jan 12 '24 22:01 Codex-

Your example uses the css JS template literal syntax — which does produce the sourceMappingURL. The bug is that this syntax didn't:

import { css } from "@emotion/react";
import { PureComponent } from "react";

export class SimpleComponent extends PureComponent {
  render() {
    return (
      <div css={{ color: 'red' }}>
        Hello
      </div>
    );
  }
}

I haven't checked if this is fixed in a recent release.

soconnor-affinity avatar Jan 12 '24 23:01 soconnor-affinity

Ah I see what you're saying, my apologies.

~~This this usage of the CSS prop we also get sourceMappingURL~~ caching got me

This is indeed still an issue:

import { jsx as _jsx } from "react/jsx-runtime";
import { PureComponent } from "react";
export class SimpleComponent extends PureComponent {
    render() {
        return /*#__PURE__*/ _jsx("div", {
            css: {
                color: "red"
            },
            children: "Hello"
        });
    }
}

Codex- avatar Jan 12 '24 23:01 Codex-

Did some further digging into why this is the case, it's because the swc emotion plugin doesn't currently implement cssPropOptimization which is enabled by default with @emotion/babel-plugin

Using this babel cfg:

...
[
  "@emotion",
  {
    autoLabel: "always",
    cssPropOptimization: false
  },
],
...

We get:

import { PureComponent } from "react";
import { jsx as _jsx } from "react/jsx-runtime";
export class SimpleComponent extends PureComponent {
  render() {
    return /*#__PURE__*/_jsx("div", {
      css: {
        color: "red"
      },
      children: "Hello"
    });
  }
}

With the option set to true, or removed, we get:

function _EMOTION_STRINGIFIED_CSS_ERROR__() { return "You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."; }
import { PureComponent } from "react";
import { jsx as _jsx } from "react/jsx-runtime";
var _ref = process.env.NODE_ENV === "production" ? {
  name: "72n1bk-SimpleComponent",
  styles: "color:red;label:SimpleComponent;"
} : {
  name: "72n1bk-SimpleComponent",
  styles: "color:red;label:SimpleComponent;",
  map: "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9pbmRleC50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBS2dCIiwiZmlsZSI6Ii4uLy4uL3NyYy9pbmRleC50c3giLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjc3MgfSBmcm9tIFwiQGVtb3Rpb24vcmVhY3RcIjtcbmltcG9ydCB7IFB1cmVDb21wb25lbnQgfSBmcm9tIFwicmVhY3RcIjtcblxuZXhwb3J0IGNsYXNzIFNpbXBsZUNvbXBvbmVudCBleHRlbmRzIFB1cmVDb21wb25lbnQge1xuICByZW5kZXIoKSB7XG4gICAgcmV0dXJuIDxkaXYgY3NzPXt7IGNvbG9yOiBcInJlZFwiIH19PkhlbGxvPC9kaXY+O1xuICB9XG59XG4iXX0= */",
  toString: _EMOTION_STRINGIFIED_CSS_ERROR__
};
export class SimpleComponent extends PureComponent {
  render() {
    return /*#__PURE__*/_jsx("div", {
      css: _ref,
      children: "Hello"
    });
  }
}

So the real request is here a feature request to implement cssPropOptimization which would be great.

We'd need to extend the behaviour of how we handle fold_jsx_element to handle the prop similarly to here

Codex- avatar Jan 13 '24 02:01 Codex-

I did a little proof of concept implementing this feature and got the following output:

export class SimpleComponent extends PureComponent {
  render() {
    return /*#__PURE__*/ _jsx("div", {
      css: /*#__PURE__*/ css(
        {
          color: "red",
        },
        "label:SimpleComponent",
        "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5wdXQudHMiLCJzb3VyY2VzIjpbImlucHV0LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNzcyB9IGZyb20gXCJAZW1vdGlvbi9yZWFjdFwiO1xuaW1wb3J0IHsgUHVyZUNvbXBvbmVudCB9IGZyb20gXCJyZWFjdFwiO1xuXG5leHBvcnQgY2xhc3MgU2ltcGxlQ29tcG9uZW50IGV4dGVuZHMgUHVyZUNvbXBvbmVudCB7XG4gIHJlbmRlcigpIHtcbiAgICByZXR1cm4gPGRpdiBjc3M9e3sgY29sb3I6IFwicmVkXCIgfX0+SGVsbG88L2Rpdj47XG4gIH1cbn1cbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFLcUIifQ== */"
      ),
      children: "Hello",
    });
  }
}

This seems to be more inline with what you're expecting, is that right?

There are a few remaining issues to work through with my approach though, as it leverages having css imported from emotion, meaning cases where this is not imported would need to have this import added which feels a bit meh

Codex- avatar Jan 15 '24 02:01 Codex-

This seems to be more inline with what you're expecting, is that right?

Yes it looks correct AFAICT.

In the output you pasted above I saw that it also uses / imports css():

import { jsx as _jsx } from "react/jsx-runtime";
import { css } from "@emotion/react";
import { PureComponent } from "react";
export class SimpleComponent extends PureComponent {
    render() {
        return /*#__PURE__*/ _jsx("div", {
            css: /*#__PURE__*/ css("color:red;", "SimpleComponent", "/*# sourceMappingURL=[snip] */"),
            children: "Hello"
        });
    }
}

There are a few remaining issues to work through with my approach though, as it leverages having css imported from emotion, meaning cases where this is not imported would need to have this import added which feels a bit meh

Is this a unique problem for css={{ color: "red" }}?

soconnor-affinity avatar Jan 15 '24 15:01 soconnor-affinity

Yeah importing css is the wrong behaviour here, from what I can tell its expected that you're using emotion jsx and the prop object is tranformed similarly though so it's progress and I'll look into it more when I can

Codex- avatar Jan 17 '24 10:01 Codex-