Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI-less api for node #4344

Merged
merged 4 commits into from
Oct 11, 2018
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion app/angular/src/server/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { buildDev } from '@storybook/core/server';

import options from './options';

buildDev(options);
8 changes: 8 additions & 0 deletions app/angular/standalone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const build = require('@storybook/core/standalone');
const frameworkOptions = require('./dist/server/options').default;

async function buildStandalone(options) {
return build(options, frameworkOptions);
}

module.exports = buildStandalone;
1 change: 0 additions & 1 deletion app/ember/src/server/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { buildDev } from '@storybook/core/server';

import options from './options';

buildDev(options);
8 changes: 8 additions & 0 deletions app/ember/standalone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const build = require('@storybook/core/standalone');
const frameworkOptions = require('./dist/server/options').default;

async function buildStandalone(options) {
return build(options, frameworkOptions);
}

module.exports = buildStandalone;
1 change: 0 additions & 1 deletion app/html/src/server/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { buildDev } from '@storybook/core/server';

import options from './options';

buildDev(options);
8 changes: 8 additions & 0 deletions app/html/standalone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const build = require('@storybook/core/standalone');
const frameworkOptions = require('./dist/server/options').default;

async function buildStandalone(options) {
return build(options, frameworkOptions);
}

module.exports = buildStandalone;
1 change: 0 additions & 1 deletion app/marko/src/server/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { buildDev } from '@storybook/core/server';

import options from './options';

buildDev(options);
8 changes: 8 additions & 0 deletions app/marko/standalone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const build = require('@storybook/core/standalone');
const frameworkOptions = require('./dist/server/options').default;

async function buildStandalone(options) {
return build(options, frameworkOptions);
}

module.exports = buildStandalone;
1 change: 0 additions & 1 deletion app/mithril/src/server/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { buildDev } from '@storybook/core/server';

import options from './options';

buildDev(options);
8 changes: 8 additions & 0 deletions app/mithril/standalone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const build = require('@storybook/core/standalone');
const frameworkOptions = require('./dist/server/options').default;

async function buildStandalone(options) {
return build(options, frameworkOptions);
}

module.exports = buildStandalone;
1 change: 0 additions & 1 deletion app/polymer/src/server/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { buildDev } from '@storybook/core/server';

import options from './options';

buildDev(options);
8 changes: 8 additions & 0 deletions app/polymer/standalone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const build = require('@storybook/core/standalone');
const frameworkOptions = require('./dist/server/options').default;

async function buildStandalone(options) {
return build(options, frameworkOptions);
}

module.exports = buildStandalone;
1 change: 0 additions & 1 deletion app/react/src/server/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { buildDev } from '@storybook/core/server';

import options from './options';

buildDev(options);
8 changes: 8 additions & 0 deletions app/react/standalone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const build = require('@storybook/core/standalone');
const frameworkOptions = require('./dist/server/options').default;

async function buildStandalone(options) {
return build(options, frameworkOptions);
}

module.exports = buildStandalone;
1 change: 0 additions & 1 deletion app/riot/src/server/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { buildDev } from '@storybook/core/server';

import options from './options';

buildDev(options);
8 changes: 8 additions & 0 deletions app/riot/standalone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const build = require('@storybook/core/standalone');
const frameworkOptions = require('./dist/server/options').default;

async function buildStandalone(options) {
return build(options, frameworkOptions);
}

module.exports = buildStandalone;
1 change: 0 additions & 1 deletion app/svelte/src/server/build.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { buildStatic } from '@storybook/core/server';

import options from './options';

buildStatic(options);
1 change: 0 additions & 1 deletion app/svelte/src/server/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { buildDev } from '@storybook/core/server';

import options from './options';

buildDev(options);
8 changes: 8 additions & 0 deletions app/svelte/standalone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const build = require('@storybook/core/standalone');
const frameworkOptions = require('./dist/server/options').default;

