Skip to content
This repository has been archived by the owner on Jan 11, 2023. It is now read-only.

better CLI #170

Merged
merged 7 commits into from
Mar 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ cypress/screenshots
test/app/.sapper
test/app/app/manifest
test/app/export
test/app/build
runtime.js
runtime.js.map
cli.js
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,21 @@
"code-frame": "^5.0.0",
"escape-html": "^1.0.3",
"express": "^4.16.2",
"get-port": "^3.2.0",
"glob": "^7.1.2",
"locate-character": "^2.0.5",
"mkdirp": "^0.5.1",
"mri": "^1.1.0",
"node-fetch": "^1.7.3",
"port-authority": "^1.0.0",
"pretty-ms": "^3.1.0",
"relative": "^3.0.2",
"require-relative": "^0.8.7",
"rimraf": "^2.6.2",
"sade": "^1.4.0",
"sander": "^0.6.0",
"serialize-javascript": "^1.4.0",
"source-map-support": "^0.5.3",
"tslib": "^1.8.1",
"tslib": "^1.9.0",
"url-parse": "^1.2.0",
"walk-sync": "^0.3.2",
"webpack-format-messages": "^1.0.1"
Expand All @@ -53,6 +54,7 @@
"electron": "^1.8.2",
"eslint": "^4.13.1",
"eslint-plugin-import": "^2.8.0",
"get-port": "^3.2.0",
"mocha": "^4.0.1",
"nightmare": "^2.10.0",
"npm-run-all": "^4.1.2",
Expand Down
13 changes: 11 additions & 2 deletions src/cli/build.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as fs from 'fs';
import * as path from 'path';
import chalk from 'chalk';
import mkdirp from 'mkdirp';
import rimraf from 'rimraf';
import { create_compilers, create_app, create_routes, create_serviceworker } from 'sapper/core.js'
Expand All @@ -19,9 +20,15 @@ export default async function build() {
const { client, server, serviceworker } = create_compilers();

const client_stats = await compile(client);
console.log(chalk.inverse(`\nbuilt client`));
console.log(client_stats.toString({ colors: true }));
fs.writeFileSync(path.join(output, 'client_info.json'), JSON.stringify(client_stats.toJson()));

await compile(server);
const server_stats = await compile(server);
console.log(chalk.inverse(`\nbuilt server`));
console.log(server_stats.toString({ colors: true }));

let serviceworker_stats;

if (serviceworker) {
create_serviceworker({
Expand All @@ -30,7 +37,9 @@ export default async function build() {
src
});

await compile(serviceworker);
serviceworker_stats = await compile(serviceworker);
console.log(chalk.inverse(`\nbuilt service worker`));
console.log(serviceworker_stats.toString({ colors: true }));
}
}

Expand Down
15 changes: 8 additions & 7 deletions src/cli/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import mkdirp from 'mkdirp';
import rimraf from 'rimraf';
import format_messages from 'webpack-format-messages';
import prettyMs from 'pretty-ms';
import { wait_for_port } from './utils';
import * as ports from 'port-authority';
import { dest } from '../config';
import { create_compilers, create_app, create_routes, create_serviceworker } from 'sapper/core.js';

Expand Down Expand Up @@ -70,15 +70,14 @@ function create_hot_update_server(port: number, interval = 10000) {
return { send };
}

export default async function dev() {
export default async function dev(port: number) {
process.env.NODE_ENV = 'development';

const dir = dest();
rimraf.sync(dir);
mkdirp.sync(dir);

// initial build
const dev_port = await require('get-port')(10000);
const dev_port = await ports.find(10000);

const routes = create_routes();
create_app({ routes, dev_port });
Expand Down Expand Up @@ -109,7 +108,7 @@ export default async function dev() {
unique_errors: new Set()
};

function restart_build(filename) {
function restart_build(filename: string) {
if (restarting) return;

restarting = true;
Expand Down Expand Up @@ -206,7 +205,7 @@ export default async function dev() {

deferreds.client.promise.then(() => {
function restart() {
wait_for_port(3000).then(deferreds.server.fulfil); // TODO control port
ports.wait(3000).then(deferreds.server.fulfil); // TODO control port
}

if (proc) {
Expand All @@ -218,7 +217,9 @@ export default async function dev() {

proc = child_process.fork(`${dir}/server.js`, [], {
cwd: process.cwd(),
env: Object.assign({}, process.env)
env: Object.assign({
PORT: port
}, process.env)
});
});
}
Expand Down
7 changes: 4 additions & 3 deletions src/cli/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import express from 'express';
import cheerio from 'cheerio';
import URL from 'url-parse';
import fetch from 'node-fetch';
import { wait_for_port } from './utils';
import * as ports from 'port-authority';
import { dest } from '../config';

const app = express();
Expand All @@ -27,7 +27,7 @@ export default async function exporter(export_dir: string) {
sander.copyFileSync(build_dir, 'service-worker.js').to(export_dir, 'service-worker.js');
}

const port = await require('get-port')(3000);
const port = await ports.find(3000);

const origin = `http://localhost:${port}`;

Expand All @@ -36,6 +36,7 @@ export default async function exporter(export_dir: string) {
env: {
PORT: port,
NODE_ENV: 'production',
SAPPER_DEST: build_dir,
SAPPER_EXPORT: 'true'
}
});
Expand Down Expand Up @@ -88,7 +89,7 @@ export default async function exporter(export_dir: string) {
});
}

wait_for_port(port)
return ports.wait(port)
.then(() => handle(new URL(origin))) // TODO all static routes
.then(() => proc.kill());
}
20 changes: 0 additions & 20 deletions src/cli/help.md

This file was deleted.

131 changes: 77 additions & 54 deletions src/cli/index.ts
Original file line number Diff line number Diff line change
@@ -1,89 +1,112 @@
import * as fs from 'fs';
import * as path from 'path';
import * as child_process from 'child_process';
import sade from 'sade';
import mri from 'mri';
import chalk from 'chalk';
import prettyMs from 'pretty-ms';
import help from './help.md';
import build from './build';
import exporter from './export';
import dev from './dev';
import upgrade from './upgrade';
import * as ports from 'port-authority';
import * as pkg from '../../package.json';

const opts = mri(process.argv.slice(2), {
alias: {
h: 'help'
}
});
const prog = sade('sapper').version(pkg.version);

prog.command('dev')
.describe('Start a development server')
.option('-p, --port', 'Specify a port')
.action(async ({ port }: { port: number }) => {
if (port) {
if (!await ports.check(port)) {
console.log(chalk.bold.red(`> Port ${port} is unavailable`));
return;
}
} else {
port = await ports.find(3000);
}

dev(port);
});

prog.command('build [dest]')
.describe('Create a production-ready version of your app')
.action((dest = 'build') => {
console.log(`> Building...`);

if (opts.help) {
const rendered = help
.replace('<@version@>', pkg.version)
.replace(/^(.+)/gm, (m: string, $1: string) => /[#>]/.test(m) ? $1 : ` ${$1}`)
.replace(/^# (.+)/gm, (m: string, $1: string) => chalk.bold.underline($1))
.replace(/^> (.+)/gm, (m: string, $1: string) => chalk.cyan($1));

console.log(`\n${rendered}\n`);
process.exit(0);
}

const [cmd] = opts._;

const start = Date.now();

switch (cmd) {
case 'build':
process.env.NODE_ENV = 'production';
process.env.SAPPER_DEST = opts._[1] || 'build';
process.env.SAPPER_DEST = dest;

const start = Date.now();

build()
.then(() => {
const elapsed = Date.now() - start;
console.error(`built in ${elapsed}ms`); // TODO beautify this, e.g. 'built in 4.7 seconds'
console.error(`\n> Finished in ${prettyMs(elapsed)}. Type ${chalk.bold.cyan(dest === 'build' ? 'npx sapper start' : `npx sapper start ${dest}`)} to run the app.`);
})
.catch(err => {
console.error(err ? err.details || err.stack || err.message || err : 'Unknown error');
});
});

prog.command('start [dir]')
.describe('Start your app')
.option('-p, --port', 'Specify a port')
.action(async (dir = 'build', { port }: { port: number }) => {
const resolved = path.resolve(dir);
const server = path.resolve(dir, 'server.js');

if (!fs.existsSync(server)) {
console.log(chalk.bold.red(`> ${dir}/server.js does not exist — type ${chalk.bold.cyan(dir === 'build' ? `npx sapper build` : `npx sapper build ${dir}`)} to create it`));
return;
}

if (port) {
if (!await ports.check(port)) {
console.log(chalk.bold.red(`> Port ${port} is unavailable`));
return;
}
} else {
port = await ports.find(3000);
}

child_process.fork(server, [], {
cwd: process.cwd(),
env: Object.assign({
NODE_ENV: 'production',
PORT: port,
SAPPER_DEST: dir
}, process.env)
});
});

break;
prog.command('export [dest]')
.describe('Export your app as static files (if possible)')
.action((dest = 'export') => {
console.log(`> Building...`);

case 'export':
process.env.NODE_ENV = 'production';
process.env.SAPPER_DEST = '.sapper/.export';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More for my own curiosity, but why not set SAPPER_DEST from within export()? Especially since the dest is variable

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used by build first — it sends the webpack output to .sapper/.export, and then sapper export runs the code therein to generate the export directory. So it has to be set before either thing happens


const export_dir = opts._[1] || 'export';
const start = Date.now();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use process.hrtime if you want to be a little more exact. Roughly the same though

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when pretty-ms is involved I don't think it'll make any difference. I generally avoid process.hrtime because, well, the signature is batshit


build()
.then(() => exporter(export_dir))
.then(() => {
const elapsed = Date.now() - start;
console.error(`extracted in ${elapsed}ms`); // TODO beautify this, e.g. 'built in 4.7 seconds'
console.error(`\n> Built in ${prettyMs(elapsed)}. Exporting...`);
})
.then(() => exporter(dest))
.then(() => {
const elapsed = Date.now() - start;
console.error(`\n> Finished in ${prettyMs(elapsed)}. Type ${chalk.bold.cyan(`npx serve ${dest}`)} to run the app.`);
})
.catch(err => {
console.error(err ? err.details || err.stack || err.message || err : 'Unknown error');
});
});

break;

case 'dev':
dev();
break;

case 'upgrade':
upgrade();
break;

case 'start':
const dir = path.resolve(opts._[1] || 'build');

child_process.fork(`${dir}/server.js`, [], {
cwd: process.cwd(),
env: Object.assign({
NODE_ENV: 'production',
SAPPER_DEST: dir
}, process.env)
});

break;
// TODO upgrade

default:
console.log(`unrecognized command ${cmd} — try \`sapper --help\` for more information`);
}
prog.parse(process.argv);
25 changes: 0 additions & 25 deletions src/cli/utils.ts

This file was deleted.

Loading