Skip to content

Commit

Permalink
feat: chalk up the cli
Browse files Browse the repository at this point in the history
Now we are ready to test through some docker container.
  • Loading branch information
swashata committed Oct 5, 2018
1 parent 3e74066 commit 270c1b2
Show file tree
Hide file tree
Showing 5 changed files with 292 additions and 23 deletions.
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,10 @@
"editor.formatOnSave": true
},
"flow.useLSP": true,
"typescript.tsdk": "node_modules/typescript/lib"
"typescript.tsdk": "node_modules/typescript/lib",
"cSpell.words": [
"Packio",
"uglifyjs",
"wpack"
]
}
51 changes: 45 additions & 6 deletions packages/scripts/PREFACE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,62 @@
- DO NOT RELY ON `process.env.NODE_ENV`. Rather set it automatically depending on cli commands.
- `start` - Start browsersync sever with webpack middleware.
- `build` - Compile files.
- `init` - Create a `wpackio.server.js` through asking some questions (only if the file is not present).
- `init` - Create a `wpackio.server.json` through asking some questions (only if the file is not present).
- Also set `process.env.BABEL_ENV` so that `babel-loader` can play nice, (especially with the preset-react).

## Structure `wpackio.project.js`
## For the PHP Script

We will need to feed it the outputPath to keep things fast and not have it load the project.js
file.

```php
<?php

$enqueue = new \WPackio\Enqueue( $plugin_path, $output_path );
$enqueue->enqueue( 'entry_name' );
$enqueue->enqueue( 'entry_name', 'chunk_name' );
$enqueue->enqueue( 'entry_name', 'chunk_name', [
'other' => 'localization',
] );
```

## Structure `wpackio.project.json`

```js
module.exports = {
// Project Identity
type: 'plugin', // Plugin or theme
slug: 'wpack-io', // Plugin or Theme slug, basically the directory name under `wp-content/<themes|plugins>`
// Used to generate banners on top of compiled stuff
bannerConfig: {
name: 'WordPress WebPack Bundler',
author: 'Swashata Ghosh',
license: 'GPL-3.0',
link: 'https://wpack.io',
version: '1.0.0',
copyrightText:
'This software is released under the GPL-3.0 License\nhttps://opensource.org/licenses/GPL-3.0',
credit: true,
},
// Files we need to compile, and where to put
files: [
// If this has length === 1, then single compiler
{
name: 'mobile',
entry: {
// stuff
vendor: 'vendor.js',
main: ['src/mobile.js'],
},
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
// Extra webpack config to be passed directly
webpackConfig: undefined,
},
// If has more length, then multi-compiler
],
// Output path relative to the context directory
// We need relative path here, else, we can not map to publicPath
outputPath: 'dist',
// Project specific config
// Needs react?
hasReact: true,
Expand All @@ -33,15 +70,17 @@ module.exports = {
externals: {
jquery: 'jQuery',
},
// Webpack Aliases
alias: undefined,
// Show overlay on development
errorOverlay: true,
// Auto optimization by webpack
// Split all common chunks with default config
// <https://webpack.js.org/plugins/split-chunks-plugin/#optimization-splitchunks>
// Won't hurt because we use PHP to automate loading
optimizeSplitChunks: true,
// Extra webpack config to be passed directly
webpackConfig: false,
// Usually PHP and other files to watch and reload when changed
watch: 'inc/**/*.php',
};
```

