8000 Tree-shake unused declarations while keeping initializer side-effects… · rollup/rollup@e960ca8 · GitHub
[go: up one dir, main page]

Skip to content

Commit e960ca8

Browse files
authored
Tree-shake unused declarations while keeping initializer side-effects (#3933)
* Tree-shake unused declarations while keeping initializer side-effects * Improve coverage
1 parent e23bb35 commit e960ca8

File tree

140 files changed

+278
-2171
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

140 files changed

+278
-2171
lines changed

src/ast/nodes/AssignmentExpression.ts

Expand all lines: src/ast/nodes/AssignmentExpression.ts
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { ExpressionNode, IncludeChildren, NodeBase } from './shared/Node';
1515
import { PatternNode } from './shared/Pattern';
1616

1717
export default class AssignmentExpression extends NodeBase {
18-
left!: PatternNode;
18+
left!: ExpressionNode | PatternNode;
1919
operator!:
2020
| '='
2121
| '+='

src/ast/nodes/ForInStatement.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export default class ForInStatement extends StatementBase {
4949

5050
include(context: InclusionContext, includeChildrenRecursively: IncludeChildren) {
5151
this.included = true;
52-
this.left.includeWithAllDeclaredVariables(includeChildrenRecursively, context);
52+
this.left.includeAllDeclaredVariables(context, includeChildrenRecursively);
5353
this.left.deoptimizePath(EMPTY_PATH);
5454
this.right.include(context, includeChildrenRecursively);
5555
const { brokenFlow } = context;

src/ast/nodes/ForOfStatement.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export default class ForOfStatement extends StatementBase {
3434

3535
include(context: InclusionContext, includeChildrenRecursively: IncludeChildren) {
3636
this.included = true;
37-
this.left.includeWithAllDeclaredVariables(includeChildrenRecursively, context);
37+
this.left.includeAllDeclaredVariables(context, includeChildrenRecursively);
3838
this.left.deoptimizePath(EMPTY_PATH);
3939
this.right.include(context, includeChildrenRecursively);
4040
const { brokenFlow } = context;

src/ast/nodes/MemberExpression.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import Identifier from './Identifier';
2323
import Literal from './Literal';
2424
import * as NodeType from './NodeType';
2525
import { ExpressionNode, IncludeChildren, NodeBase } from './shared/Node';
26-
import { PatternNode } from './shared/Pattern';
2726
import SpreadElement from './SpreadElement';
2827
import Super from './Super';
2928

@@ -70,7 +69,7 @@ function getStringFromPath(path: PathWithPositions): string {
7069
return pathString;
7170
}
7271

73-
export default class MemberExpression extends NodeBase implements DeoptimizableEntity, PatternNode {
72+
export default class MemberExpression extends NodeBase implements DeoptimizableEntity {
7473
computed!: boolean;
7574
object!: ExpressionNode | Super;
7675
optional!: boolean;
@@ -84,8 +83,6 @@ export default class MemberExpression extends NodeBase implements DeoptimizableE
8483
private replacement: string | null = null;
8584
private wasPathDeoptimizedWhileOptimized = false;
8685

87-
addExportedVariables(): void {}
88-
8986
bind() {
9087
if (this.bound) return;
9188
this.bound = true;

src/ast/nodes/Property.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@ import { LiteralValueOrUnknown, UNKNOWN_EXPRESSION } from '../values';
1414
import * as NodeType from './NodeType';
1515
import { ExpressionEntity } from './shared/Expression';
1616
import { ExpressionNode, NodeBase } from './shared/Node';
17+
import { PatternNode } from './shared/Pattern';
1718

18-
export default class Property extends NodeBase implements DeoptimizableEntity {
19+
export default class Property extends NodeBase implements DeoptimizableEntity, PatternNode {
1920
computed!: boolean;
2021
key!: ExpressionNode;
2122
kind!: 'init' | 'get' | 'set';
2223
method!: boolean;
2324
shorthand!: boolean;
2425
type!: NodeType.tProperty;
25-
value!: ExpressionNode;
26+
value!: ExpressionNode | (ExpressionNode & PatternNode);
2627

2728
private accessorCallOptions!: CallOptions;
2829
private declarationInit: ExpressionEntity | null = null;
@@ -41,7 +42,7 @@ export default class Property extends NodeBase implements DeoptimizableEntity {
4142

4243
declare(kind: string, init: ExpressionEntity) {
4344
this.declarationInit = init;
44-
return this.value.declare(kind, UNKNOWN_EXPRESSION);
45+
return (this.value as PatternNode).declare(kind, UNKNOWN_EXPRESSION);
4546
}
4647

4748
// As getter properties directly receive their values from function expressions that always

src/ast/nodes/VariableDeclaration.ts

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ function areAllDeclarationsIncludedAndNotExported(
3333
exportNamesByVariable: Map<Variable, string[]>
3434
): boolean {
3535
for (const declarator of declarations) {
36-
if (!declarator.included) return false;
36+
if (!declarator.id.included) return false;
3737
if (declarator.id.type === NodeType.Identifier) {
3838
if (exportNamesByVariable.has(declarator.id.variable!)) return false;
3939
} else {
@@ -68,13 +68,14 @@ export default class VariableDeclaration extends NodeBase {
6868
}
6969
}
7070

71-
includeWithAllDeclaredVariables(
72-
includeChildrenRecursively: IncludeChildren,
73-
context: InclusionContext
74-
) {
71+
includeAllDeclaredVariables(
72+
context: InclusionContext,
73+
includeChildrenRecursively: IncludeChildren
74+
): void {
7575
this.included = true;
7676
for (const declarator of this.declarations) {
77-
declarator.include(context, includeChildrenRecursively);
77+
declarator.id.included = true;
78+
declarator.includeAllDeclaredVariables(context, includeChildrenRecursively);
7879
}
7980
}
8081

@@ -108,16 +109,13 @@ export default class VariableDeclaration extends NodeBase {
108109
lastSeparatorPos: number | null,
109110
actualContentEnd: number,
110111
renderedContentEnd: number,
111-
addSemicolon: boolean,
112112
systemPatternExports: Variable[],
113113
options: RenderOptions
114114
): void {
115115
if (code.original.charCodeAt(this.end - 1) === 59 /*";"*/) {
116116
code.remove(this.end - 1, this.end);
117117
}
118-
if (addSemicolon) {
119-
separatorString += ';';
120-
}
118+
separatorString += ';';
121119
if (lastSeparatorPos !== null) {
122120
if (
123121
code.original.charCodeAt(actualContentEnd - 1) === 10 /*"\n"*/ &&
@@ -149,7 +147,7 @@ export default class VariableDeclaration extends NodeBase {
149147
private renderReplacedDeclarations(
150148
code: MagicString,
151149
options: RenderOptions,
152-
{ start = this.start, end = this.end, isNoStatement }: NodeRenderOptions
150+
{ start = this.start, end = this.end }: NodeRenderOptions
153151
): void {
154152
const separatedNodes = getCommaSeparatedNodesWithBoundaries(
155153
this.declarations,
@@ -158,11 +156,7 @@ export default class VariableDeclaration extends NodeBase {
158156
this.end - (code.original.charCodeAt(this.end - 1) === 59 /*";"*/ ? 1 : 0)
159157
);
160158
let actualContentEnd: number | undefined, renderedContentEnd: number;
161-
if (/\n\s*$/.test(code.slice(this.start, separatedNodes[0].start))) {
162-
renderedContentEnd = this.start + this.kind.length;
163-
} else {
164-
renderedContentEnd = separatedNodes[0].start;
165-
}
159+
renderedContentEnd = findNonWhiteSpace(code.original, this.start + this.kind.length);
166160
let lastSeparatorPos = renderedContentEnd - 1;
167161
code.remove(this.start, lastSeparatorPos);
168162
let isInDeclaration = false;
@@ -187,11 +181,12 @@ export default class VariableDeclaration extends NodeBase {
187181
leadingString = '';
188182
nextSeparatorString = '';
189183
if (
190-
node.id instanceof Identifier &&
191-
isReassignedExportsMember(
192-
(node.id as IdentifierWithVariable).variable,
193-
options.exportNamesByVariable
194-
)
184+
!node.id.included ||
185+
(node.id instanceof Identifier &&
186+
isReassignedExportsMember(
187+
(node.id as IdentifierWithVariable).variable,
188+
options.exportNamesByVariable
189+
))
195190
) {
196191
if (hasRenderedContent) {
197192
separatorString += ';';
@@ -250,7 +245,6 @@ export default class VariableDeclaration extends NodeBase {
250245
lastSeparatorPos,
251246
actualContentEnd!,
252247
renderedContentEnd,
253-
!isNoStatement,
254248
systemPatternExports,
255249
options
256250
);

src/ast/nodes/VariableDeclarator.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1+
import MagicString from 'magic-string';
2+
import { BLANK } from '../../utils/blank';
3+
import {
4+
findFirstOccurrenceOutsideComment,
5+
findNonWhiteSpace,
6+
RenderOptions
7+
} from '../../utils/renderHelpers';
8+
import { HasEffectsContext, InclusionContext } from '../ExecutionContext';
19
import { ObjectPath } from '../utils/PathTracker';
210
import { UNDEFINED_EXPRESSION } from '../values';
311
import * as NodeType from './NodeType';
4-
import { ExpressionNode, NodeBase } from './shared/Node';
12+
import { ExpressionNode, IncludeChildren, NodeBase } from './shared/Node';
513
import { PatternNode } from './shared/Pattern';
614

715
export default class VariableDeclarator extends NodeBase {
@@ -16,4 +24,43 @@ export default class VariableDeclarator extends NodeBase {
1624
deoptimizePath(path: ObjectPath) {
1725
this.id.deoptimizePath(path);
1826
}
27+
28+
hasEffects(context: HasEffectsContext): boolean {
29+
return this.id.hasEffects(context) || (this.init !== null && this.init.hasEffects(context));
30+
}
31+
32+
include(context: InclusionContext, includeChildrenRecursively: IncludeChildren) {
33+
this.included = true;
34+
if (includeChildrenRecursively || this.id.shouldBeIncluded(context)) {
35+
this.id.include(context, includeChildrenRecursively);
36+
}
37+
if (this.init) {
38+
this.init.include(context, includeChildrenRecursively);
39+
}
40+
}
41+
42+
includeAllDeclaredVariables(
43+
context: InclusionContext,
44+
includeChildrenRecursively: IncludeChildren
45+
): void {
46+
this.included = true;
47+
this.id.include(context, includeChildrenRecursively);
48+
}
49+
50+
render(code: MagicString, options: RenderOptions) {
51+
const renderId = this.id.included;
52+
if (renderId) {
53+
this.id.render(code, options);
54+
} else {
55+
const operatorPos = findFirstOccurrenceOutsideComment(code.original, '=', this.id.end);
56+
code.remove(this.start, findNonWhiteSpace(code.original, operatorPos + 1));
57+
}
58+
if (this.init) {
59+
this.init.render(
60+
code,
61+
options,
62+
renderId ? BLANK : { renderedParentType: NodeType.ExpressionStatement }
63+
);
64+
}
65+
}
1966
}

src/ast/nodes/shared/Node.ts

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import { getAndCreateKeys, keys } from '../../keys';
1515
import ChildScope from '../../scopes/ChildScope';
1616
import { ObjectPath, PathTracker } from '../../utils/PathTracker';
1717
import { LiteralValueOrUnknown, UnknownValue, UNKNOWN_EXPRESSION } from '../../values';
18-
import LocalVariable from '../../variables/LocalVariable';
1918
import Variable from '../../variables/Variable';
2019
import * as NodeType from '../NodeType';
2120
import SpreadElement from '../SpreadElement';
@@ -42,16 +41,13 @@ export interface Node extends Entity {
4241
type: string;
4342
variable?: Variable | null;
4443

44+
addExportedVariables(variables: Variable[], exportNamesByVariable: Map<Variable, string[]>): void;
45+
4546
/**
4647
* Called once all nodes have been initialised and the scopes have been populated.
4748
*/
4849
bind(): void;
4950

50-
/**
51-
* Declare a new variable with the optional initialisation.
52-
*/
53-
declare(kind: string, init: ExpressionEntity | null): LocalVariable[];
54-
5551
/**
5652
* Determine if this Node would have an effect on the bundle.
5753
* This is usually true for already included nodes. Exceptions are e.g. break statements
@@ -72,10 +68,11 @@ export interface Node extends Entity {
7268
* declarations to only include nodes for declarators that have an effect. Necessary
7369
* for for-loops that do not use a declared loop variable.
7470
*/
75-
includeWithAllDeclaredVariables(
76-
includeChildrenRecursively: IncludeChildren,
77-
context: InclusionContext
71+
includeAllDeclaredVariables(
72+
context: InclusionContext,
73+
includeChildrenRecursively: IncludeChildren
7874
): void;
75+
7976
render(code: MagicString, options: RenderOptions, nodeRenderOptions?: NodeRenderOptions): void;
8077

8178
/**
@@ -118,6 +115,11 @@ export class NodeBase implements ExpressionNode {
118115
this.context.magicString.addSourcemapLocation(this.end);
119116
}
120117

118+
addExportedVariables(
119+
_variables: Variable[],
120+
_exportNamesByVariable: Map<Variable, string[]>
121+
): void {}
122+
121123
/**
122124
* Override this to bind assignments to variables and do any initialisations that
123125
* require the scopes to be populated with variables.
@@ -143,10 +145,6 @@ export class NodeBase implements ExpressionNode {
143145
this.scope = parentScope;
144146
}
145147

146-
declare(_kind: string, _init: ExpressionEntity | null): LocalVariable[] {
147-
return [];
148-
}
149-
150148
deoptimizePath(_path: ObjectPath) {}
151149

152150
getLiteralValueAtPath(
@@ -209,19 +207,19 @@ export class NodeBase implements ExpressionNode {
209207
}
210208
}
211209

210+
includeAllDeclaredVariables(
211+
context: InclusionContext,
212+
includeChildrenRecursively: IncludeChildren
213+
): void {
214+
this.include(context, includeChildrenRecursively);
215+
}
216+
212217
includeCallArguments(context: InclusionContext, args: (ExpressionNode | SpreadElement)[]): void {
213218
for (const arg of args) {
214219
arg.include(context, false);
215220
}
216221
}
217222

218-
includeWithAllDeclaredVariables(
219-
includeChildrenRecursively: IncludeChildren,
220-
context: InclusionContext
221-
) {
222-
this.include(context, includeChildrenRecursively);
223-
}
224-
225223
/**
226224
* Override to perform special initialisation steps after the scope is initialised
227225
*/
@@ -274,10 +272,6 @@ export class NodeBase implements ExpressionNode {
274272
shouldBeIncluded(context: InclusionContext): boolean {
275273
return this.included || (!context.brokenFlow && this.hasEffects(createHasEffectsContext()));
276274
}
277-
278-
toString() {
279-
return this.context.code.slice(this.start, this.end);
280-
}
281275
}
282276

283277
export { NodeBase as StatementBase };
@@ -290,3 +284,7 @@ export function locateNode(node: Node) {
290284

291285
return location;
292286
}
287+
288+
export function logNode(node: Node) {
289+
console.log(node.context.code.slice(node.start, node.end));
290+
}

src/ast/nodes/shared/Pattern.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { WritableEntity } from '../../Entity';
2-
import Variable from '../../variables/Variable';
2+
import LocalVariable from '../../variables/LocalVariable';
3+
import { ExpressionEntity } from './Expression';
34
import { Node } from './Node';
45

56
export interface PatternNode extends WritableEntity, Node {
6-
addExportedVariables(variables: Variable[], exportNamesByVariable: Map<Variable, string[]>): void;
7+
declare(kind: string, init: ExpressionEntity | null): LocalVariable[];
78
}

test/chunking-form/samples/preserve-entry-signatures/false/_expected/amd/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ define(['require', 'exports'], function (require, exports) { 'use strict';
22

33
const shared = 'shared';
44

5-
const dynamic = new Promise(function (resolve, reject) { require(['./generated-dynamic'], resolve, reject) });
5+
new Promise(function (resolve, reject) { require(['./generated-dynamic'], resolve, reject) });
66

77
globalThis.sharedStatic = shared;
88

0 commit comments

Comments
 (0)
0