async function buildStandalone(options) {
return build(options, frameworkOptions);
}

module.exports = buildStandalone;
1 change: 0 additions & 1 deletion app/vue/src/server/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { buildDev } from '@storybook/core/server';

import options from './options';

buildDev(options);
8 changes: 8 additions & 0 deletions app/vue/standalone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const build = require('@storybook/core/standalone');
const frameworkOptions = require('./dist/server/options').default;

async function buildStandalone(options) {
return build(options, frameworkOptions);
}

module.exports = buildStandalone;
167 changes: 67 additions & 100 deletions lib/core/src/server/build-dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,121 +2,59 @@ import express from 'express';
import https from 'https';
import ip from 'ip';
import favicon from 'serve-favicon';
import program from 'commander';
import path from 'path';
import fs from 'fs';
import chalk from 'chalk';
import detectFreePort from 'detect-port';
import inquirer from 'inquirer';
import { logger } from '@storybook/node-logger';
import opn from 'opn';

import storybook, { webpackValid } from './middleware';
import { parseList, getEnvConfig } from './utils';
import { getDevCli } from './cli';
import './config/env';

const defaultFavIcon = require.resolve('./public/favicon.ico');

const getFreePort = port =>
detectFreePort(port).catch(error => {
logger.error(error);
process.exit(-1);
});

