Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在 vite 中无法按需加载样式文件 #4966

Closed
liuweiGL opened this issue Mar 23, 2022 · 33 comments
Closed

在 vite 中无法按需加载样式文件 #4966

liuweiGL opened this issue Mar 23, 2022 · 33 comments

Comments

@liuweiGL
Copy link

liuweiGL commented Mar 23, 2022

Version of antd-mobile

latest

Operating system and its version

Others

Browser and its version

No response

Sandbox to reproduce

https://github.com/liuweiGL/vite-plugin-demand-import

What happened?

在组件中自动导入样式跟依赖 esm 规范的 tree shaking 冲突,导致样式无法按需加载:我遇到的问题

Relevant log output

No response

@liuweiGL liuweiGL added the bug label Mar 23, 2022
@liuweiGL liuweiGL changed the title 在组件中自动导入样式不是很合理 在 vite 中无法按需加载样式文件 Mar 23, 2022
@awmleer
Copy link
Member

awmleer commented Mar 24, 2022

有点奇怪,webpack 对 tree shaking 的处理逻辑是,如果依赖树是这样的:

a.js
  |- b.js
    |- b.css
  |- c.js
    |- c.css

如果 c.js 被 tree shaking 了,那么 c.css 也会被 tree shaking 的

@liuweiGL
Copy link
Author

liuweiGL commented Mar 24, 2022

css 添加在 sideEffects 里面了,不应该被 tree shaking。

@zzzgydi
Copy link
Contributor

zzzgydi commented Mar 24, 2022

这个应该是vite的dev吧,dev不做tree shaking的

@liuweiGL
Copy link
Author

liuweiGL commented Mar 24, 2022

这个应该是vite的dev吧,dev不做tree shaking的

build 也不会 tree shaking:
image

image

js 文件变大了是因为我把 minify 关闭了,确认组件 js 文件是 tree shaking 的。

@liuweiGL
Copy link
Author

create-react-app :
image

image

@zzzgydi
Copy link
Contributor

zzzgydi commented Mar 24, 2022

build没有tree shaking 我也测到过 #4300

@liuweiGL
Copy link
Author

vite 不支持 css tree shaking,内部默认是按照“副作用”处理的:vitejs/vite#4389 (comment)

@liuweiGL
Copy link
Author

liuweiGL commented Mar 24, 2022

总结一下问题

  1. vite、webpack 均无法按需加载样式。
  2. vite dev 模式下无用的样式文件增加请求数量影响性能。

原因

组件 index.js 中自动导入了样式。

建议

取消组件中的自动导入,让用户选择按需加载或者全局导入。

@zzzgydi
Copy link
Contributor

zzzgydi commented Mar 24, 2022

从issue来看,应该是只有vite build时不支持css 的 tree shaking,webpack是支持的。

vite dev不支持我猜是因为默认根本不做啥细致的ast解析,也就没有tree shaking,dev启动的速度和dev时浏览器加载资源的性能问题,可以自己取舍。

@liuweiGL
Copy link
Author

liuweiGL commented Mar 24, 2022

vite dev 是因为 optimize 操作会把 antd-mobile 所有的组件打包成一个文件,减少网络请求数量。


vite dev 模式下需要的不是 tree shaking 减少的“代码量”,而是"请求数量"。

@zzzgydi
Copy link
Contributor

zzzgydi commented Mar 24, 2022

vite dev 会事先将antd mobile bundle 成一个文件,加载这个文件就会加载全部css。我能想到的可能的解决方案:1. antd mobile改变样式的引入方式;2. vite 改变处理流程;3. 用 vite 插件

@liuweiGL
Copy link
Author

现在就讨论的这个啊,库里面自动引入 css 导致用户失去了控制权。

一方案是这个 issue 的主题。
二方案不可能,这不属于对方的问题。
三方案也是我正在用的,但是有个问题:

import { Button } from 'antd-mobile'
↓↓↓↓↓↓↓↓↓
import Button  from 'antd-mobile/Button '

代码转换之后,vite optimize 初次只能收集到 Button 组件的依赖。后续开发的时候再导入个 Modal 组件,optimize 又得再收集一次然后 reload page。

@zzzgydi
Copy link
Contributor

zzzgydi commented Mar 24, 2022

vite build对css sideEffects这个处理,我觉得需要调整一下。这样antd mobile在引入的时候,js和css都自动tree shaking,挺优雅的了。

方案一,如果按你说的,库不自己引入css,那每次引入一个button,都得引入对应的样式文件,这个对用户来说更难受吧。或者提供多一个导出目录,用户可以引入 import {Button} from 'antd-mobile/nocss',然后这个需要自己额外引入样式文件,这样?
方案二,不考虑
方案三,比较推荐,谁都不用改,用户自己按自己的想法引入。dev时看这么多请求不爽的就可以用插件,对这些无感的就默认不管。(鉴于目前vite build的问题,都用一下比较好)

