linaria
本篇主要记录在Taro中使用Linaria碰到的问题,其他环境下可能也会碰到,原理类似。可能部分地方理解有误,欢迎指正。
原理
所有问题根源是linaria是零运行时的css in js库,所以需要在webpack中配置相关loader在构建时解析组件中的样式,并将其提取出来,最终生成 CSS 文件。具体流程如下
- 解析依赖:Loader 需要找到并解析所有使用 Linaria 样式的组件文件,这样才能确保所有样式都被提取和处理。
- 执行文件:通过执行组件文件,loader 可以收集到所有的样式信息。这是因为 Linaria 使用了标签模板字面量(tagged templates)来定义样式,这些模板字面量在 JavaScript 的执行上下文中被处理,并且只有在执行代码时才能被解析。
- 生成源码:执行文件后,loader 会根据收集到的样式信息生成对应的 CSS 源码,并将其插入到 Webpack 的构建流程中,以便最终输出到 CSS 文件中。
- 替换引用:在 JavaScript 文件中,原始的 Linaria 样式引用会被替换为生成的 CSS 文件路径,这样在运行时,样式表就可以被正确加载。
具体代码产出如下三张图
const ScreenView = styled(ScrollView)`
width: 100%;
-webkit-overflow-scrolling: touch;
overflow: auto;
`
var ScreenView = /*#__PURE__*/Object(linaria_react__WEBPACK_IMPORTED_MODULE_6__[/* styled */ "a"])(_tarojs_components__WEBPACK_IMPORTED_MODULE_11__[/* ScrollView */ "r"])({
name: "ScreenView",
class: "s1jvex0m"
});
.s1jvex0m{width:100%;-webkit-overflow-scrolling:touch;overflow:auto;}
loader 未收集到相关样式信息问题
版本未匹配,比如linaria源码库版本为6+,loader和babel-preset库版本为5+,因此无法成功收集到相关信息。 最近按官方文档配置的可能都有这个问题。 考虑linaria库最新版本6+中使用了新的loader,没有相关教程跟案例,升级风险较大,因此我项目中先将相关库都降级为 5+。
ESM 文件问题
- EvalError: Unexpected token 'export'
- import state out of module
有些库的默认导出是 esm 格式,需要经过 @linaria/shaker 转换后才能使用,将其加入配置
module.exports = {
rules: [
{
action: require.resolve('@linaria/shaker'),
},
{
test: /node_modules[\/\\](?!@tarojs)/,
action: 'ignore',
},
{
// Do not ignore ES-modules
test: (filename, code) => {
if (!/[\\/]node_modules[\\/]/.test(filename)) {
return false;
}
// If a file contains `export` or `import` keywords, we assume it's an ES-module
return /(?:^|\*\/|;|})\s*(?:export|import)\s/m.test(code);
},
action: require.resolve('@linaria/shaker'),
}
]
}
变量 not found 问题
有些全局变量是通过DefinePlugin进行注入,有些Taro相关的api是通过webpack处理进行注入,在 loader 的执行环境中不存在。需通过配置注入。
module.exports = {
overrideContext: (context, filename) => {
if (/taro-ui/.test(filename)) {
otherParams['Taro__default'] = {
getEnv: () => {
return 'WEAPP'
}
}
}
return ({
...context,
ENABLE_INNER_HTML: true,
ENABLE_ADJACENT_HTML: false,
ENABLE_SIZE_APIS: false,
ENABLE_TEMPLATE_CONTENT: false,
ENABLE_CLONE_NODE: false,
ENABLE_CONTAINS: false,
ENABLE_MUTATION_OBSERVER: false,
__TARO_FRAMEWORK__: '"react"',
// ...其他需要注入的变量
})
},
}
Module XXXX is disposed
某些import其实在页面文件中并未使用,被回收了。解决方法为删除掉页面中未使用的变量。
(0 , i.styled) is not found
解决方案:将 @linaria/react 加入到 prebundle 的 exclude 中
换种思路
考虑 Taro 通过插件等方式注入了很多变量以及方法,linaria loader 无法成功读取这些,通过 overrideContext 注入也非常麻烦。 最终选择将styled的组件从jsx文件中移出来,使 linaria loader只处理这些导出了styled组件的文件。
修改前
// index.jsx
import { styled } from 'linaria/react'
import { View } from '@tarojs/components'
const FlexView = styled(View)`
display: flex;
flex-direction: column;
background: linear-gradient(180deg, ${props => props.startColor} 0%, ${props => props.endColor} 41%);
transition: all .3s ease-in;
`
修改后(拆成两个文件)
// index.styled.js
import { styled } from '@linaria/react'
import { View } from '@tarojs/components'
export const FlexView = styled(View)`
display: flex;
flex-direction: column;
background: linear-gradient(180deg, ${props => props.startColor} 0%, ${props => props.endColor} 41%);
transition: all .3s ease-in;
`
// index.jsx
import { FlexView } from './index.styled.js'