Skip to content

Commit

Permalink
Watch Mode (#51)
Browse files Browse the repository at this point in the history
* Add a watch mode to standard command set, uses production configuration and the Dev server watch polling options
* Add Watch to check-configuration
* Update a couple vulnerabilities
  • Loading branch information
rleeson authored Mar 25, 2024
1 parent 9d184a1 commit c8a8e40
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 50 deletions.
6 changes: 3 additions & 3 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The main goals of Kanopi Pack are the following:

* Are you using Grunt, Gulp, some other older technology, or even nothing to manage your static assets?
* Do you want to incrementally add a front-end application, written in React or Vue, alongside your existing site JS code?
* Do you want to start writing or supporting ES Modules, SCSS, or Typescript within your project?
* Do you want to start writing or supporting ES Modules, Modern CSS with PostCSS, SCSS, or Typescript within your project?
* Do you want to utilize code quality tools like ESLint or StyleLint without managing additional modules and figuring out how to integrate it with your build pipeline?
* Are you using static image/icon assets and want the ability to update them during development without a full bundle build or separate platform integration?

Expand Down Expand Up @@ -72,8 +72,8 @@ Configuration is implemented via the Main Configuration File, with Preferred loc

| Package | Minimum | Recommended |
|:--------|:--------|:------------|
| Node | 16.x | 20.x |
| NPM | 8.x | 9.x |
| Node | 18.x | 20.x |
| NPM | 9.x | 10.x |

### Dependent Packages

Expand Down
32 changes: 19 additions & 13 deletions bin/kanopi-pack.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,46 @@ const utility = require('util');
const {
commands: { standard: program },
configuration: { development, production },
runners: { runDevServer, runWebpack }
environment: { standard: { watchOptions } },
runners: { runDevServer, runWebpack, watchWebpack }
} = kanopiPack;

const PACKAGE_MODES = {
'development': { configuration: development, name: 'Development', runner: () => runDevServer(development) },
'production': { configuration: production, name: 'Production', runner: () => runWebpack(production) },
'watch': { configuration: production, name: 'Watch', runner: () => watchWebpack(production, watchOptions) }
};

program
.command('check-configuration')
.description('Output the Webpack configuration for the specified environment.')
.argument('[depth]', 'Number of levels deep (default 6) to show the configuration')
.argument('[environment]', 'Choose production (default) or development')
.argument('[environment]', 'Choose production (default), development, or watch')
.argument('[color]', 'Whether to show the output in color (default false)')
.action((depth = 6, environment = 'production', color = false) => {
const isDevelopment = 'development' === environment;
const selectedMode = PACKAGE_MODES[environment] ?? PACKAGE_MODES['production'];
const { configuration, name } = selectedMode;

console.log(chalk.greenBright('Package:\tKanopi Pack Standard'))
console.log(chalk.yellow('Environment:\t' + (isDevelopment ? 'Development' : 'Production')));
console.log(chalk.yellow('Environment:\t' + name));
console.log('');
console.log(chalk.yellow('Current configuration:'));
console.log('');
console.log(utility.inspect(isDevelopment ? development : production, { depth: depth, colors: color }));
console.log(utility.inspect(configuration, { depth: depth, colors: color }));
});

program
.command('standard')
.description('Run Webpack builds, set environment to development for HMR')
.argument('[environment]', 'Choose production (default) or development')
.description('Run Webpack builds, set environment to development for HMR, or watch for rebuilds without HMR.')
.argument('[environment]', 'Choose production (default), development, or watch')
.action((environment = 'production') => {
const isDevelopment = 'development' === environment;
const selectedMode = PACKAGE_MODES[environment] ?? PACKAGE_MODES['production'];
const { name, runner } = selectedMode;

console.log(chalk.greenBright('Package:\tKanopi Pack Standard'))
console.log(chalk.yellow('Environment:\t' + (isDevelopment ? 'Development' : 'Production')));
console.log(chalk.yellow('Environment:\t' + name));
console.log('');

isDevelopment
? runDevServer(development)
: runWebpack(production);
runner();
});

program.parse(process.argv);
2 changes: 2 additions & 0 deletions documentation/extending.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ When`@kanopi/pack` is referenced in another package (i.e. `require('@kanopi/pack
"common": 'Common profile and plugins for all build profiles',
"development": 'Development server profile and plugins',
"production": 'Production build profile and plugins',
"watch": 'Production build profile and plugins',
},
"components": {
"loaders": {
Expand All @@ -39,5 +40,6 @@ When`@kanopi/pack` is referenced in another package (i.e. `require('@kanopi/pack
"runners": {
"runDevServer": 'Runs Webpack Dev Server based on the provided configuration',
"runWebpack": 'Runs Webpack production build based on the provided configuration'
"watchWebpack": 'Runs Webpack production build based on the provided configuration and watchOptions'
}
}
4 changes: 4 additions & 0 deletions documentation/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

The development side of the bundler runs as a server, and automatically reloads the changed parts of styles and supporting scripts/applications through a process called hot-module reload (HMR). The configuration offers multiple options to change the IP and Port of the development server, along with the ability to listen for proxied requests when include inside a container based solution.

## Watch Mode

For systems like Drupal's asset mapping system or WordPress Full Site Editor iFrame, which may not support Development mode, you can use Watch mode. Watch mode continues to rebuild assets as source files change, without the HMR style functionality. In this mode, the developer refreshes whatever browser they are using to see the recompiled changes. Watch mode uses the polling/watchOptions specified in the Development Server configuration.

### Project Integration

The Development Server solution is different than some other similar middleware based solutions, or full application frameworks which fully control the whole page and therefore included scripts and styles. Any Kanopi Pack based project needs to reference the Development and Production assets at a different set of URLs, typically a different hostname with the same directory structure, for instance `https://0.0.0.0:4400/assets/dist/*` versus `https://my.site/assets/dist/*`. [Kanopi Pack Asset Loader](https://github.com/kanopi/kanopi-pack-asset-loader) is available as a PHP based library to coordinate this and offers a full integration with WordPress.
Expand Down
2 changes: 1 addition & 1 deletion package-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ catch (exception) {
console.log(exception);
}

if ({} === packageTree) {
if (packageTree && 0 === Object.keys(packageTree).length) {
console.log('Kanopi Pack is not installed properly, its internal file structure is not found or unable to load. Check the NPM installation and permissions.');
}

Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 27 additions & 27 deletions src/components/loaders/babel.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
module.exports = (environment) => {
const {
scripts: { useJsxSyntax },
sourceMaps
} = environment;
const {
scripts: { useJsxSyntax },
sourceMaps
} = environment;

let presets = [
[
'@babel/preset-env',
{
targets: {
esmodules: true
}
}
]
];
let presets = [
[
'@babel/preset-env',
{
targets: {
esmodules: true
}
}
]
];

if (useJsxSyntax) {
presets = presets.concat(['@babel/preset-react']);
}
if (useJsxSyntax) {
presets = presets.concat(['@babel/preset-react']);
}

return [
{
loader: 'babel-loader',
options: {
presets: presets,
sourceMaps: sourceMaps
}
}
];
}
return [
{
loader: 'babel-loader',
options: {
presets: presets,
sourceMaps: sourceMaps
}
}
];
}
36 changes: 36 additions & 0 deletions src/runners/watchWebpack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const chalk = require('chalk');
const webpack = require('webpack');

/**
* Start the watch process for Webpack
*/
module.exports = function watchWebpack(config, watchOptions) {
try {
const { poll = 1000, aggregateTimeout = 600 } = watchOptions;
const compiler = webpack(config);
console.log(chalk.yellow('Start watch process...'));
console.log('');

const watching = compiler.watch({ poll: poll, aggregateTimeout: aggregateTimeout }, (err, stats) => {
if (err) {
console.error(err);
return;
}

console.log(stats.toString({
colors: true
}));
});

process.on('SIGINT', () => {
watching.close(() => {
console.log('Watching stopped.');
process.exit(0);
});
});
}
catch (error) {
console.error(chalk.red('Build failed...'))
console.error(error);
}
}

0 comments on commit c8a8e40

Please sign in to comment.