背景以及用法
在写vue3项目的时候(我的项目是vite+vue3),引入的css和scss文件过大,由于项目只用到里面部分的样式,而打包却把整个文件都打包进去,这就导致包体积过大,因此写了这么一个vite插件以作优化(新版本添加的规则:现已可以自动按需打包vue文件中的style标签下已使用的样式),现在已经发布至npm官网,具体用法如下:
Install:
首先必须先下载的依赖包:(vite-plugin-vue-purifycss引用了autoprefixer、postcss、precss这三个依赖包)
npm install autoprefixer -D
npm install postcss -D
npm install precss -D
下载vite-plugin-vue-purifycss的方式:
npm install vite-plugin-vue-purifycss -D
# or
yarn add vite-plugin-vue-purifycss -D
# or
cnpm install vite-plugin-vue-purifycss -D
# or
pnpm install vite-plugin-vue-purifycss -D
Usage1:cssList需要输入按需打包的css或scss样式文件名的用法(现已可以自动按需打包vue文件中的
style标签下已使用的样式)
vite.config.ts/vite.config.js
import vitePluginPurifycss from "vite-plugin-vue-purifycss"
export default defineConfig({
plugins: [
vue(),
vitePluginPurifycss({
cssList: ["xxxxx.css","xxxxx.scss","xxxxx.less"....],
}),
]})
main.js/main.ts
import "xxxxxxxxx.css";
或者
import "xxxxxxxxx.scss";
或者
import "xxxxxxxxx.less";
Usage2:cssList无需输入按需打包的css或scss样式文件名,只要自动按需打包vue文件中的style标签下已使用的样式的功能的用法
vite.config.ts/vite.config.js
import vitePluginPurifycss from "vite-plugin-vue-purifycss"
export default defineConfig({
plugins: [
vue(),
vitePluginPurifycss(),
]})
1.现已可以自动按需打包vue文件中的style标签下已使用的样式(强烈提议每个vue文件的style标签添加scoped属性)
2.如果想按需打包全局引入的css或scss或less样式文件,cssList必须输入按需打包对应的css或scss或less样式文件名(前提是该样式文件必须在mian.js/main.ts已经引入,按需打包才会生效)
3.如果cssList无需输入按需打包的css或scss样式文件名,则使用插件无需填入参数亦可
4.默认扫描全局的vue文件
Vite Plugin API
一个 Vite 插件可以额外指定一个 enforce 属性(类似于 webpack 加载器)来调整它的应用顺序。enforce 的值可以是pre 或 post。解析后的插件将按照以下顺序排列:
-
Alias
-
带有 enforce: 'pre' 的用户插件
-
Vite 核心插件
-
没有 enforce 值的用户插件
-
Vite 构建用的插件
-
带有 enforce: 'post' 的用户插件
-
Vite 后置构建插件(最小化,manifest,报告)
开发Vite核心插件必须知道插件运行顺序,因为我们现在要处理冗余的css样式,所以现在我们要在vite的打包产物中剔除些没用的css样式,也就是“带有 enforce: 'post' 的用户插件”(输出阶段)这一阶段执行。
编写vite插件思路
按需打包css或scss文件的思路:目前需要获取全局vue文件引用到的选择器,再将文件中用到的选择器和cssList中的选择器根据设定的规则进行对比,最后剔除没有用到的选择器,剩下的选择器就是有用到的,这就达到按需打包css或scss效果了。
新版本添加的规则:现已可以自动按需打包vue文件中的style标签下已使用的样式--总体思路也是跟按需打包css或scss文件的思路大致一样的,不一样的是,绝大多数情况下,开发者总会在vue文件下的style标签后面加上scoped标识,这是为了保证在该style标签下修改样式不会影响到全局,确保样式私有化。在有scoped标识情况下,编译的时候会加上[data-v-xxxx]的唯一标识(该标识是从钩子transform(code, id, opt)的code中的__scopeId的字段可获取),所以我会在每一个vue文件下用到的选择器后面加上相应的[data-v-xxxx]唯一标识,如果style标签下的样式和vue文件的选择器带有的[data-v-xxxx]唯一标识是一致的证明该样式是在该vue文件下的style标签下的样式,再将样式文件中用到的选择器和对应的style标签下的选择器根据设定的规则进行对比,剔除没有用到的选择器,则达到按需打包vue文件中的style标签下已使用的样式。
以上我们知道了总体思路,接下来就需要得知vite和Rollup的钩子,我们需要在相应的钩子里做正确的事。查看vite官网和网上众多资料得知,钩子transform和generateBundle是我们需要的:
transform:这个钩子是处于把文件源码转换成目标代码这一阶段。transform(code, id, opt)中的code是文件转化之后的代码(实际是string类型),id是文件路径,我们可以根据文件后缀名,获得整个项目的vue文件对应的样式选择器和样式文件的路径(css和scss文件)。
generateBundle:这个钩子是处于把处于构建输出这一阶段,这里输出的已经是bundle产物,我们的目标就是改造输出的产物,所以在这里操作最为合适。generateBundle(__,bundle)中就是输出的Bundle文件列表。详细步骤:
-
获取cssList里面所有选择器(前提是用户填写的cssList中的样式文件名是项目中含有的,这里我会做个筛选)
-
与从钩子transform获取所有vue文件中的样式选择器进行对比,对比出多余的css样式。
-
引入postcss插件先把对应的Bundle文件转化为AST语法树,用多余的css样式匹配AST语法树相应的节点,并remove,余下的则是有用的selector节点,最后把余下的AST语法树转化成我们需要的source,这就是vite-plugin-vue-purifycs这个插件大概思路
具体可以去npm官网查看vite-plugin-vue-purifycss插件源代码