你可听说过Vue SFC TreeShaking

2,186 阅读5分钟

前言

我们都知道,webpack 有treeshaking 特性,可以在生产环境将没有副作用(sideEffect)的 模块导出移除,但是它仍然具有局限性,在此就不赘述了。更不用说移除一个vue 单文件组件中的无用代码,因为单文件组件最后会编译成render函数,看下下面这段代码。

<template>
 <div id="app">
   
 </div>
</template>

<script>
export default {
 name: 'app',
 components: {
 },
 data() {
   return {
     test: 'this is deadcode',
   }
 }
};
</script>

可以很清晰的看出data.test属性是没有用过的,我们看下使用webpack打包后的结果

i={name:"app",components:{},data:function(){return{test:"this is deadcode"}}}

正题

在多人协作迭代过程中,不可避免的需要改动别人的代码,如果某一天业务变更,在template 中删除了某个标签或者组件以后,它所绑定的属性,绑定的方法,可能就会变成无用的,没有其他地方引用,在深入一层,这些方法中调用的方法,或者计算属性也有可能变成无用的,举个🌰

<template>
 <div id="app" >
   <li @click="handleFn"></li>
 </div>
</template>

<script>
export default {
 name: 'app',
 components: {
 },
 data() {
   return {
     test: 'this is deadcode',
   }
 },
 methods: {
   handleFn() {
     this.test
   }
 }
};

当我们将li 标签删除

<template>
 <div id="app" >
-    <li @click="handleFn"></li>
 </div>
</template>

那么对于当前组件来说,methods.handleFn是无用代码,data.test也变成了无用代码。一个很简单的例子,大家都可以一眼看出来变动后的依赖关系,但是当你维护的代码几百上千行之后,你在改动代码之后还是否能这么敏锐的察觉无用代码呢?特别是大家写代码时,在业务相似时可能会将之前代码copy过来改改逻辑就ok了,这个工程你产生无用代码的概率会大大增加。

小插曲

我有了这个想法以后,就上网搜了一下,有没有现成的lint 工具可以使用,一开始发现了这个 pull request,基本实现了我的需求,但是因为有几个特性没有实现,因此也没有被eslint-plugin-vue官方 maintainer 接受一直挂到现在,我就想着自己实现一下。

目前我已经通过了所有该pr 的测试用例,以及 两个未实现的 feature。

主要思路

通过分析模板中使用到的变量,方法等得到一个 id列表,如果在分析导出的对象时发现某个标签是使用过的就将其标记为已使用,如果是一个方法,那么将其所有使用的属性(method, data property)都标记为使用,最终那些未标记的id 就是没有使用的节点也就是死代码,当然有一些特殊情况,比如生命周期函数中的函数调用,属性使用都将标记成已使用等等。

eslint-plugin-vueunused

通过调用用这个检测类,写了一个eslint工具,可以通过在开发期间提示我们有哪些潜在的未使用代码,手动treeshaking(删) 掉,这里就是我在题目中提到的Vue SFC TreeShaking, 你可能会说我是标题党,其实我这里引用的是webpack中 dev 模式下的treeshaking,帮你标记出来,至于为什么做不到 production模式中的treeshaking ,后面我会列举原因。

使用方法

首先你需要安装 ESLint:

$ npm i eslint --save-dev

然后, 安装 eslint-plugin-vueunused

$ npm install eslint-plugin-vueunused --save-dev

注意: 如果您全局安装了ESLint(使用-g标志),则还必须全局安装eslint-plugin-vueunused

vueunused 添加至你的 .eslintrc 配置文件中的plugins部分. 你可以省略 eslint-plugin- 前缀:

{
    "plugins": [
        "vueunused"
    ]
}

然后继承插件推荐配置即可

{
    "extends": ["plugin:vueunused/recommend"],
}

支持的规则

只有一条规则

  1. vueunused/unused

警告

该插件与eslint-plugin-html不兼容,因为该插件可能会破坏您的scf(.vue)组件模板信息,因此我建议您使用eslint-plugin-vue,本插件用于弥补eslint-plugin-vue某些未完成的功能,例如no-unused-methods,no-unused-variables,等等挂载在this上的属性实际上,您在组件范围内定义的大多数未使用的属性都可以被检测到。

建议

  1. 如果您使用VSCode编辑器,我强烈建议您安装ESlint VSCode插件,它可以用更加直观的方式指出单文件中的无用代码代码。 如果正确配置,我们在编辑器中将看到如下提示:

绿色部分即使无用代码。

  1. 特别的,如果你使用的eslint 版本 >= 6.7.0 那么可以使用 vscode 插件eslint 的重构选项,将无用代码删除。

总结

  1. 我写完这个插件以后已经在几个项目中验证了,基本上可以覆盖到日常中的场景,而且也写了许多测试保证代码的正确性。(测试样例都写在 linter 的依赖 vsfc-deadcode-detect中)
  2. 改插件的局限性在于只能测试单文件中的代码,但是我们知道有些组件中的方法是暴露给其他组件调用的,所以可能在该组件中没有使用但是不能保证所有未使用过的就是无用代码,因此也是把 eslint 等级调为 warning 的原因,鉴于我们一般只有在组件中存在这样的情况,所以这个插件的准确率应该是还是比较高的。

赶紧试试这个插件吧,看看你的项目中有多少无用代码,如果能帮助到你,就点个 star呗👇。
github地址: eslint-plugin-vueunused
当然,如果遇到任何检查错误,欢迎你提issue 帮助改善这个项目🚀