Expand All @@ -53,7 +92,7 @@ Possible `package.json`
{
"name": "@wpackio/scripts",
"version": "0.0.0",
"description": "@wpackios/scripts is a single dependency for using WordPress webpack script.",
"description": "@wpackio/scripts is a single dependency for using WordPress webpack script.",
"main": "index.js",
"repository": "https://github.com/swashata/wp-webpack-script",
"author": "Swashata Ghosh",
Expand Down
2 changes: 2 additions & 0 deletions packages/scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@babel/preset-typescript": "^7.1.0",
"@types/browser-sync": "^0.0.42",
"@types/node": "^10.11.3",
"@types/signale": "^1.2.0",
"@types/webpack": "^4.4.13",
"@types/webpack-dev-middleware": "^2.0.2",
"@types/webpack-hot-middleware": "^2.16.4",
Expand All @@ -37,6 +38,7 @@
"optimize-css-assets-webpack-plugin": "^5.0.1",
"postcss-loader": "^3.0.0",
"sass-loader": "^7.1.0",
"signale": "^1.3.0",
"slugify": "^1.3.1",
"style-loader": "^0.23.0",
"uglifyjs-webpack-plugin": "^2.0.1",
Expand Down
232 changes: 217 additions & 15 deletions packages/scripts/src/bin/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#!/usr/bin/env node
import program from 'commander';
import path from 'path';
import signale from 'signale';
import { ProjectConfig } from '../config/project.config.default';
import { ServerConfig } from '../config/server.config.default';
import { Build } from '../scripts/Build';
import { Server } from '../scripts/Server';

/* tslint:disable:no-require-imports no-var-requires */
const pkg = require('../../package.json');
Expand Down Expand Up @@ -43,16 +48,68 @@ program
'-s, --server-config [path]',
'Path to server config. If it differs from ./wpackio.server.js'
)
.action(options => {
isValidCommand = true;
console.log('should start script.', options.context);
// Set process.env.NODE_ENV to development
// Set process.env.BABEL_ENV to development
// Get project and server config JSONs.
// Start the webpack/browserSync server
// Listen for SIGTERM and quit properly
// Listen for keyinput <r> and invalidate webpack builds.
});
.action(
(
options:
| {
context?: string;
projectConfig?: string;
serverConfig?: string;
}
| undefined
) => {
isValidCommand = true;
signale.start('Starting up wpack.io development server');
// Set process.env.NODE_ENV to development
process.env.NODE_ENV = 'development';
// Set process.env.BABEL_ENV to development
process.env.BABEL_ENV = 'development';
// Get project and server config JSONs.
const cwd = resolveCWD(options);
signale.info(`Using startup path: ${cwd}`);
try {
const {
projectConfig,
serverConfig,
projectConfigPath,
serverConfigPath,
} = getProjectAndServerConfig(cwd, options);
signale.info(`Using project config from ${projectConfigPath}`);
signale.info(`Using server config from ${serverConfigPath}`);
// Start the webpack/browserSync server
const server: Server = new Server(
projectConfig,
serverConfig,
cwd
);
server.serve();
// Listen for SIGINT and quit properly
process.on('SIGINT', () => {
signale.complete('Gracefully ending development server');
server.stop();
signale.success(
'To create production build, run `yarn build` or `npm run build`'
);
signale.star('Thank you for using https://wpack.io.');
signale.star('To spread the ❤️ please tweet.');
process.exit(0);
});
process.on('SIGKILL', () => {
server.stop();
});
process.on('SIGTERM', () => {
server.stop();
});
} catch (e) {
signale.error(
'Could not start development server. Please check the log below.'
);
signale.fatal(e);
process.exit(1);
}
// Listen for keyinput <r> and invalidate webpack builds.
}
);

