Babel 移除 class 中无用的属性和方法

1,045 阅读2分钟

 我在 dev.to 上分享了一篇文章,为了同步信息,我也将这篇文章用中文方式复述一遍。

虽然我们用 webpack 的 optimization 能帮我们压缩代码,但是我们无法做到一件事,就是将一个属性名或方法名进行压缩和混淆,一旦这些名称被混淆,那么我们就无法调用到对应的接口,即使我们认为这些接口不应该暴露出来,目前而言,webpack 也无法做到这件事,因为,太难了。举个例子:

if (type === 'tap') {
  some[name + 'Type']()
}

这样的调用并非没有,webpack 怎么可能解决这种事情。

所以,它的办法,就是不解决。开发者自己想办法。既然如此,我们就自己来做吧。我写了一个 babel-plugin-shake-class-properties ,帮助开发者完成这件事。

简单说下原理。

babel 整个流程最重要的是 3 个阶段:parse、transform、print. 对于一个 babel 插件而言,最重要的就是 transform 阶段,对 ast 进行调整。在我们这里的需求中,就是需要在 ast 中删除掉对应的 node 即可。解下来就是各种判断,然后删掉节点就好了。

怎么用呢?

npm i -D babel-plugin-shake-class-properties

然后在 babel.config.js 中增加插件及其配置。之所以必须是 babel.config.js 而不能用 .babelrc 是因为我们需要读取文件的绝对路径。

// babel.config.js
const path = require('path')

module.exports = {
  ...
  plugins: [
    ['babel-plugin-shake-class-properties', {
      // the only properties we want to keep, other properties will be removed (except constructor)
      retain: [
        {
          file: path.resolve(__dirname, 'node_modules/tyshemo/src/store.js'), // the file's absolute path to match
          class: 'Store', // the class name from which properties will be removed
          properties: ['update', 'set'], // the properties which will be kept
        },
      ],
      // the properties we want to remove, properties even in `retain` will be removed
      remove: [
        {
          file: path.resolve(__dirname, 'node_modules/tyshemo/src/store.js'),
          class: 'Store',
          properties: ['update', 'set'], // the properties which will be removed
        },
      ],
    }],
    ...
  ],
}

主体上两个配置项,retain 指你想要保留的属性,remove 指你想要移除的属性。remove 的优先级更高,在 retain 中被保留下来的属性,在 remove 中仍然会被删除。

另外,利用这个插件还能删除 static, async 等属性,而且它具有严格匹配的规则,如果在源码中是一个 static 方法,但是你在配置中没有声明,那么这个属性不会被匹配到。

remove: {
  ...
  properties: [
    'static a',
    'get name',
    'set name',
    '* f',
    'async fetch',
    'async * r',
    'static async * p',
    'static get e',
  ],
}

计算类型属性名匹配比较复杂,例如:

remove: {
  ...
  properties: [
    '[a]',
    '["a"]'
  ],
}

这样是可以匹配的,其他 [] 类型的属性全部不能匹配。

使用这个插件可以移除 react 组件的 static propTypes 属性,但是如果是写在 class 体外,就不能被移除,这种形式的可以使用我写的另外一个插件来移除。

通过这个插件,你就可以再对你的构建包进行精简了,是不是很好呢?