不过用了vite插件,确实会出现,vite会针对各个组件按需分别进行一次bundle。

@liuweiGL
Copy link
Author

方案一,如果按你说的,库不自己引入css,那每次引入一个button,都得引入对应的样式文件,这个对用户来说更难受吧。或者提供多一个导出目录,用户可以引入 import {Button} from 'antd-mobile/nocss',然后这个需要自己额外引入样式文件,这样?

你这个说法不对,现在这个行为不就相当于“全局引入”吗?按这种用法用户只要直接导入 “global/index.css” 就好了。

@awmleer
Copy link
Member

awmleer commented Mar 24, 2022

你这个说法不对,现在这个行为不就相当于“全局引入”吗?按这种用法用户只要直接导入 “global/index.css” 就好了。

现在不是全局引入啊,如果用 webpack,样式也是会自动做按需加载的

@zzzgydi
Copy link
Contributor

zzzgydi commented Mar 24, 2022

现在的代码实现中,如果没有tree shaking的话,确实都是全局引入。但是设置了sideEffects,像webpack,rollup这些打包器,就会tree shaking实现按需引入。现在antd mobile推荐的不就是这样的按需引入方式吗,antd mobile 文档

至于vite,我始终觉得应该分dev和build两种阶段去讨论,毕竟它两个实现逻辑就不一样。build的时候,对于css sideEffects的处理能和webpack一致,那就没问题(但是现在不一致)。dev阶段由于没有tree shaking,确实都引入了。

@awmleer
Copy link
Member

awmleer commented Mar 24, 2022

po 一下我根据目前讨论的总结:

dev 模式下:
webpack 和 vite 都不会做 tree shaking 的

  • 对于 webpack 来说,tree shaking 是一个开销比较大的操作,会影响到本地开发时构建的速度和用户体验,所以是默认不开启的(但是你可以通过配置项手动打开)
  • 对于 vite 来说,如 @liuweiGL 所说,应该是为了减少网络请求,所以也是默认不会开启 tree shaking 的

prod 模式下:

  • webpack 是可以正常的 tree shaking 的,包括对 js 和对 css 的 tree shaking
  • 根据现象来看,vite 似乎只能对 js 做 tree shaking,css 文件还是会被全量引入的

这么看起来,感觉像是 vite 的 tree shaking 能力有点不完备?

@awmleer
Copy link
Member

awmleer commented Mar 24, 2022

dev 环境下不做 tree shaking 我觉得是挺正常的行为呀,我们就只讨论 prod 模式下的 tree shaking 行为好了

@awmleer
Copy link
Member

awmleer commented Mar 24, 2022

如果保守一点,所有 css 打成一个大的 css 文件(就像目前 v4 版本的 antd 这样处理),的确是可以的,但是这种方案也不是完美的,主要的问题是:

  1. 样式文件默认只能全量引入,如果想对样式文件也做按需加载,就得配合 babel-plugin-import(而使用 babel-plugin-import 意味着额外的引入成本和维护成本)
  2. 还需要留意在项目中额外 import 一下 css 文件(这个我觉得倒还好,就一行代码的事,麻烦不了太多)

看起来似乎问题也不大,但是,移动端和 PC 端不同,移动端更加在意包体积大小和加载速度,所以全量引入样式在大多数的项目中,基本是不可行的,所以第 1 点的问题影响就被放大了很多

@zzzgydi
Copy link
Contributor

zzzgydi commented Mar 24, 2022

@awmleer vite按需引入的插件配置是不是也可以考虑加到文档中呢

@liuweiGL
Copy link
Author

我在正式项目里面试了,vite dev 模式没法使用替换 import 的方式进行按需加载:
image

image

@liuweiGL
Copy link
Author

项目稍微复杂一点,optimize 状态会一直重置。

@liuweiGL
Copy link
Author

liuweiGL commented Mar 24, 2022

配置 optimizeDeps.exclude 也是行不通的:一是因为 antd-mobile 里面依赖了 commonjs 规范的类库,二是不进行 pre-bundle 的话加载文件实在太多。

@awmleer
Copy link
Member

awmleer commented Mar 25, 2022

@liuweiGL 为啥要在 dev 环境下实现按需加载啊?引用一下我在上面的评论里发的:

dev 环境下不做 tree shaking 我觉得是挺正常的行为呀,我们就只讨论 prod 模式下的 tree shaking 行为好了

@awmleer
Copy link
Member

awmleer commented Mar 25, 2022

