Skip to content
This repository was archived by the owner on Oct 1, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Object of webpack options. Just `require` in the options from your `webpack.conf

```javascript
{
mode: 'development',
module: {
rules: [
{
Expand All @@ -92,7 +93,9 @@ Object of webpack options. Just `require` in the options from your `webpack.conf
}
```

Source maps are always enabled unless explicitly disabled by specifying `devtool: false`.
Source maps are **always enabled** unless explicitly disabled by specifying `devtool: false`.

Webpack [mode](https://webpack.js.org/configuration/mode/) is set to `development` if not present. You can set `mode` to "development", "production" or "none".

### use babelrc

Expand Down Expand Up @@ -172,6 +175,18 @@ DEBUG=cypress:webpack:stats

Use the [version of Node that matches Cypress](https://github.com/cypress-io/cypress/blob/develop/.node-version).

Build the typescript files:

```shell
yarn build
```

Watch the typescript files and rebuild on file change:

```shell
yarn build --watch
```

Run all tests once:

```shell
Expand Down
7 changes: 2 additions & 5 deletions cypress/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,11 @@
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)

const webpack = require('../../')

// const webpackOptions = require('@packages/runner/webpack.config.ts').default
const webpackPreprocessor = require('../../')

/**
* @type {Cypress.PluginConfig}
*/
module.exports = (on) => {
// on('file:preprocessor', webpack({ webpackOptions }))
on('file:preprocessor', webpack({ }))
on('file:preprocessor', webpackPreprocessor())
}
49 changes: 29 additions & 20 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import * as webpack from 'webpack'
import * as Promise from 'bluebird'
import * as events from 'events'

import * as _ from 'lodash'
import * as webpack from 'webpack'
import { createDeferred } from './deferred'

const path = require('path')
const debug = require('debug')('cypress:webpack')
const debugStats = require('debug')('cypress:webpack:stats')

const stubbableRequire = require('./stubbable-require')

type FilePath = string

// bundle promises from input spec filename to output bundled file paths
Expand All @@ -21,16 +19,17 @@ const getDefaultWebpackOptions = (): webpack.Configuration => {
debug('load default options')

return {
mode: 'development',
module: {
rules: [
{
test: /\.jsx?$/,
exclude: [/node_modules/],
use: [
{
loader: stubbableRequire.resolve('babel-loader'),
loader: 'babel-loader',
options: {
presets: [stubbableRequire.resolve('@babel/preset-env')],
presets: ['@babel/preset-env'],
},
},
],
Expand Down Expand Up @@ -123,34 +122,45 @@ const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): F
return bundles[filePath]
}

// user can override the default options
let webpackOptions: webpack.Configuration = options.webpackOptions || getDefaultWebpackOptions()
const watchOptions = options.watchOptions || {}
const defaultWebpackOptions = getDefaultWebpackOptions()

debug('webpackOptions: %o', webpackOptions)
debug('watchOptions: %o', watchOptions)

const entry = [filePath].concat(options.additionalEntries || [])
// we're provided a default output path that lives alongside Cypress's
// app data files so we don't have to worry about where to put the bundled
// file on disk
const outputPath = path.extname(file.outputPath) === '.js'
? file.outputPath
: `${file.outputPath}.js`

// we need to set entry and output
webpackOptions = Object.assign(webpackOptions, {
const entry = [filePath].concat(options.additionalEntries || [])

const watchOptions = options.watchOptions || {}

// user can override the default options
const webpackOptions: webpack.Configuration = _
.chain(options.webpackOptions)
.defaultTo(defaultWebpackOptions)
.defaults({
mode: defaultWebpackOptions.mode,
})
.assign({
// we need to set entry and output
entry,
output: {
path: path.dirname(outputPath),
filename: path.basename(outputPath),
},
})
.tap((opts) => {
if (opts.devtool !== false) {
debug('setting devtool to inline-source-map')

if (webpackOptions.devtool !== false) {
webpackOptions.devtool = 'inline-source-map'
}
opts.devtool = 'inline-source-map'
}
})
.value() as any

debug('webpackOptions: %o', webpackOptions)
debug('watchOptions: %o', watchOptions)
debug(`input: ${filePath}`)
debug(`output: ${outputPath}`)

Expand Down Expand Up @@ -277,8 +287,7 @@ const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): F
}
}

// provide a clone of the default options, lazy-loading them
// so they aren't required unless the user utilizes them
// provide a clone of the default options
Object.defineProperty(preprocessor, 'defaultOptions', {
get () {
debug('get default options')
Expand Down
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
"secure": "nsp check",
"semantic-release": "semantic-release",
"size": "npm pack --dry",
"pretest": "npm run lint && npm run build",
"test": "npm run test-unit && npm run test-e2e",
"pretest": "yarn lint && yarn build",
"test": "yarn test-unit && yarn test-e2e",
"test-debug": "node --inspect --debug-brk ./node_modules/.bin/_mocha",
"test-e2e": "mocha test/e2e/*.spec.js",
"test-unit": "mocha test/unit/*.spec.js",
"test-watch": "chokidar '*.js' 'test/unit/*.js' -c 'npm run test-unit'",
"test-watch": "yarn test-unit & chokidar '*.js' 'test/unit/*.js' -c 'yarn test-unit'",
"types": "tsc --noEmit"
},
"husky": {
Expand All @@ -29,7 +29,8 @@
},
"dependencies": {
"bluebird": "3.7.1",
"debug": "4.1.1"
"debug": "4.1.1",
"lodash": "4.17.15"
},
"devDependencies": {
"@babel/core": "^7.0.1",
Expand Down
5 changes: 0 additions & 5 deletions stubbable-require.ts

This file was deleted.

7 changes: 6 additions & 1 deletion test/e2e/compilation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ describe('webpack preprocessor - e2e', () => {
})

it('correctly preprocesses the file', () => {
return preprocessor()(file).then(() => {
const options = preprocessor.defaultOptions

// our snapshot is minified
options.webpackOptions.mode = 'production'

return preprocessor(options)(file).then(() => {
snapshot(fs.readFileSync(outputPath).toString())
})
})
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/e2e.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const glob = require('fast-glob')

describe('can test', async () => {
// runs every test in cypress/tests/e2e as its own test
// the comment above the test will determince the assertion on the results
// the comment above the test will determine the assertion on the results
glob.sync(path.join(__dirname, '../../cypress/tests/e2e/**/*'))
.map((v) => {
const filename = path.relative(process.cwd(), v)
Expand Down
100 changes: 62 additions & 38 deletions test/unit/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ mockery.enable({
mockery.registerMock('webpack', webpack)

const preprocessor = require('../../dist/index')
const stubbableRequire = require('../../dist/stubbable-require')

describe('webpack preprocessor', function () {
beforeEach(function () {
Expand Down Expand Up @@ -107,27 +106,33 @@ describe('webpack preprocessor', function () {

it('specifies the entry file', function () {
return this.run().then(() => {
expect(webpack.lastCall.args[0].entry).to.eql([this.file.filePath])
expect(webpack).to.be.calledWithMatch({
entry: [this.file.filePath],
})
})
})

it('includes additional entry files', function () {
return this.run({
additionalEntries: ['entry-1.js', 'entry-2.js'],
}).then(() => {
expect(webpack.lastCall.args[0].entry).to.eql([
this.file.filePath,
'entry-1.js',
'entry-2.js',
])
expect(webpack).to.be.calledWithMatch({
entry: [
this.file.filePath,
'entry-1.js',
'entry-2.js',
],
})
})
})

it('specifies output path and filename', function () {
return this.run().then(() => {
expect(webpack.lastCall.args[0].output).to.eql({
path: 'output',
filename: 'output.js',
expect(webpack).to.be.calledWithMatch({
output: {
path: 'output',
filename: 'output.js',
},
})
})
})
Expand All @@ -143,17 +148,53 @@ describe('webpack preprocessor', function () {
})
})

it('enables inline source maps', function () {
return this.run().then(() => {
expect(webpack.lastCall.args[0].devtool).to.equal('inline-source-map')
describe('devtool', function () {
it('enables inline source maps', function () {
return this.run().then(() => {
expect(webpack).to.be.calledWithMatch({
devtool: 'inline-source-map',
})
})
})

it('does not enable inline source maps when devtool is false', function () {
const options = { webpackOptions: { devtool: false } }

return this.run(options).then(() => {
expect(webpack).to.be.calledWithMatch({
devtool: false,
})
})
})

it('always sets devtool even when mode is "production"', function () {
const options = { webpackOptions: { mode: 'production' } }

return this.run(options).then(() => {
expect(webpack).to.be.calledWithMatch({
devtool: 'inline-source-map',
})
})
})
})

it('does not enable inline source maps when devtool is false', function () {
const options = { webpackOptions: { devtool: false } }
describe('mode', function () {
it('sets mode to development by default', function () {
return this.run().then(() => {
expect(webpack).to.be.calledWithMatch({
mode: 'development',
})
})
})

return this.run(options).then(() => {
expect(webpack.lastCall.args[0].devtool).to.be.false
it('follows user mode if present', function () {
const options = { webpackOptions: { mode: 'production' } }

return this.run(options).then(() => {
expect(webpack).to.be.calledWithMatch({
mode: 'production',
})
})
})
})

Expand All @@ -178,7 +219,7 @@ describe('webpack preprocessor', function () {
const options = { watchOptions: { poll: true } }

return this.run(options).then(() => {
expect(this.compilerApi.watch.lastCall.args[0]).to.eql({
expect(this.compilerApi.watch).to.be.calledWith({
poll: true,
})
})
Expand Down Expand Up @@ -252,26 +293,9 @@ describe('webpack preprocessor', function () {
const options = { webpackOptions: { module: { rules: [] } } }

return this.run(options).then(() => {
expect(webpack.lastCall.args[0].module).to.equal(options.webpackOptions.module)
})
})

it('requires babel dependencies when default options are used', function () {
sinon.spy(stubbableRequire, 'resolve')

return this.run().then(() => {
expect(stubbableRequire.resolve).to.be.calledWith('babel-loader')
expect(stubbableRequire.resolve).to.be.calledWith('@babel/preset-env')
})
})

it('does not requires babel dependencies when user options are non-default', function () {
sinon.spy(stubbableRequire, 'resolve')
const options = { webpackOptions: { module: { rules: [] } } }

return this.run(options).then(() => {
expect(stubbableRequire.resolve).not.to.be.calledWith('babel-loader')
expect(stubbableRequire.resolve).not.to.be.calledWith('@babel/preset-env')
expect(webpack).to.be.calledWithMatch({
module: options.webpackOptions.module,
})
})
})
})
Expand Down