-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(global-cli): initial draft of global cli module
- Loading branch information
1 parent
7397d42
commit f7a245f
Showing
4 changed files
with
187 additions
and
163 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,183 @@ | ||
#!/usr/bin/env node | ||
'use strict'; | ||
|
||
var program = require('commander'); | ||
var rimraf = require('rimraf'); | ||
|
||
var hopsConfig = require('hops-config'); | ||
var commands = require('./'); | ||
|
||
function cleanup () { | ||
var dirs = [hopsConfig.buildDir, hopsConfig.cacheDir]; | ||
return Promise.all(dirs.map(function (dir) { | ||
return new Promise(function (resolve) { | ||
rimraf(dir, resolve); | ||
}); | ||
})); | ||
} | ||
|
||
program | ||
.version(require('./package.json').version) | ||
.description('Commands: start, serve, develop, build') | ||
.option('-s, --static', 'Statically build locations') | ||
.arguments('<command>') | ||
.action(function run (command) { | ||
cleanup().then(function () { | ||
switch (command) { | ||
case 'start': | ||
return run(process.env.NODE_ENV === 'production' ? 'serve' : 'develop'); | ||
case 'serve': | ||
return commands.runServe(program); | ||
case 'develop': | ||
return commands.runDevelop(program); | ||
case 'build': | ||
return commands.runBuild(program); | ||
default: | ||
console.error('invalid command: ' + command); | ||
process.exit(1); | ||
var fs = require('fs'); | ||
var path = require('path'); | ||
var execSync = require('child_process').execSync; | ||
var resolveCwd = require('resolve-cwd'); | ||
var validatePackageName = require('validate-npm-package-name'); | ||
|
||
var packageManifest = require('./package.json'); | ||
|
||
var getLocalCliPath = function () { | ||
try { | ||
return resolveCwd('hops-local-cli'); | ||
} catch (error) { | ||
return null; | ||
} | ||
}; | ||
|
||
var PACKAGES_TO_INSTALL = [ | ||
'hops-local-cli' | ||
]; | ||
|
||
function globalCLI (argv) { | ||
return require('yargs') | ||
.version(packageManifest.version) | ||
.usage('Usage: $0 <command> [options]') | ||
.command('init <project-name>', 'Generates a new project with the specified name') | ||
.option('template', { | ||
type: 'string', | ||
describe: 'Use this with the npm package name of a template to ' + | ||
'initialize with a different template', | ||
default: 'hops-template-default' | ||
}) | ||
.option('verbose', { | ||
type: 'boolean', | ||
describe: 'Increase verbosity of command', | ||
default: false | ||
}) | ||
.option('npm', { | ||
type: 'boolean', | ||
describe: 'Force usage of `npm` instead of yarn', | ||
default: false | ||
}) | ||
.example( | ||
'$0 init my-project', | ||
'Creates the folder my-project inside the current directory and ' + | ||
'initializes a sample hops project inside it.' | ||
) | ||
.example( | ||
'$0 init --template hops-template-malt my-project', | ||
'Creates the folder my-project inside the current directory and ' + | ||
'initializes an example project using malt inside it.' | ||
) | ||
.help('h') | ||
.alias('h', 'help') | ||
.demandCommand() | ||
.wrap(72) | ||
.parse(argv); | ||
} | ||
|
||
function validateName (name) { | ||
var validationResult = validatePackageName(name); | ||
if (!validationResult.validForNewPackages) { | ||
console.error( | ||
'Cannot create a project with the name:', | ||
name, | ||
'because of the following npm restrictions:' | ||
); | ||
if (validationResult.errors) { | ||
validationResult.errors.forEach(function (msg) { console.error(msg); }); | ||
} | ||
if (validationResult.warnings) { | ||
validationResult.warnings.forEach(function (msg) { console.warn(msg); }); | ||
} | ||
}); | ||
}) | ||
.parse(process.argv); | ||
process.exit(1); | ||
} | ||
} | ||
|
||
function createDirectory (root) { | ||
if (fs.existsSync(root)) { | ||
console.error( | ||
'A directory with the name:', | ||
name, | ||
'already exists in:', | ||
process.cwd(), | ||
'\nPlease remove this directory or choose a different project-name.' | ||
); | ||
process.exit(1); | ||
} | ||
|
||
fs.mkdirSync(root); | ||
} | ||
|
||
function writePackageManifest (root) { | ||
fs.writeFileSync( | ||
path.join(root, 'package.json'), | ||
JSON.stringify({ | ||
name: name, | ||
version: '1.0.0', | ||
private: true | ||
}, null, 2) | ||
); | ||
} | ||
|
||
function isYarnAvailable () { | ||
try { | ||
execSync('yarn --version', { stdio: 'ignore' }); | ||
return true; | ||
} catch (error) { | ||
return false; | ||
} | ||
} | ||
|
||
function installPackages (packages, options) { | ||
var command = null; | ||
if (isYarnAvailable() && !options.npm) { | ||
command = [ | ||
'yarn', | ||
'add', | ||
'--exact' | ||
]; | ||
} else { | ||
command = [ | ||
'npm', | ||
'install', | ||
'--save', | ||
'--save-exact' | ||
]; | ||
} | ||
if (options.verbose) { | ||
command.push('--verbose'); | ||
} | ||
Array.prototype.push.apply(command, packages); | ||
|
||
try { | ||
execSync(command.join(' '), { stdio: 'inherit' }); | ||
} catch (error) { | ||
console.error(error.message); | ||
if (options.verbose) { | ||
console.error(error); | ||
console.error('Command: "', command.join(' '), 'has failed.'); | ||
} | ||
process.exit(1); | ||
} | ||
} | ||
|
||
var localCliPath = getLocalCliPath(); | ||
var argv = process.argv.slice(2); | ||
|
||
var isInsideHopsProject = false; | ||
try { | ||
var manifest = require(path.resolve(process.cwd(), 'package.json')); | ||
if (manifest.dependencies) { | ||
isInsideHopsProject = Boolean(manifest.dependencies['hops-local-cli']); | ||
} | ||
} catch (error) { | ||
isInsideHopsProject = false; | ||
} | ||
|
||
if (isInsideHopsProject) { | ||
if (localCliPath) { | ||
require(localCliPath).run(argv); | ||
} else { | ||
console.error( | ||
'It appears that we are inside a hops project but the dependencies have', | ||
'not been installed.\n', | ||
'Please execute "yarn install" or "npm install" and retry.' | ||
); | ||
process.exit(1); | ||
} | ||
} else { | ||
var options = globalCLI(argv); | ||
var name = options.projectName; | ||
var root = process.cwd(); | ||
|
||
validateName(name); | ||
createDirectory(path.resolve(root, name)); | ||
writePackageManifest(path.resolve(root, name)); | ||
process.chdir(path.resolve(root, name)); | ||
installPackages(PACKAGES_TO_INSTALL, options); | ||
require(getLocalCliPath()).init(root, name, options); | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,95 +1,11 @@ | ||
# Hops CLI | ||
|
||
hops-cli provides a small set of commands to manage your hops project. Installing hops-cli is the minimum requirement for being able to start working with Hops. | ||
|
||
# Installation | ||
## Minimum installation for any project | ||
We assume that you already created a folder for your project and initialized it with `npm init -y`. Go to the root folder of your project and install hops-cli. This installs hops-config and hops-server as dependencies as well: | ||
``` bash | ||
npm install --save hops-cli | ||
``` | ||
|
||
That's it - at least this is sufficient to get you started with a very basic setup. | ||
|
||
## Additional setup for a React project | ||
In case you are going to implement a project with React, you need to install further packages: | ||
``` bash | ||
npm install --save react react-dom react-helmet react-router react-router-dom hops-react | ||
``` | ||
|
||
# Usage | ||
## Available commands | ||
The following commands are provided by hops-cli: | ||
|
||
- `hops build` - initiates a project build | ||
- `hops develop` - starts a Webpack development server | ||
- `hops serve` - initiates a project build, stores the build artifacts in the file system and starts a production (Express) server | ||
- `hops start` - if NODE_ENV is set to production, this runs `hops serve`. Otherwise, `hops develop` gets executed | ||
|
||
Please note that hops-cli is not meant to be called directly, but rather to be added to your project's package.json file and then called indirectly by using npm or yarn (see below). | ||
|
||
## Configure package.json | ||
To actually use the hops-cli commands, you have to add them to the scripts section of your project's package.json. Hops is designed to leverage npm/yarn features, so it does not make much sense to call the hops executable directly. | ||
|
||
``` JSON | ||
"scripts": { | ||
"build": "hops build", | ||
"develop": "hops develop", | ||
"serve": "hops serve", | ||
"start": "hops start" | ||
}, | ||
"config": { | ||
"hops": {} | ||
} | ||
``` | ||
|
||
However, for simple projects, it should be sufficient to just add `"start": "hops start"` here. | ||
|
||
To learn what configuration options are supported, please see the [`hops-config` docs](https://github.com/xing/hops/tree/master/packages/config#hops-config). | ||
|
||
## Static mode | ||
hops-cli can be used as a static site generator, too. To enable static mode, pass `--static` or `-s` to the above commands and configure a `locations` array to your package.json file. | ||
# Hops CLI | ||
|
||
``` JSON | ||
"scripts": { | ||
"start": "hops start --static" | ||
}, | ||
"config": { | ||
"hops": { | ||
"locations": ["/"] | ||
} | ||
} | ||
``` | ||
|
||
## Use via npm | ||
After that, you can execute them via npm like so: | ||
|
||
``` bash | ||
npm run build | ||
npm run develop | ||
npm run serve | ||
npm start | ||
npm start --production | ||
``` | ||
### Target Audience | ||
|
||
## Very basic example app | ||
To try out the [minimum installation described above](#minimum-installation-for-any-project), create an index.js file in the root folder of your project and put the following code in there: | ||
|
||
``` js | ||
export default function (req, res, next) { | ||
if (req) { | ||
console.log('server'); | ||
if (req.path === '/') { | ||
res.set('Content-Type', 'text/html'); | ||
res.send('<script src="/main.js"></script>'); | ||
} else { | ||
next(); | ||
} | ||
} else { | ||
console.log('browser'); | ||
} | ||
} | ||
|
||
``` | ||
### Example | ||
|
||
Don't forget to [configure the scripts section](#configure-packagejson) of your package.json. And you're done! |