一是因为 antd-mobile 里面依赖了 commonjs 规范的类库

antd-mobile 试试 v5.8.0 及以上的版本吧?我昨天调整了,把之前对 floating-ui 的临时 import 方案去掉了,现在应该所有的依赖都是 esmodule 的了

@zzzgydi
Copy link
Contributor

zzzgydi commented Mar 25, 2022

使用插件 vite-plugin-imp,vite.config插件配置如下,其余optimizeDeps啥都没配:

    vitePluginImp({
      libList: [
        {
          libName: "antd-mobile",
          style: () => false,
          libDirectory: "es/components",
          replaceOldImport: true,
        },
      ],
    }),

再全局引入 import "antd-mobile/es/global"; 我开demo测试,hmr没有问题。

我原先采用 vite 2.8.6 + @vitejs/plugin-react ^1.0.0(非最新的1.2.0,具体的忘了看lock),就有热更新的问题。不论是不是用了插件按需,改个文本都reload。换了@vitejs/plugin-react到最新的1.2.0,用不用插件按需hmr都正常。

@liuweiGL
Copy link
Author

你这个是正式项目测试的吗,模块多不多?如果只是一个 demo 页面确实没问题,模块多了之后才会出现我上面截图的情况。

@liuweiGL
Copy link
Author

liuweiGL commented Mar 25, 2022

@liuweiGL 为啥要在 dev 环境下实现按需加载啊?引用一下我在上面的评论里发的:

dev 环境下不做 tree shaking 我觉得是挺正常的行为呀,我们就只讨论 prod 模式下的 tree shaking 行为好了


现在的情况是得用插件走按需加载啊?我后面发的是用插件之后遇到的问题。难道再区分一下环境,打包模式才走插件?

@zzzgydi
Copy link
Contributor

zzzgydi commented Mar 25, 2022

你这个是正式项目测试的吗,模块多不多?如果只是一个 demo 页面确实没问题,模块多了之后才会出现我上面截图的情况。

如果你不开任何插件去搞什么按需,测试了hmr也没有问题的话,你的论点“开插件实现按需导致正式项目(复杂项目)hmr出现问题”,才有说服力吧。

现在的情况是得用插件走按需加载啊?我后面发的是用插件之后遇到的问题。

这种问题,建议你直接给个可以复现的demo,或者贴一下vite配置。

demo里针对了antd mobile 开不开按需,我都测试过没有问题。如果你项目里有问题,也可以是其他内容配置导致的问题。还是建议你直接给个可以复现的demo。

@liuweiGL
Copy link
Author

抽空弄了个 demo :https://github.com/liuweiGL/antd-mobile-test

@zzzgydi
Copy link
Contributor

zzzgydi commented Mar 26, 2022

简单测了一下,开启插件按需引入之后hmr的情况:

  • main.tsx:任何修改 reload
  • 其他tsx:不涉及import的修改 hmr;涉及import且触发了依赖bundle的修改 reload

不搞按需引入,自然就不会在import变化的时候触发依赖bundle。但是按需的话,同一个组件也只会bundle一次,后续的import该组件就不会造成reload了。

所以,你这个demo的例子,第一次,从组件页A跳到组件页B,会触发bundle会reload。但是第二次第三次再跳回A或B,都不会bundle和reload。

另外,不在dev的时候搞什么按需引入,哪怕引入一个button的简单demo都只是大概100个左右的request,这大部分都是css内容的加载。但是这个资源总体积比较小。如果按需引入了,request数量少了点(单个页面引入10个组件,89个requests(大约))。

我不是很懂这100个,哪怕100个都是多余的css,大概300k不到,能如何影响网络请求进而影响开发体验。但是,对我而言,每次开发的时候增加一个组件,导致 vite 需要bundle一次,然后reload一次,这个倒是很影响开发体验。要我选,我就选在dev的时候关掉按需,仅build的时候用,然后等vite处理css sideEffects问题,啥按需都不用搞。

@awmleer
Copy link
Member

awmleer commented Mar 26, 2022

在 vite 的仓库中发现了这个 issue: vitejs/vite#4389

看起来 vite 是不会去读取 package.json 中的 sideEffects 配置的,而且它认为所有的 css 文件一定是有副作用的,不论上层引入它的 js 文件是不是有副作用、是不是被使用了,vite 认为这是目前的预期行为而非 bug,这个 issue 也是八个月之前提的了,不确定 vite 还有没有意向调整这个对 css 文件的处理策略……

@Werner-Klier
Copy link

@zzzgydi zzzgydi 完美的解决了我的问题,nice,用vite-plugin-imp不会报错,并且刷新页面加载时间变快了1.几秒

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants