Closed lili21 closed 1 year ago
先说结论:在Remix中写样式/css,对于Remix的其他功能来说,开发体验是相对不友好的。甚至对于最后的用户体验,也不够好。
Remix中,路由模块支持export出一个links方法,通过links来引入样式。就和<link />标签一样。
export
links
<link />
import styleUrl from './app.css'; export const links = () => [ { rel: 'stylesheet', href: styleUrl } ];
可以看到,links方法最终返回的是一个数组,所以引入多个样式也很简单
import globalUrl from './global.css'; import styleUrl from './app.css'; export const links = () => [ { rel: 'stylesheet', href: globalUrl }, { rel: 'stylesheet', href: styleUrl } ];
在访问到这个路由的时候,这些样式会被加载。同时在离开这个路由的时候,相应的样式也会被卸载,避免了路由之间样式的冲突。Easy and Simple.
项目中难免会封装通用的组件,组件也会有自己的样式。在以往的项目中,我们只需要在组件代码中import css就可以了。那在Remix中呢?直接export links可以吗?。答案是否定的,links方法只在路由模块中生效。Remix官方推荐了两种做法
import css
export links
组件代码直接写在全局样式中 - 维护性不够友好,也会导致页面加载很多不必要的样式
组件代码export出一个links方法,在使用到该组件的路由模块中,引入并与路由样式一块输出。代码如下
// components/Button.jsx import buttonStyle from './button.css'; // 组件内export出一个link方法 export const links = () => [ { rel: 'stylesheet', href: buttonStyle } ]; export function Button() { return <button className="btn">click me</button> } // routes/index.jsx import Button, { links as buttonLinks } from '~/components/Button'; import styleUrl from './app.css'; export const links = () => [ { rel: 'stylesheet', href: styleUrl }, ...buttonLinks() // 在使用到该组件的地方,输出组件样式 ];
这种写法从开发体验上还是可以接受的,虽然引入组件会变得麻烦一点点。但好处是
简单介绍了Remix中如何引入样式后,那在实际项目中,又会遇到哪些问题呢?
Remix对于css处理是最简单/简陋的 - 只是帮你加一个文件名hash,不会做任何处理。这意味着如果你想对css做压缩的,你需要自己做
大家可能已经习惯写Less, Sass 甚至css in js。但这些在Remix中都不是开箱即用的,你需要自己扩展这些功能。好在Remix Examples中有很对例子可以参考
大家项目里可能会用到像antd这样的组件库,那你是需要按Remix的方式去引入样式的。如果你想支持按需加载的,就需要在每个用到组件的地方,都单独引入组件的样式。不再像之前一样直接引入组件,再加上babel-import-plugin就可以了。
这个是我遇到的最大问题了。我们项目内引入了一个内部的组件库,该组件库还不支持样式的按需引入,所以需要引入全部的样式。组件库样式大小在100KB左右。所以我想着引入一下purgecss,移除一下未使用到的样式。效果还是很明显的,组件库样式大小减小到20KB左右。但有一个问题,应该在什么时候做purge呢?
100KB
20KB
我一开始的方案是在Remix打包构建后,过程如图所示
问题就在于,purge过程修改了css文件的内容,但文件名没有变化。而CDN文件都是有强缓存的,这会导致
所以我想着那就在Remix构建前做吧,这样文件内容变了,文件名就会变。就不会缓存的问题了,但这就引入的新的问题,purge移除掉了不该移除的样式 - 为啥呢?
如果我们要在构建前做purge,那我们能分析的代码只有我们的源代码 - 即我们会看源代码中用到了哪些css样式,没用到的都删除。但是我们的代码中会引入三方组件,这部分组件也会用到css样式。由于purge过程中没有包括我们引入的组件,就导致这些样式被误删了。打包构建后就出问题了
这个问题我还没想到好的解法
前面有提到,Remix不会对css做过多处理,你有几个css文件,最终就会生成几个css文件,最终也就会加载几个css文件。想象一下如果你的路由中引入了8个组件,每个组件都有自己的样式,而你的路由也有自己的样式。你可能还会有全局样式,和normalize样式。这时候访问这个路由就需要加载11个样式文件,每个样式文件都很小。
虽然这样可以达到很精确的缓存控制,虽然你可以开启http 2了。但css毕竟是会阻塞我们页面渲染的资源,在用户网络不好的情况下,加载11个网络资源是一个好的方案吗?对于这个问题,同样需要你自己去解决。无论是inline critical css,懒加载其他css。还是合并css为一个文件
Remix官方也并非不想更好的支持样式,只是他们还没想好怎么做。对样式更好的支持也在他们的规划中。目前links的方式,除了我上面说的这些问题,从API设计的角度上看,我觉得还是很好的。links基本就是我们的link标签,所以你不仅仅可以用来加载样式。你可以可以用来做preload和prefetch
link
preload
prefetch
export const links = () => [ { rel: 'preload', href: xxx, }, { rel: 'prefetch', href: xxxx } ]
你也可以根据loader返回的数据,返回不同的值
loader
export const links = (data) => { if (data.lang = 'en') { return []; } else { return []; } }
对于这里提到的css问题,最好的解法我认为是预处理。无论是语法,代码合并,压缩,purge都需要在remix构建之前做好。
目前我正在尝试用parcel-css实现,当然你也可以直接用postcss做
先说结论:在Remix中写样式/css,对于Remix的其他功能来说,开发体验是相对不友好的。甚至对于最后的用户体验,也不够好。
怎么写
Remix中,路由模块支持
export
出一个links
方法,通过links
来引入样式。就和<link />
标签一样。可以看到,
links
方法最终返回的是一个数组,所以引入多个样式也很简单在访问到这个路由的时候,这些样式会被加载。同时在离开这个路由的时候,相应的样式也会被卸载,避免了路由之间样式的冲突。Easy and Simple.
那组件样式怎么写呢?
项目中难免会封装通用的组件,组件也会有自己的样式。在以往的项目中,我们只需要在组件代码中
import css
就可以了。那在Remix中呢?直接export links
可以吗?。答案是否定的,links
方法只在路由模块中生效。Remix官方推荐了两种做法组件代码直接写在全局样式中 - 维护性不够友好,也会导致页面加载很多不必要的样式
组件代码
export
出一个links
方法,在使用到该组件的路由模块中,引入并与路由样式一块输出。代码如下这种写法从开发体验上还是可以接受的,虽然引入组件会变得麻烦一点点。但好处是
简单介绍了Remix中如何引入样式后,那在实际项目中,又会遇到哪些问题呢?
Remix在打包中不会压缩css
Remix对于css处理是最简单/简陋的 - 只是帮你加一个文件名hash,不会做任何处理。这意味着如果你想对css做压缩的,你需要自己做
Remix默认只支持css
大家可能已经习惯写Less, Sass 甚至css in js。但这些在Remix中都不是开箱即用的,你需要自己扩展这些功能。好在Remix Examples中有很对例子可以参考
组件库的样式引入
大家项目里可能会用到像antd这样的组件库,那你是需要按Remix的方式去引入样式的。如果你想支持按需加载的,就需要在每个用到组件的地方,都单独引入组件的样式。不再像之前一样直接引入组件,再加上babel-import-plugin就可以了。
Purge CSS - 移除未使用的样式
这个是我遇到的最大问题了。我们项目内引入了一个内部的组件库,该组件库还不支持样式的按需引入,所以需要引入全部的样式。组件库样式大小在
100KB
左右。所以我想着引入一下purgecss,移除一下未使用到的样式。效果还是很明显的,组件库样式大小减小到20KB
左右。但有一个问题,应该在什么时候做purge呢?我一开始的方案是在Remix打包构建后,过程如图所示
问题就在于,purge过程修改了css文件的内容,但文件名没有变化。而CDN文件都是有强缓存的,这会导致
所以我想着那就在Remix构建前做吧,这样文件内容变了,文件名就会变。就不会缓存的问题了,但这就引入的新的问题,purge移除掉了不该移除的样式 - 为啥呢?
如果我们要在构建前做purge,那我们能分析的代码只有我们的源代码 - 即我们会看源代码中用到了哪些css样式,没用到的都删除。但是我们的代码中会引入三方组件,这部分组件也会用到css样式。由于purge过程中没有包括我们引入的组件,就导致这些样式被误删了。打包构建后就出问题了
这个问题我还没想到好的解法
css文件过多的问题
前面有提到,Remix不会对css做过多处理,你有几个css文件,最终就会生成几个css文件,最终也就会加载几个css文件。想象一下如果你的路由中引入了8个组件,每个组件都有自己的样式,而你的路由也有自己的样式。你可能还会有全局样式,和normalize样式。这时候访问这个路由就需要加载11个样式文件,每个样式文件都很小。
虽然这样可以达到很精确的缓存控制,虽然你可以开启http 2了。但css毕竟是会阻塞我们页面渲染的资源,在用户网络不好的情况下,加载11个网络资源是一个好的方案吗?对于这个问题,同样需要你自己去解决。无论是inline critical css,懒加载其他css。还是合并css为一个文件
后记
Remix官方也并非不想更好的支持样式,只是他们还没想好怎么做。对样式更好的支持也在他们的规划中。目前
links
的方式,除了我上面说的这些问题,从API设计的角度上看,我觉得还是很好的。links
基本就是我们的link
标签,所以你不仅仅可以用来加载样式。你可以可以用来做preload
和prefetch
你也可以根据
loader
返回的数据,返回不同的值