mirror of
https://github.com/modernweb-dev/rocket.git
synced 2026-03-10 08:51:24 +00:00
feat(cli): add start message with local and network url
This commit is contained in:
5
.changeset/kind-bats-occur.md
Normal file
5
.changeset/kind-bats-occur.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@rocket/engine': patch
|
||||
---
|
||||
|
||||
Add `engine.getVersion()` method
|
||||
12
.changeset/thirty-scissors-jam.md
Normal file
12
.changeset/thirty-scissors-jam.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
'@rocket/cli': patch
|
||||
---
|
||||
|
||||
Add start message for `rocket start`
|
||||
|
||||
```
|
||||
🚀 Rocket Engine v0.2.5
|
||||
|
||||
🚧 Local: http://localhost:8000/
|
||||
🌐 Network: http://xxx.xxx.xxx.xxx:8000/
|
||||
```
|
||||
@@ -36,7 +36,7 @@
|
||||
"start:experimental": "NODE_DEBUG=engine:rendering node --no-warnings --experimental-loader ./packages/engine/src/litCssLoader.js packages/cli/src/cli.js start --open",
|
||||
"start": "NODE_DEBUG=engine:rendering node --trace-warnings packages/cli/src/cli.js start --open",
|
||||
"test": "yarn test:node && yarn test:web",
|
||||
"test:integration": "playwright test packages/*/test-node/*.spec.js",
|
||||
"test:integration": "playwright test packages/*/test-node/*.spec.js --retries=3",
|
||||
"test:node": "yarn test:unit && yarn test:integration",
|
||||
"test:unit": "node --trace-warnings ./node_modules/.bin/mocha --require ./scripts/testMochaGlobalHooks.js \"packages/*/test-node/**/*.test.{ts,js,mjs,cjs}\" -- --timeout 8000 --reporter dot --exit",
|
||||
"test:web": "web-test-runner",
|
||||
|
||||
@@ -59,10 +59,12 @@
|
||||
"commander": "^9.0.0",
|
||||
"fs-extra": "^9.0.1",
|
||||
"gray-matter": "^4.0.3",
|
||||
"ip": "^1.1.5",
|
||||
"plugins-manager": "^0.3.0",
|
||||
"puppeteer": "^13.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/ip": "^1.1.0",
|
||||
"koa-proxy": "^1.0.0-alpha.3"
|
||||
},
|
||||
"types": "./dist-types/src/index.d.ts",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { fromRollup } from '@web/dev-server-rollup';
|
||||
|
||||
import { Engine } from '@rocket/engine/server';
|
||||
import { logStartMessage } from './start/logStartMessage.js';
|
||||
|
||||
export class RocketStart {
|
||||
/** @type {Engine | undefined} */
|
||||
@@ -60,7 +61,14 @@ export class RocketStart {
|
||||
setupDevServerPlugins: [...this.cli.options.setupDevServerPlugins, ...withWrap],
|
||||
});
|
||||
try {
|
||||
console.log('🚀 Engines online');
|
||||
this.engine.events.on('devServerStarted', () => {
|
||||
if (this.engine?.devServer) {
|
||||
logStartMessage(
|
||||
{ devServerOptions: this.engine.devServer?.config, engine: this.engine },
|
||||
console,
|
||||
);
|
||||
}
|
||||
});
|
||||
await this.engine.start();
|
||||
} catch (e) {
|
||||
console.log('Engine start errored');
|
||||
@@ -71,7 +79,6 @@ export class RocketStart {
|
||||
async stop({ hard = true } = {}) {
|
||||
if (this.engine) {
|
||||
await this.engine.stop({ hard });
|
||||
console.log('🚀 Engines offline');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
54
packages/cli/src/start/logStartMessage.js
Normal file
54
packages/cli/src/start/logStartMessage.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import ip from 'ip';
|
||||
import { white, bold, cyan, gray } from 'colorette';
|
||||
|
||||
/** @typedef {import('@web/dev-server').DevServerConfig} DevServerConfig */
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {DevServerConfig} devServerOptions
|
||||
* @param {string} host
|
||||
* @param {string} path
|
||||
* @returns {string}
|
||||
*/
|
||||
function createAddress(devServerOptions, host, path) {
|
||||
return `http${devServerOptions.http2 ? 's' : ''}://${host}:${devServerOptions.port}${path}`;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {DevServerConfig} devServerOptions
|
||||
* @param {console} logger
|
||||
* @param {string} openPath
|
||||
*/
|
||||
function logNetworkAddress(devServerOptions, logger, openPath) {
|
||||
try {
|
||||
const address = ip.address();
|
||||
if (typeof address === 'string') {
|
||||
logger.log(
|
||||
`${white(' 🌐 Network:')} ${cyan(createAddress(devServerOptions, address, openPath))}`,
|
||||
);
|
||||
}
|
||||
} catch (_a) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ devServerOptions: DevServerConfig, engine: import('@rocket/engine/server').Engine}} options
|
||||
* @param {console} logger
|
||||
*/
|
||||
export function logStartMessage({ devServerOptions, engine }, logger) {
|
||||
const prettyHost = devServerOptions.hostname ?? 'localhost';
|
||||
let openPath = typeof devServerOptions.open === 'string' ? devServerOptions.open : '/';
|
||||
if (!openPath.startsWith('/')) {
|
||||
openPath = `/${openPath}`;
|
||||
}
|
||||
|
||||
logger.log(`${bold(`🚀 Rocket Engine`)} ${gray(`v${engine.getVersion()}`)}`);
|
||||
logger.log('');
|
||||
logger.log(
|
||||
`${white(' 🚧 Local:')} ${cyan(createAddress(devServerOptions, prettyHost, openPath))}`,
|
||||
);
|
||||
logNetworkAddress(devServerOptions, logger, openPath);
|
||||
logger.log('');
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import { setupTestCli } from './test-helpers.js';
|
||||
|
||||
export function prepareTestCli(importMetaUrl) {
|
||||
const dir = path.dirname(fileURLToPath(importMetaUrl));
|
||||
return (cwd, cliOptions = ['build'], options = {}) => setupTestCli(cwd, cliOptions, options, dir);
|
||||
return fullOptions => setupTestCli({ dir, ...fullOptions });
|
||||
}
|
||||
|
||||
const { expect } = chai;
|
||||
|
||||
@@ -60,7 +60,13 @@ function cleanupLitMarkersFn(text) {
|
||||
return newText;
|
||||
}
|
||||
|
||||
export async function setupTestCli(cwd, cliOptions = ['build'], options = {}, dir) {
|
||||
export async function setupTestCli({
|
||||
cwd,
|
||||
cliOptions = ['build'],
|
||||
options = {},
|
||||
testOptions = {},
|
||||
dir,
|
||||
}) {
|
||||
const resolvedCwd = path.join(dir, cwd.split('/').join(path.sep));
|
||||
const useOptions = { buildOptimize: false, buildAutoStop: false, ...options, cwd: resolvedCwd };
|
||||
if (useOptions.inputDir) {
|
||||
@@ -69,6 +75,18 @@ export async function setupTestCli(cwd, cliOptions = ['build'], options = {}, di
|
||||
useOptions.outputDir = path.join(resolvedCwd, '__output');
|
||||
useOptions.outputDevDir = path.join(resolvedCwd, '__output-dev');
|
||||
|
||||
const capturedLogs = [];
|
||||
const origLog = console.log;
|
||||
const origError = console.error;
|
||||
if (testOptions.captureLogs) {
|
||||
console.log = msg => {
|
||||
capturedLogs.push(msg);
|
||||
};
|
||||
console.error = msg => {
|
||||
capturedLogs.push(msg);
|
||||
};
|
||||
}
|
||||
|
||||
const cli = new RocketCli({
|
||||
argv: [process.argv[0], new URL('../src/cli.js', import.meta.url).pathname, ...cliOptions],
|
||||
});
|
||||
@@ -184,6 +202,10 @@ export async function setupTestCli(cwd, cliOptions = ['build'], options = {}, di
|
||||
|
||||
async function cleanup() {
|
||||
await cli.stop({ hard: false });
|
||||
if (testOptions.captureLogs) {
|
||||
console.log = origLog;
|
||||
console.error = origError;
|
||||
}
|
||||
}
|
||||
|
||||
async function build() {
|
||||
@@ -243,5 +265,6 @@ export async function setupTestCli(cwd, cliOptions = ['build'], options = {}, di
|
||||
renameSource,
|
||||
backupOrRestoreSource,
|
||||
restoreSource,
|
||||
capturedLogs,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@ const { expect } = chai;
|
||||
|
||||
describe('Config', () => {
|
||||
it('01: no config file', async () => {
|
||||
const { build, readOutput, readDevOutput } = await setupTestCli(
|
||||
'fixtures/01-config/01-no-config/',
|
||||
undefined,
|
||||
{ buildOptimize: true },
|
||||
);
|
||||
const { build, readOutput, readDevOutput } = await setupTestCli({
|
||||
cwd: 'fixtures/01-config/01-no-config/',
|
||||
options: { buildOptimize: true },
|
||||
testOptions: { captureLogs: true },
|
||||
});
|
||||
await build();
|
||||
|
||||
expect(readOutput('index.html')).to.equal(
|
||||
@@ -31,14 +31,21 @@ describe('Config', () => {
|
||||
});
|
||||
|
||||
it('02: change input dir', async () => {
|
||||
const { build, readDevOutput } = await setupTestCli('fixtures/01-config/02-change-input-dir/');
|
||||
const { build, readDevOutput } = await setupTestCli({
|
||||
cwd: 'fixtures/01-config/02-change-input-dir/',
|
||||
testOptions: { captureLogs: true },
|
||||
});
|
||||
await build();
|
||||
|
||||
expect(readDevOutput('index.html')).to.equal(['Hello World!'].join('\n'));
|
||||
});
|
||||
|
||||
it('03: can add a middleware (api proxy) to the dev server', async () => {
|
||||
const { cleanup, cli } = await setupTestCli('fixtures/01-config/03-add-middleware/', ['start']);
|
||||
const { cleanup, cli } = await setupTestCli({
|
||||
cwd: 'fixtures/01-config/03-add-middleware/',
|
||||
cliOptions: ['start'],
|
||||
testOptions: { captureLogs: true },
|
||||
});
|
||||
const apiServer = http.createServer((request, response) => {
|
||||
if (request.url === '/api/message') {
|
||||
response.writeHead(200);
|
||||
@@ -61,20 +68,22 @@ describe('Config', () => {
|
||||
});
|
||||
|
||||
it('04: can add a rollup plugin via setupDevServerAndBuildPlugins to build', async () => {
|
||||
const { build, readOutput } = await setupTestCli(
|
||||
'fixtures/01-config/04-add-rollup-plugin/',
|
||||
undefined,
|
||||
{ buildOptimize: true },
|
||||
);
|
||||
const { build, readOutput } = await setupTestCli({
|
||||
cwd: 'fixtures/01-config/04-add-rollup-plugin/',
|
||||
options: { buildOptimize: true },
|
||||
testOptions: { captureLogs: true },
|
||||
});
|
||||
await build();
|
||||
const inlineModule = await readOutput('e97af63d.js', { format: false });
|
||||
expect(inlineModule).to.equal('var a={test:"data"};console.log(a);\n');
|
||||
});
|
||||
|
||||
it('04a: can add a rollup plugin via setupDevServerAndBuildPlugins to start', async () => {
|
||||
const { cli, cleanup } = await setupTestCli('fixtures/01-config/04-add-rollup-plugin/', [
|
||||
'start',
|
||||
]);
|
||||
const { cli, cleanup } = await setupTestCli({
|
||||
cwd: 'fixtures/01-config/04-add-rollup-plugin/',
|
||||
cliOptions: ['start'],
|
||||
testOptions: { captureLogs: true },
|
||||
});
|
||||
await cli.start();
|
||||
const { port } = cli?.activePlugin?.engine.devServer.config;
|
||||
|
||||
@@ -88,9 +97,10 @@ describe('Config', () => {
|
||||
});
|
||||
|
||||
it('05: long file header comments', async () => {
|
||||
const { build, readSource } = await setupTestCli(
|
||||
'fixtures/01-config/05-long-file-header-comment/',
|
||||
);
|
||||
const { build, readSource } = await setupTestCli({
|
||||
cwd: 'fixtures/01-config/05-long-file-header-comment/',
|
||||
testOptions: { captureLogs: true },
|
||||
});
|
||||
await build();
|
||||
|
||||
expect(readSource('index.rocket.js', { format: false })).to.equal(
|
||||
|
||||
@@ -5,13 +5,13 @@ const { expect } = chai;
|
||||
|
||||
describe('Build', () => {
|
||||
it('01: copy public files', async () => {
|
||||
const { build, readOutput, outputExists, readDevOutput } = await setupTestCli(
|
||||
'fixtures/02-build/01-copy-public-files/',
|
||||
undefined,
|
||||
{
|
||||
const { build, readOutput, outputExists, readDevOutput } = await setupTestCli({
|
||||
cwd: 'fixtures/02-build/01-copy-public-files/',
|
||||
options: {
|
||||
buildOptimize: true,
|
||||
},
|
||||
);
|
||||
testOptions: { captureLogs: true },
|
||||
});
|
||||
await build();
|
||||
|
||||
expect(readOutput('index.html')).to.equal(
|
||||
|
||||
@@ -6,7 +6,11 @@ const { expect } = chai;
|
||||
describe('Upgrade System', () => {
|
||||
it('2021-09-menu', async () => {
|
||||
const { build, sourceExists, readSource, backupOrRestoreSource, restoreSource } =
|
||||
await setupTestCli('fixtures/03-upgrade/2022-03-menu', ['upgrade']);
|
||||
await setupTestCli({
|
||||
cwd: 'fixtures/03-upgrade/2022-03-menu',
|
||||
cliOptions: ['upgrade'],
|
||||
testOptions: { captureLogs: true },
|
||||
});
|
||||
await backupOrRestoreSource();
|
||||
|
||||
await build();
|
||||
|
||||
@@ -5,13 +5,13 @@ const { expect } = chai;
|
||||
|
||||
describe('Open Graph', () => {
|
||||
it('generates the image and adds the meta tags', async () => {
|
||||
const { build, readOutput, outputExists } = await setupTestCli(
|
||||
'fixtures/04-open-graph/01-generate-image-and-inject-meta',
|
||||
undefined,
|
||||
{
|
||||
const { build, readOutput, outputExists } = await setupTestCli({
|
||||
cwd: 'fixtures/04-open-graph/01-generate-image-and-inject-meta',
|
||||
options: {
|
||||
buildOptimize: true,
|
||||
},
|
||||
);
|
||||
testOptions: { captureLogs: true },
|
||||
});
|
||||
await build();
|
||||
|
||||
expect(readOutput('index.html', { replaceImageHashes: true })).to.equal(
|
||||
@@ -35,13 +35,13 @@ describe('Open Graph', () => {
|
||||
});
|
||||
|
||||
it('handles multiple pages', async () => {
|
||||
const { build, readOutput } = await setupTestCli(
|
||||
'fixtures/04-open-graph/02-multiple-pages',
|
||||
undefined,
|
||||
{
|
||||
const { build, readOutput } = await setupTestCli({
|
||||
cwd: 'fixtures/04-open-graph/02-multiple-pages',
|
||||
options: {
|
||||
buildOptimize: true,
|
||||
},
|
||||
);
|
||||
testOptions: { captureLogs: true },
|
||||
});
|
||||
await build();
|
||||
|
||||
expect(readOutput('index.html', { replaceImageHashes: true })).to.equal(
|
||||
|
||||
25
packages/cli/test-node/05-start.test.js
Normal file
25
packages/cli/test-node/05-start.test.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import chai from 'chai';
|
||||
import { white, bold } from 'colorette';
|
||||
|
||||
import { setupTestCli } from './test-helpers.js';
|
||||
|
||||
const { expect } = chai;
|
||||
|
||||
describe('Start', () => {
|
||||
it('Start Message', async () => {
|
||||
const { cli, capturedLogs, cleanup } = await setupTestCli({
|
||||
cwd: 'fixtures/05-start/01-start-message',
|
||||
cliOptions: ['start'],
|
||||
testOptions: { captureLogs: true },
|
||||
});
|
||||
|
||||
await cli.start();
|
||||
await cleanup();
|
||||
|
||||
expect(capturedLogs[0].startsWith(`${bold(`🚀 Rocket Engine`)} `)).to.be.true;
|
||||
expect(capturedLogs[1]).to.equal('');
|
||||
expect(capturedLogs[2].startsWith(`${white(' 🚧 Local:')}`)).to.be.true;
|
||||
expect(capturedLogs[3].startsWith(`${white(' 🌐 Network:')}`)).to.be.true;
|
||||
expect(capturedLogs[4]).to.equal('');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
/* START - Rocket auto generated - do not touch */
|
||||
export const sourceRelativeFilePath = 'index.rocket.js';
|
||||
/* END - Rocket auto generated - do not touch */
|
||||
|
||||
export default () => 'Hello World!';
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "index.rocket.js",
|
||||
"menuLinkText": "index.rocket.js",
|
||||
"url": "/",
|
||||
"outputRelativeFilePath": "index.html",
|
||||
"sourceRelativeFilePath": "index.rocket.js",
|
||||
"level": 0
|
||||
}
|
||||
@@ -36,7 +36,7 @@
|
||||
"debug": "DEBUG=engine:rendering yarn test",
|
||||
"debug:integration": "PWDEBUG=1 yarn test:integration",
|
||||
"test": "mocha --require ../../scripts/testMochaGlobalHooks.js --timeout 8000 test-node/**/*.test.js test-node/*.test.js",
|
||||
"test:integration": "playwright test test-node/*.spec.js",
|
||||
"test:integration": "playwright test test-node/*.spec.js --retries=3",
|
||||
"test:watch": "onchange 'src/**/*.js' 'test-node/**/*.js' -- npm test",
|
||||
"types:copy": "copyfiles \"./types/**/*.d.ts\" dist-types/"
|
||||
},
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import { existsSync } from 'fs';
|
||||
// TODO: implement copy without extra dependency => node 16.7.0 copy has recursive
|
||||
import fse from 'fs-extra';
|
||||
import { mkdir, rm } from 'fs/promises';
|
||||
import { mkdir, readFile, rm } from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { EventEmitter } from 'events';
|
||||
import { startDevServer } from '@web/dev-server';
|
||||
@@ -32,6 +32,8 @@ import { RocketHeader } from './file-header/RocketHeader.js';
|
||||
|
||||
const logRendering = debuglog('engine:rendering');
|
||||
|
||||
const pkgJson = JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8'));
|
||||
|
||||
export class Engine {
|
||||
/** @type {EngineOptions} */
|
||||
options = {
|
||||
@@ -267,6 +269,7 @@ export class Engine {
|
||||
readFileConfig: false,
|
||||
// argv: this.__argv,
|
||||
});
|
||||
this.events.emit('devServerStarted');
|
||||
|
||||
this.devServer.webSockets.on(
|
||||
'message',
|
||||
@@ -469,4 +472,8 @@ export class Engine {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
getVersion() {
|
||||
return pkgJson.version;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,13 +7,13 @@ const { expect } = chai;
|
||||
|
||||
describe('Search', () => {
|
||||
it('01: writes the search index', async () => {
|
||||
const { build, readOutput, readPublic } = await setupTestCli(
|
||||
'fixtures/01-single-page/',
|
||||
undefined,
|
||||
{
|
||||
const { build, readOutput, readPublic } = await setupTestCli({
|
||||
cwd: 'fixtures/01-single-page/',
|
||||
options: {
|
||||
buildOptimize: true,
|
||||
},
|
||||
);
|
||||
testOptions: { captureLogs: true },
|
||||
});
|
||||
await build();
|
||||
|
||||
const indexString =
|
||||
|
||||
@@ -1656,6 +1656,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-1.8.2.tgz#7315b4c4c54f82d13fa61c228ec5c2ea5cc9e0e1"
|
||||
integrity sha512-EqX+YQxINb+MeXaIqYDASb6U6FCHbWjkj4a1CKDBks3d/QiB2+PqBLyO72vLDgAO1wUI4O+9gweRcQK11bTL/w==
|
||||
|
||||
"@types/ip@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/ip/-/ip-1.1.0.tgz#aec4f5bfd49e4a4c53b590d88c36eb078827a7c0"
|
||||
integrity sha512-dwNe8gOoF70VdL6WJBwVHtQmAX4RMd62M+mAB9HQFjG1/qiCLM/meRy95Pd14FYBbEDwCq7jgJs89cHpLBu4HQ==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/is-ci@^3.0.0":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/is-ci/-/is-ci-3.0.0.tgz#7e8910af6857601315592436f030aaa3ed9783c3"
|
||||
|
||||
Reference in New Issue
Block a user