export async function buildDev({ packageJson, ...loadOptions }) {
process.env.NODE_ENV = process.env.NODE_ENV || 'development';

program
.version(packageJson.version)
.option('-p, --port [number]', 'Port to run Storybook', str => parseInt(str, 10))
.option('-h, --host [string]', 'Host to run Storybook')
.option('-s, --static-dir <dir-names>', 'Directory where to load static files from')
.option('-c, --config-dir [dir-name]', 'Directory where to load Storybook configurations from')
.option(
'--https',
'Serve Storybook over HTTPS. Note: You must provide your own certificate information.'
)
.option(
'--ssl-ca <ca>',
'Provide an SSL certificate authority. (Optional with --https, required if using a self-signed certificate)',
parseList
)
.option('--ssl-cert <cert>', 'Provide an SSL certificate. (Required with --https)')
.option('--ssl-key <key>', 'Provide an SSL key. (Required with --https)')
.option('--smoke-test', 'Exit after successful start')
.option('--ci', "CI mode (skip interactive prompts, don't open browser")
.option('--quiet', 'Suppress verbose build output')
.parse(process.argv);

logger.info(chalk.bold(`${packageJson.name} v${packageJson.version}`) + chalk.reset('\n'));

// The key is the field created in `program` variable for
// each command line argument. Value is the env variable.
getEnvConfig(program, {
port: 'SBCONFIG_PORT',
host: 'SBCONFIG_HOSTNAME',
staticDir: 'SBCONFIG_STATIC_DIR',
configDir: 'SBCONFIG_CONFIG_DIR',
});

const port = await getFreePort(program.port);

if (!program.ci && !program.smokeTest && program.port != null && port !== program.port) {
const { shouldChangePort } = await inquirer.prompt({
type: 'confirm',
default: true,
name: 'shouldChangePort',
message: `Port ${program.port} is not available.
Would you like to run Storybook on port ${port} instead?`,
});
if (!shouldChangePort) {
process.exit(1);
}
function getServer(app, options) {
if (!options.https) {
return app;
}

// Used with `app.listen` below
const listenAddr = [port];

if (program.host) {
listenAddr.push(program.host);
if (!options.sslCert) {
logger.error('Error: --ssl-cert is required with --https');
process.exit(-1);
}

const app = express();
let server = app;

if (program.https) {
if (!program.sslCert) {
logger.error('Error: --ssl-cert is required with --https');
process.exit(-1);
}
if (!program.sslKey) {
logger.error('Error: --ssl-key is required with --https');
process.exit(-1);
}
if (!options.sslKey) {
logger.error('Error: --ssl-key is required with --https');
process.exit(-1);
}

const sslOptions = {
ca: (program.sslCa || []).map(ca => fs.readFileSync(ca, 'utf-8')),
cert: fs.readFileSync(program.sslCert, 'utf-8'),
key: fs.readFileSync(program.sslKey, 'utf-8'),
};
const sslOptions = {
ca: (options.sslCa || []).map(ca => fs.readFileSync(ca, 'utf-8')),
cert: fs.readFileSync(options.sslCert, 'utf-8'),
key: fs.readFileSync(options.sslKey, 'utf-8'),
};

server = https.createServer(sslOptions, app);
}
return https.createServer(sslOptions, app);
}

function applyStatic(app, options) {
const { staticDir } = options;
let hasCustomFavicon = false;

if (program.staticDir) {
program.staticDir = parseList(program.staticDir);
program.staticDir.forEach(dir => {
if (staticDir) {
staticDir.forEach(dir => {
const staticPath = path.resolve(dir);

if (!fs.existsSync(staticPath)) {
logger.error(`Error: no such directory to load static files: ${staticPath}`);
process.exit(-1);
}

logger.info(`=> Loading static files from: ${staticPath} .`);
app.use(express.static(staticPath, { index: false }));

const faviconPath = path.resolve(staticPath, 'favicon.ico');

if (fs.existsSync(faviconPath)) {
hasCustomFavicon = true;
app.use(favicon(faviconPath));
Expand All @@ -127,21 +65,17 @@ Would you like to run Storybook on port ${port} instead?`,
if (!hasCustomFavicon) {
app.use(favicon(defaultFavIcon));
}
}

// Build the webpack configuration using the `baseConfig`
// custom `.babelrc` file and `webpack.config.js` files
const configDir = program.configDir || './.storybook';

// NOTE changes to env should be done before calling `getBaseConfig`
// `getBaseConfig` function which is called inside the middleware
app.use(storybook(configDir, loadOptions, program.quiet));

function listenToServer(server, listenAddr) {
let serverResolve = () => {};
let serverReject = () => {};

const serverListening = new Promise((resolve, reject) => {
serverResolve = resolve;
serverReject = reject;
});

server.listen(...listenAddr, error => {
if (error) {
serverReject(error);
Expand All @@ -150,24 +84,57 @@ Would you like to run Storybook on port ${port} instead?`,
}
});

return serverListening;
}

export async function buildDevStandalone(options) {
const { port, host } = options;

// Used with `app.listen` below
const listenAddr = [port];

if (host) {
listenAddr.push(host);
}

const app = express();
const server = getServer(app, options);

applyStatic(app, options);

app.use(storybook(options));

const serverListening = listenToServer(server, listenAddr);

try {
const [stats] = await Promise.all([webpackValid, serverListening]);
const proto = program.https ? 'https' : 'http';
const address = `${proto}://${program.host || 'localhost'}:${port}/`;
const proto = options.https ? 'https' : 'http';
const address = `${proto}://${host || 'localhost'}:${port}/`;
const networkAddress = `${proto}://${ip.address()}:${port}/`;
logger.info(`Storybook started on => ${chalk.cyan(address)}`);
logger.info(`Available on the network at => ${chalk.cyan(networkAddress)}\n`);
if (program.smokeTest) {

if (options.smokeTest) {
process.exit(stats.toJson().warnings.length ? 1 : 0);
} else if (!program.ci) {
} else if (!options.ci) {
opn(address);
}
} catch (error) {
if (error instanceof Error) {
logger.error(error);
}
if (program.smokeTest) {
if (options.smokeTest) {
process.exit(1);
}
}
}

export async function buildDev({ packageJson, ...loadOptions }) {
const cliOptions = await getDevCli(packageJson);

await buildDevStandalone({
...cliOptions,
...loadOptions,
configDir: cliOptions.configDir || './.storybook',
});
}