Compare commits

...

15 Commits

Author SHA1 Message Date
github-actions[bot]
58692147e9 Version Packages 2022-08-19 19:19:37 +02:00
Thomas Allmer
8dedc56afa feat(cli): add start message with local and network url 2022-08-19 19:15:01 +02:00
Thomas Allmer
bcbfae332d chore: docs update public folder is in site/public 2022-08-18 21:27:46 +02:00
Thomas Allmer
0fae0037d8 chore: set default file path to site/pages in getting started 2022-08-18 20:39:48 +02:00
Thomas Allmer
390335da18 fix(engine): reparse html if pageTree requests a second pass 2022-08-17 16:51:54 +02:00
Thomas Allmer
6d2f469d26 chore: nice open graph text for tools 2022-08-16 11:37:33 +02:00
“Nirmal
94a6f54585 docs: correct path of examples link. 2022-08-16 09:07:35 +02:00
github-actions[bot]
ff8b4c5cd5 Version Packages 2022-08-15 23:04:55 +02:00
Thomas Allmer
5122ea8639 chore: add docs & tests for link-text for headlines 2022-08-15 23:02:29 +02:00
Thomas Allmer
3032ba9b82 feat(engine): menus now support special characters in markdown headings 2022-08-15 23:02:29 +02:00
Thomas Allmer
93503ed309 feat(engine): HTML in headings will be ignored for the menu 2022-08-15 23:02:29 +02:00
George Raptis
77646abbee Fix documentation link 2022-08-15 14:54:42 +02:00
github-actions[bot]
9ae3966fef Version Packages 2022-08-14 22:51:30 +02:00
Thomas Allmer
09a47b43dc fix(engine): prevent fatal error because of simultaneous write to file 2022-08-14 22:48:10 +02:00
Thomas Allmer
42d794bdfc chore: remove drawer pkg & fix contribution link in README.md 2022-08-13 21:40:50 +02:00
68 changed files with 1026 additions and 511 deletions

View File

@@ -28,7 +28,7 @@
<p align="center"> <p align="center">
<a href="https://rocket.modern-web.dev">Website</a> <a href="https://rocket.modern-web.dev">Website</a>
· ·
<a href="https://rocket.modern-web.dev/doc/">Documentation</a> <a href="https://rocket.modern-web.dev/docs/">Documentation</a>
· ·
<a href="https://rocket.modern-web.dev/chat">Discord Community</a> <a href="https://rocket.modern-web.dev/chat">Discord Community</a>
</p> </p>
@@ -68,7 +68,7 @@ npx @rocket/create@latest
We are always looking for contributors of all skill levels! If you're looking to ease your way into the project, try out a [good first issue](https://github.com/modernweb-dev/rocket/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22). We are always looking for contributors of all skill levels! If you're looking to ease your way into the project, try out a [good first issue](https://github.com/modernweb-dev/rocket/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22).
If you are interested in helping contribute to Modern Web, please take a look at our [Contributing Guide](https://github.com/modernweb-dev/rocket/blob/next/CONTRIBUTING.md). Also, feel free to drop into [discord](https://rocket.modern-web.dev/chat) and say hi. 👋 If you are interested in helping contribute to Modern Web, please take a look at our [Contributing Guide](https://github.com/modernweb-dev/rocket/blob/main/CONTRIBUTING.md). Also, feel free to drop into [discord](https://rocket.modern-web.dev/chat) and say hi. 👋
### Financial Contributors ### Financial Contributors

View File

@@ -30,13 +30,13 @@
"rocket:build": "NODE_DEBUG=engine:rendering node --trace-warnings packages/cli/src/cli.js build", "rocket:build": "NODE_DEBUG=engine:rendering node --trace-warnings packages/cli/src/cli.js build",
"rocket:upgrade": "node packages/cli/src/cli.js upgrade", "rocket:upgrade": "node packages/cli/src/cli.js upgrade",
"search": "node packages/cli/src/cli.js search", "search": "node packages/cli/src/cli.js search",
"setup": "npm run setup:ts-configs && npm run setup:patches", "setup": "npm run setup:ts-configs",
"setup:patches": "npx patch-package", "setup:patches": "npx patch-package",
"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",
"test": "yarn test:node && yarn test:web", "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: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: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", "test:web": "web-test-runner",

View File

@@ -1,5 +1,22 @@
# @rocket/cli # @rocket/cli
## 0.20.1
### Patch Changes
- 8dedc56: Add start message for `rocket start`
```
🚀 Rocket Engine v0.2.5
🚧 Local: http://localhost:8000/
🌐 Network: http://xxx.xxx.xxx.xxx:8000/
```
- Updated dependencies [8dedc56]
- Updated dependencies [390335d]
- @rocket/engine@0.2.6
## 0.20.0 ## 0.20.0
### Minor Changes ### Minor Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@rocket/cli", "name": "@rocket/cli",
"version": "0.20.0", "version": "0.20.1",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
@@ -53,16 +53,18 @@
], ],
"dependencies": { "dependencies": {
"@rocket/building-rollup": "^0.4.0", "@rocket/building-rollup": "^0.4.0",
"@rocket/engine": "^0.2.0", "@rocket/engine": "^0.2.6",
"@web/rollup-plugin-copy": "^0.3.0", "@web/rollup-plugin-copy": "^0.3.0",
"colorette": "^2.0.16", "colorette": "^2.0.16",
"commander": "^9.0.0", "commander": "^9.0.0",
"fs-extra": "^9.0.1", "fs-extra": "^9.0.1",
"gray-matter": "^4.0.3", "gray-matter": "^4.0.3",
"ip": "^1.1.5",
"plugins-manager": "^0.3.0", "plugins-manager": "^0.3.0",
"puppeteer": "^13.0.0" "puppeteer": "^13.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/ip": "^1.1.0",
"koa-proxy": "^1.0.0-alpha.3" "koa-proxy": "^1.0.0-alpha.3"
}, },
"types": "./dist-types/src/index.d.ts", "types": "./dist-types/src/index.d.ts",

View File

@@ -1,6 +1,7 @@
import { fromRollup } from '@web/dev-server-rollup'; import { fromRollup } from '@web/dev-server-rollup';
import { Engine } from '@rocket/engine/server'; import { Engine } from '@rocket/engine/server';
import { logStartMessage } from './start/logStartMessage.js';
export class RocketStart { export class RocketStart {
/** @type {Engine | undefined} */ /** @type {Engine | undefined} */
@@ -60,7 +61,14 @@ export class RocketStart {
setupDevServerPlugins: [...this.cli.options.setupDevServerPlugins, ...withWrap], setupDevServerPlugins: [...this.cli.options.setupDevServerPlugins, ...withWrap],
}); });
try { 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(); await this.engine.start();
} catch (e) { } catch (e) {
console.log('Engine start errored'); console.log('Engine start errored');
@@ -71,7 +79,6 @@ export class RocketStart {
async stop({ hard = true } = {}) { async stop({ hard = true } = {}) {
if (this.engine) { if (this.engine) {
await this.engine.stop({ hard }); await this.engine.stop({ hard });
console.log('🚀 Engines offline');
} }
} }
} }

View 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('');
}

View File

