1
- const cloneDeep = require ( 'lodash.clonedeep' )
2
1
const path = require ( 'path' )
3
2
const webpack = require ( 'webpack' )
4
- const log = require ( 'debug' ) ( 'cypress:webpack' )
3
+ const debug = require ( 'debug' ) ( 'cypress:webpack' )
5
4
6
5
const createDeferred = require ( './deferred' )
6
+ const stubbableRequire = require ( './stubbable-require' )
7
7
8
8
const bundles = { }
9
9
10
- // by default, we transform JavaScript supported by @babel/preset-env
11
- const defaultBabelLoaderRules = ( ) => {
12
- return [
13
- {
14
- test : / \. j s ? $ / ,
15
- exclude : [ / n o d e _ m o d u l e s / ] ,
16
- use : [
17
- {
18
- loader : require . resolve ( 'babel-loader' ) ,
19
- options : {
20
- presets : [ require . resolve ( '@babel/preset-env' ) ] ,
21
- } ,
22
- } ,
23
- ] ,
24
- } ,
25
- ]
26
- }
27
-
28
10
// we don't automatically load the rules, so that the babel dependencies are
29
11
// not required if a user passes in their own configuration
30
- const defaultOptions = {
31
- webpackOptions : {
12
+ const getDefaultWebpackOptions = ( ) => {
13
+ debug ( 'load default options' )
14
+
15
+ return {
32
16
module : {
33
- rules : [ ] ,
17
+ rules : [
18
+ {
19
+ test : / \. j s x ? $ / ,
20
+ exclude : [ / n o d e _ m o d u l e s / ] ,
21
+ use : [
22
+ {
23
+ loader : stubbableRequire . resolve ( 'babel-loader' ) ,
24
+ options : {
25
+ presets : [ stubbableRequire . resolve ( '@babel/preset-env' ) ] ,
26
+ } ,
27
+ } ,
28
+ ] ,
29
+ } ,
30
+ ] ,
34
31
} ,
35
- } ,
36
- watchOptions : { } ,
32
+ }
37
33
}
38
34
39
35
// export a function that returns another function, making it easy for users
@@ -42,7 +38,7 @@ const defaultOptions = {
42
38
// on('file:preprocessor', webpack(options))
43
39
//
44
40
const preprocessor = ( options = { } ) => {
45
- log ( 'user options:' , options )
41
+ debug ( 'user options:' , options )
46
42
47
43
// we return function that accepts the arguments provided by
48
44
// the event 'file:preprocessor'
@@ -57,24 +53,24 @@ const preprocessor = (options = {}) => {
57
53
// the supported file and spec file to be requested again
58
54
return ( file ) => {
59
55
const filePath = file . filePath
60
- log ( 'get' , filePath )
56
+
57
+ debug ( 'get' , filePath )
61
58
62
59
// since this function can get called multiple times with the same
63
60
// filePath, we return the cached bundle promise if we already have one
64
61
// since we don't want or need to re-initiate webpack for it
65
62
if ( bundles [ filePath ] ) {
66
- log ( `already have bundle for ${ filePath } ` )
63
+ debug ( `already have bundle for ${ filePath } ` )
64
+
67
65
return bundles [ filePath ]
68
66
}
69
67
70
68
// user can override the default options
71
- let webpackOptions = Object . assign ( { } , defaultOptions . webpackOptions , options . webpackOptions )
72
- // here is where we load the default rules if the user has not passed
73
- // in their own configuration
74
- if ( webpackOptions . module . rules === defaultOptions . webpackOptions ) {
75
- webpackOptions . module . rules = defaultBabelLoaderRules ( )
76
- }
77
- let watchOptions = Object . assign ( { } , defaultOptions . watchOptions , options . watchOptions )
69
+ let webpackOptions = options . webpackOptions || getDefaultWebpackOptions ( )
70
+ const watchOptions = options . watchOptions || { }
71
+
72
+ debug ( 'webpackOptions: %o' , webpackOptions )
73
+ debug ( 'watchOptions: %o' , watchOptions )
78
74
79
75
// we're provided a default output path that lives alongside Cypress's
80
76
// app data files so we don't have to worry about where to put the bundled
@@ -90,8 +86,12 @@ const preprocessor = (options = {}) => {
90
86
} ,
91
87
} )
92
88
93
- log ( `input: ${ filePath } ` )
94
- log ( `output: ${ outputPath } ` )
89
+ if ( webpackOptions . devtool !== false ) {
90
+ webpackOptions . devtool = 'inline-source-map'
91
+ }
92
+
93
+ debug ( `input: ${ filePath } ` )
94
+ debug ( `output: ${ outputPath } ` )
95
95
96
96
const compiler = webpack ( webpackOptions )
97
97
@@ -108,7 +108,7 @@ const preprocessor = (options = {}) => {
108
108
err . filePath = filePath
109
109
// backup the original stack before it's potentially modified by bluebird
110
110
err . originalStack = err . stack
111
- log ( `errored bundling ${ outputPath } ` , err )
111
+ debug ( `errored bundling ${ outputPath } ` , err )
112
112
latestBundle . reject ( err )
113
113
}
114
114
@@ -129,11 +129,11 @@ const preprocessor = (options = {}) => {
129
129
130
130
// these stats are really only useful for debugging
131
131
if ( jsonStats . warnings . length > 0 ) {
132
- log ( `warnings for ${ outputPath } ` )
133
- log ( jsonStats . warnings )
132
+ debug ( `warnings for ${ outputPath } ` )
133
+ debug ( jsonStats . warnings )
134
134
}
135
135
136
- log ( 'finished bundling' , outputPath )
136
+ debug ( 'finished bundling' , outputPath )
137
137
// resolve with the outputPath so Cypress knows where to serve
138
138
// the file from
139
139
latestBundle . resolve ( outputPath )
@@ -143,12 +143,12 @@ const preprocessor = (options = {}) => {
143
143
const plugin = { name : 'CypressWebpackPreprocessor' }
144
144
145
145
const onCompile = ( ) => {
146
- log ( 'compile' , filePath )
146
+ debug ( 'compile' , filePath )
147
147
// we overwrite the latest bundle, so that a new call to this function
148
148
// returns a promise that resolves when the bundling is finished
149
149
latestBundle = createDeferred ( )
150
150
bundles [ filePath ] = latestBundle . promise . tap ( ( ) => {
151
- log ( '- compile finished for' , filePath )
151
+ debug ( '- compile finished for' , filePath )
152
152
// when the bundling is finished, emit 'rerun' to let Cypress
153
153
// know to rerun the spec
154
154
file . emit ( 'rerun' )
@@ -158,7 +158,7 @@ const preprocessor = (options = {}) => {
158
158
// when we should watch, we hook into the 'compile' hook so we know when
159
159
// to rerun the tests
160
160
if ( file . shouldWatch ) {
161
- log ( 'watching' )
161
+ debug ( 'watching' )
162
162
163
163
if ( compiler . hooks ) {
164
164
compiler . hooks . compile . tap ( plugin , onCompile )
@@ -172,7 +172,7 @@ const preprocessor = (options = {}) => {
172
172
// when the spec or project is closed, we need to clean up the cached
173
173
// bundle promise and stop the watcher via `bundler.close()`
174
174
file . on ( 'close' , ( ) => {
175
- log ( 'close' , filePath )
175
+ debug ( 'close' , filePath )
176
176
delete bundles [ filePath ]
177
177
178
178
if ( file . shouldWatch ) {
@@ -186,14 +186,16 @@ const preprocessor = (options = {}) => {
186
186
}
187
187
}
188
188
189
- // provide a clone of the default options, making sure to lazy-load
190
- // babel dependencies so that they aren't required unless the user
191
- // utilizes them
189
+ // provide a clone of the default options, lazy-loading them
190
+ // so they aren't required unless the user utilizes them
192
191
Object . defineProperty ( preprocessor , 'defaultOptions' , {
193
192
get ( ) {
194
- const clonedDefaults = cloneDeep ( defaultOptions )
195
- clonedDefaults . webpackOptions . module . rules = defaultBabelLoaderRules ( )
196
- return clonedDefaults
193
+ debug ( 'get default options' )
194
+
195
+ return {
196
+ webpackOptions : getDefaultWebpackOptions ( ) ,
197
+ watchOptions : { } ,
198
+ }
197
199
} ,
198
200
} )
199
201
0 commit comments