我在 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 体外,就不能被移除,这种形式的可以使用我写的另外一个插件来移除。
通过这个插件,你就可以再对你的构建包进行精简了,是不是很好呢?