// Build the script
program
Expand All @@ -69,21 +126,166 @@ program
)
.action(options => {
isValidCommand = true;
console.log('should build the script', options.context);
signale.start('Creating production builds...');
// Set process.env.NODE_ENV to production
process.env.NODE_ENV = 'production';
// Set process.env.BABEL_ENV to production
process.env.BABEL_ENV = 'production';
// Get project and server config JSONs.
// Compile scripts using webpack
const cwd = resolveCWD(options);
signale.info(`Using startup path: ${cwd}`);
try {
const {
projectConfig,
serverConfig,
projectConfigPath,
serverConfigPath,
} = getProjectAndServerConfig(cwd, options);
signale.info(`Using project config from ${projectConfigPath}`);
signale.info(`Using server config from ${serverConfigPath}`);
// Start the webpack/browserSync server
const build: Build = new Build(projectConfig, serverConfig, cwd);
build
.build()
.then(log => {
signale.success(
'Build Successful. Please check the log below'
);
console.log(log);
process.exit(0);
})
.catch(err => {
signale.fatal(
'Could not create production build. Please check the log below'
);
console.log(err);
process.exit(1);
});
} catch (e) {
signale.error(
'Could not start development server. Please check the log below.'
);
signale.fatal(e);
process.exit(1);
}
});

// Init
program.parse(process.argv);

// error on unknown commands
if (!isValidCommand) {
console.error(
'Invalid command: %s\nSee --help for a list of available commands.',
signale.error(
'Invalid command: %s\nSee usage below.\n\n',
program.args.join(' ')
);
process.exit(1);
program.help();
}

/**
* Resolve `cwd`, a.k.a, current working directory or context from user input.
* It takes into account the `--context [path]` option from CLI and uses process
* cwd, if not provided.
*
* @param options Options as received from CLI
*/
function resolveCWD(
options: { context?: string | undefined } | undefined
): string {
let cwd = process.cwd();
// If user has provided cwd, then use that instead
if (options && options.context) {
const { context } = options;
if (path.isAbsolute(options.context)) {
cwd = context;
} else {
cwd = path.resolve(cwd, context);
}
}

return cwd;
}

// tslint:disable: non-literal-require
function getProjectAndServerConfig(
cwd: string,
options: { projectConfig?: string; serverConfig?: string } | undefined
): {
projectConfig: ProjectConfig;
serverConfig: ServerConfig;
projectConfigPath: string;
serverConfigPath: string;
} {
// Get the config file paths from options
// If user is passing relative path, then it will be used along with cwd
// If it is absolute path, then the absolute would be used instead
// This is how path.resolve works.
const projectConfigPath = path.resolve(
cwd,
options && options.projectConfig
? options.projectConfig
: 'wpackio.project.js'
);

const serverConfigPath = path.resolve(
cwd,
options && options.serverConfig
? options.serverConfig
: 'wpackio.server.js'
);

// Now create the configuration objects
let projectConfig: ProjectConfig;
let serverConfig: ServerConfig;

// First check to see if the files are present
try {
projectConfig = require(projectConfigPath) as ProjectConfig;
} catch (e) {
throw new Error(
`Could not find project configuration at:\n${projectConfigPath}\nPlease make sure the file exists or adjust your --context or --project-config parameters.`
);
}
try {
serverConfig = require(serverConfigPath) as ServerConfig;
} catch (e) {
throw new Error(
`Could not find server configuration at:\n${serverConfigPath}\nPlease make sure the file exists or adjust your --context or --server-config parameters.`
);
}

// Now validate them
if (typeof projectConfig !== 'object') {
throw new Error(
`Project configuration must export an object literal. Right now it is ${typeof projectConfig}`
);
}
if (typeof serverConfig !== 'object') {
throw new Error(
`Server configuration must export an object literal. Right now it is ${typeof serverConfig}`
);
}
// @todo
// Also validate the config, but let's leave it for now
// Make sure to do it in future

return { projectConfig, serverConfig, projectConfigPath, serverConfigPath };
}

// Error out on force close
process.on('SIGKILL', () => {
signale.fatal(
'The operation failed because the process exited too early. ' +
'This probably means the system ran out of memory or someone called ' +
'`kill -9` on the process.'
);
process.exit(1);
});
process.on('SIGTERM', () => {
signale.fatal(
'The operation failed because the process exited too early. ' +
'Someone might have called `kill` or `killall`, or the system could ' +
'be shutting down.'
);
process.exit(1);
});
Loading

0 comments on commit 270c1b2

Please sign in to comment.