Skip to content

Commit

Permalink
Implement the watch mode
Browse files Browse the repository at this point in the history
  • Loading branch information
homer0 committed Aug 10, 2018
1 parent 794c97f commit 7c61d44
Show file tree
Hide file tree
Showing 12 changed files with 416 additions and 46 deletions.
10 changes: 6 additions & 4 deletions src/services/building/configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,15 @@ class WebpackConfiguration {
this.webpackConfigurations = webpackConfigurations;
}
/**
* This method generates a complete Webpack configuration for a target.
* @param {Target} target The target information.
* @param {string} buildType The intended build type: `production` or `development`.
* This method generates a complete webpack configuration for a target.
* @param {Target} target The target information.
* @param {string} buildType The intended build type: `production` or `development`.
* @param {boolean} watch Whether or not webpack should use the watch mode.
* @return {Object}
* @throws {Error} If there's no base configuration for the target type.
* @throws {Error} If there's no base configuration for the target type and build type.
*/
getConfig(target, buildType) {
getConfig(target, buildType, watch) {
const targetType = target.type;
if (!this.webpackConfigurations[targetType]) {
throw new Error(`There's no configuration for the selected target type: ${targetType}`);
Expand Down Expand Up @@ -93,6 +94,7 @@ class WebpackConfiguration {
output: target.output[buildType],
copy,
buildType,
watch,
};

let config = this.targetConfiguration(
Expand Down
38 changes: 24 additions & 14 deletions src/services/building/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,28 +50,35 @@ class WebpackBuildEngine {
* @property {string} run Whether or not to execute the target. This will be like a fake
* boolean as the CLI doesn't support boolean variables, so its value
* will be either `'true'` or `'false'`.
* @property {string} watch Whether or not to watch the target files. This will be like a fake
* boolean as the CLI doesn't support boolean variables, so its value
* will be either `'true'` or `'false'`.
* @access protected
* @ignore
*/
this._envVars = {
target: 'PROJEXT_WEBPACK_TARGET',
type: 'PROJEXT_WEBPACK_BUILD_TYPE',
run: 'PROJEXT_WEBPACK_RUN',
target: 'PXTWPK_TARGET',
type: 'PXTWPK_TYPE',
run: 'PXTWPK_RUN',
watch: 'PXTWPK_WATCH',
};
}
/**
* Get the CLI build command to bundle a target.
* @param {Target} target The target information.
* @param {string} buildType The intended build type: `development` or `production`.
* @param {boolean} [forceRun=false] Force the target to run even if the `runOnDevelopment`
* setting is `false`.
* @param {Target} target The target information.
* @param {string} buildType The intended build type: `development` or `production`.
* @param {boolean} [forceRun=false] Force the target to run even if the `runOnDevelopment`
* setting is `false`.
* @param {boolean} [forceWatch=false] Force webpack to use the watch mode even if the `watch`
* setting for the required build type is set to `false`.
* @return {string}
*/
getBuildCommand(target, buildType, forceRun = false) {
getBuildCommand(target, buildType, forceRun = false, forceWatch = false) {
const vars = this._getEnvVarsAsString({
target: target.name,
type: buildType,
run: forceRun,
watch: forceWatch,
});

const config = path.join(
Expand All @@ -94,13 +101,14 @@ class WebpackBuildEngine {
return `${vars} ${command} --config ${config} ${options}`;
}
/**
* Get a Webpack configuration for a target.
* @param {Target} target The target configuration.
* @param {string} buildType The intended build type: `development` or `production`.
* Get a webpack configuration for a target.
* @param {Target} target The target configuration.
* @param {string} buildType The intended build type: `development` or `production`.
* @param {boolean} watch Whether or not the webpack watch mode should be enabled.
* @return {object}
*/
getConfiguration(target, buildType) {
return this.webpackConfiguration.getConfig(target, buildType);
getConfiguration(target, buildType, watch) {
return this.webpackConfiguration.getConfig(target, buildType, watch);
}
/**
* Get a Webpack configuration by reading the environment variables sent by the CLI command
Expand All @@ -120,7 +128,9 @@ class WebpackBuildEngine {
target.runOnDevelopment = true;
}

return this.getConfiguration(target, type);
const watch = vars.watch === 'true' || target.watch[type];

return this.getConfiguration(target, type, watch);
}
/**
* Given a dictionary with the environment variables purpose and values, this method generates
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class WebpackBrowserDevelopmentConfiguration extends ConfigurationFile {
entry,
target,
output,
watch,
} = params;
// Define the basic stuff: entry, output and mode.
const config = {
Expand Down Expand Up @@ -197,6 +198,12 @@ class WebpackBrowserDevelopmentConfiguration extends ConfigurationFile {
* required entry to the list.
*/
hotEntries.push('webpack-hot-middleware/client?reload=true');
} else if (watch) {
/**
* If the target is not running nor it requires HMR (which means is not being served either),
* and the watch parameter is `true`, enable the watch mode.
*/
config.watch = true;
}
// If there are entries for HMR...
if (hotEntries.length) {
Expand Down
6 changes: 6 additions & 0 deletions src/services/configurations/browserProductionConfiguration.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class WebpackBrowserProductionConfiguration extends ConfigurationFile {
entry,
target,
output,
watch,
} = params;
// Define the basic stuff: entry, output and mode.
const config = {
Expand Down Expand Up @@ -127,6 +128,11 @@ class WebpackBrowserProductionConfiguration extends ConfigurationFile {
})]
),
];
// Enable the watch mode if required...
if (watch) {
config.watch = true;
}

// Reduce the configuration
return this.events.reduce(
[
Expand Down
3 changes: 3 additions & 0 deletions src/services/configurations/nodeDevelopmentConfiguration.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ class WebpackNodeDevelopmentConfiguration extends ConfigurationFile {
plugins.push(new ProjextWebpackBundleRunner({
logger: this.appLogger,
}));
} else if (params.watch) {
// Enable the watch mode if required.
watch = true;
}
// Define the rest of the configuration.
const config = {
Expand Down
2 changes: 2 additions & 0 deletions src/services/configurations/nodeProductionConfiguration.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class WebpackNodeProductionConfiguration extends ConfigurationFile {
target,
output,
copy,
watch,
} = params;
const config = {
entry,
Expand All @@ -79,6 +80,7 @@ class WebpackNodeProductionConfiguration extends ConfigurationFile {
__dirname: false,
},
mode: 'production',
watch,
};
// Reduce the configuration.
return this.events.reduce(
Expand Down
2 changes: 2 additions & 0 deletions src/typedef.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@
* @property {Array} copy
* A list of {@link TargetExtraFile} with the information of files that need to be copied during
* the bundling process.
* @property {boolean} watch
* Whether or not webpack should use the watch mode.
*/

/**
Expand Down
72 changes: 44 additions & 28 deletions tests/services/building/engine.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ describe('services/building:engine', () => {
);
result = sut.getBuildCommand(target, buildType);
// Then
expect(result).toMatch(/PROJEXT_WEBPACK_TARGET=(?:[\w0-9-_]*?).*?webpack/);
expect(result).toMatch(/PROJEXT_WEBPACK_BUILD_TYPE=(?:\w+).*?webpack/);
expect(result).toMatch(/PROJEXT_WEBPACK_RUN=(?:true|false).*?webpack/);
expect(result).toMatch(/PXTWPK_TARGET=(?:[\w0-9-_]*?).*?webpack/);
expect(result).toMatch(/PXTWPK_TYPE=(?:\w+).*?webpack/);
expect(result).toMatch(/PXTWPK_RUN=(?:true|false).*?webpack/);
expect(result).toMatch(new RegExp(`webpack --config ${expectedConfigPath}`));
expect(result).toMatch(/webpack --config.*?--progress/);
expect(result).toMatch(/webpack --config.*?--profile/);
Expand Down Expand Up @@ -100,9 +100,9 @@ describe('services/building:engine', () => {
);
result = sut.getBuildCommand(target, buildType);
// Then
expect(result).toMatch(/PROJEXT_WEBPACK_TARGET=(?:[\w0-9-_]*?).*?webpack-dev-server/);
expect(result).toMatch(/PROJEXT_WEBPACK_BUILD_TYPE=(?:\w+).*?webpack-dev-server/);
expect(result).toMatch(/PROJEXT_WEBPACK_RUN=(?:true|false).*?webpack-dev-server/);
expect(result).toMatch(/PXTWPK_TARGET=(?:[\w0-9-_]*?).*?webpack-dev-server/);
expect(result).toMatch(/PXTWPK_TYPE=(?:\w+).*?webpack-dev-server/);
expect(result).toMatch(/PXTWPK_RUN=(?:true|false).*?webpack-dev-server/);
expect(result).toMatch(new RegExp(`webpack-dev-server --config ${expectedConfigPath}`));
expect(result).toMatch(/webpack-dev-server --config.*?--progress/);
expect(result).toMatch(/webpack-dev-server --config.*?--profile/);
Expand Down Expand Up @@ -137,9 +137,9 @@ describe('services/building:engine', () => {
);
result = sut.getBuildCommand(target, buildType, true);
// Then
expect(result).toMatch(/PROJEXT_WEBPACK_TARGET=(?:[\w0-9-_]*?).*?webpack-dev-server/);
expect(result).toMatch(/PROJEXT_WEBPACK_BUILD_TYPE=(?:\w+).*?webpack-dev-server/);
expect(result).toMatch(/PROJEXT_WEBPACK_RUN=(?:true|false).*?webpack-dev-server/);
expect(result).toMatch(/PXTWPK_TARGET=(?:[\w0-9-_]*?).*?webpack-dev-server/);
expect(result).toMatch(/PXTWPK_TYPE=(?:\w+).*?webpack-dev-server/);
expect(result).toMatch(/PXTWPK_RUN=(?:true|false).*?webpack-dev-server/);
expect(result).toMatch(/webpack-dev-server --config ([\w_\-/]*?)webpack\.config\.js/);
expect(result).toMatch(/webpack-dev-server --config.*?--progress/);
expect(result).toMatch(/webpack-dev-server --config.*?--profile/);
Expand All @@ -152,6 +152,7 @@ describe('services/building:engine', () => {
const targets = 'targets';
const target = 'some-target';
const buildType = 'production';
const watch = false;
const config = 'config';
const webpackConfiguration = {
getConfig: jest.fn(() => config),
Expand All @@ -169,25 +170,30 @@ describe('services/building:engine', () => {
webpackConfiguration,
webpackPluginInfo
);
result = sut.getConfiguration(target, buildType);
result = sut.getConfiguration(target, buildType, watch);
// Then
expect(result).toBe(config);
expect(webpackConfiguration.getConfig).toHaveBeenCalledTimes(1);
expect(webpackConfiguration.getConfig).toHaveBeenCalledWith(target, buildType);
expect(webpackConfiguration.getConfig).toHaveBeenCalledWith(target, buildType, watch);
});

it('should return a target Webpack configuration', () => {
// Given
const targetName = 'some-target';
const buildType = 'development';
const run = false;
const watch = false;
const target = {
name: targetName,
watch: {
[buildType]: watch,
},
};
const envVars = {
PROJEXT_WEBPACK_TARGET: targetName,
PROJEXT_WEBPACK_BUILD_TYPE: buildType,
PROJEXT_WEBPACK_RUN: run.toString(),
PXTWPK_TARGET: targetName,
PXTWPK_TYPE: buildType,
PXTWPK_RUN: run.toString(),
PXTWPK_WATCH: watch.toString(),
};
const envVarsNames = Object.keys(envVars);
const environmentUtils = {
Expand Down Expand Up @@ -217,7 +223,7 @@ describe('services/building:engine', () => {
// Then
expect(result).toBe(config);
expect(webpackConfiguration.getConfig).toHaveBeenCalledTimes(1);
expect(webpackConfiguration.getConfig).toHaveBeenCalledWith(target, buildType);
expect(webpackConfiguration.getConfig).toHaveBeenCalledWith(target, buildType, false);
expect(targets.getTarget).toHaveBeenCalledTimes(1);
expect(targets.getTarget).toHaveBeenCalledWith(targetName);
expect(environmentUtils.get).toHaveBeenCalledTimes(envVarsNames.length);
Expand All @@ -231,13 +237,18 @@ describe('services/building:engine', () => {
const targetName = 'some-target';
const buildType = 'development';
const run = true;
const watch = true;
const target = {
name: targetName,
watch: {
[buildType]: watch,
},
};
const envVars = {
PROJEXT_WEBPACK_TARGET: targetName,
PROJEXT_WEBPACK_BUILD_TYPE: buildType,
PROJEXT_WEBPACK_RUN: run.toString(),
PXTWPK_TARGET: targetName,
PXTWPK_TYPE: buildType,
PXTWPK_RUN: run.toString(),
PXTWPK_WATCH: watch.toString(),
};
const envVarsNames = Object.keys(envVars);
const environmentUtils = {
Expand Down Expand Up @@ -267,13 +278,17 @@ describe('services/building:engine', () => {
// Then
expect(result).toBe(config);
expect(webpackConfiguration.getConfig).toHaveBeenCalledTimes(1);
expect(webpackConfiguration.getConfig).toHaveBeenCalledWith(Object.assign(
{},
target,
{
runOnDevelopment: true,
}
), buildType);
expect(webpackConfiguration.getConfig).toHaveBeenCalledWith(
Object.assign(
{},
target,
{
runOnDevelopment: true,
}
),
buildType,
watch
);
expect(targets.getTarget).toHaveBeenCalledTimes(1);
expect(targets.getTarget).toHaveBeenCalledWith(targetName);
expect(environmentUtils.get).toHaveBeenCalledTimes(envVarsNames.length);
Expand All @@ -285,9 +300,10 @@ describe('services/building:engine', () => {
it('should throw an error when getting a configuration without the env variables', () => {
// Given
const envVarsNames = [
'PROJEXT_WEBPACK_TARGET',
'PROJEXT_WEBPACK_BUILD_TYPE',
'PROJEXT_WEBPACK_RUN',
'PXTWPK_TARGET',
'PXTWPK_TYPE',
'PXTWPK_RUN',
'PXTWPK_WATCH',
];
const environmentUtils = {
get: jest.fn(),
Expand Down
Loading

0 comments on commit 7c61d44

Please sign in to comment.