mirror of
https://github.com/modernweb-dev/rocket.git
synced 2026-03-21 15:54:57 +00:00
Compare commits
3 Commits
@rocket/en
...
@rocket/cl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b48fb9760 | ||
|
|
39206a1738 | ||
|
|
cbfb0f91e2 |
@@ -35,6 +35,7 @@
|
|||||||
"setup:ts-configs": "node scripts/generate-ts-configs.mjs",
|
"setup:ts-configs": "node scripts/generate-ts-configs.mjs",
|
||||||
"start:experimental": "NODE_DEBUG=engine:rendering node --no-warnings --experimental-loader ./packages/engine/src/litCssLoader.js packages/cli/src/cli.js start --open",
|
"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",
|
"start": "NODE_DEBUG=engine:rendering node --trace-warnings packages/cli/src/cli.js start --open",
|
||||||
|
"preview": "node packages/cli/src/cli.js preview --open",
|
||||||
"test": "yarn test:node && yarn test:web",
|
"test": "yarn test:node && yarn test:web",
|
||||||
"test:integration": "playwright test packages/*/test-node/*.spec.js --retries=3",
|
"test:integration": "playwright test packages/*/test-node/*.spec.js --retries=3",
|
||||||
"test:node": "yarn test:unit && yarn test:integration",
|
"test:node": "yarn test:unit && yarn test:integration",
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# @rocket/cli
|
# @rocket/cli
|
||||||
|
|
||||||
|
## 0.20.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 39206a1: `rocket start` now outputs to `_site-dev` instead of `_site`.
|
||||||
|
- 39206a1: `rocket start` clears only its output folder (defaults to `_site-dev`)
|
||||||
|
- cbfb0f9: Add `rocket preview` command to enable fast checking of the production build
|
||||||
|
|
||||||
## 0.20.1
|
## 0.20.1
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@rocket/cli",
|
"name": "@rocket/cli",
|
||||||
"version": "0.20.1",
|
"version": "0.20.2",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ export class RocketBuild {
|
|||||||
|
|
||||||
async build() {
|
async build() {
|
||||||
await this.cli.events.dispatchEventDone('build-start');
|
await this.cli.events.dispatchEventDone('build-start');
|
||||||
|
await this.cli.clearOutputDir();
|
||||||
|
await this.cli.clearOutputDevDir();
|
||||||
|
|
||||||
this.engine = new Engine();
|
this.engine = new Engine();
|
||||||
this.engine.setOptions({
|
this.engine.setOptions({
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { RocketStart } from './RocketStart.js';
|
|||||||
import { RocketBuild } from './RocketBuild.js';
|
import { RocketBuild } from './RocketBuild.js';
|
||||||
import { RocketInit } from './RocketInit.js';
|
import { RocketInit } from './RocketInit.js';
|
||||||
import { RocketUpgrade } from './RocketUpgrade.js';
|
import { RocketUpgrade } from './RocketUpgrade.js';
|
||||||
|
import { RocketPreview } from './RocketPreview.js';
|
||||||
// import { ignore } from './images/ignore.js';
|
// import { ignore } from './images/ignore.js';
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
@@ -34,7 +35,7 @@ export class RocketCli {
|
|||||||
open: false,
|
open: false,
|
||||||
cwd: process.cwd(),
|
cwd: process.cwd(),
|
||||||
inputDir: 'FALLBACK',
|
inputDir: 'FALLBACK',
|
||||||
outputDir: '_site',
|
outputDir: 'FALLBACK',
|
||||||
outputDevDir: '_site-dev',
|
outputDevDir: '_site-dev',
|
||||||
|
|
||||||
serviceWorkerSourcePath: '',
|
serviceWorkerSourcePath: '',
|
||||||
@@ -93,6 +94,9 @@ export class RocketCli {
|
|||||||
if (this.options.inputDir === 'FALLBACK') {
|
if (this.options.inputDir === 'FALLBACK') {
|
||||||
this.options.inputDir = path.join(this.options.cwd, 'site', 'pages');
|
this.options.inputDir = path.join(this.options.cwd, 'site', 'pages');
|
||||||
}
|
}
|
||||||
|
if (this.options.outputDir === 'FALLBACK') {
|
||||||
|
this.options.outputDir = path.join(this.options.cwd, '_site');
|
||||||
|
}
|
||||||
if (this.options.inputDir instanceof URL) {
|
if (this.options.inputDir instanceof URL) {
|
||||||
this.options.inputDir = this.options.inputDir.pathname;
|
this.options.inputDir = this.options.inputDir.pathname;
|
||||||
}
|
}
|
||||||
@@ -122,7 +126,6 @@ export class RocketCli {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async prepare() {
|
async prepare() {
|
||||||
await this.clearOutputDirs();
|
|
||||||
if (!this.options.presets) {
|
if (!this.options.presets) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -180,6 +183,7 @@ export class RocketCli {
|
|||||||
{ plugin: RocketInit, options: {} },
|
{ plugin: RocketInit, options: {} },
|
||||||
// { plugin: RocketLint },
|
// { plugin: RocketLint },
|
||||||
{ plugin: RocketUpgrade, options: {} },
|
{ plugin: RocketUpgrade, options: {} },
|
||||||
|
{ plugin: RocketPreview, options: {} },
|
||||||
];
|
];
|
||||||
|
|
||||||
if (Array.isArray(this.options.setupCliPlugins)) {
|
if (Array.isArray(this.options.setupCliPlugins)) {
|
||||||
@@ -230,10 +234,13 @@ export class RocketCli {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async clearOutputDirs() {
|
async clearOutputDir() {
|
||||||
if (this.options.outputDir && existsSync(this.options.outputDir)) {
|
if (this.options.outputDir && existsSync(this.options.outputDir)) {
|
||||||
await rm(this.options.outputDir, { recursive: true, force: true });
|
await rm(this.options.outputDir, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async clearOutputDevDir() {
|
||||||
if (this.options.outputDevDir && existsSync(this.options.outputDevDir)) {
|
if (this.options.outputDevDir && existsSync(this.options.outputDevDir)) {
|
||||||
await rm(this.options.outputDevDir, { recursive: true, force: true });
|
await rm(this.options.outputDevDir, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
|
|||||||
79
packages/cli/src/RocketPreview.js
Executable file
79
packages/cli/src/RocketPreview.js
Executable file
@@ -0,0 +1,79 @@
|
|||||||
|
import { logPreviewMessage } from './preview/logPreviewMessage.js';
|
||||||
|
import { startDevServer } from '@web/dev-server';
|
||||||
|
import path from 'path';
|
||||||
|
import { existsSync } from 'fs';
|
||||||
|
import { gray, bold } from 'colorette';
|
||||||
|
|
||||||
|
export class RocketPreview {
|
||||||
|
/**
|
||||||
|
* @param {import('commander').Command} program
|
||||||
|
* @param {import('./RocketCli.js').RocketCli} cli
|
||||||
|
*/
|
||||||
|
async setupCommand(program, cli) {
|
||||||
|
this.cli = cli;
|
||||||
|
this.active = true;
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('preview')
|
||||||
|
.option('-i, --input-dir <path>', 'path to the folder with the build html files')
|
||||||
|
.option('-o, --open', 'automatically open the browser')
|
||||||
|
.action(async cliOptions => {
|
||||||
|
cli.setOptions(cliOptions);
|
||||||
|
cli.activePlugin = this;
|
||||||
|
|
||||||
|
await this.preview();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async preview() {
|
||||||
|
if (!this.cli) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for typescript as `this.cli.options.outputDir` supports other inputs as well
|
||||||
|
// but the cli will normalize it to a string before calling plugins
|
||||||
|
if (
|
||||||
|
typeof this.cli.options.inputDir !== 'string' ||
|
||||||
|
typeof this.cli.options.outputDir !== 'string'
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rootIndexHtml = path.join(this.cli.options.outputDir, 'index.html');
|
||||||
|
if (!existsSync(rootIndexHtml)) {
|
||||||
|
console.log(`${bold(`👀 Previewing Production Build`)}`);
|
||||||
|
console.log('');
|
||||||
|
console.log(` 🛑 No index.html found in the build directory ${gray(`${rootIndexHtml}`)}`);
|
||||||
|
console.log(' 🤔 Did you forget to run `rocket build` before?');
|
||||||
|
console.log('');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {import('@web/dev-server').DevServerConfig} */
|
||||||
|
const config = {
|
||||||
|
open: this.cli.options.open,
|
||||||
|
rootDir: this.cli.options.outputDir,
|
||||||
|
clearTerminalOnReload: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.devServer = await startDevServer({
|
||||||
|
config,
|
||||||
|
logStartMessage: false,
|
||||||
|
readCliArgs: false,
|
||||||
|
readFileConfig: false,
|
||||||
|
// argv: this.__argv,
|
||||||
|
});
|
||||||
|
logPreviewMessage({ devServerOptions: this.devServer.config }, console);
|
||||||
|
} catch (e) {
|
||||||
|
console.log('🛑 Starting preview server failed');
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async stop() {
|
||||||
|
if (this.devServer) {
|
||||||
|
await this.devServer.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,11 +31,12 @@ export class RocketStart {
|
|||||||
if (!this.cli) {
|
if (!this.cli) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
await this.cli.clearOutputDevDir();
|
||||||
|
|
||||||
// TODO: enable URL support in the Engine and remove this "workaround"
|
// TODO: enable URL support in the Engine and remove this "workaround"
|
||||||
if (
|
if (
|
||||||
typeof this.cli.options.inputDir !== 'string' ||
|
typeof this.cli.options.inputDir !== 'string' ||
|
||||||
typeof this.cli.options.outputDir !== 'string'
|
typeof this.cli.options.outputDevDir !== 'string'
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -50,7 +51,7 @@ export class RocketStart {
|
|||||||
this.engine = new Engine();
|
this.engine = new Engine();
|
||||||
this.engine.setOptions({
|
this.engine.setOptions({
|
||||||
docsDir: this.cli.options.inputDir,
|
docsDir: this.cli.options.inputDir,
|
||||||
outputDir: this.cli.options.outputDir,
|
outputDir: this.cli.options.outputDevDir,
|
||||||
setupPlugins: this.cli.options.setupEnginePlugins,
|
setupPlugins: this.cli.options.setupEnginePlugins,
|
||||||
open: this.cli.options.open,
|
open: this.cli.options.open,
|
||||||
longFileHeaderWidth: this.cli.options.longFileHeaderWidth,
|
longFileHeaderWidth: this.cli.options.longFileHeaderWidth,
|
||||||
|
|||||||
34
packages/cli/src/helpers/infoMessages.js
Normal file
34
packages/cli/src/helpers/infoMessages.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import ip from 'ip';
|
||||||
|
import { white, cyan } from 'colorette';
|
||||||
|
|
||||||
|
/** @typedef {import('@web/dev-server').DevServerConfig} DevServerConfig */
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {DevServerConfig} devServerOptions
|
||||||
|
* @param {string} host
|
||||||
|
* @param {string} path
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function createAddress(devServerOptions, host, path) {
|
||||||
|
return `http${devServerOptions.http2 ? 's' : ''}://${host}:${devServerOptions.port}${path}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {DevServerConfig} devServerOptions
|
||||||
|
* @param {console} logger
|
||||||
|
* @param {string} openPath
|
||||||
|
*/
|
||||||
|
export 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) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
33
packages/cli/src/preview/logPreviewMessage.js
Normal file
33
packages/cli/src/preview/logPreviewMessage.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { white, bold, cyan, gray } from 'colorette';
|
||||||
|
import { createAddress, logNetworkAddress } from '../helpers/infoMessages.js';
|
||||||
|
|
||||||
|
/** @typedef {import('@web/dev-server').DevServerConfig} DevServerConfig */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{ devServerOptions: DevServerConfig}} options
|
||||||
|
* @param {console} logger
|
||||||
|
*/
|
||||||
|
export function logPreviewMessage({ devServerOptions }, logger) {
|
||||||
|
const prettyHost = devServerOptions.hostname ?? 'localhost';
|
||||||
|
let openPath = typeof devServerOptions.open === 'string' ? devServerOptions.open : '/';
|
||||||
|
if (!openPath.startsWith('/')) {
|
||||||
|
openPath = `/${openPath}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log(`${bold(`👀 Previewing Production Build`)}`);
|
||||||
|
logger.log('');
|
||||||
|
logger.log(
|
||||||
|
`${white(' 🚧 Local:')} ${cyan(createAddress(devServerOptions, prettyHost, openPath))}`,
|
||||||
|
);
|
||||||
|
logNetworkAddress(devServerOptions, logger, openPath);
|
||||||
|
const sourceDir = devServerOptions.rootDir;
|
||||||
|
if (sourceDir) {
|
||||||
|
logger.log(`${white(' 📝 Source:')} ${cyan(sourceDir)}`);
|
||||||
|
}
|
||||||
|
logger.log('');
|
||||||
|
logger.log(
|
||||||
|
gray(
|
||||||
|
'If what you see works as expected then you can upload "source" to your production web server.',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,38 +1,8 @@
|
|||||||
import ip from 'ip';
|
|
||||||
import { white, bold, cyan, gray } from 'colorette';
|
import { white, bold, cyan, gray } from 'colorette';
|
||||||
|
import { createAddress, logNetworkAddress } from '../helpers/infoMessages.js';
|
||||||
|
|
||||||
/** @typedef {import('@web/dev-server').DevServerConfig} DevServerConfig */
|
/** @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 {{ devServerOptions: DevServerConfig, engine: import('@rocket/engine/server').Engine}} options
|
||||||
* @param {console} logger
|
* @param {console} logger
|
||||||
|
|||||||
49
packages/cli/test-node/06-preview.test.js
Normal file
49
packages/cli/test-node/06-preview.test.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import chai from 'chai';
|
||||||
|
import { white, bold, gray } from 'colorette';
|
||||||
|
|
||||||
|
import { setupTestCli } from './test-helpers.js';
|
||||||
|
|
||||||
|
const { expect } = chai;
|
||||||
|
|
||||||
|
describe('Preview', () => {
|
||||||
|
it('01: Preview Message', async () => {
|
||||||
|
const { cli, capturedLogs, cleanup } = await setupTestCli({
|
||||||
|
cwd: 'fixtures/06-preview/01-preview-message',
|
||||||
|
cliOptions: ['preview'],
|
||||||
|
testOptions: { captureLogs: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
await cli.start();
|
||||||
|
await cleanup();
|
||||||
|
|
||||||
|
expect(capturedLogs[0]).to.equal(`${bold(`👀 Previewing Production Build`)}`);
|
||||||
|
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].startsWith(`${white(' 📝 Source:')}`)).to.be.true;
|
||||||
|
expect(capturedLogs[5]).to.equal('');
|
||||||
|
expect(capturedLogs[6]).to.equal(
|
||||||
|
`${gray(
|
||||||
|
'If what you see works as expected then you can upload "source" to your production web server.',
|
||||||
|
)}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('02: Error Message if there is no build output', async () => {
|
||||||
|
const { cli, capturedLogs, cleanup } = await setupTestCli({
|
||||||
|
cwd: 'fixtures/06-preview/02-error-no-build',
|
||||||
|
cliOptions: ['preview'],
|
||||||
|
testOptions: { captureLogs: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
await cli.start();
|
||||||
|
await cleanup();
|
||||||
|
|
||||||
|
expect(capturedLogs[0]).to.equal(`${bold(`👀 Previewing Production Build`)}`);
|
||||||
|
expect(capturedLogs[1]).to.equal('');
|
||||||
|
expect(capturedLogs[2].startsWith(` 🛑 No index.html found in the build directory`)).to.be
|
||||||
|
.true;
|
||||||
|
expect(capturedLogs[3]).to.equal(' 🤔 Did you forget to run `rocket build` before?');
|
||||||
|
expect(capturedLogs[4]).to.equal('');
|
||||||
|
});
|
||||||
|
});
|
||||||
1
packages/cli/test-node/fixtures/06-preview/01-preview-message/.gitignore
vendored
Normal file
1
packages/cli/test-node/fixtures/06-preview/01-preview-message/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
!__output
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
so preview does not stop
|
||||||
Reference in New Issue
Block a user