mirror of
https://github.com/storybookjs/storybook.git
synced 2025-03-31 05:03:21 +08:00
161 lines
5.0 KiB
JavaScript
Executable File
161 lines
5.0 KiB
JavaScript
Executable File
import express from 'express';
|
|
import https from 'https';
|
|
import favicon from 'serve-favicon';
|
|
import program from 'commander';
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
import chalk from 'chalk';
|
|
import shelljs from 'shelljs';
|
|
import storybook, { webpackValid } from './middleware';
|
|
import packageJson from '../../package.json';
|
|
import { parseList, getEnvConfig } from './utils';
|
|
|
|
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
|
|
|
const logger = console;
|
|
|
|
program
|
|
.version(packageJson.version)
|
|
.option('-p, --port [number]', 'Port to run Storybook (Required)', 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('-d, --db-path [db-file]', 'DEPRECATED!')
|
|
.option('--enable-db', 'DEPRECATED!')
|
|
.parse(process.argv);
|
|
|
|
logger.info(chalk.bold(`${packageJson.name} v${packageJson.version}`) + chalk.reset('\n'));
|
|
|
|
if (program.enableDb || program.dbPath) {
|
|
logger.error(
|
|
[
|
|
'Error: the experimental local database addon is no longer bundled with',
|
|
'react-storybook. Please remove these flags (-d,--db-path,--enable-db)',
|
|
'from the command or npm script and try again.',
|
|
].join(' ')
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
// 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',
|
|
});
|
|
|
|
if (!program.port) {
|
|
logger.error('Error: port to run Storybook is required!\n');
|
|
program.help();
|
|
process.exit(-1);
|
|
}
|
|
|
|
// Used with `app.listen` below
|
|
const listenAddr = [program.port];
|
|
|
|
if (program.host) {
|
|
listenAddr.push(program.host);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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'),
|
|
};
|
|
|
|
server = https.createServer(sslOptions, app);
|
|
}
|
|
|
|
let hasCustomFavicon = false;
|
|
|
|
if (program.staticDir) {
|
|
program.staticDir = parseList(program.staticDir);
|
|
program.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.log(`=> 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));
|
|
}
|
|
});
|
|
}
|
|
|
|
if (!hasCustomFavicon) {
|
|
app.use(favicon(path.resolve(__dirname, 'public/favicon.ico')));
|
|
}
|
|
|
|
// Build the webpack configuration using the `baseConfig`
|
|
// custom `.babelrc` file and `webpack.config.js` files
|
|
const configDir = program.configDir || './.storybook';
|
|
|
|
// The repository info is sent to the storybook while running on
|
|
// development mode so it'll be easier for tools to integrate.
|
|
const exec = cmd => shelljs.exec(cmd, { silent: true }).stdout.trim();
|
|
process.env.STORYBOOK_GIT_ORIGIN =
|
|
process.env.STORYBOOK_GIT_ORIGIN || exec('git remote get-url origin');
|
|
process.env.STORYBOOK_GIT_BRANCH =
|
|
process.env.STORYBOOK_GIT_BRANCH || exec('git symbolic-ref HEAD --short');
|
|
|
|
// NOTE changes to env should be done before calling `getBaseConfig`
|
|
// `getBaseConfig` function which is called inside the middleware
|
|
app.use(storybook(configDir));
|
|
|
|
let serverResolve = () => {};
|
|
let serverReject = () => {};
|
|
const serverListening = new Promise((resolve, reject) => {
|
|
serverResolve = resolve;
|
|
serverReject = reject;
|
|
});
|
|
server.listen(...listenAddr, error => {
|
|
if (error) {
|
|
serverReject(error);
|
|
} else {
|
|
serverResolve();
|
|
}
|
|
});
|
|
|
|
Promise.all([webpackValid, serverListening])
|
|
.then(() => {
|
|
const proto = program.https ? 'https' : 'http';
|
|
const address = `${proto}://${program.host || 'localhost'}:${program.port}/`;
|
|
logger.info(`Storybook started on => ${chalk.cyan(address)}\n`);
|
|
if (program.smokeTest) {
|
|
process.exit(0);
|
|
}
|
|
})
|
|
.catch(error => logger.error(error));
|