@@ -5,7 +5,7 @@ import { setupTestCli } from './test-helpers.js';
export function prepareTestCli(importMetaUrl) { export function prepareTestCli(importMetaUrl) {
const dir = path.dirname(fileURLToPath(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; const { expect } = chai;

View File

@@ -60,7 +60,13 @@ function cleanupLitMarkersFn(text) {
return newText; 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 resolvedCwd = path.join(dir, cwd.split('/').join(path.sep));
const useOptions = { buildOptimize: false, buildAutoStop: false, ...options, cwd: resolvedCwd }; const useOptions = { buildOptimize: false, buildAutoStop: false, ...options, cwd: resolvedCwd };
if (useOptions.inputDir) { if (useOptions.inputDir) {
@@ -69,6 +75,18 @@ export async function setupTestCli(cwd, cliOptions = ['build'], options = {}, di
useOptions.outputDir = path.join(resolvedCwd, '__output'); useOptions.outputDir = path.join(resolvedCwd, '__output');
useOptions.outputDevDir = path.join(resolvedCwd, '__output-dev'); 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({ const cli = new RocketCli({
argv: [process.argv[0], new URL('../src/cli.js', import.meta.url).pathname, ...cliOptions], 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() { async function cleanup() {
await cli.stop({ hard: false }); await cli.stop({ hard: false });
if (testOptions.captureLogs) {
console.log = origLog;
console.error = origError;
}
} }
async function build() { async function build() {
@@ -243,5 +265,6 @@ export async function setupTestCli(cwd, cliOptions = ['build'], options = {}, di
renameSource, renameSource,
backupOrRestoreSource, backupOrRestoreSource,
restoreSource, restoreSource,
capturedLogs,
}; };
} }

View File

@@ -8,11 +8,11 @@ const { expect } = chai;
describe('Config', () => { describe('Config', () => {
it('01: no config file', async () => { it('01: no config file', async () => {
const { build, readOutput, readDevOutput } = await setupTestCli( const { build, readOutput, readDevOutput } = await setupTestCli({
'fixtures/01-config/01-no-config/', cwd: 'fixtures/01-config/01-no-config/',
undefined, options: { buildOptimize: true },
{ buildOptimize: true }, testOptions: { captureLogs: true },
); });
await build(); await build();
expect(readOutput('index.html')).to.equal( expect(readOutput('index.html')).to.equal(
@@ -31,14 +31,21 @@ describe('Config', () => {
}); });
it('02: change input dir', async () => { 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(); await build();
expect(readDevOutput('index.html')).to.equal(['Hello World!'].join('\n')); expect(readDevOutput('index.html')).to.equal(['Hello World!'].join('\n'));
}); });
it('03: can add a middleware (api proxy) to the dev server', async () => { 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) => { const apiServer = http.createServer((request, response) => {
if (request.url === '/api/message') { if (request.url === '/api/message') {
response.writeHead(200); response.writeHead(200);
@@ -61,20 +68,22 @@ describe('Config', () => {
}); });
it('04: can add a rollup plugin via setupDevServerAndBuildPlugins to build', async () => { it('04: can add a rollup plugin via setupDevServerAndBuildPlugins to build', async () => {
const { build, readOutput } = await setupTestCli( const { build, readOutput } = await setupTestCli({
'fixtures/01-config/04-add-rollup-plugin/', cwd: 'fixtures/01-config/04-add-rollup-plugin/',
undefined, options: { buildOptimize: true },
{ buildOptimize: true }, testOptions: { captureLogs: true },
); });
await build(); await build();
const inlineModule = await readOutput('e97af63d.js', { format: false }); const inlineModule = await readOutput('e97af63d.js', { format: false });
expect(inlineModule).to.equal('var a={test:"data"};console.log(a);\n'); expect(inlineModule).to.equal('var a={test:"data"};console.log(a);\n');
}); });
it('04a: can add a rollup plugin via setupDevServerAndBuildPlugins to start', async () => { it('04a: can add a rollup plugin via setupDevServerAndBuildPlugins to start', async () => {
const { cli, cleanup } = await setupTestCli('fixtures/01-config/04-add-rollup-plugin/', [ const { cli, cleanup } = await setupTestCli({
'start', cwd: 'fixtures/01-config/04-add-rollup-plugin/',
]); cliOptions: ['start'],
testOptions: { captureLogs: true },
});
await cli.start(); await cli.start();
const { port } = cli?.activePlugin?.engine.devServer.config; const { port } = cli?.activePlugin?.engine.devServer.config;
@@ -88,9 +97,10 @@ describe('Config', () => {
}); });
it('05: long file header comments', async () => { it('05: long file header comments', async () => {
const { build, readSource } = await setupTestCli( const { build, readSource } = await setupTestCli({
'fixtures/01-config/05-long-file-header-comment/', cwd: 'fixtures/01-config/05-long-file-header-comment/',
); testOptions: { captureLogs: true },
});
await build(); await build();
expect(readSource('index.rocket.js', { format: false })).to.equal( expect(readSource('index.rocket.js', { format: false })).to.equal(

View File

@@ -5,13 +5,13 @@ const { expect } = chai;
describe('Build', () => { describe('Build', () => {
it('01: copy public files', async () => { it('01: copy public files', async () => {
const { build, readOutput, outputExists, readDevOutput } = await setupTestCli( const { build, readOutput, outputExists, readDevOutput } = await setupTestCli({
'fixtures/02-build/01-copy-public-files/', cwd: 'fixtures/02-build/01-copy-public-files/',
undefined, options: {
{
buildOptimize: true, buildOptimize: true,
}, },
); testOptions: { captureLogs: true },
});
await build(); await build();
expect(readOutput('index.html')).to.equal( expect(readOutput('index.html')).to.equal(

View File

@@ -6,7 +6,11 @@ const { expect } = chai;
describe('Upgrade System', () => { describe('Upgrade System', () => {
it('2021-09-menu', async () => { it('2021-09-menu', async () => {
const { build, sourceExists, readSource, backupOrRestoreSource, restoreSource } = 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 backupOrRestoreSource();
await build(); await build();

View File

@@ -5,13 +5,13 @@ const { expect } = chai;
describe('Open Graph', () => { describe('Open Graph', () => {
it('generates the image and adds the meta tags', async () => { it('generates the image and adds the meta tags', async () => {
const { build, readOutput, outputExists } = await setupTestCli( const { build, readOutput, outputExists } = await setupTestCli({
'fixtures/04-open-graph/01-generate-image-and-inject-meta', cwd: 'fixtures/04-open-graph/01-generate-image-and-inject-meta',
undefined, options: {
{
buildOptimize: true, buildOptimize: true,
}, },
); testOptions: { captureLogs: true },
});
await build(); await build();
expect(readOutput('index.html', { replaceImageHashes: true })).to.equal( expect(readOutput('index.html', { replaceImageHashes: true })).to.equal(
@@ -35,13 +35,13 @@ describe('Open Graph', () => {
}); });
it('handles multiple pages', async () => { it('handles multiple pages', async () => {
const { build, readOutput } = await setupTestCli( const { build, readOutput } = await setupTestCli({
'fixtures/04-open-graph/02-multiple-pages', cwd: 'fixtures/04-open-graph/02-multiple-pages',
undefined, options: {
{
buildOptimize: true, buildOptimize: true,
}, },
); testOptions: { captureLogs: true },
});
await build(); await build();
expect(readOutput('index.html', { replaceImageHashes: true })).to.equal( expect(readOutput('index.html', { replaceImageHashes: true })).to.equal(

View 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('');
});
});

View File

@@ -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!';

View File

@@ -0,0 +1,8 @@
{
"name": "index.rocket.js",
"menuLinkText": "index.rocket.js",
"url": "/",
"outputRelativeFilePath": "index.html",
"sourceRelativeFilePath": "index.rocket.js",
"level": 0
}

View File

@@ -1,37 +0,0 @@
# @rocket/drawer
## 0.1.5
### Patch Changes
- 1f14105: Add export map which enables side effect import via `@rocket/drawer/define`
## 0.1.4
### Patch Changes
- 445b028: Update to latest lit, @open-wc, @lion packages
## 0.1.3
### Patch Changes
- 0b64116: Update @lion dependencies
## 0.1.2
### Patch Changes
- 897892d: bump dependencies
## 0.1.1
### Patch Changes
- d955b43: reset translation on teardown overlay controller
## 0.1.0
### Minor Changes
- 1971f5d: Initial Release

View File

@@ -1,7 +0,0 @@
# Rocket Drawer
For mobile navigation on [Rocket sites](https://rocket.modern-web.dev/).
--
Inspired by [kenchris's menu-drawer](https://github.com/kenchris/websensor-compass/blob/master/scripts/menu-drawer.js).

View File

@@ -1 +0,0 @@
export { RocketDrawer } from './src/RocketDrawer.js';

View File

@@ -1,45 +0,0 @@
{
"name": "@rocket/drawer",
"version": "0.1.5",
"publishConfig": {
"access": "public"
},
"description": "Rocket stuff",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/modernweb-dev/rocket.git",
"directory": "packages/drawer"
},
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
"main": "index.js",
"exports": {
".": "./index.js",
"./rocket-drawer.js": "./rocket-drawer.js",
"./define": "./rocket-drawer.js"
},
"scripts": {
"dev": "web-dev-server --node-resolve --root-dir ../../ --open packages/drawer/ --watch",
"rocket:build": "node src/build/cli.js -c demo/docs",
"rocket:start": "node src/start/cli.js -c demo/docs --root-dir ../../ --open packages/cli/demo/docs/README.md",
"start": "npm run rocket:start",
"test": "mocha test-node/**/*.test.js test-node/*.test.js",
"test:watch": "mocha test-node/**/*.test.js test-node/*.test.js --watch"
},
"files": [
"*.js",
"dist-types",
"src"
],
"keywords": [
"storybook",
"demo",
"demo-states",
"testing"
],
"dependencies": {
"@lion/overlays": "^0.32.0",
"lit": "^2.0.0"
},
"types": "dist-types/index.d.ts"
}

View File

@@ -1,3 +0,0 @@
import { RocketDrawer } from './src/RocketDrawer.js';
customElements.define('rocket-drawer', RocketDrawer);

View File

@@ -1,264 +0,0 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { LitElement, html } from 'lit-element';
import { OverlayMixin, withModalDialogConfig } from '@lion/overlays';
/** @typedef {import('@lion/overlays/types/OverlayConfig').OverlayConfig} OverlayConfig */
/**
* @param {HTMLElement} el
*/
function transitionend(el) {
return new Promise(resolve => {
el.addEventListener('transitionend', resolve, { once: true });
});
}
// @ts-expect-error
export class RocketDrawer extends OverlayMixin(LitElement) {
static get properties() {
return {
useOverlay: { type: Boolean, reflect: true },
useOverlayMediaQuery: { type: String },
mediaMatcher: { type: Object },
};
}
// eslint-disable-next-line class-methods-use-this
// @ts-ignore
_defineOverlayConfig() {
return /** @type {OverlayConfig} */ {
...withModalDialogConfig(),
hidesOnOutsideClick: true,
viewportConfig: {
placement: 'slide',
},
};
}
_setupOverlayCtrl() {
if (this.useOverlay) {
super._setupOverlayCtrl();
/* eslint-disable no-param-reassign */
this._overlayCtrl.transitionHide = async ({ contentNode }) => {
contentNode.style.transition = 'transform 0.20s cubic-bezier(0.4, 0.0, 0.2, 1)';
contentNode.style.transform = 'translateX(-100%)';
await transitionend(contentNode);
// contentNode.style.display = 'none';
};
this._overlayCtrl.transitionShow = async ({ contentNode }) => {
contentNode.style.display = 'block';
contentNode.style.transform = 'translateX(-100%)';
contentNode.style.transition = 'transform 0.25s cubic-bezier(0.4, 0.0, 0.2, 1)';
// wait for display block to be "updated in the dom" and then translate otherwise there will be no animation
await new Promise(resolve => requestAnimationFrame(resolve));
await new Promise(resolve => requestAnimationFrame(resolve));
contentNode.style.transform = 'translateX(0)';
await transitionend(contentNode);
};
/* eslint-enable no-param-reassign */
this._overlayCtrl.contentNode.style.transform = 'translateX(-100%)';
this._overlayCtrl.contentNode.style.willChange = 'transform';
// gesture
this.containerEl = this._overlayCtrl.contentNode;
}
}
_teardownOverlayCtrl() {
super._teardownOverlayCtrl();
this._overlayCtrl.contentNode.style.transform = 'translateX(0)';
}
/** @param {import('lit-element').PropertyValues } changedProperties */
updated(changedProperties) {
super.updated(changedProperties);
if (changedProperties.has('opened')) {
if (this.opened) {
document.body.addEventListener('touchstart', this.onGestureStart, { passive: true });
} else {
document.body.removeEventListener('touchstart', this.onGestureStart);
}
}
if (changedProperties.has('useOverlay')) {
if (this.useOverlay) {
this._setupOverlayCtrl();
} else {
if (this._overlayCtrl) {
this._teardownOverlayCtrl();
}
}
}
if (changedProperties.has('useOverlayMediaQuery')) {
this.mediaMatcher.removeEventListener('change', this.onMatchMedia);
this.mediaMatcher = window.matchMedia(this.useOverlayMediaQuery);
this.mediaMatcher.addEventListener('change', this.onMatchMedia);
this.useOverlay = !!this.mediaMatcher.matches;
}
}
/**
* @param { MediaQueryListEvent } query
*/
onMatchMedia(query) {
this.useOverlay = !!query.matches;
}
_setupOpenCloseListeners() {
super._setupOpenCloseListeners();
if (this._overlayInvokerNode) {
this._overlayInvokerNode.addEventListener('click', this.__toggle);
}
}
_teardownOpenCloseListeners() {
super._teardownOpenCloseListeners();
if (this._overlayInvokerNode) {
this._overlayInvokerNode.removeEventListener('click', this.__toggle);
}
}
__toggle() {
this.opened = !this.opened;
}
// ********************* GESTURE ***********************
constructor() {
super();
this.useOverlay = false;
this.useOverlayMediaQuery = '(max-width: 1024px)';
this.__toggle = this.__toggle.bind(this);
this.onMatchMedia = this.onMatchMedia.bind(this);
this.onGestureStart = this.onGestureStart.bind(this);
this.onGestureMove = this.onGestureMove.bind(this);
this.onGestureEnd = this.onGestureEnd.bind(this);
this.updateFromTouch = this.updateFromTouch.bind(this);
this.mediaMatcher = window.matchMedia(this.useOverlayMediaQuery);
this.mediaMatcher.addEventListener('change', this.onMatchMedia);
this._startX = 0;
this._currentX = 0;
this._velocity = 0;
this._left = 0;
this.__touching = false;
this._timestamp = 0;
}
connectedCallback() {
super.connectedCallback();
this.useOverlay = !!this.mediaMatcher.matches;
}
render() {
return html`
<slot name="invoker"></slot>
<slot name="_overlay-shadow-outlet"></slot>
<div id="overlay-content-node-wrapper">
<slot name="content"></slot>
</div>
`;
}
/**
* @param {TouchEvent} ev
*/
onGestureStart(ev) {
if (!this.containerEl) {
return;
}
this.__touching = true;
this._left = this.containerEl.getBoundingClientRect().left;
this._startX = ev.targetTouches[0].clientX;
this._currentX = this._startX;
this._timestamp = new Date().getTime();
this._velocity = 0;
this._overlayCtrl.contentNode.style.transition = '';
document.body.addEventListener('touchmove', this.onGestureMove, { passive: true });
document.body.addEventListener('touchend', this.onGestureEnd, { passive: true });
document.body.addEventListener('touchcancel', this.onGestureEnd, { passive: true });
requestAnimationFrame(this.updateFromTouch);
}
/**
* @param {number} dDist
* @param {number} dTime
*/
addVelocitySample(dDist, dTime) {
if (dTime === 0) {
return;
}
const velocitySample = dDist / dTime;
// Low pass filter.
const alpha = 0.75;
this._velocity *= alpha;
this._velocity += (1 - alpha) * velocitySample;
}
/**
* @param {TouchEvent} ev
*/
onGestureMove(ev) {
if (!this.__touching) {
return;
}
const lastTimestamp = this._timestamp;
this._timestamp = new Date().getTime();
const dTime = this._timestamp - lastTimestamp;
const lastX = this._currentX;
this._currentX = ev.targetTouches[0].clientX;
const dX = this._currentX - lastX;
this.addVelocitySample(dX, dTime);
}
onGestureEnd() {
if (!this.__touching || !this.containerEl) {
this.opened = false;
return;
}
this.__touching = false;
let endOpenedState;
// Check for fling.
if (Math.abs(this._velocity) > 1) {
endOpenedState = this._velocity > 0;
} else {
// Check depending on percentage visible.
const { left } = this.containerEl.getBoundingClientRect();
const width = this.containerEl.clientWidth;
const percentageVisible = (left + width) / width;
endOpenedState = percentageVisible >= 0.5;
}
this._overlayCtrl.contentNode.style.transition =
'transform 0.20s cubic-bezier(0.4, 0.0, 0.2, 1)';
this.containerEl.style.transform = '';
this.opened = endOpenedState;
document.body.removeEventListener('touchmove', this.onGestureMove);
document.body.removeEventListener('touchend', this.onGestureEnd);
document.body.removeEventListener('touchcancel', this.onGestureEnd);
}
updateFromTouch() {
if (!this.__touching || !this.containerEl) {
return;
}
requestAnimationFrame(this.updateFromTouch);
const translateX = Math.min(0, this._currentX - this._startX + this._left);
this.containerEl.style.transform = `translateX(${translateX}px)`;
}
}

View File

@@ -1,24 +0,0 @@
// Don't edit this file directly. It is generated by /scripts/update-package-configs.ts
{
"extends": "../../tsconfig.browser-base.json",
"compilerOptions": {
"module": "ESNext",
"outDir": "./dist-types",
"rootDir": ".",
"composite": true,
"allowJs": true,
"checkJs": true,
"emitDeclarationOnly": true
},
"references": [],
"include": [
"src",
"*.js",
"types"
],
"exclude": [
"dist",
"dist-types"
]
}

View File

@@ -1,5 +1,42 @@
# @rocket/engine # @rocket/engine
## 0.2.6
### Patch Changes
- 8dedc56: Add `engine.getVersion()` method
- 390335d: Improve title tag handling
## 0.2.5
### Patch Changes
- 93503ed: HTML in headings will be ignored for the menu
Some examples:
- `<h1>Hello <em>Word</em></h1>` => `Hello Word`
- `<h1>Hello <strong>World</strong> of <span>JS <em>(JavaScript)</em></span>!</h1>` => `Hello World of JS (JavaScript)!`
- 3032ba9: Menus now support special characters in markdown headings.
Examples:
```md
# Fun Errors & Feedback
# &lt;some-button>
```
## 0.2.4
### Patch Changes
- 09a47b4: Prevent fatal error because of simultaneous write to file.
When the browser requested a file to be rendered and that file also needed an update in the "rocket header" (the top of the file) then it could be that the watcher trigger a simultaneous render of the file while the first render was still in progress.
The solution is that the watcher ignores changes to a file until a full render is finished.
## 0.2.3 ## 0.2.3
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@rocket/engine", "name": "@rocket/engine",
"version": "0.2.3", "version": "0.2.6",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
@@ -36,7 +36,7 @@
"debug": "DEBUG=engine:rendering yarn test", "debug": "DEBUG=engine:rendering yarn test",
"debug:integration": "PWDEBUG=1 yarn test:integration", "debug:integration": "PWDEBUG=1 yarn test:integration",
"test": "mocha --require ../../scripts/testMochaGlobalHooks.js --timeout 8000 test-node/**/*.test.js test-node/*.test.js", "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", "test:watch": "onchange 'src/**/*.js' 'test-node/**/*.js' -- npm test",
"types:copy": "copyfiles \"./types/**/*.d.ts\" dist-types/" "types:copy": "copyfiles \"./types/**/*.d.ts\" dist-types/"
}, },

View File

@@ -7,7 +7,7 @@
import { existsSync } from 'fs'; import { existsSync } from 'fs';
// TODO: implement copy without extra dependency => node 16.7.0 copy has recursive // TODO: implement copy without extra dependency => node 16.7.0 copy has recursive
import fse from 'fs-extra'; import fse from 'fs-extra';
import { mkdir, rm } from 'fs/promises'; import { mkdir, readFile, rm } from 'fs/promises';
import path from 'path'; import path from 'path';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { startDevServer } from '@web/dev-server'; import { startDevServer } from '@web/dev-server';
@@ -32,6 +32,8 @@ import { RocketHeader } from './file-header/RocketHeader.js';
const logRendering = debuglog('engine:rendering'); const logRendering = debuglog('engine:rendering');
const pkgJson = JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8'));
export class Engine { export class Engine {
/** @type {EngineOptions} */ /** @type {EngineOptions} */
options = { options = {
@@ -121,8 +123,10 @@ export class Engine {
if (pageTree.pageTreeChangedOnSave) { if (pageTree.pageTreeChangedOnSave) {
for (const sourceFilePath of sourceFiles) { for (const sourceFilePath of sourceFiles) {
const result = await this.renderFile({ sourceFilePath, throwOnError: true }); const result = await this.renderFile({ sourceFilePath, throwOnError: true });
await pageTree.add(result.sourceRelativeFilePath);
await cleanupAutoGeneratedFiles(result); await cleanupAutoGeneratedFiles(result);
} }
await pageTree.save();
} }
} }
@@ -265,6 +269,7 @@ export class Engine {
readFileConfig: false, readFileConfig: false,
// argv: this.__argv, // argv: this.__argv,
}); });
this.events.emit('devServerStarted');
this.devServer.webSockets.on( this.devServer.webSockets.on(
'message', 'message',
@@ -444,7 +449,9 @@ export class Engine {
} }
return result; return result;
} }
if (this.watcher) {
this.watcher.addFileToIgnore(sourceFilePath);
}
if (rocketHeader) { if (rocketHeader) {
const { needsAnotherRenderingPass } = await rocketHeader.syncComponents({ const { needsAnotherRenderingPass } = await rocketHeader.syncComponents({
outputFileContent: result.fileContent, outputFileContent: result.fileContent,
@@ -460,6 +467,13 @@ export class Engine {
} }
} }
if (this.watcher) {
this.watcher.removeFileToIgnore(sourceFilePath);
}
return result; return result;
} }
getVersion() {
return pkgJson.version;
}
} }

View File

@@ -78,6 +78,11 @@ export class Watcher {
acceptPageUpdates = true; acceptPageUpdates = true;
/**
* @type {Set<string>}
*/
_filesToIgnore = new Set();
/** /**
* @type {Map<string, { type: string, jsDependencies?: string[], webSockets?: Set<import('@web/dev-server-core').WebSocket> }>} * @type {Map<string, { type: string, jsDependencies?: string[], webSockets?: Set<import('@web/dev-server-core').WebSocket> }>}
*/ */
@@ -96,6 +101,9 @@ export class Watcher {
async (err, events) => { async (err, events) => {
if (this.acceptPageUpdates) { if (this.acceptPageUpdates) {
for (const event of events) { for (const event of events) {
if (this.isIgnoredFile(event.path)) {
return;
}
if (event.type === 'create') { if (event.type === 'create') {
await this.addCreateTask(event.path); await this.addCreateTask(event.path);
} }
@@ -109,6 +117,9 @@ export class Watcher {
await this.executeTaskQueue(); await this.executeTaskQueue();
} else { } else {
for (const event of events) { for (const event of events) {
if (this.isIgnoredFile(event.path)) {
return;
}
if ( if (
this._taskQueue.has(event.path) || this._taskQueue.has(event.path) ||
// we exclude files here as `@parcel/watcher` does not support globs in `ignore` // we exclude files here as `@parcel/watcher` does not support globs in `ignore`
@@ -340,4 +351,26 @@ export class Watcher {
this._taskQueue.clear(); this._taskQueue.clear();
this.acceptPageUpdates = true; this.acceptPageUpdates = true;
} }
/**
* @param {string} filePath
*/
addFileToIgnore(filePath) {
this._filesToIgnore.add(filePath);
}
/**
* @param {string} filePath
*/
removeFileToIgnore(filePath) {
this._filesToIgnore.delete(filePath);
}
/**
* @param {string} filePath
* @returns {boolean}
*/
isIgnoredFile(filePath) {
return this._filesToIgnore.has(filePath);
}
} }

View File

@@ -28,10 +28,28 @@ export function getHtmlMetaData(htmlFilePath) {
const metaData = { const metaData = {
// headlinesWithId: [], // headlinesWithId: [],
}; };
/** @type {string | undefined} */
let capturedHeadlineText = undefined;
let withinHTMLHead = false;
parser.eventHandler = (ev, _data) => { parser.eventHandler = (ev, _data) => {
if (ev === SaxEventType.OpenTag) {
const data = /** @type {Tag} */ (/** @type {any} */ (_data));
if (isHeadline(data)) {
capturedHeadlineText = '';
}
if (data.name === 'head') {
withinHTMLHead = true;
}
}
if (capturedHeadlineText !== undefined && ev === SaxEventType.Text) {
const data = /** @type {Text} */ (/** @type {any} */ (_data));
capturedHeadlineText += data.value;
}
if (ev === SaxEventType.CloseTag) { if (ev === SaxEventType.CloseTag) {
const data = /** @type {Tag} */ (/** @type {any} */ (_data)); const data = /** @type {Tag} */ (/** @type {any} */ (_data));
// ********** <meta name="*" content="*">
if (data.name === 'meta') { if (data.name === 'meta') {
const metaName = getAttribute(data, 'name'); const metaName = getAttribute(data, 'name');
if (metaName === 'menu:link.text') { if (metaName === 'menu:link.text') {
@@ -60,29 +78,39 @@ export function getHtmlMetaData(htmlFilePath) {
metaData.menuNoLink = getAttribute(data, 'content') !== 'false'; metaData.menuNoLink = getAttribute(data, 'content') !== 'false';
} }
} }
if (!metaData.title && data.name === 'title') { if (withinHTMLHead && data.name === 'title') {
metaData.title = getText(data); metaData.title = getText(data);
} }
if (!metaData.h1 && data.name === 'h1') {
metaData.h1 = getText(data);
}
// ********** <h1> - <h6>
if (isHeadline(data)) { if (isHeadline(data)) {
const id = getAttribute(data, 'id'); const id = getAttribute(data, 'id');
const rawText = getText(data);
const linkText = getAttribute(data, 'link-text'); const linkText = getAttribute(data, 'link-text');
if (id && rawText) { const processedCapturedHeadlineText = capturedHeadlineText
?.replace(/&#x3C;/g, '&lt;')
.replace(/&#x26;/g, '&')
.trim();
const text = linkText || processedCapturedHeadlineText || '';
if (!metaData.h1 && data.name === 'h1') {
metaData.h1 = text;
}
if (id && text) {
if (!metaData.headlinesWithId) { if (!metaData.headlinesWithId) {
metaData.headlinesWithId = []; metaData.headlinesWithId = [];
} }
const rawTextObj = linkText ? { rawText } : {}; const rawTextObj = linkText ? { rawText: processedCapturedHeadlineText } : {};
metaData.headlinesWithId.push({ metaData.headlinesWithId.push({
text: linkText || rawText, text,
id, id,
level: parseInt(data.name[1], 10), level: parseInt(data.name[1], 10),
...rawTextObj, ...rawTextObj,
}); });
} }
capturedHeadlineText = undefined;
}
if (data.name === 'head') {
withinHTMLHead = false;
} }
} }
}; };
@@ -97,6 +125,7 @@ export function getHtmlMetaData(htmlFilePath) {
}); });
readable.on('end', () => { readable.on('end', () => {
parser.end(); parser.end();
capturedHeadlineText = undefined;
resolve(metaData); resolve(metaData);
}); });

View File

@@ -9,6 +9,9 @@ const require = createRequire(import.meta.url);
export const streamOptions = { highWaterMark: 128 * 1024 }; export const streamOptions = { highWaterMark: 128 * 1024 };
const saxPath = require.resolve('sax-wasm/lib/sax-wasm.wasm'); const saxPath = require.resolve('sax-wasm/lib/sax-wasm.wasm');
const saxWasmBuffer = await readFile(saxPath); const saxWasmBuffer = await readFile(saxPath);
export const parser = new SAXParser(SaxEventType.CloseTag, streamOptions); export const parser = new SAXParser(
SaxEventType.OpenTag | SaxEventType.CloseTag | SaxEventType.Text,
streamOptions,
);
await parser.prepareWasm(saxWasmBuffer); await parser.prepareWasm(saxWasmBuffer);

View File

@@ -834,4 +834,118 @@ describe('Engine menus', () => {
await cleanup(); await cleanup();
}); });
it('14: get-all-text-but-strip-html', async () => {
const { build, readSource } = await setupTestEngine(
'fixtures/05-menu/14-get-all-text-but-strip-html/docs',
);
await build();
expect(JSON.parse(readSource('pageTreeData.rocketGenerated.json'))).to.deep.equal({
h1: 'Hello World of JS (JavaScript)!',
name: 'Hello World of JS (JavaScript)!',
menuLinkText: 'Hello World of JS (JavaScript)!',
url: '/',
outputRelativeFilePath: 'index.html',
sourceRelativeFilePath: 'index.rocket.js',
level: 0,
});
});
it('15: markdown special characters', async () => {
const { build, readSource } = await setupTestEngine(
'fixtures/05-menu/15-md-special-characters/docs',
);
await build();
expect(JSON.parse(readSource('pageTreeData.rocketGenerated.json'))).to.deep.equal({
children: [
{
h1: '&lt;some-button>',
headlinesWithId: [
{
id: 'some-button',
level: 1,
text: '&lt;some-button>',
},
],
level: 1,
menuLinkText: '&lt;some-button>',
name: '&lt;some-button>',
outputRelativeFilePath: 'component/index.html',
sourceRelativeFilePath: 'component.rocket.md',
url: '/component/',
},
],
h1: 'Fun Errors & Feedback',
headlinesWithId: [
{
id: 'fun-errors--feedback',
level: 1,
text: 'Fun Errors & Feedback',
},
],
level: 0,
menuLinkText: 'Fun Errors & Feedback',
name: 'Fun Errors & Feedback',
outputRelativeFilePath: 'index.html',
sourceRelativeFilePath: 'index.rocket.md',
url: '/',
});
});
it('16: link-text attribute', async () => {
const { build, readSource } = await setupTestEngine(
'fixtures/05-menu/16-link-text-attribute/docs',
);
await build();
expect(JSON.parse(readSource('pageTreeData.rocketGenerated.json'))).to.deep.equal({
h1: 'Home',
headlinesWithId: [
{
id: 'home',
level: 1,
rawText: 'Welcome to Rocket',
text: 'Home',
},
{
id: 'first',
level: 2,
text: 'First',
},
{
id: 'second',
level: 2,
rawText: 'Second is best',
text: 'Second',
},
],
level: 0,
menuLinkText: 'Home',
name: 'Home',
outputRelativeFilePath: 'index.html',
sourceRelativeFilePath: 'index.rocket.js',
url: '/',
});
});
it('17: title-tag', async () => {
const { build, readSource, deleteSource } = await setupTestEngine(
'fixtures/05-menu/17-title-tag/docs',
);
await deleteSource('pageTreeData.rocketGenerated.json');
await build();
expect(JSON.parse(readSource('pageTreeData.rocketGenerated.json'))).to.deep.equal({
h1: 'Welcome to Rocket',
level: 0,
menuLinkText: 'Welcome to Rocket',
name: 'Welcome to Rocket',
outputRelativeFilePath: 'index.html',
sourceRelativeFilePath: 'index.rocket.js',
title: 'Welcome to Rocket | Rocket',
url: '/',
});
});
}); });

View File

@@ -114,4 +114,77 @@ describe('Engine start error handling', () => {
); );
await cleanup(); await cleanup();
}); });
it('04: update-header-while-rendering', async () => {
const {
readOutput,
writeSource,
cleanup,
engine,
setAsOpenedInBrowser,
outputExists,
anEngineEvent,
} = await setupTestEngine(
'fixtures/09b-watch-error-handling/04-update-header-while-rendering/docs',
);
expect(outputExists('index.html')).to.be.false;
await engine.start();
setAsOpenedInBrowser('index.rocket.js');
await writeSource(
'index.rocket.js',
[
'/* START - Rocket auto generated - do not touch */',
"export const sourceRelativeFilePath = 'index.rocket.js';",
"import { html, components, layout } from './recursive.data.js';",
'export { html, components, layout };',
'export async function registerCustomElements() {',
' // hydrate-able components',
" customElements.define('hello-typer', await import('#c/HelloTyper.js').then(m => m.HelloTyper));",
'}',
'export const needsLoader = true;',
'/* END - Rocket auto generated - do not touch */',
'',
'export default () => html`',
' <h1>Hello World</h1>',
' <hello-typer loading="hydrate:onVisible"></hello-typer>',
'`;',
].join('\n'),
);
await anEngineEvent('rocketUpdated');
expect(readOutput('index.html')).to.equal(
[
'<!DOCTYPE html>',
'<html lang="en">',
' <head>',
' <meta charset="utf-8" />',
' </head>',
' <body>',
' <h1>Hello World</h1>',
' <hello-typer loading="hydrate:onVisible"',
' ><template shadowroot="open"',
' ><style>',
' button {',
' font-size: 200%;',
' width: 64px;',
' height: 64px;',
' border: none;',
' border-radius: 10px;',
' background-color: seagreen;',
' color: white;',
' }',
' </style>',
' <p>🤔 Hello <span> </span></p>',
' <button>+</button>',
' </template></hello-typer',
' >',
' <script type="module" src="index-loader-generated.js"></script>',
' </body>',
'</html>',
].join('\n'),
);
await cleanup();
});
}); });

View File

@@ -1,15 +1,15 @@
{ {
"title": "Fixed Title", "title": "Fixed Title",
"h1": "\n Welcome Members:\n ", "h1": "Welcome Members:",
"headlinesWithId": [ "headlinesWithId": [
{ {
"text": "\n Welcome Members:\n ", "text": "Welcome Members:",
"id": "welcome-members", "id": "welcome-members",
"level": 1 "level": 1
} }
], ],
"name": "Fixed Title", "name": "Fixed Title",
"menuLinkText": "\n Welcome Members:\n ", "menuLinkText": "Welcome Members:",
"url": "/", "url": "/",
"outputRelativeFilePath": "index.html", "outputRelativeFilePath": "index.html",
"sourceRelativeFilePath": "index.rocket.js", "sourceRelativeFilePath": "index.rocket.js",

View File

@@ -6,7 +6,13 @@ export { layout };
import { html } from 'lit'; import { html } from 'lit';
export default () => html` export default () => html`
<meta name="menu:link.text" content="About" /> <html>
<head>
<title>About | MyPage</title> <title>About | MyPage</title>
</head>
<body>
<meta name="menu:link.text" content="About" />
<h1>This is About</h1> <h1>This is About</h1>
</body>
</html>
`; `;

View File

@@ -8,8 +8,8 @@
"level": 0, "level": 0,
"children": [ "children": [
{ {
"menuLinkText": "About",
"title": "About | MyPage", "title": "About | MyPage",
"menuLinkText": "About",
"h1": "This is About", "h1": "This is About",
"name": "This is About", "name": "This is About",
"url": "/about/", "url": "/about/",

View File

@@ -0,0 +1,11 @@
/* START - Rocket auto generated - do not touch */
export const sourceRelativeFilePath = 'index.rocket.js';
import { layout, html } from './recursive.data.js';
export { layout, html };
/* END - Rocket auto generated - do not touch */
export default () =>
html`<h1>
Hello <strong>World</strong> of <span>JS <em>(JavaScript)</em></span
>!
</h1>`;

View File

@@ -0,0 +1,9 @@
{
"h1": "Hello World of JS (JavaScript)!",
"name": "Hello World of JS (JavaScript)!",
"menuLinkText": "Hello World of JS (JavaScript)!",
"url": "/",
"outputRelativeFilePath": "index.html",
"sourceRelativeFilePath": "index.rocket.js",
"level": 0
}

View File

@@ -0,0 +1,18 @@
import { PageTree, SiteMenu } from '@rocket/engine';
import { html } from 'lit';
const pageTree = new PageTree({
inputDir: new URL('./', import.meta.url),
outputDir: new URL('../__output', import.meta.url),
});
await pageTree.restore();
export const layout = data => {
return html`
${pageTree.renderMenu(new SiteMenu(), data.sourceRelativeFilePath)}
<main>${data.content()}</main>
`;
};
export { html };

View File

@@ -0,0 +1,9 @@
```js server
/* START - Rocket auto generated - do not touch */
export const sourceRelativeFilePath = 'component.rocket.md';
import { layout, html } from './recursive.data.js';
export { layout, html };
/* END - Rocket auto generated - do not touch */
```
# &lt;some-button>

View File

@@ -0,0 +1,9 @@
```js server
/* START - Rocket auto generated - do not touch */
export const sourceRelativeFilePath = 'index.rocket.md';
import { layout, html } from './recursive.data.js';
export { layout, html };
/* END - Rocket auto generated - do not touch */
```
# Fun Errors & Feedback

View File

@@ -0,0 +1,34 @@
{
"h1": "Fun Errors & Feedback",
"headlinesWithId": [
{
"text": "Fun Errors & Feedback",
"id": "fun-errors--feedback",
"level": 1
}
],
"name": "Fun Errors & Feedback",
"menuLinkText": "Fun Errors & Feedback",
"url": "/",
"outputRelativeFilePath": "index.html",
"sourceRelativeFilePath": "index.rocket.md",
"level": 0,
"children": [
{
"h1": "&lt;some-button>",
"headlinesWithId": [
{
"text": "&lt;some-button>",
"id": "some-button",
"level": 1
}
],
"name": "&lt;some-button>",
"menuLinkText": "&lt;some-button>",
"url": "/component/",
"outputRelativeFilePath": "component/index.html",
"sourceRelativeFilePath": "component.rocket.md",
"level": 1
}
]
}

View File

@@ -0,0 +1,18 @@
import { PageTree, SiteMenu } from '@rocket/engine';
import { html } from 'lit';
const pageTree = new PageTree({
inputDir: new URL('./', import.meta.url),
outputDir: new URL('../__output', import.meta.url),
});
await pageTree.restore();
export const layout = data => {
return html`
${pageTree.renderMenu(new SiteMenu(), data.sourceRelativeFilePath)}
<main>${data.content()}</main>
`;
};
export { html };

View File

@@ -0,0 +1,11 @@
/* START - Rocket auto generated - do not touch */
export const sourceRelativeFilePath = 'index.rocket.js';
import { layout, html } from './recursive.data.js';
export { layout, html };
/* END - Rocket auto generated - do not touch */
export default () => html`
<h1 id="home" link-text="Home">Welcome to Rocket</h1>
<h2 id="first">First</h2>
<h2 link-text="Second" id="second">Second is best</h2>
`;

View File

@@ -0,0 +1,28 @@
{
"h1": "Home",
"headlinesWithId": [
{
"text": "Home",
"id": "home",
"level": 1,
"rawText": "Welcome to Rocket"
},
{
"text": "First",
"id": "first",
"level": 2
},
{
"text": "Second",
"id": "second",
"level": 2,
"rawText": "Second is best"
}
],
"name": "Home",
"menuLinkText": "Home",
"url": "/",
"outputRelativeFilePath": "index.html",
"sourceRelativeFilePath": "index.rocket.js",
"level": 0
}

View File

@@ -0,0 +1,18 @@
import { PageTree, SiteMenu } from '@rocket/engine';
import { html } from 'lit';
const pageTree = new PageTree({
inputDir: new URL('./', import.meta.url),
outputDir: new URL('../__output', import.meta.url),
});
await pageTree.restore();
export const layout = data => {
return html`
${pageTree.renderMenu(new SiteMenu(), data.sourceRelativeFilePath)}
<main>${data.content()}</main>
`;
};
export { html };

View File

@@ -0,0 +1,7 @@
/* START - Rocket auto generated - do not touch */
export const sourceRelativeFilePath = 'index.rocket.js';
import { layout, html } from './recursive.data.js';
export { layout, html };
/* END - Rocket auto generated - do not touch */
export default () => html` <h1>Welcome to Rocket</h1> `;

View File

@@ -0,0 +1,10 @@
{
"title": "Welcome to Rocket | Rocket",
"h1": "Welcome to Rocket",
"name": "Welcome to Rocket",
"menuLinkText": "Welcome to Rocket",
"url": "/",
"outputRelativeFilePath": "index.html",
"sourceRelativeFilePath": "index.rocket.js",
"level": 0
}

View File

@@ -0,0 +1,28 @@
import { PageTree } from '@rocket/engine';
import { html } from 'lit';
const pageTree = new PageTree({
inputDir: new URL('./', import.meta.url),
outputDir: new URL('../__output', import.meta.url),
});
await pageTree.restore();
const titleWrapperFn = title => (title ? `${title} | Rocket` : '');
export const layout = data => {
const title = titleWrapperFn(pageTree.getPage(data.sourceRelativeFilePath)?.model?.name);
return html`
<html>
<head>
<title-server-only>${title}</title-server-only>
</head>
</html>
<body>
<main>${data.content()}</main>
</body>
</html>
`;
};
export { html };

View File

@@ -0,0 +1,54 @@
import { LitElement, html, css } from 'lit';
let i = 0;
const fullText = [...'to this wonderful world of progressive hydration 🤯'];
export class HelloTyper extends LitElement {
static properties = {
msg: { type: String },
counter: { type: Number },
};
constructor() {
super();
this.msg = ' ';
this.counter = 0;
}
updated(changedProperties) {
super.updated(changedProperties);
if (i < fullText.length) {
setTimeout(() => {
this.msg += fullText[i];
i += 1;
}, Math.floor(Math.random() * 50) + 40);
}
}
render() {
return html`
<p>🤔 Hello <span>${this.msg}</span>${'🤯'.repeat(this.counter)}</p>
<button @click=${this._inc}>+</button>
`;
}
_inc() {
if (i >= fullText.length) {
this.counter += 1;
}
}
static styles = [
css`
button {
font-size: 200%;
width: 64px;
height: 64px;
border: none;
border-radius: 10px;
background-color: seagreen;
color: white;
}
`,
];
}

View File

@@ -0,0 +1,15 @@
/* START - Rocket auto generated - do not touch */
export const sourceRelativeFilePath = 'index.rocket.js';
import { html, components, layout } from './recursive.data.js';
export { html, components, layout };
export async function registerCustomElements() {
// hydrate-able components
customElements.define('hello-typer', await import('#c/HelloTyper.js').then(m => m.HelloTyper));
}
export const needsLoader = true;
/* END - Rocket auto generated - do not touch */
export default () => html`
<h1>Hello World</h1>
<hello-typer loading="hydrate:onVisible"></hello-typer>
`;

View File

@@ -0,0 +1,22 @@
{
"url": "/",
"outputRelativeFilePath": "index.html",
"sourceRelativeFilePath": "index.rocket.js",
"level": 0,
"children": [
{
"url": "/about/",
"outputRelativeFilePath": "about/index.html",
"sourceRelativeFilePath": "about.rocket.js",
"level": 1
}
],
"menuLinkText": "Hello World",
"name": "Hello World",
"title": "name is not defined",
"h1": "Hello World",
"components": {
"hello-typer": "#c/HelloTyper.js::HelloTyper"
},
"needsLoader": true
}

View File

@@ -0,0 +1,19 @@
import { html } from 'lit';
export { html };
export const components = {
'hello-typer': '#c/HelloTyper.js::HelloTyper',
};
export const layout = data => html`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
</head>
<body>
${data.content()}
</body>
</html>
`;

View File

@@ -0,0 +1,7 @@
{
"name": "@test/components",
"type": "module",
"imports": {
"#c/*": "./components/*"
}
}

View File

@@ -1,5 +1,16 @@
# @rocket/launch # @rocket/launch
## 0.21.1
### Patch Changes
- 390335d: Improve title tag handling
- Updated dependencies [8dedc56]
- Updated dependencies [390335d]
- Updated dependencies [8dedc56]
- @rocket/engine@0.2.6
- @rocket/cli@0.20.1
## 0.21.0 ## 0.21.0
### Minor Changes ### Minor Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@rocket/launch", "name": "@rocket/launch",
"version": "0.21.0", "version": "0.21.1",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
@@ -46,9 +46,9 @@
"preset" "preset"
], ],
"dependencies": { "dependencies": {
"@rocket/cli": "^0.20.0", "@rocket/cli": "^0.20.1",
"@rocket/components": "^0.2.0", "@rocket/components": "^0.2.0",
"@rocket/engine": "^0.2.0", "@rocket/engine": "^0.2.6",
"@webcomponents/template-shadowroot": "^0.1.0", "@webcomponents/template-shadowroot": "^0.1.0",
"lit": "^2.3.0", "lit": "^2.3.0",
"workbox-window": "^6.1.5" "workbox-window": "^6.1.5"

View File

@@ -65,7 +65,7 @@ export class LayoutMain extends Layout {
}, },
], ],
footerMenu: [], footerMenu: [],
titleWrapperFn: title => `${title} | ${this.options.siteName}`, titleWrapperFn: title => (title ? `${title} | ${this.options.siteName}` : ''),
}; };
/** /**

View File

@@ -7,13 +7,13 @@ const { expect } = chai;
describe('Search', () => { describe('Search', () => {
it('01: writes the search index', async () => { it('01: writes the search index', async () => {
const { build, readOutput, readPublic } = await setupTestCli( const { build, readOutput, readPublic } = await setupTestCli({
'fixtures/01-single-page/', cwd: 'fixtures/01-single-page/',
undefined, options: {
{
buildOptimize: true, buildOptimize: true,
}, },
); testOptions: { captureLogs: true },
});
await build(); await build();
const indexString = const indexString =

View File

@@ -1,5 +1,14 @@
# @rocket/spark # @rocket/spark
## 0.2.1
### Patch Changes
- 390335d: Improve title tag handling
- Updated dependencies [8dedc56]
- Updated dependencies [390335d]
- @rocket/engine@0.2.6
## 0.2.0 ## 0.2.0
### Minor Changes ### Minor Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@rocket/spark", "name": "@rocket/spark",
"version": "0.2.0", "version": "0.2.1",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
@@ -41,7 +41,7 @@
], ],
"dependencies": { "dependencies": {
"@rocket/components": "^0.2.0", "@rocket/components": "^0.2.0",
"@rocket/engine": "^0.2.0", "@rocket/engine": "^0.2.6",
"lit": "^2.3.0" "lit": "^2.3.0"
}, },
"devDependencies": {}, "devDependencies": {},

View File

@@ -31,7 +31,7 @@ export class LayoutHome extends Layout {
return nothing; return nothing;
} }
const page = this.options.pageTree.getPage(data.sourceRelativeFilePath); const page = this.options.pageTree.getPage(data.sourceRelativeFilePath);
if (page.model.headlinesWithId) { if (page?.model?.headlinesWithId) {
return html` return html`
${page.model.headlinesWithId.map( ${page.model.headlinesWithId.map(
headline => html` headline => html`

View File

@@ -54,7 +54,7 @@ Like any unfamiliar technology, Rocket comes with a slight learning curve. Howev
### Example Projects ### Example Projects
If you prefer to learn Rocket by example, check out our [examples](https://github.com/modernweb-dev/rocket/tree/next/examples) on GitHub. If you prefer to learn Rocket by example, check out our [examples](https://github.com/modernweb-dev/rocket/tree/main/examples) on GitHub.
You locally install any of these examples by running `npx @rocket/create@latest` and selecting it within the wizard. You locally install any of these examples by running `npx @rocket/create@latest` and selecting it within the wizard.

View File

@@ -48,11 +48,11 @@ This with start rocket in development mode and you will see your site running in
## What is a page? ## What is a page?
A page is a file that ends either with `*.rocket.js`, `*.rocket.md` or `*.rocket.html` and is located in the input directory (`docs` by default). Pages will make up the majority or your website. A page is a file that ends either with `*.rocket.js`, `*.rocket.md` or `*.rocket.html` and is located in the input directory (`site/pages` by default). Pages will make up the majority or your website.
The simplest way to get started is to create a file The simplest way to get started is to create a file
👉 `docs/index.rocket.md` 👉 `site/pages/index.rocket.md`
```md ```md
# Hello World # Hello World
@@ -78,15 +78,23 @@ This section will be used to auto inject settings and data via a data cascade.
To test it you can create a file To test it you can create a file
👉 `docs/recursive.data.js` 👉 `site/pages/recursive.data.js`
```js ```js
import { html } from 'lit'; import { html } from 'lit';
export const layout = data => html`<div>${data.content()}</div>`; export const layout = data => html`
<!DOCTYPE html>
<html>
<body>
<header>My Website</header>
<div>${data.content()}</div>
</body>
</html>
`;
``` ```
Now if you go back to your `docs/index.rocket.md` you will see that `layout` got automatically injected. Now if you go back to your `site/pages/index.rocket.md` you will see that `layout` got automatically injected.
````md ````md
```js server ```js server

View File

@@ -31,7 +31,7 @@ export const description = 'Learn how to structure a project with Rocket.';
# Project Structure # Project Structure
Rocket works with one input folder for all your pages that defaults to `site/pages`. Rocket works with one input folder for all your pages that defaults to `site/pages`.
Within `pages` there is a `__public` folder that will be copied as is to the output folder. Within `pages` there is a `public` folder that will be copied as is to the output folder.
All other files like `layouts`, `css`, `data`, ... can be placed anywhere in your project. All other files like `layouts`, `css`, `data`, ... can be placed anywhere in your project.

View File

@@ -11,6 +11,8 @@ export async function registerCustomElements() {
// prettier-ignore // prettier-ignore
customElements.define('rocket-header', await import('@rocket/components/header.js').then(m => m.RocketHeader)); customElements.define('rocket-header', await import('@rocket/components/header.js').then(m => m.RocketHeader));
// prettier-ignore // prettier-ignore
customElements.define('inline-notification', await import('@rocket/components/inline-notification.js').then(m => m.InlineNotification));
// prettier-ignore
customElements.define('rocket-main-docs', await import('@rocket/components/main-docs.js').then(m => m.RocketMainDocs)); customElements.define('rocket-main-docs', await import('@rocket/components/main-docs.js').then(m => m.RocketMainDocs));
// prettier-ignore // prettier-ignore
customElements.define('rocket-content-area', await import('@rocket/components/content-area.js').then(m => m.RocketContentArea)); customElements.define('rocket-content-area', await import('@rocket/components/content-area.js').then(m => m.RocketContentArea));
@@ -85,22 +87,22 @@ In most cases you probably will not need to do anything as it will take the text
So if you have a page like this: So if you have a page like this:
```md ```md
# Hello World # Learning Rocket
``` ```
then it will be called "Hello World" in the menu. then it will be called "Learning Rocket" in the menu.
You can overwrite that by using the property `menuLinkText`; You can overwrite that by using the property `menuLinkText`;
````md ````md
```js server ```js server
export const menuLinkText = 'Hello'; export const menuLinkText = 'Docs';
``` ```
# Hello World # Learning Rocket
```` ````
Now the menu will be called "Hello". Now the menu will be called "Docs".
Within a menu the text of the links is defined by the following priority: Within a menu the text of the links is defined by the following priority:
@@ -111,6 +113,32 @@ Within a menu the text of the links is defined by the following priority:
You can influence that data that gets provided to the menu by setting exports. You can influence that data that gets provided to the menu by setting exports.
### link-text="..."
If you want to rename the menu text you can use the attribute `link-text`.
It works on your h1 for the page title as well as on your h2-h6 for a table of contents menu.
Examples:
```html
<h1 link-text="Docs">Learning Rocket</h1>
<h2 link-text="Contact">Write us a message</h2>
```
<inline-notification>
You can use HTML within markdown too!
</inline-notification>
## Headings with HTML
HTML in headings will be ignored for the menu
Some examples:
- `<h1>Hello <em>Word</em></h1>` => `Hello Word`
- `<h1>Hello <strong>World</strong> of <span>JS <em>(JavaScript)</em></span>!</h1>` => `Hello World of JS (JavaScript)!`
## Menu No Link ## Menu No Link
Often you have sections or groups of pages which you want to provide a heading for. Often you have sections or groups of pages which you want to provide a heading for.

View File

@@ -22,6 +22,8 @@ export async function registerCustomElements() {
} }
export const needsLoader = true; export const needsLoader = true;
/* END - Rocket auto generated - do not touch */ /* END - Rocket auto generated - do not touch */
export const title = 'Plugins Manager';
export const subTitle = 'Enable fully customizable options for your plugin system';
``` ```
# Overview # Overview

View File

@@ -22,6 +22,9 @@ export async function registerCustomElements() {
} }
export const needsLoader = true; export const needsLoader = true;
/* END - Rocket auto generated - do not touch */ /* END - Rocket auto generated - do not touch */
export const title = 'Markdown JavaScript';
export const subTitle = 'Executable JavaScript in markdown by annotating code blocks';
``` ```
# Overview # Overview

View File

@@ -22,6 +22,10 @@ export async function registerCustomElements() {
} }
export const needsLoader = true; export const needsLoader = true;
/* END - Rocket auto generated - do not touch */ /* END - Rocket auto generated - do not touch */
export const title = 'Rocket Rollup Config';
export const subTitle =
'A ready to use and customizable rollup config for web sites, MPAs and SPAs';
``` ```
# Overview # Overview

View File

@@ -24,11 +24,14 @@ export async function registerCustomElements() {
} }
export const needsLoader = true; export const needsLoader = true;
/* END - Rocket auto generated - do not touch */ /* END - Rocket auto generated - do not touch */
export const title = 'Check HTML links';
export const subTitle = 'A fast checker for broken links/references in HTML files';
``` ```
# Overview # Overview
A fast checker for broken links/references in HTML. A fast checker for broken links/references in HTML files.
<inline-notification type="tip"> <inline-notification type="tip">

View File

@@ -1,8 +1,8 @@
{ {
"title": "Welcome to Rocket", "title": "Welcome to Rocket",
"h1": "\n \n ", "h1": "",
"name": "\n \n ", "name": "Welcome to Rocket",
"menuLinkText": "\n \n ", "menuLinkText": "Welcome to Rocket",
"url": "/", "url": "/",
"outputRelativeFilePath": "index.html", "outputRelativeFilePath": "index.html",
"sourceRelativeFilePath": "index.rocket.js", "sourceRelativeFilePath": "index.rocket.js",
@@ -386,6 +386,31 @@
"text": "Recommended Project Structure", "text": "Recommended Project Structure",
"id": "recommended-project-structure", "id": "recommended-project-structure",
"level": 2 "level": 2
},
{
"text": "site/pages/",
"id": "sitepages",
"level": 3
},
{
"text": "site/src/",
"id": "sitesrc",
"level": 3
},
{
"text": "site/src/components",
"id": "sitesrccomponents",
"level": 3
},
{
"text": "site/src/layouts",
"id": "sitesrclayouts",
"level": 3
},
{
"text": "site/public/",
"id": "sitepublic",
"level": 3
} }
], ],
"name": "Project Structure", "name": "Project Structure",
@@ -758,6 +783,16 @@
"id": "menu-link-text", "id": "menu-link-text",
"level": 3 "level": 3
}, },
{
"text": "link-text=\"...\"",
"id": "link-text",
"level": 3
},
{
"text": "Headings with HTML",
"id": "headings-with-html",
"level": 2
},
{ {
"text": "Menu No Link", "text": "Menu No Link",
"id": "menu-no-link", "id": "menu-no-link",
@@ -937,7 +972,7 @@
"level": 2 "level": 2
}, },
{ {
"text": "The Function", "text": "The :resolve Function",
"id": "the-resolve-function", "id": "the-resolve-function",
"level": 2 "level": 2
}, },
@@ -1432,7 +1467,7 @@
"level": 2 "level": 2
}, },
{ {
"text": "1. Simple Tags and External Files", "text": "1. Simple &lt;link> Tags and External Files",
"id": "1-simple-link-tags-and-external-files", "id": "1-simple-link-tags-and-external-files",
"level": 3 "level": 3
}, },
@@ -1447,7 +1482,7 @@
"level": 3 "level": 3
}, },
{ {
"text": "Recommendations &#x26; Best Practices", "text": "Recommendations & Best Practices",
"id": "recommendations--best-practices", "id": "recommendations--best-practices",
"level": 2 "level": 2
}, },
@@ -2239,7 +2274,7 @@
"needsLoader": true, "needsLoader": true,
"children": [ "children": [
{ {
"title": "Overview | Rocket", "title": "Plugins Manager",
"h1": "Overview", "h1": "Overview",
"headlinesWithId": [ "headlinesWithId": [
{ {
@@ -2313,7 +2348,7 @@
"level": 2 "level": 2
} }
], ],
"name": "Overview", "name": "Plugins Manager",
"menuLinkText": "Overview", "menuLinkText": "Overview",
"url": "/tools/plugins-manager/overview/", "url": "/tools/plugins-manager/overview/",
"outputRelativeFilePath": "tools/plugins-manager/overview/index.html", "outputRelativeFilePath": "tools/plugins-manager/overview/index.html",
@@ -2345,7 +2380,8 @@
"launch-blog-details": "@rocket/launch/blog-details.js::LaunchBlogDetails", "launch-blog-details": "@rocket/launch/blog-details.js::LaunchBlogDetails",
"my-counter": "#src/components/MyCounter.js::MyCounter" "my-counter": "#src/components/MyCounter.js::MyCounter"
}, },
"needsLoader": true "needsLoader": true,
"subTitle": "Enable fully customizable options for your plugin system"
} }
] ]
}, },
@@ -2388,7 +2424,7 @@
"needsLoader": true, "needsLoader": true,
"children": [ "children": [
{ {
"title": "Overview | Rocket", "title": "Markdown JavaScript",
"h1": "Overview", "h1": "Overview",
"headlinesWithId": [ "headlinesWithId": [
{ {
@@ -2451,13 +2487,23 @@
"id": "basic", "id": "basic",
"level": 3 "level": 3
}, },
{
"text": "mdjsDocPage",
"id": "mdjsdocpage",
"level": 4
},
{
"text": "mdjsProcess",
"id": "mdjsprocess",
"level": 4
},
{ {
"text": "Advanced", "text": "Advanced",
"id": "advanced", "id": "advanced",
"level": 3 "level": 3
} }
], ],
"name": "Overview", "name": "Markdown JavaScript",
"menuLinkText": "Overview", "menuLinkText": "Overview",
"url": "/tools/markdown-javascript/overview/", "url": "/tools/markdown-javascript/overview/",
"outputRelativeFilePath": "tools/markdown-javascript/overview/index.html", "outputRelativeFilePath": "tools/markdown-javascript/overview/index.html",
@@ -2489,7 +2535,8 @@
"launch-blog-details": "@rocket/launch/blog-details.js::LaunchBlogDetails", "launch-blog-details": "@rocket/launch/blog-details.js::LaunchBlogDetails",
"my-counter": "#src/components/MyCounter.js::MyCounter" "my-counter": "#src/components/MyCounter.js::MyCounter"
}, },
"needsLoader": true "needsLoader": true,
"subTitle": "Executable JavaScript in markdown by annotating code blocks"
}, },
{ {
"title": "Preview | Rocket", "title": "Preview | Rocket",
@@ -2655,7 +2702,7 @@
"needsLoader": true, "needsLoader": true,
"children": [ "children": [
{ {
"title": "Overview | Rocket", "title": "Rocket Rollup Config",
"h1": "Overview", "h1": "Overview",
"headlinesWithId": [ "headlinesWithId": [
{ {
@@ -2689,7 +2736,7 @@
"level": 3 "level": 3
} }
], ],
"name": "Overview", "name": "Rocket Rollup Config",
"menuLinkText": "Overview", "menuLinkText": "Overview",
"url": "/tools/rollup-config/overview/", "url": "/tools/rollup-config/overview/",
"outputRelativeFilePath": "tools/rollup-config/overview/index.html", "outputRelativeFilePath": "tools/rollup-config/overview/index.html",
@@ -2721,7 +2768,8 @@
"launch-blog-details": "@rocket/launch/blog-details.js::LaunchBlogDetails", "launch-blog-details": "@rocket/launch/blog-details.js::LaunchBlogDetails",
"my-counter": "#src/components/MyCounter.js::MyCounter" "my-counter": "#src/components/MyCounter.js::MyCounter"
}, },
"needsLoader": true "needsLoader": true,
"subTitle": "A ready to use and customizable rollup config for web sites, MPAs and SPAs"
} }
] ]
}, },
@@ -2764,7 +2812,7 @@
"needsLoader": true, "needsLoader": true,
"children": [ "children": [
{ {
"title": "Overview | Rocket", "title": "Check HTML links",
"h1": "Overview", "h1": "Overview",
"headlinesWithId": [ "headlinesWithId": [
{ {
@@ -2803,7 +2851,7 @@
"level": 2 "level": 2
} }
], ],
"name": "Overview", "name": "Check HTML links",
"menuLinkText": "Overview", "menuLinkText": "Overview",
"url": "/tools/check-html-links/overview/", "url": "/tools/check-html-links/overview/",
"outputRelativeFilePath": "tools/check-html-links/overview/index.html", "outputRelativeFilePath": "tools/check-html-links/overview/index.html",
@@ -2835,7 +2883,8 @@
"launch-blog-details": "@rocket/launch/blog-details.js::LaunchBlogDetails", "launch-blog-details": "@rocket/launch/blog-details.js::LaunchBlogDetails",
"my-counter": "#src/components/MyCounter.js::MyCounter" "my-counter": "#src/components/MyCounter.js::MyCounter"
}, },
"needsLoader": true "needsLoader": true,
"subTitle": "A fast checker for broken links/references in HTML files"
} }
] ]
} }

View File

@@ -1248,15 +1248,6 @@
"@open-wc/scoped-elements" "^2.1.1" "@open-wc/scoped-elements" "^2.1.1"
lit "^2.0.2" lit "^2.0.2"
"@lion/overlays@^0.32.0":
version "0.32.0"
resolved "https://registry.yarnpkg.com/@lion/overlays/-/overlays-0.32.0.tgz#d9c7d0bfd7895768efcf9bcc65a97e330bdcf424"
integrity sha512-VyHilarcgWYYM+NDNXxuAiAT8EHipJUHNiaV85OLzwgqqMFC5TsG9wyekqj5iu3mk96R4s/RU1gjqfR9O88INQ==
dependencies:
"@lion/core" "^0.22.0"
"@popperjs/core" "^2.5.4"
singleton-manager "^1.4.3"
"@lit-labs/ssr-client@^1.0.0": "@lit-labs/ssr-client@^1.0.0":
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/@lit-labs/ssr-client/-/ssr-client-1.0.1.tgz#b97e121184aa201bbe6f165f3a7dc919f67129a2" resolved "https://registry.yarnpkg.com/@lit-labs/ssr-client/-/ssr-client-1.0.1.tgz#b97e121184aa201bbe6f165f3a7dc919f67129a2"
@@ -1402,11 +1393,6 @@
"@types/node" "*" "@types/node" "*"
playwright-core "1.25.0" playwright-core "1.25.0"
"@popperjs/core@^2.5.4":
version "2.11.6"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45"
integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==
"@rollup/plugin-babel@^5.2.2": "@rollup/plugin-babel@^5.2.2":
version "5.3.1" version "5.3.1"
resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283" resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283"
@@ -1670,6 +1656,13 @@
resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-1.8.2.tgz#7315b4c4c54f82d13fa61c228ec5c2ea5cc9e0e1" resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-1.8.2.tgz#7315b4c4c54f82d13fa61c228ec5c2ea5cc9e0e1"
integrity sha512-EqX+YQxINb+MeXaIqYDASb6U6FCHbWjkj4a1CKDBks3d/QiB2+PqBLyO72vLDgAO1wUI4O+9gweRcQK11bTL/w== 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": "@types/is-ci@^3.0.0":
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/is-ci/-/is-ci-3.0.0.tgz#7e8910af6857601315592436f030aaa3ed9783c3" resolved "https://registry.yarnpkg.com/@types/is-ci/-/is-ci-3.0.0.tgz#7e8910af6857601315592436f030aaa3ed9783c3"
@@ -2099,9 +2092,9 @@
glob "^7.1.6" glob "^7.1.6"
"@web/rollup-plugin-html@^1.8.0": "@web/rollup-plugin-html@^1.8.0":
version "1.10.3" version "1.11.0"
resolved "https://registry.yarnpkg.com/@web/rollup-plugin-html/-/rollup-plugin-html-1.10.3.tgz#78fa06a9a7f2ec6973a12bd1000b900c1fd4e4eb" resolved "https://registry.yarnpkg.com/@web/rollup-plugin-html/-/rollup-plugin-html-1.11.0.tgz#46c2bcb3a3b9db55d53b897ffc7e7ef2f618a052"
integrity sha512-2RMIeKxpGtrcXiqPTgMVq5neGa5xa69MfNK860BHVMEO2N/MrHFuQNr1eNLsspcq2DL/xnymwC3w5hgjtlgxag== integrity sha512-EqUcV5plGYTV/utdbX8g5t8Yq/z6VfFuQuPD39ckOQuRj7Rj6HD15FHwLHpFAWOR0+GrDnNzR74RvI4ipGm0qQ==
dependencies: dependencies:
"@web/parse5-utils" "^1.3.0" "@web/parse5-utils" "^1.3.0"
glob "^7.1.6" glob "^7.1.6"
@@ -7394,11 +7387,6 @@ signal-exit@^3.0.2:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
singleton-manager@^1.4.3:
version "1.5.0"
resolved "https://registry.yarnpkg.com/singleton-manager/-/singleton-manager-1.5.0.tgz#725827e3c516cd28c1d1a8533fac04a3f2a75e2b"
integrity sha512-38sWGgQlhX4TM9xLHNTdp/qVmD3kGKty8j/d4/xZUL2FLycyCPhYjctWK1gO4FZQa4mc2orPxLmzS5I1QwFMhw==
sinon@^9.2.3: sinon@^9.2.3:
version "9.2.4" version "9.2.4"
resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.2.4.tgz#e55af4d3b174a4443a8762fa8421c2976683752b" resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.2.4.tgz#e55af4d3b174a4443a8762fa8421c2976683752b"