记一次 rollup 打包代码缺失问题

前言

记一次 rollup 打包代码缺失问题

正文

起因是公司使用了一个名为 @elastic/apm-rum-core 的库

该库的作用可以理解为上报用户的操作,比如点击了什么按钮,发起了什么请求等等

官方的文档:Introduction | APM Real User Monitoring JavaScript Agent Reference [5.x] | Elastic

在源码中,有这么一个 patchAll 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import {patchXMLHttpRequest} from './xhr-patch';
import {patchFetch} from './fetch-patch';
import {patchHistory} from './history-patch';
import {patchEventTarget} from './event-target-patch';
import EventHandler from '../event-handler';
import {HISTORY, FETCH, XMLHTTPREQUEST, EVENT_TARGET} from '../constants';

var patchEventHandler = new EventHandler();
var alreadyPatched = false;

function patchAll() {
if (!alreadyPatched) {
alreadyPatched = true;
patchXMLHttpRequest(function (event, task) {
patchEventHandler.send(XMLHTTPREQUEST, [event, task]);
});
patchFetch(function (event, task) {
patchEventHandler.send(FETCH, [event, task]);
});
patchHistory(function (event, task) {
patchEventHandler.send(HISTORY, [event, task]);
});
patchEventTarget(function (event, task) {
patchEventHandler.send(EVENT_TARGET, [event, task]);
});
}

return patchEventHandler;
}

export {patchAll, patchEventHandler};

其中这个方法使用了 patchEventTarget 来包装 addEventListenerremoveEventListener 这两个方法

但是很奇怪的是在开发环境下代码没有问题,但是打包之后事件监听的包装效果就不存在了

后面分析打包后的代码发现是 patchEventTarget 这个函数被删除了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function patchAll() {
if (!alreadyPatched) {
alreadyPatched = true;
patchXMLHttpRequest(function (event, task) {
patchEventHandler.send(XMLHTTPREQUEST, [event, task]);
});
patchFetch(function (event, task) {
patchEventHandler.send(FETCH, [event, task]);
});
patchHistory(function (event, task) {
patchEventHandler.send(HISTORY, [event, task]);
});
// patchEventTarget 函数消失
}

return patchEventHandler;
}

所以建了一个 demo 最小化复现这个现象

Dedicatus546 / rollup-build-demo

在关闭 treeshake 之后,该现象消失,但是很明显即使开启 treeshake 功能, patchEventTarget 也不应该被优化掉的

另一个很有意思的是如果我们在 patchAll 源码中加入一个 console.log 来引用 patchEventTarget ,那么代码就能正常地打包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// ...

function patchAll() {
if (!alreadyPatched) {
alreadyPatched = true;
patchXMLHttpRequest(function (event, task) {
patchEventHandler.send(XMLHTTPREQUEST, [event, task]);
});
patchFetch(function (event, task) {
patchEventHandler.send(FETCH, [event, task]);
});
patchHistory(function (event, task) {
patchEventHandler.send(HISTORY, [event, task]);
});
patchEventTarget(function (event, task) {
patchEventHandler.send(EVENT_TARGET, [event, task]);
});
// 加入一个 console
console.log(patchEventTarget)
}

return patchEventHandler;
}

export {patchAll, patchEventHandler};

或者在 patchEventTarget 函数内加入一个随意的 console.log ,也能正常地打包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// ...

export function patchEventTarget(callback) {
if (!window.EventTarget) {
return;
}

// 加入一个 console
console.log('hello world!');

var proto = window.EventTarget.prototype;
var nativeAddEventListener = proto[ADD_EVENT_LISTENER_STR];
var nativeRemoveEventListener = proto[REMOVE_EVENT_LISTENER_STR];

function findTaskIndex(existingTasks, eventType, listenerFn, capture) {
// ...
}

function isCapture(options) {
// ...
}

function createListenerWrapper(target, eventType, listenerFn, options) {
// ...
}

function getWrappingFn(target, eventType, listenerFn, options) {
// ...
}

proto[ADD_EVENT_LISTENER_STR] = function (eventType, listenerFn, optionsOrCapture) {
// ...
};

proto[REMOVE_EVENT_LISTENER_STR] = function (eventType, listenerFn, optionsOrCapture) {
// ...
};
}

后记

已经给 vite 提了一个 issue 了,不过其实应该给 rollupissue

some code disappeared when build project

趁着写这篇帖子,也给 rollup 提了个 issue

som code in @elastic/apm-rum-core disappear when build