Skip to content

Commit

Permalink
Webpack v4 support (#211)
Browse files Browse the repository at this point in the history
resolves #209
  • Loading branch information
astorije authored and zinserjan committed Mar 18, 2018
1 parent 9f1929d commit 02864e2
Show file tree
Hide file tree
Showing 71 changed files with 344 additions and 320 deletions.
12 changes: 4 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,13 @@ branches:
language: node_js

node_js:
- "4"
- "6"

env:
- WEBPACK_VERSION=2 MOCHA_VERSION=2
- WEBPACK_VERSION=2 MOCHA_VERSION=3
- WEBPACK_VERSION=2 MOCHA_VERSION=4
- WEBPACK_VERSION=2 MOCHA_VERSION=5
- WEBPACK_VERSION=3 MOCHA_VERSION=3
- WEBPACK_VERSION=3 MOCHA_VERSION=4
- WEBPACK_VERSION=3 MOCHA_VERSION=5
- WEBPACK_VERSION=4 MOCHA_VERSION=2
- WEBPACK_VERSION=4 MOCHA_VERSION=3
- WEBPACK_VERSION=4 MOCHA_VERSION=4
- WEBPACK_VERSION=4 MOCHA_VERSION=5

before_script:
- "npm install webpack@$WEBPACK_VERSION"
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Let's use `npm link` to symlink the fork into your project.
$ npm link mocha-webpack
```

1. If your using webpack 2, you need to configure loader resolution in your webpack config, like below
1. You need to configure loader resolution in your webpack config, like below
```js
var path = require('path');

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ If any build errors happens, they will be shown like below
## Which version works with mocha-webpack?

mocha-webpack works with
- webpack in version `2.x.x` & `3.x.x`
- webpack in version `4.x.x`
- mocha in version `2.x.x`, `3.x.x`, `4.x.x` & `5.x.x`

## Installation
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/code-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ module.exports = {
```

In this config we add `istanbul-instrumenter-loader` only when we want coverage reports. The loader must be the first entry in the loaders array to ensure that it gets applied as last.
Alternatively you can also use the [`postLoaders` option](https://webpack.github.io/docs/configuration.html#module-preloaders-module-postloaders) when you are using webpack@1 or for webpack@2 the [`enforce` option](https://webpack.js.org/configuration/module/#rule-enforce).
Alternatively you can also use the [`enforce` option](https://webpack.js.org/configuration/module/#rule-enforce).

Another important detail is that the `include` option should be configured in the same way (but webpack compatible) as in the `package.json`. `istanbul-instrumenter-loader` does not respect the value in the package.json, that's why you need to configure it again.

Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@
"license": "MIT",
"peerDependencies": {
"mocha": ">=2.4.5 <=5",
"webpack": "^2.0.0 || ^3.0.0"
"webpack": "^4.0.0"
},
"devDependencies": {
"anymatch": "^1.3.0",
"babel-cli": "^6.5.1",
"babel-core": "^6.26.0",
"babel-eslint": "^7.2.3",
"babel-eslint": "^8.2.2",
"babel-loader": "~7.1.0",
"babel-plugin-istanbul": "^4.1.5",
"babel-plugin-lodash": "^3.2.10",
Expand All @@ -69,7 +69,7 @@
"css-loader": "~0.28.7",
"del": "^3.0.0",
"del-cli": "^1.1.0",
"eslint": "^3.1.0",
"eslint": "^4.19.0",
"eslint-config-airbnb-base": "^4.0.2",
"eslint-plugin-flowtype": "^2.29.1",
"eslint-plugin-flowtype-errors": "^1.5.0",
Expand All @@ -86,7 +86,7 @@
"nyc": "^11.3.0",
"sass-loader": "~6.0.0",
"sinon": "^4.0.1",
"webpack": "^3.7.1"
"webpack": "^4"
},
"dependencies": {
"babel-runtime": "^6.18.0",
Expand Down
1 change: 0 additions & 1 deletion src/MochaWebpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export type MochaWebpackOptions = {
};

export default class MochaWebpack {

/**
* Files to run test against
*
Expand Down
7 changes: 6 additions & 1 deletion src/cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ options.require.forEach((mod) => {

options.include = options.include.map(resolve);

options.webpackConfig = requireWebpackConfig(options.webpackConfig, requiresWebpackConfig, options.webpackEnv);
options.webpackConfig = requireWebpackConfig(
options.webpackConfig,
requiresWebpackConfig,
options.webpackEnv,
options.mode
);

const mochaWebpack = createMochaWebpack();

Expand Down
7 changes: 7 additions & 0 deletions src/cli/parseArgv.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,13 @@ const options = {
group: ADVANCED_GROUP,
default: false,
},
mode: {
type: 'string',
choices: ['development', 'production'],
describe: 'webpack mode to use',
group: BASIC_GROUP,
requiresArg: true,
},
'webpack-config': {
type: 'string',
describe: 'path to webpack-config file',
Expand Down
12 changes: 9 additions & 3 deletions src/cli/requireWebpackConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ function registerCompiler(moduleDescriptor) {
}
}

export default function requireWebpackConfig(webpackConfig, required, env) {
export default function requireWebpackConfig(webpackConfig, required, env, mode) {
const configPath = path.resolve(webpackConfig);
const configExtension = getConfigExtension(configPath);
let configFound = false;
let config;
let config = {};

if (fileExists(configPath)) {
// config exists, register compiler for non-js extensions
Expand All @@ -94,8 +94,10 @@ export default function requireWebpackConfig(webpackConfig, required, env) {
if (!configFound) {
if (required) {
throw new Error(`Webpack config could not be found: ${webpackConfig}`);
} else if (mode != null) {
config.mode = mode;
}
return {};
return config;
}

config = config.default || config;
Expand All @@ -104,6 +106,10 @@ export default function requireWebpackConfig(webpackConfig, required, env) {
config = config(env);
}

if (mode != null) {
config.mode = mode;
}

if (Array.isArray(config)) {
throw new Error('Passing multiple configs as an Array is not supported. Please provide a single config instead.');
}
Expand Down
34 changes: 18 additions & 16 deletions src/runner/TestRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ type Mocha = {
};

export default class TestRunner extends EventEmitter {

entries: Array<string>;
includes: Array<string>;
tmpPath: string;
Expand Down Expand Up @@ -73,7 +72,7 @@ export default class TestRunner extends EventEmitter {
let failures = 0;
const compiler: Compiler = createCompiler(config);

compiler.plugin('run', (c, cb) => {
compiler.hooks.run.tapAsync('mocha-webpack', (c, cb) => {
this.emit('webpack:start');
// $FlowFixMe
cb();
Expand All @@ -88,16 +87,20 @@ export default class TestRunner extends EventEmitter {
reject();
return;
}
const mocha = this.prepareMocha(config, webpackStats);
this.emit('mocha:begin');
try {
mocha.run((fails) => {
this.emit('mocha:finished', fails);
resolve(fails);
});
const mocha = this.prepareMocha(config, webpackStats);
this.emit('mocha:begin');
try {
mocha.run((fails) => {
this.emit('mocha:finished', fails);
resolve(fails);
});
} catch (e) {
this.emit('exception', e);
resolve(1);
}
} catch (e) {
this.emit('exception', e);
resolve(1);
reject(e);
}
});
compiler.run(noop);
Expand All @@ -123,10 +126,9 @@ export default class TestRunner extends EventEmitter {
};

const runMocha = () => {
// $FlowFixMe
const mocha = this.prepareMocha(config, stats);

try {
// $FlowFixMe
const mocha = this.prepareMocha(config, stats);
// unregister our custom exception handler (see declaration)
process.removeListener('uncaughtException', uncaughtExceptionListener);

Expand Down Expand Up @@ -156,7 +158,7 @@ export default class TestRunner extends EventEmitter {
const compiler = createCompiler(config);
registerInMemoryCompiler(compiler);
// register webpack start callback
compiler.plugin('watch-run', (w, cb) => {
compiler.hooks.watchRun.tapAsync('mocha-webpack', (c, cb) => {
// check if mocha tests are still running, abort them and start compiling
if (mochaRunner) {
compilationScheduler = () => {
Expand Down Expand Up @@ -256,7 +258,7 @@ export default class TestRunner extends EventEmitter {
plugins.push(buildProgressPlugin());
}

const userLoaders = _.get(webpackConfig, 'module.rules', _.get(webpackConfig, 'module.loaders', []));
const userLoaders = _.get(webpackConfig, 'module.rules', []);
userLoaders.unshift(
{
test: entryPath,
Expand All @@ -282,7 +284,7 @@ export default class TestRunner extends EventEmitter {
entry: entryPath,
module: {
...(webpackConfig: any).module,
[_.has(webpackConfig, 'module.loaders') ? 'loaders' : 'rules']: userLoaders,
rules: userLoaders,
},
output: {
...(webpackConfig: any).output,
Expand Down
1 change: 0 additions & 1 deletion src/runner/testRunnerReporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ const formatTitleWarn = (title) => chalk.black.bgYellow('', title, '');
const formatTitleError = (title) => chalk.white.bold.bgRed('', title, '');

class Reporter {

added: Array<string>;
removed: Array<string>;
interactive: boolean;
Expand Down
2 changes: 1 addition & 1 deletion src/util/glob.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const isDirectory = (filePath) => path.extname(filePath).length === 0;
export const glob = async (
patterns: Array<string>,
options: {}
): Promise<Array<string>> => await globby(patterns, options);
): Promise<Array<string>> => await globby(patterns, options);

export const ensureGlob = (entry: string, recursive: boolean = false, pattern: string = '*.js'): string => {
const normalized = normalizePath(entry);
Expand Down
8 changes: 5 additions & 3 deletions src/webpack/compiler/createWatchCompiler.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @flow
import _ from 'lodash';
import Watching from 'webpack/lib/Watching';
import type { Compiler } from '../types';

export type WatchCompiler = {
Expand All @@ -16,7 +17,7 @@ const noop = () => void 0;
export default function createWatchCompiler(compiler: Compiler, watchOptions: {}): WatchCompiler {
// this ugly statement to create a watch compiler is unfortunately necessary,
// as webpack clears the file timestamps with the official compiler.watch()
const createWatcher = () => new compiler.constructor.Watching(compiler, watchOptions, noop);
const createWatcher = () => new Watching(compiler, watchOptions, noop);
let watchCompiler = null;

return {
Expand All @@ -29,11 +30,12 @@ export default function createWatchCompiler(compiler: Compiler, watchOptions: {}
// the non-empty check is necessary as the times will be reseted after .close()
// and we don't want to reset already existing timestamps
if (Object.keys(times).length > 0) {
const timesMap = new Map(Object.keys(times).map(key => [key, times[key]]));
// set already collected file timestamps to cache compiled files
// webpack will do this only after a file change, but that will not happen when we add or delete files
// and this means that we have to test the whole test suite again ...
compiler.fileTimestamps = times; // eslint-disable-line no-param-reassign
compiler.contextTimestamps = times; // eslint-disable-line no-param-reassign
compiler.fileTimestamps = timesMap; // eslint-disable-line no-param-reassign
compiler.contextTimestamps = timesMap; // eslint-disable-line no-param-reassign
}

watchCompiler.close(() => {
Expand Down
4 changes: 2 additions & 2 deletions src/webpack/compiler/registerReadyCallback.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import type { Compiler, Stats } from '../types';

export default function registerReadyCallback(compiler: Compiler, cb: (err: ?({} | string), stats: Stats) => void) {
compiler.plugin('failed', cb);
compiler.plugin('done', (stats: Stats) => {
compiler.hooks.failed.tap('mocha-webpack', cb);
compiler.hooks.done.tap('mocha-webpack', (stats: Stats) => {
if (stats.hasErrors()) {
const jsonStats = stats.toJson();
const [err] = jsonStats.errors;
Expand Down
3 changes: 0 additions & 3 deletions src/webpack/loader/entryLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import normalizePath from 'normalize-path';
import createEntry from '../util/createEntry';

class EntryConfig {

files: Array<string>;

constructor() {
Expand All @@ -24,7 +23,6 @@ class EntryConfig {
getFiles(): Array<string> {
return this.files;
}

}

const entryLoader = function entryLoader() {
Expand All @@ -50,4 +48,3 @@ const entryLoader = function entryLoader() {

module.exports = entryLoader;
module.exports.EntryConfig = EntryConfig;

26 changes: 21 additions & 5 deletions src/webpack/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type Compiler = {
watch: (watchOptions: {}, cb: () => void) => void,
outputFileSystem: any,
watchFileSystem: any,
hooks: any,
fileTimestamps: {},
contextTimestamps: {},
}
Expand All @@ -30,8 +31,8 @@ export type Module = {
dependencies: Array<{ module: Module }>,
readableIdentifier: ?any,
chunks: Array<Chunk>, // eslint-disable-line no-use-before-define
getChunks?: () => Array<Chunk>, // eslint-disable-line no-use-before-define
blocks: Array<{chunks: Array<Chunk>}> // eslint-disable-line no-use-before-define
getChunks: () => Array<Chunk>, // eslint-disable-line no-use-before-define
blocks: Array<DependenciesBlock> // eslint-disable-line no-use-before-define
};

/**
Expand All @@ -53,9 +54,23 @@ export type Chunk = {
chunks: Array<Chunk>,
parents: Array<Chunk>,
files: Array<string>,
isInitial?: () => boolean, // webpack >= 2
initial?: boolean, // webpack 1
getModules?: () => Array<Module>, // webpack 3
isOnlyInitial: () => boolean,
getModules: () => Array<Module>,
};

/**
* webpack/lib/ChunkGroup.js
*/
export type ChunkGroup = {
chunks: Array<Chunk>,
};

/**
* webpack/lib/DependenciesBlock.js
* webpack/lib/AsyncDependenciesBlock.js
*/
export type DependenciesBlock = {
chunkGroup?: ChunkGroup,
};

/**
Expand All @@ -66,6 +81,7 @@ export type Compilation = {
plugin: (hook: string, fn: () => void) => void,
modules: Module[],
chunks: Chunk[],
chunkGroups: ChunkGroup[],
errors: Array<string | WebpackError>,
warnings: Array<string | WebpackError>,
assets: {
Expand Down

0 comments on commit 02864e2

Please sign in to comment.