Skip to content
This repository was archived by the owner on Oct 1, 2020. It is now read-only.

Commit b1a3749

Browse files
committed
Merge branch 'release' into issue-50-source-maps
2 parents c661012 + 49b4f48 commit b1a3749

File tree

4 files changed

+103
-59
lines changed

4 files changed

+103
-59
lines changed

index.js

Lines changed: 49 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,35 @@
1-
const cloneDeep = require('lodash.clonedeep')
21
const path = require('path')
32
const webpack = require('webpack')
4-
const log = require('debug')('cypress:webpack')
3+
const debug = require('debug')('cypress:webpack')
54

65
const createDeferred = require('./deferred')
6+
const stubbableRequire = require('./stubbable-require')
77

88
const bundles = {}
99

10-
// by default, we transform JavaScript supported by @babel/preset-env
11-
const defaultBabelLoaderRules = () => {
12-
return [
13-
{
14-
test: /\.js?$/,
15-
exclude: [/node_modules/],
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-
2810
// we don't automatically load the rules, so that the babel dependencies are
2911
// 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 {
3216
module: {
33-
rules: [],
17+
rules: [
18+
{
19+
test: /\.jsx?$/,
20+
exclude: [/node_modules/],
21+
use: [
22+
{
23+
loader: stubbableRequire.resolve('babel-loader'),
24+
options: {
25+
presets: [stubbableRequire.resolve('@babel/preset-env')],
26+
},
27+
},
28+
],
29+
},
30+
],
3431
},
35-
},
36-
watchOptions: {},
32+
}
3733
}
3834

