1
1
'use strict'
2
- const relative = require ( 'path' ) . relative
2
+ const path = require ( 'path' )
3
3
const Analyzer = require ( '@goto-bus-stop/common-shake' ) . Analyzer
4
+ const evaluateConst = require ( '@goto-bus-stop/common-shake' ) . evaluateConst
4
5
const transformAst = require ( 'transform-ast' )
5
6
const wrapComment = require ( 'wrap-comment' )
6
7
const through = require ( 'through2' )
@@ -17,9 +18,9 @@ module.exports = function commonShake (b, opts) {
17
18
const seen = { }
18
19
opts = Object . assign ( {
19
20
verbose : false ,
20
- onExportDelete ( path , name ) {
21
+ onExportDelete ( source , name ) {
21
22
if ( opts . verbose || opts . v ) {
22
- console . warn ( 'common-shake: removed' , `\`${ name } \`` , 'in' , relative ( basedir , path ) )
23
+ console . warn ( 'common-shake: removed' , `\`${ name } \`` , 'in' , path . relative ( basedir , source ) )
23
24
}
24
25
} ,
25
26
onModuleBailout ( resource , reasons ) {
@@ -29,15 +30,15 @@ module.exports = function commonShake (b, opts) {
29
30
seen [ resource . resource + reason . reason ] = true
30
31
const loc = reason . loc . start
31
32
const source = reason . source || resource . resource
32
- console . warn ( 'common-shake: bailed out: ' , reason . reason , 'in' , `${ relative ( basedir , source ) } :${ loc . line } :${ loc . column } ` )
33
+ console . warn ( 'common-shake: bailed out: ' , reason . reason , 'in' , `${ path . relative ( basedir , source ) } :${ loc . line } :${ loc . column } ` )
33
34
} )
34
35
}
35
36
} ,
36
37
onGlobalBailout ( reasons ) {
37
38
if ( opts . verbose || opts . v ) {
38
39
reasons . forEach ( ( reason ) => {
39
40
const loc = reason . loc . start
40
- console . warn ( 'common-shake: GLOBAL BAILOUT:' , reason . reason , 'in' , `${ relative ( basedir , reason . source ) } :${ loc . line } :${ loc . column } ` )
41
+ console . warn ( 'common-shake: GLOBAL BAILOUT:' , reason . reason , 'in' , `${ path . relative ( basedir , reason . source ) } :${ loc . line } :${ loc . column } ` )
41
42
} )
42
43
}
43
44
}
@@ -48,11 +49,29 @@ module.exports = function commonShake (b, opts) {
48
49
addHooks ( )
49
50
b . on ( 'reset' , addHooks )
50
51
function addHooks ( ) {
51
- b . pipeline . get ( 'label' ) . unshift ( createStream ( opts ) )
52
+ const packages = new Map ( )
53
+ const aliases = new Map ( )
54
+ b . _mdeps . on ( 'package' , ( pkg ) => {
55
+ packages . set ( pkg . __dirname , pkg )
56
+ } )
57
+ b . _mdeps . on ( 'file' , ( file , id ) => {
58
+ aliases . set ( id , file )
59
+ } )
60
+ b . pipeline . get ( 'label' ) . unshift ( createStream ( opts , {
61
+ getSideEffects ( name ) {
62
+ const file = aliases . get ( name ) || name
63
+ let pkg
64
+ let dir = file
65
+ while ( ! pkg && ( dir = path . dirname ( dir ) ) ) {
66
+ pkg = packages . get ( dir )
67
+ }
68
+ return pkg && pkg . sideEffects === false ? false : true
69
+ }
70
+ } ) )
52
71
}
53
72
}
54
73
55
- function createStream ( opts ) {
74
+ function createStream ( opts , api ) {
56
75
const analyzer = new Analyzer ( )
57
76
58
77
const rows = new Map ( )
@@ -87,7 +106,9 @@ function createStream (opts) {
87
106
} , ( node ) => {
88
107
if ( node . type === 'Program' ) ast = node
89
108
} )
90
- analyzer . run ( ast , index )
109
+ analyzer . run ( ast , index , {
110
+ sideEffects : api . getSideEffects ( row . file )
111
+ } )
91
112
92
113
Object . keys ( row . indexDeps ) . forEach ( ( name ) => {
93
114
if ( row . indexDeps [ name ] ) {
@@ -124,13 +145,15 @@ function createStream (opts) {
124
145
// If this module was a duplicate of another module,
125
146
// the original module will have been rewritten already.
126
147
if ( row . dedupe ) {
127
- this . push ( row )
128
148
return
129
149
}
130
150
131
151
if ( module . bailouts ) {
132
152
opts . onModuleBailout ( module , module . bailouts )
133
- this . push ( row )
153
+ return
154
+ }
155
+
156
+ if ( module . getInfo ( ) . removeImport ) {
134
157
return
135
158
}
136
159
@@ -142,15 +165,6 @@ function createStream (opts) {
142
165
}
143
166
} )
144
167
145
- const transformed = string . toString ( )
146
- if ( opts . sourceMap ) {
147
- row . source = transformed + '\n' + convertSourceMap . fromObject ( string . map ) . toComment ( )
148
- } else {
149
- row . source = transformed
150
- }
151
-
152
- this . push ( row )
153
-
154
168
// Check if a name was used in this module, or
155
169
// in any of this module's deduped versions.
156
170
function isUsed ( name ) {
@@ -167,6 +181,44 @@ function createStream (opts) {
167
181
}
168
182
} )
169
183
184
+ rows . forEach ( ( row , index ) => {
185
+ const module = analyzer . getModule ( index )
186
+ if ( module && module . getInfo ( ) . removeImport ) {
187
+ return
188
+ }
189
+
190
+ if ( row . dedupe || module . bailouts ) {
191
+ this . push ( row )
192
+ return
193
+ }
194
+
195
+ const string = strings . get ( index )
196
+
197
+ Object . keys ( row . indexDeps ) . forEach ( ( depName ) => {
198
+ const depModule = analyzer . getModule ( row . indexDeps [ depName ] )
199
+ if ( depModule && depModule . getInfo ( ) . removeImport ) {
200
+ delete row . indexDeps [ depName ]
201
+ delete row . deps [ depName ]
202
+ const imports = module . requireNodes . get ( depName ) || [ ]
203
+ imports . forEach ( ( node ) => {
204
+ // We can replace this with `undefined` because this will not be a .property.
205
+ // If it was a require('mod').property, the .property would be marked as used,
206
+ // and the module's import would not be removable
207
+ node . edit . update ( `void 0 ${ wrapComment ( node . getSource ( ) ) } ` )
208
+ } )
209
+ }
210
+ } )
211
+
212
+ const transformed = string . toString ( )
213
+ if ( opts . sourceMap ) {
214
+ row . source = transformed + '\n' + convertSourceMap . fromObject ( string . map ) . toComment ( )
215
+ } else {
216
+ row . source = transformed
217
+ }
218
+
219
+ this . push ( row )
220
+ } )
221
+
170
222
next ( )
171
223
}
172
224
0 commit comments