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