3935
// export a function that returns another function, making it easy for users
@@ -42,7 +38,7 @@ const defaultOptions = {
4238
// on('file:preprocessor', webpack(options))
4339
//
4440
const preprocessor = (options = {}) => {
45-
log('user options:', options)
41+
debug('user options:', options)
4642

4743
// we return function that accepts the arguments provided by
4844
// the event 'file:preprocessor'
@@ -57,24 +53,24 @@ const preprocessor = (options = {}) => {
5753
// the supported file and spec file to be requested again
5854
return (file) => {
5955
const filePath = file.filePath
60-
log('get', filePath)
56+
57+
debug('get', filePath)
6158

6259
// since this function can get called multiple times with the same
6360
// filePath, we return the cached bundle promise if we already have one
6461
// since we don't want or need to re-initiate webpack for it
6562
if (bundles[filePath]) {
66-
log(`already have bundle for ${filePath}`)
63+
debug(`already have bundle for ${filePath}`)
64+
6765
return bundles[filePath]
6866
}
6967

7068
// 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)
7874

7975
// we're provided a default output path that lives alongside Cypress's
8076
// app data files so we don't have to worry about where to put the bundled
@@ -94,8 +90,8 @@ const preprocessor = (options = {}) => {
9490
webpackOptions.devtool = 'inline-source-map'
9591
}
9692

97-
log(`input: ${filePath}`)
98-
log(`output: ${outputPath}`)
93+
debug(`input: ${filePath}`)
94+
debug(`output: ${outputPath}`)
9995

10096
const compiler = webpack(webpackOptions)
10197

@@ -112,7 +108,7 @@ const preprocessor = (options = {}) => {
112108
err.filePath = filePath
113109
// backup the original stack before it's potentially modified by bluebird
114110
err.originalStack = err.stack
115-
log(`errored bundling ${outputPath}`, err)
111+
debug(`errored bundling ${outputPath}`, err)
116112
latestBundle.reject(err)
117113
}
118114

@@ -133,11 +129,11 @@ const preprocessor = (options = {}) => {
133129

134130
// these stats are really only useful for debugging
135131
if (jsonStats.warnings.length > 0) {
136-
log(`warnings for ${outputPath}`)
137-
log(jsonStats.warnings)
132+
debug(`warnings for ${outputPath}`)
133+
debug(jsonStats.warnings)
138134
}
139135

140-
log('finished bundling', outputPath)
136+
debug('finished bundling', outputPath)
141137
// resolve with the outputPath so Cypress knows where to serve
142138
// the file from
143139
latestBundle.resolve(outputPath)
@@ -147,12 +143,12 @@ const preprocessor = (options = {}) => {
147143
const plugin = { name: 'CypressWebpackPreprocessor' }
148144

149145
const onCompile = () => {
150-
log('compile', filePath)
146+
debug('compile', filePath)
151147
// we overwrite the latest bundle, so that a new call to this function
152148
// returns a promise that resolves when the bundling is finished
153149
latestBundle = createDeferred()
154150
bundles[filePath] = latestBundle.promise.tap(() => {
155-
log('- compile finished for', filePath)
151+
debug('- compile finished for', filePath)
156152
// when the bundling is finished, emit 'rerun' to let Cypress
157153
// know to rerun the spec
158154
file.emit('rerun')
@@ -162,7 +158,7 @@ const preprocessor = (options = {}) => {
162158
// when we should watch, we hook into the 'compile' hook so we know when
163159
// to rerun the tests
164160
if (file.shouldWatch) {
165-
log('watching')
161+
debug('watching')
166162

167163
if (compiler.hooks) {
168164
compiler.hooks.compile.tap(plugin, onCompile)
@@ -176,7 +172,7 @@ const preprocessor = (options = {}) => {
176172
// when the spec or project is closed, we need to clean up the cached
177173
// bundle promise and stop the watcher via `bundler.close()`
178174
file.on('close', () => {
179-
log('close', filePath)
175+
debug('close', filePath)
180176
delete bundles[filePath]
181177

182178
if (file.shouldWatch) {
@@ -190,14 +186,16 @@ const preprocessor = (options = {}) => {
190186
}
191187
}
192188

193-
// provide a clone of the default options, making sure to lazy-load
194-
// babel dependencies so that they aren't required unless the user
195-
// utilizes them
189+
// provide a clone of the default options, lazy-loading them
190+
// so they aren't required unless the user utilizes them
196191
Object.defineProperty(preprocessor, 'defaultOptions', {
197192
get () {
198-
const clonedDefaults = cloneDeep(defaultOptions)
199-
clonedDefaults.webpackOptions.module.rules = defaultBabelLoaderRules()
200-
return clonedDefaults
193+
debug('get default options')
194+
195+
return {
196+
webpackOptions: getDefaultWebpackOptions(),
197+
watchOptions: {},
198+
}
201199
},
202200
})
203201

package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"secure": "nsp check",
3030
"size": "t=\"$(npm pack .)\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";",
3131
"test": "mocha",
32-
"test-watch": "chokidar '*.js' 'test/*.js' -c 'npm test'",
32+
"test-watch": "chokidar '*.js' 'test/*.js' -c 'mocha'",
3333
"semantic-release": "semantic-release pre && npm publish --access public && semantic-release post"
3434
},
3535
"devDependencies": {
@@ -68,8 +68,7 @@
6868
},
6969
"dependencies": {
7070
"bluebird": "3.5.0",
71-
"debug": "3.1.0",
72-
"lodash.clonedeep": "4.5.0"
71+
"debug": "3.1.0"
7372
},
7473
"release": {
7574
"verifyConditions": "condition-circle",

stubbable-require.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
resolve (dependency) {
3+
return require.resolve(dependency)
4+
},
5+
}

test/index_spec.js

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mockery.enable({
1515
mockery.registerMock('webpack', webpack)
1616

1717
const preprocessor = require('../index')
18+
const stubbableRequire = require('../stubbable-require')
1819

1920
describe('webpack preprocessor', function () {
2021
beforeEach(function () {
@@ -43,15 +44,14 @@ describe('webpack preprocessor', function () {
4344
on: sandbox.stub(),
4445
emit: sandbox.spy(),
4546
}
46-
this.options = {}
4747
this.util = {
4848
getOutputPath: sandbox.stub().returns(this.outputPath),
4949
fileUpdated: sandbox.spy(),
5050
onClose: sandbox.stub(),
5151
}
5252

53-
this.run = () => {
54-
return preprocessor(this.options)(this.file)
53+
this.run = (options, file = this.file) => {
54+
return preprocessor(options)(file)
5555
}
5656
})
5757

@@ -142,8 +142,9 @@ describe('webpack preprocessor', function () {
142142
it('includes watchOptions if provided', function () {
143143
this.file.shouldWatch = true
144144
this.compilerApi.watch.yields(null, this.statsApi)
145-
this.options.watchOptions = { poll: true }
146-
return this.run().then(() => {
145+
const options = { watchOptions: { poll: true } }
146+
147+
return this.run(options).then(() => {
147148
expect(this.compilerApi.watch.lastCall.args[0]).to.eql({
148149
poll: true,
149150
})
@@ -188,6 +189,47 @@ describe('webpack preprocessor', function () {
188189
expect(this.watchApi.close).not.to.be.called
189190
})
190191
})
192+
193+
it('uses default webpack options when no user options', function () {
194+
return this.run().then(() => {
195+
expect(webpack.lastCall.args[0].module.rules[0].use).to.have.length(1)
196+
expect(webpack.lastCall.args[0].module.rules[0].use[0].loader).to.be.a('string')
197+
})
198+
})
199+
200+
it('uses default options when no user webpack options', function () {
201+
return this.run({}).then(() => {
202+
expect(webpack.lastCall.args[0].module.rules[0].use).to.have.length(1)
203+
expect(webpack.lastCall.args[0].module.rules[0].use[0].loader).to.be.a('string')
204+
})
205+
})
206+
207+
it('does not use default options when user options are non-default', function () {
208+
const options = { webpackOptions: { module: { rules: [] } } }
209+
210+
return this.run(options).then(() => {
211+
expect(webpack.lastCall.args[0].module).to.equal(options.webpackOptions.module)
212+
})
213+
})
214+
215+
it('requires babel dependencies when default options are used', function () {
216+
sandbox.spy(stubbableRequire, 'resolve')
217+
218+
return this.run().then(() => {
219+
expect(stubbableRequire.resolve).to.be.calledWith('babel-loader')
220+
expect(stubbableRequire.resolve).to.be.calledWith('@babel/preset-env')
221+
})
222+
})
223+
224+
it('does not requires babel dependencies when user options are non-default', function () {
225+
sandbox.spy(stubbableRequire, 'resolve')
226+
const options = { webpackOptions: { module: { rules: [] } } }
227+
228+
return this.run(options).then(() => {
229+
expect(stubbableRequire.resolve).not.to.be.calledWith('babel-loader')
230+
expect(stubbableRequire.resolve).not.to.be.calledWith('@babel/preset-env')
231+
})
232+
})
191233
})
192234

193235
describe('when it errors', function () {

0 commit comments

Comments
 (0)