乐趣区

Linaria-替换-Emotion-操作记录

Emotion 和 Linaria 是两个 CSS in JS 方案, API 相近.
项目里有特殊的场景, 希望能减小体积, 我们一贯基于 Emotion 比较大,

我们的 Emotion 现在都是跟着 JavaScript 走到, 没有做 CSS 分离,
之前尝试过生产环境分离 CSS, 但是因为 CSS 规则顺序问题, 效果不够可控,
加上不想在 TypeScript 后面套一层 Babel, 这条路也就不想走了.
所以目前打包的 JavaScript 里面就有图片上这么大的 Emotion 代码的体积.

Linaria

justineo 提醒我说 Emotion 可以用 Linaria 替换, 我就去看了一下.
这个库的 API 基本上跟 Emotion 一致, 我们的写法大致用到了,

import {css, cx} from "emotion"

let styleA = css`
  color: red;
`;

在 Linaria 当中基本上无缝替换了,

import {css, cx} from "linaria"

let styleA = css`
  color: red;
`;

另外我关注的 prefix vendor, 在 linaria 里边一样也是有支持的.
其他的 API 应该也出跟着 style-components 的方案一致的.

跟 Emotion 相比, linaria 有个比较完善的静态的 css 分离的功能.

https://callstack.com/blog/ho…

In short, CSS in JS libraries such as Emotion and Styled Components parse and apply your styles when your page loads in the browser, Linaria extracts the styles to CSS files when you build your project (e.g. with webpack), and the CSS files are loaded normally.

Emotion used to have a static extraction mode, which was limited in the sense that it doesn’t support interpolations in the CSS string and can’t use many of Emotion’s features. Linaria will evaluate the interpolations such as JavaScript variables and functions in the CSS string at build time.

推测是去掉了 Emotion 某些动态的特性的支持把, 方便分离 CSS.
分离的过程是通过 Babel 完成的, 所以在特殊的场景当中我还是需要 Babel.

相关配置

这个修改增加了几个相关依赖,

    "babel-loader": "^8.0.6",
    "linaria": "^1.3.1",
    "core-js": "^2.6.5",
    "string-replace-loader": "^2.2.0",

core-js 需要锁定版本, 过高的版本因为不兼容是出现了报错的.
string-replace 是为了处理依赖当中引用了 Emotion 的代码.
项目当中的代码我可以手动更改, 但是依赖组件因为其他项目复用, 不好直接改掉,
通过 Webpack 增加配置, 把 Emotion 的依赖都指向 Linaria(不一定需要):

  resolve: {
    alias: {emotion: "linaria"}
  },

然后考虑到依赖代码引用得早, 还是要通过字符串替换把已有的引用提早替换掉:

  test: /\.js?$/,
  use: [
    {
      loader: "string-replace-loader",
      options: {
        search: `"emotion"`,
        replace: `"linaria"`
      }
    }
  ]

其他的部分主要靠 Linaria 自己的工具配合 Babel 去搞了.

loader: require.resolve("linaria/loader")

我这边 CSS 最终没有分离出去, 因为需求方面要打成一个 js 的包, 所以还是用 style 标签运行.
打包以后带着 style-loadercss-loader 的代码会显得比较大一点,

另外也要增加配置让 Webpack 去掉 Node 相关的代码, 不需要打包进来:

node: false,

而 CSS 部分的代码, 被 Linaria 处理, 单独以 CSS 文件的形式存在了.

道理讲应该是还可以去掉 style-loader 等等, 直接把 CSS 引入标签当中,
没想好建构方面怎么处理, 暂时先不管了.

其他

整体处理下来, Emotion 换上了 style-loader 等, 体积减小 20k,
压缩以后大致上也就是 2k 多一些, 跟预想的还是可以的.
但是如果能有办法把 style-loader 部分也简化掉, 还能减小一些, 再找找建构方案 …

退出移动版