mirror of
https://github.com/modernweb-dev/rocket.git
synced 2026-03-21 15:54:57 +00:00
Compare commits
31 Commits
@mdjs/mdjs
...
@rocket/cl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b48fb9760 | ||
|
|
39206a1738 | ||
|
|
cbfb0f91e2 | ||
|
|
58692147e9 | ||
|
|
8dedc56afa | ||
|
|
bcbfae332d | ||
|
|
0fae0037d8 | ||
|
|
390335da18 | ||
|
|
6d2f469d26 | ||
|
|
94a6f54585 | ||
|
|
ff8b4c5cd5 | ||
|
|
5122ea8639 | ||
|
|
3032ba9b82 | ||
|
|
93503ed309 | ||
|
|
77646abbee | ||
|
|
9ae3966fef | ||
|
|
09a47b43dc | ||
|
|
42d794bdfc | ||
|
|
b8a1b45953 | ||
|
|
379f08ff47 | ||
|
|
50bb68ab7f | ||
|
|
250ca87a9d | ||
|
|
6f88d8ef6f | ||
|
|
35ed64dca1 | ||
|
|
2555a8698d | ||
|
|
367529c211 | ||
|
|
ce3298d218 | ||
|
|
a22da493dd | ||
|
|
7a8f165625 | ||
|
|
c8081071f7 | ||
|
|
ab2436162c |
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -7,5 +7,6 @@
|
|||||||
"search.exclude": {
|
"search.exclude": {
|
||||||
"**/*-mdjs-generated.js": true,
|
"**/*-mdjs-generated.js": true,
|
||||||
"**/dist-types": true,
|
"**/dist-types": true,
|
||||||
}
|
},
|
||||||
|
"editor.experimental.stickyScroll.enabled": true
|
||||||
}
|
}
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<picture width="60%">
|
<picture width="60%">
|
||||||
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/modernweb-dev/rocket/next/site/src/assets/rocket-logo-dark-with-text.svg">
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/modernweb-dev/rocket/main/site/src/assets/rocket-logo-dark-with-text.svg">
|
||||||
<img alt="Rocket Logo" src="https://raw.githubusercontent.com/modernweb-dev/rocket/next/site/src/assets/rocket-logo-light-with-text.svg">
|
<img alt="Rocket Logo" src="https://raw.githubusercontent.com/modernweb-dev/rocket/main/site/src/assets/rocket-logo-light-with-text.svg">
|
||||||
</picture>
|
</picture>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/modernweb-dev/rocket/actions"
|
<a href="https://github.com/modernweb-dev/rocket/actions"
|
||||||
><img
|
><img
|
||||||
src="https://img.shields.io/github/workflow/status/modernweb-dev/rocket/Release/next?label=workflow&style=flat-square"
|
src="https://img.shields.io/github/workflow/status/modernweb-dev/rocket/Release/main?label=workflow&style=flat-square"
|
||||||
alt="GitHub Actions workflow status"
|
alt="GitHub Actions workflow status"
|
||||||
/></a>
|
/></a>
|
||||||
<a href="https://twitter.com/modern_web_dev"
|
<a href="https://twitter.com/modern_web_dev"
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
"@rocket/cli": "^0.20.0",
|
"@rocket/cli": "^0.20.0",
|
||||||
"@rocket/engine": "^0.2.0",
|
"@rocket/engine": "^0.2.0",
|
||||||
"@webcomponents/template-shadowroot": "^0.1.0",
|
"@webcomponents/template-shadowroot": "^0.1.0",
|
||||||
"lit": "^2.2.5"
|
"lit": "^2.3.0"
|
||||||
},
|
},
|
||||||
"@rocket/template-name": "Hydration Starter",
|
"@rocket/template-name": "Hydration Starter",
|
||||||
"imports": {
|
"imports": {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rocket/cli": "^0.20.0",
|
"@rocket/cli": "^0.20.0",
|
||||||
"@rocket/engine": "^0.2.0",
|
"@rocket/engine": "^0.2.0",
|
||||||
"lit": "^2.2.5"
|
"lit": "^2.3.0"
|
||||||
},
|
},
|
||||||
"@rocket/template-name": "Blog Starter"
|
"@rocket/template-name": "Blog Starter"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rocket/cli": "^0.20.0",
|
"@rocket/cli": "^0.20.0",
|
||||||
"@rocket/engine": "^0.2.0",
|
"@rocket/engine": "^0.2.0",
|
||||||
"lit": "^2.2.5"
|
"lit": "^2.3.0"
|
||||||
},
|
},
|
||||||
"@rocket/template-name": "Minimal Starter"
|
"@rocket/template-name": "Minimal Starter"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"@sanity/client": "^3.1.0",
|
"@sanity/client": "^3.1.0",
|
||||||
"@sanity/image-url": "^1.0.1",
|
"@sanity/image-url": "^1.0.1",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.0",
|
||||||
"lit": "^2.2.5"
|
"lit": "^2.3.0"
|
||||||
},
|
},
|
||||||
"@rocket/template-name": "Sanity Minimal Starter"
|
"@rocket/template-name": "Sanity Minimal Starter"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
"@rocket/components": "^0.2.0",
|
"@rocket/components": "^0.2.0",
|
||||||
"@rocket/engine": "^0.2.0",
|
"@rocket/engine": "^0.2.0",
|
||||||
"@rocket/spark": "^0.2.0",
|
"@rocket/spark": "^0.2.0",
|
||||||
"lit": "^2.2.5"
|
"lit": "^2.3.0"
|
||||||
},
|
},
|
||||||
"@rocket/template-name": "Landing Page (@rocket/spark Theme)",
|
"@rocket/template-name": "Landing Page (@rocket/spark Theme)",
|
||||||
"imports": {
|
"imports": {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
"@rocket/engine": "^0.2.0",
|
"@rocket/engine": "^0.2.0",
|
||||||
"@rocket/launch": "^0.21.0",
|
"@rocket/launch": "^0.21.0",
|
||||||
"@rocket/search": "^0.7.0",
|
"@rocket/search": "^0.7.0",
|
||||||
"lit": "^2.2.5"
|
"lit": "^2.3.0"
|
||||||
},
|
},
|
||||||
"@rocket/template-name": "Documentation Website (@rocket/launch Theme)",
|
"@rocket/template-name": "Documentation Website (@rocket/launch Theme)",
|
||||||
"imports": {
|
"imports": {
|
||||||
|
|||||||
@@ -30,13 +30,14 @@
|
|||||||
"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",
|
||||||
|
"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",
|
"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",
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# @rocket/building-rollup
|
# @rocket/building-rollup
|
||||||
|
|
||||||
|
## 0.4.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- a22da49: Make sure user provided `developmentMode` actually gets applied.
|
||||||
|
|
||||||
## 0.4.0
|
## 0.4.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@rocket/building-rollup",
|
"name": "@rocket/building-rollup",
|
||||||
"version": "0.4.0",
|
"version": "0.4.1",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export function createBasicConfig(userConfig) {
|
|||||||
|
|
||||||
export function createBasicMetaConfig(userConfig = { output: {} }) {
|
export function createBasicMetaConfig(userConfig = { output: {} }) {
|
||||||
const developmentMode =
|
const developmentMode =
|
||||||
typeof userConfig.developmentMode !== undefined
|
typeof userConfig.developmentMode !== 'undefined'
|
||||||
? userConfig.developmentMode
|
? userConfig.developmentMode
|
||||||
: !!process.env.ROLLUP_WATCH;
|
: !!process.env.ROLLUP_WATCH;
|
||||||
delete userConfig.developmentMode;
|
delete userConfig.developmentMode;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export function createServiceWorkerConfig(userConfig) {
|
|||||||
|
|
||||||
export function createServiceWorkerMetaConfig(userConfig = { output: {} }) {
|
export function createServiceWorkerMetaConfig(userConfig = { output: {} }) {
|
||||||
const developmentMode =
|
const developmentMode =
|
||||||
typeof userConfig.developmentMode !== undefined
|
typeof userConfig.developmentMode !== 'undefined'
|
||||||
? userConfig.developmentMode
|
? userConfig.developmentMode
|
||||||
: !!process.env.ROLLUP_WATCH;
|
: !!process.env.ROLLUP_WATCH;
|
||||||
delete userConfig.developmentMode;
|
delete userConfig.developmentMode;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
"glob": "^7.0.0",
|
"glob": "^7.0.0",
|
||||||
"minimatch": "^3.0.4",
|
"minimatch": "^3.0.4",
|
||||||
"sax-wasm": "^2.0.0",
|
"sax-wasm": "^2.0.0",
|
||||||
"slash": "^3.0.0"
|
"slash": "^4.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/glob": "^7.0.0"
|
"@types/glob": "^7.0.0"
|
||||||
|
|||||||
@@ -1,5 +1,30 @@
|
|||||||
# @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
|
||||||
|
|
||||||
|
### 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
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@rocket/cli",
|
"name": "@rocket/cli",
|
||||||
"version": "0.20.0",
|
"version": "0.20.2",
|
||||||
"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",
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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} */
|
||||||
@@ -30,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;
|
||||||
}
|
}
|
||||||
@@ -49,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,
|
||||||
@@ -60,7 +62,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 +80,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');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
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.',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
24
packages/cli/src/start/logStartMessage.js
Normal file
24
packages/cli/src/start/logStartMessage.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { white, bold, cyan, gray } from 'colorette';
|
||||||
|
import { createAddress, logNetworkAddress } from '../helpers/infoMessages.js';
|
||||||
|
|
||||||
|
/** @typedef {import('@web/dev-server').DevServerConfig} DevServerConfig */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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) {
|
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;
|
||||||
|
|||||||
@@ -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,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
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('');
|
||||||
|
});
|
||||||
|
});
|
||||||
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('');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -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
|
||||||
|
}
|
||||||
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
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@webcomponents/template-shadowroot": "^0.1.0",
|
"@webcomponents/template-shadowroot": "^0.1.0",
|
||||||
"fontawesome-free": "^1.0.4",
|
"fontawesome-free": "^1.0.4",
|
||||||
"lit": "^2.2.5"
|
"lit": "^2.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {},
|
"devDependencies": {},
|
||||||
"types": "./dist-types/exports/index.d.ts",
|
"types": "./dist-types/exports/index.d.ts",
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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).
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { RocketDrawer } from './src/RocketDrawer.js';
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import { RocketDrawer } from './src/RocketDrawer.js';
|
|
||||||
|
|
||||||
customElements.define('rocket-drawer', RocketDrawer);
|
|
||||||
@@ -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)`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,64 @@
|
|||||||
# @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
|
||||||
|
|
||||||
|
# <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
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 379f08f: Remove the lit workaround to globally load the `global-dom-shim` in the "main thread".
|
||||||
|
Which means only the worker that does the actual SSR rendering will load it.
|
||||||
|
|
||||||
|
## 0.2.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 6f88d8e: Get rid of the `rehype-prism` workaround by using latest esm version of mdjs that uses `rehype-prism-plus`
|
||||||
|
- Updated dependencies [35ed64d]
|
||||||
|
- Updated dependencies [6f88d8e]
|
||||||
|
- @mdjs/core@0.20.0
|
||||||
|
|
||||||
|
## 0.2.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 367529c: Make sure user provided content in the folder `site/public/*` wins over public folders content provided by plugins.
|
||||||
|
|
||||||
## 0.2.0
|
## 0.2.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@rocket/engine",
|
"name": "@rocket/engine",
|
||||||
"version": "0.2.0",
|
"version": "0.2.6",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
@@ -35,9 +35,9 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"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 5000 test-node/**/*.test.{js,cjs} test-node/*.test.{js,cjs}",
|
"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,cjs}' 'test-node/**/*.{js,cjs}' -- 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/"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
@@ -47,14 +47,15 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@d4kmor/tree-model": "^0.1.3",
|
"@d4kmor/tree-model": "^0.1.3",
|
||||||
"@lit-labs/ssr": "^2.0.4",
|
"@lit-labs/ssr": "^2.2.3",
|
||||||
"@mdjs/core": "^0.9.5",
|
"@mdjs/core": "^0.20.0",
|
||||||
"@parcel/watcher": "^2.0.5",
|
"@parcel/watcher": "^2.0.5",
|
||||||
"@web/dev-server": "^0.1.4",
|
"@web/dev-server": "^0.1.4",
|
||||||
"es-module-lexer": "^0.9.3",
|
"es-module-lexer": "^0.10.5",
|
||||||
"lit": "^2.2.5",
|
"lit": "^2.3.0",
|
||||||
"plugins-manager": "^0.3.0",
|
"plugins-manager": "^0.3.0",
|
||||||
"sax-wasm": "^2.1.3"
|
"sax-wasm": "^2.1.3",
|
||||||
|
"unist-util-visit": "^4.1.0"
|
||||||
},
|
},
|
||||||
"types": "./dist-types/src/index.d.ts",
|
"types": "./dist-types/src/index.d.ts",
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,12 +156,7 @@ export class Engine {
|
|||||||
* @param {string} targetDir
|
* @param {string} targetDir
|
||||||
*/
|
*/
|
||||||
async copyPublicFilesTo(targetDir) {
|
async copyPublicFilesTo(targetDir) {
|
||||||
// copy public files
|
// 1. copy public files of plugins
|
||||||
const publicDir = path.join(this.docsDir, '..', 'public');
|
|
||||||
if (existsSync(publicDir)) {
|
|
||||||
await fse.copy(publicDir, targetDir);
|
|
||||||
}
|
|
||||||
// copy public files of plugins
|
|
||||||
if (this.options.plugins) {
|
if (this.options.plugins) {
|
||||||
for (const plugin of this.options.plugins) {
|
for (const plugin of this.options.plugins) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -171,6 +170,12 @@ export class Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. copy public files from inputDir (e.g. user public folder always wins)
|
||||||
|
const publicDir = path.join(this.docsDir, '..', 'public');
|
||||||
|
if (existsSync(publicDir)) {
|
||||||
|
await fse.copy(publicDir, targetDir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async start(options = {}) {
|
async start(options = {}) {
|
||||||
@@ -264,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',
|
||||||
@@ -443,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,
|
||||||
@@ -459,6 +467,13 @@ export class Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.watcher) {
|
||||||
|
this.watcher.removeFileToIgnore(sourceFilePath);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getVersion() {
|
||||||
|
return pkgJson.version;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ export function devServerAdjustAssetUrls({
|
|||||||
const outputFilePath = getOutputFilePath(sourceFilePath);
|
const outputFilePath = getOutputFilePath(sourceFilePath);
|
||||||
const sourceRelativeFilePath = path.relative(inputDir, sourceFilePath);
|
const sourceRelativeFilePath = path.relative(inputDir, sourceFilePath);
|
||||||
const outputRelativeFilePath = path.relative(outputDir, outputFilePath);
|
const outputRelativeFilePath = path.relative(outputDir, outputFilePath);
|
||||||
const newBody = await adjustAssetUrl.transform(context.body, {
|
const body = /** @type {string} */ (context.body);
|
||||||
|
const newBody = await adjustAssetUrl.transform(body, {
|
||||||
sourceFilePath,
|
sourceFilePath,
|
||||||
sourceRelativeFilePath,
|
sourceRelativeFilePath,
|
||||||
outputFilePath,
|
outputFilePath,
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
// we load this before the global-dom-shim as otherwise prism thinks it's running in a browser 🙈
|
|
||||||
// we need to load the global-dom-shim as otherwise import { html } from 'lit'; breaks
|
|
||||||
import 'rehype-prism';
|
|
||||||
import '@lit-labs/ssr/lib/install-global-dom-shim.js';
|
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||||
|
// @ts-ignore
|
||||||
import { mdjsProcess } from '@mdjs/core';
|
import { mdjsProcess } from '@mdjs/core';
|
||||||
import { existsSync } from 'fs';
|
import { existsSync } from 'fs';
|
||||||
import { readFile, writeFile } from 'fs/promises';
|
import { readFile, writeFile } from 'fs/promises';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { addPlugin } from 'plugins-manager';
|
import { addPlugin } from 'plugins-manager';
|
||||||
import markdown from 'remark-parse';
|
import markdown from 'remark-parse';
|
||||||
import visit from 'unist-util-visit';
|
import { visit } from 'unist-util-visit';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} string
|
* @param {string} string
|
||||||
@@ -22,7 +18,7 @@ function escapeRegExp(string) {
|
|||||||
|
|
||||||
const REGEX_REPLACE_ESCAPES = new RegExp(
|
const REGEX_REPLACE_ESCAPES = new RegExp(
|
||||||
escapeRegExp(
|
escapeRegExp(
|
||||||
'\\\\</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>',
|
'\\\\<span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>',
|
||||||
),
|
),
|
||||||
'g',
|
'g',
|
||||||
);
|
);
|
||||||
@@ -145,7 +141,7 @@ export async function mdInJsToMdHtmlInJs(toImportFilePath) {
|
|||||||
// this corrects it - escaped
|
// this corrects it - escaped
|
||||||
mdHTML = mdHTML.replace(
|
mdHTML = mdHTML.replace(
|
||||||
REGEX_REPLACE_ESCAPES,
|
REGEX_REPLACE_ESCAPES,
|
||||||
'</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">\\\\${</span>',
|
'<span class="token interpolation"><span class="token interpolation-punctuation punctuation">\\\\${</span>',
|
||||||
);
|
);
|
||||||
return [mdHTML, ...mdjsScriptTag].join('\n');
|
return [mdHTML, ...mdjsScriptTag].join('\n');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
// we load this before the global-dom-shim as otherwise prism thinks it's running in a browser 🙈
|
|
||||||
// we need to load the global-dom-shim as otherwise import { html } from 'lit'; breaks
|
|
||||||
import 'rehype-prism';
|
|
||||||
import '@lit-labs/ssr/lib/install-global-dom-shim.js';
|
|
||||||
|
|
||||||
export { renderJoiningGroup } from './helpers/renderJoiningGroup.js';
|
export { renderJoiningGroup } from './helpers/renderJoiningGroup.js';
|
||||||
export { inlineFile } from './helpers/inlineFile.js';
|
export { inlineFile } from './helpers/inlineFile.js';
|
||||||
|
|
||||||
|
|||||||
@@ -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(/</g, '<')
|
||||||
|
.replace(/&/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);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
// we load this before the global-dom-shim as otherwise prism thinks it's running in a browser 🙈
|
|
||||||
// we need to load the global-dom-shim as otherwise import { html } from 'lit'; breaks
|
|
||||||
import 'rehype-prism';
|
|
||||||
import '@lit-labs/ssr/lib/install-global-dom-shim.js';
|
|
||||||
|
|
||||||
import { parentPort } from 'worker_threads';
|
import { parentPort } from 'worker_threads';
|
||||||
// import { convertMdFile, convertHtmlFile } from '../converts.js';
|
// import { convertMdFile, convertHtmlFile } from '../converts.js';
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
// we load this before the global-dom-shim as otherwise prism thinks it's running in a browser 🙈
|
|
||||||
// we need to load the global-dom-shim as otherwise import { html } from 'lit'; breaks
|
|
||||||
import 'rehype-prism';
|
|
||||||
import '@lit-labs/ssr/lib/install-global-dom-shim.js';
|
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { parentPort } from 'worker_threads';
|
import { parentPort } from 'worker_threads';
|
||||||
import { mkdir, writeFile } from 'fs/promises';
|
import { mkdir, writeFile } from 'fs/promises';
|
||||||
|
|||||||
@@ -72,10 +72,10 @@ describe('Format Markdown', () => {
|
|||||||
'<p>Escape JS</p>',
|
'<p>Escape JS</p>',
|
||||||
'<pre',
|
'<pre',
|
||||||
' class="language-js"',
|
' class="language-js"',
|
||||||
'><code class="language-js"><span class="token keyword">const</span> foo <span class="token operator">=</span> <span class="token string">\'one\'</span><span class="token punctuation">;</span>',
|
'><code class="language-js code-highlight"><span class="code-line"><span class="token keyword">const</span> foo <span class="token operator">=</span> <span class="token string">\'one\'</span><span class="token punctuation">;</span>',
|
||||||
'<span class="token keyword">const</span> bar <span class="token operator">=</span> html<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><p>${foo}</p></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>',
|
'</span><span class="code-line"><span class="token keyword">const</span> bar <span class="token operator">=</span> html<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token html language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>${foo}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>',
|
||||||
'<span class="token keyword">const</span> baz <span class="token operator">=</span> html<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><span></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">\\${</span>foo<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"></span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>',
|
'</span><span class="code-line"><span class="token keyword">const</span> baz <span class="token operator">=</span> html<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token html language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">\\${</span>foo<span class="token interpolation-punctuation punctuation">}</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>',
|
||||||
'</code></pre>',
|
'</span></code></pre>',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import chai from 'chai';
|
import chai from 'chai';
|
||||||
// import '@lit-labs/ssr/lib/install-global-dom-shim.js';
|
|
||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
import { renderJoiningGroup } from '../src/helpers/renderJoiningGroup.js';
|
import { renderJoiningGroup } from '../src/helpers/renderJoiningGroup.js';
|
||||||
import { testLitServerRender } from './test-helpers.js';
|
import { testLitServerRender } from './test-helpers.js';
|
||||||
|
|||||||
@@ -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: '<some-button>',
|
||||||
|
headlinesWithId: [
|
||||||
|
{
|
||||||
|
id: 'some-button',
|
||||||
|
level: 1,
|
||||||
|
text: '<some-button>',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
level: 1,
|
||||||
|
menuLinkText: '<some-button>',
|
||||||
|
name: '<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: '/',
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,23 +4,42 @@ import { setupTestEngine } from './test-helpers.js';
|
|||||||
|
|
||||||
const { expect } = chai;
|
const { expect } = chai;
|
||||||
|
|
||||||
class MyPlugin {
|
|
||||||
static publicFolder = new URL(
|
|
||||||
'./fixtures/10-plugins/01-add-public-files/plugin-add-to-public/preset/__public',
|
|
||||||
import.meta.url,
|
|
||||||
).pathname;
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Plugins', () => {
|
describe('Plugins', () => {
|
||||||
it('add plugin with custom public files', async () => {
|
it('01: add plugin with custom public files', async () => {
|
||||||
|
class TestPlugin01 {
|
||||||
|
static publicFolder = new URL(
|
||||||
|
'./fixtures/10-plugins/01-add-public-files/plugin-add-to-public/preset/__public',
|
||||||
|
import.meta.url,
|
||||||
|
).pathname;
|
||||||
|
}
|
||||||
const { build, outputExists } = await setupTestEngine(
|
const { build, outputExists } = await setupTestEngine(
|
||||||
'fixtures/10-plugins/01-add-public-files/docs',
|
'fixtures/10-plugins/01-add-public-files/docs',
|
||||||
{
|
{
|
||||||
setupPlugins: [addPlugin(MyPlugin)],
|
setupPlugins: [addPlugin(TestPlugin01)],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
await build();
|
await build();
|
||||||
|
|
||||||
expect(outputExists('added-via-plugin.txt')).to.be.true;
|
expect(outputExists('added-via-plugin.txt')).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('02: add plugin with custom public files', async () => {
|
||||||
|
class TestPlugin02 {
|
||||||
|
static publicFolder = new URL(
|
||||||
|
'./fixtures/10-plugins/02-input-folder-public-always-wins/plugin-add-to-public/preset/__public',
|
||||||
|
import.meta.url,
|
||||||
|
).pathname;
|
||||||
|
}
|
||||||
|
const { build, readOutput } = await setupTestEngine(
|
||||||
|
'fixtures/10-plugins/02-input-folder-public-always-wins/docs',
|
||||||
|
{
|
||||||
|
setupPlugins: [addPlugin(TestPlugin02)],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
await build();
|
||||||
|
|
||||||
|
expect(readOutput('added-via-plugin-and-input-public.txt')).to.equal(
|
||||||
|
'from input public folder\n',
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -179,15 +179,16 @@ test.describe('hydration', async () => {
|
|||||||
await cleanup();
|
await cleanup();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("55: hydrate onMedia('(min-width: 640px)') || onClick", async ({ page }) => {
|
test("55: hydrate onMedia('(min-width: 640px)') || onClick - on desktop", async ({ page }) => {
|
||||||
const { engine, cleanup } = await setupTestEngine(
|
const { engine, cleanup } = await setupTestEngine(
|
||||||
'fixtures/14-components/55-hydration-onMedia-or-onClick/docs',
|
'fixtures/14-components/55-hydration-onMedia-or-onClick/docs',
|
||||||
);
|
);
|
||||||
await engine.start();
|
await engine.start();
|
||||||
const { port } = engine.devServer.config;
|
const { port } = engine.devServer.config;
|
||||||
|
|
||||||
|
// 1. start on small screen
|
||||||
await page.setViewportSize({
|
await page.setViewportSize({
|
||||||
width: 640,
|
width: 320,
|
||||||
height: 480,
|
height: 480,
|
||||||
});
|
});
|
||||||
await page.goto(`localhost:${port}`);
|
await page.goto(`localhost:${port}`);
|
||||||
@@ -195,25 +196,40 @@ test.describe('hydration', async () => {
|
|||||||
const hydrated1 = await myEl.getAttribute('hydrated');
|
const hydrated1 = await myEl.getAttribute('hydrated');
|
||||||
expect(hydrated1).toBe(null); // not hydrated
|
expect(hydrated1).toBe(null); // not hydrated
|
||||||
|
|
||||||
|
// 2. go bigger
|
||||||
|
await page.setViewportSize({
|
||||||
|
width: 640,
|
||||||
|
height: 480,
|
||||||
|
});
|
||||||
await page.waitForLoadState('networkidle0');
|
await page.waitForLoadState('networkidle0');
|
||||||
|
|
||||||
const hydrated2 = await myEl.getAttribute('hydrated');
|
const hydrated2 = await myEl.getAttribute('hydrated');
|
||||||
expect(hydrated2).toBe(''); // boolean attribute is there
|
expect(hydrated2).toBe(''); // boolean attribute is there
|
||||||
|
|
||||||
// revisit page on "mobile"
|
await cleanup();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("55b: hydrate onMedia('(min-width: 640px)') || onClick - on mobile", async ({ page }) => {
|
||||||
|
const { engine, cleanup } = await setupTestEngine(
|
||||||
|
'fixtures/14-components/55-hydration-onMedia-or-onClick/docs',
|
||||||
|
);
|
||||||
|
await engine.start();
|
||||||
|
const { port } = engine.devServer.config;
|
||||||
|
|
||||||
await page.setViewportSize({
|
await page.setViewportSize({
|
||||||
width: 320,
|
width: 320,
|
||||||
height: 480,
|
height: 480,
|
||||||
});
|
});
|
||||||
await page.reload();
|
await page.goto(`localhost:${port}`);
|
||||||
const myEl2 = await page.locator('my-el');
|
const myEl = await page.locator('my-el');
|
||||||
const hydrated3 = await myEl2.getAttribute('hydrated');
|
|
||||||
|
const hydrated3 = await myEl.getAttribute('hydrated');
|
||||||
expect(hydrated3).toBe(null); // not hydrated
|
expect(hydrated3).toBe(null); // not hydrated
|
||||||
|
|
||||||
await myEl.click();
|
await myEl.click();
|
||||||
await page.waitForLoadState('networkidle0');
|
await page.waitForLoadState('networkidle0');
|
||||||
|
|
||||||
const hydrated4 = await myEl2.getAttribute('hydrated');
|
const hydrated4 = await myEl.getAttribute('hydrated');
|
||||||
expect(hydrated4).toBe(''); // boolean attribute is there
|
expect(hydrated4).toBe(''); // boolean attribute is there
|
||||||
|
|
||||||
await cleanup();
|
await cleanup();
|
||||||
@@ -243,7 +259,7 @@ test.describe('hydration', async () => {
|
|||||||
const focusInEv = await myEl.getAttribute('focusin-ev');
|
const focusInEv = await myEl.getAttribute('focusin-ev');
|
||||||
expect(focusInEv).toBe('');
|
expect(focusInEv).toBe('');
|
||||||
|
|
||||||
// NOTE: focus event is NOT supported as it does not bubble
|
// NOTE: we are using the focusin event as the focus event is NOT supported as it does not bubble
|
||||||
await cleanup();
|
await cleanup();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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>
|
||||||
<title>About | MyPage</title>
|
<head>
|
||||||
<h1>This is About</h1>
|
<title>About | MyPage</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<meta name="menu:link.text" content="About" />
|
||||||
|
<h1>This is About</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -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/",
|
||||||
|
|||||||
@@ -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>`;
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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 };
|
||||||
@@ -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 */
|
||||||
|
```
|
||||||
|
|
||||||
|
# <some-button>
|
||||||
@@ -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
|
||||||
@@ -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": "<some-button>",
|
||||||
|
"headlinesWithId": [
|
||||||
|
{
|
||||||
|
"text": "<some-button>",
|
||||||
|
"id": "some-button",
|
||||||
|
"level": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "<some-button>",
|
||||||
|
"menuLinkText": "<some-button>",
|
||||||
|
"url": "/component/",
|
||||||
|
"outputRelativeFilePath": "component/index.html",
|
||||||
|
"sourceRelativeFilePath": "component.rocket.md",
|
||||||
|
"level": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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 };
|
||||||
@@ -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>
|
||||||
|
`;
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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 };
|
||||||
@@ -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> `;
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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 };
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
`;
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
`;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "@test/components",
|
||||||
|
"type": "module",
|
||||||
|
"imports": {
|
||||||
|
"#c/*": "./components/*"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
/* START - Rocket auto generated - do not touch */
|
||||||
|
export const sourceRelativeFilePath = 'index.rocket.js';
|
||||||
|
/* END - Rocket auto generated - do not touch */
|
||||||
|
|
||||||
|
import { html } from 'lit';
|
||||||
|
|
||||||
|
export default () => html`<p>content</p>`;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name": "index.rocket.js",
|
||||||
|
"menuLinkText": "index.rocket.js",
|
||||||
|
"url": "/",
|
||||||
|
"outputRelativeFilePath": "index.html",
|
||||||
|
"sourceRelativeFilePath": "index.rocket.js",
|
||||||
|
"level": 0
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from plugin
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from input public folder
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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,11 +46,11 @@
|
|||||||
"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.2.5",
|
"lit": "^2.3.0",
|
||||||
"workbox-window": "^6.1.5"
|
"workbox-window": "^6.1.5"
|
||||||
},
|
},
|
||||||
"types": "./dist-types/src/index.d.ts",
|
"types": "./dist-types/src/index.d.ts",
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export class LayoutMain extends Layout {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
footerMenu: [],
|
footerMenu: [],
|
||||||
titleWrapperFn: title => `${title} | ${this.options.siteName}`,
|
titleWrapperFn: title => (title ? `${title} | ${this.options.siteName}` : ''),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## 0.20.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 35ed64d: BREAKING: Refactor to ESM-only package, use latest rehype/remark/unified dependencies.
|
||||||
|
- 6f88d8e: BREAKING: Replace `rehype-prism` with `rehype-prism-plus` as it does not get confused as running in the browser in the SSR context.
|
||||||
|
|
||||||
## 0.9.5
|
## 0.9.5
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -2,18 +2,11 @@
|
|||||||
/** @typedef {import('./types/code.js').Story} Story */
|
/** @typedef {import('./types/code.js').Story} Story */
|
||||||
/** @typedef {import('./types/code.js').MdjsProcessPlugin} MdjsProcessPlugin */
|
/** @typedef {import('./types/code.js').MdjsProcessPlugin} MdjsProcessPlugin */
|
||||||
|
|
||||||
const { mdjsParse } = require('./src/mdjsParse.js');
|
import { mdjsParse } from './src/mdjsParse.js';
|
||||||
const { mdjsSetupCode } = require('./src/mdjsSetupCode.js');
|
import { mdjsSetupCode } from './src/mdjsSetupCode.js';
|
||||||
const { mdjsStoryParse } = require('./src/mdjsStoryParse.js');
|
import { mdjsStoryParse } from './src/mdjsStoryParse.js';
|
||||||
const { mdjsDocPage } = require('./src/mdjsDocPage.js');
|
import { mdjsDocPage } from './src/mdjsDocPage.js';
|
||||||
const { mdjsProcess } = require('./src/mdjsProcess.js');
|
import { mdjsProcess } from './src/mdjsProcess.js';
|
||||||
const { isMdjsContent } = require('./src/isMdjsContent.js');
|
import { isMdjsContent } from './src/isMdjsContent.js';
|
||||||
|
|
||||||
module.exports = {
|
export { mdjsParse, mdjsStoryParse, mdjsDocPage, mdjsProcess, isMdjsContent, mdjsSetupCode };
|
||||||
mdjsParse,
|
|
||||||
mdjsStoryParse,
|
|
||||||
mdjsDocPage,
|
|
||||||
mdjsProcess,
|
|
||||||
isMdjsContent,
|
|
||||||
mdjsSetupCode,
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
import cjsEntrypoint from './index.js';
|
|
||||||
|
|
||||||
const { mdjsParse, mdjsStoryParse, mdjsDocPage, mdjsProcess, isMdjsContent, mdjsSetupCode } =
|
|
||||||
cjsEntrypoint;
|
|
||||||
|
|
||||||
export { mdjsParse, mdjsStoryParse, mdjsDocPage, mdjsProcess, isMdjsContent, mdjsSetupCode };
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mdjs/core",
|
"name": "@mdjs/core",
|
||||||
"version": "0.9.5",
|
"version": "0.20.0",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
@@ -14,11 +14,11 @@
|
|||||||
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
|
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
|
||||||
"homepage": "https://rocket.modern-web.dev/docs/markdown-javascript/overview/",
|
"homepage": "https://rocket.modern-web.dev/docs/markdown-javascript/overview/",
|
||||||
"main": "./index.js",
|
"main": "./index.js",
|
||||||
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"types": "./dist-types/index.d.ts",
|
"types": "./dist-types/index.d.ts",
|
||||||
"require": "./index.js",
|
"default": "./index.js"
|
||||||
"default": "./index.mjs"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -46,32 +46,32 @@
|
|||||||
"remark"
|
"remark"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mdjs/mdjs-preview": "^0.5.8",
|
"@mdjs/mdjs-preview": "^0.5.9",
|
||||||
"@mdjs/mdjs-story": "^0.3.2",
|
"@mdjs/mdjs-story": "^0.3.2",
|
||||||
"@types/unist": "^2.0.3",
|
"@types/unist": "^2.0.6",
|
||||||
"es-module-lexer": "^0.9.3",
|
"es-module-lexer": "^0.10.5",
|
||||||
"github-markdown-css": "^4.0.0",
|
"github-markdown-css": "^5.1.0",
|
||||||
"plugins-manager": "^0.3.0",
|
"plugins-manager": "^0.3.1",
|
||||||
"rehype-autolink-headings": "^5.0.1",
|
"rehype-autolink-headings": "^6.1.1",
|
||||||
"rehype-prism": "^1.0.1",
|
"rehype-prism-plus": "^1.4.2",
|
||||||
"rehype-raw": "^5.0.0",
|
"rehype-raw": "^6.1.1",
|
||||||
"rehype-slug": "^4.0.1",
|
"rehype-slug": "^5.0.1",
|
||||||
"rehype-stringify": "^8.0.0",
|
"rehype-stringify": "^9.0.3",
|
||||||
"remark": "^13.0.0",
|
"remark": "^14.0.2",
|
||||||
"remark-gfm": "^1.0.0",
|
"remark-gfm": "^3.0.1",
|
||||||
"remark-parse": "^9.0.0",
|
"remark-parse": "^10.0.1",
|
||||||
"remark-rehype": "^8.0.0",
|
"remark-rehype": "^10.1.0",
|
||||||
"slash": "^3.0.0",
|
"slash": "^4.0.0",
|
||||||
"unified": "^9.2.0",
|
"unified": "^10.1.2",
|
||||||
"unist-util-remove": "^2.0.1",
|
"unist-util-remove": "^3.1.0",
|
||||||
"unist-util-visit": "^2.0.3"
|
"unist-util-visit": "^4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"demo-wc-card": "^0.1.0",
|
"demo-wc-card": "^0.1.0",
|
||||||
"remark-autolink-headings": "^6.0.1",
|
"remark-autolink-headings": "^7.0.1",
|
||||||
"remark-html": "^13.0.2",
|
"remark-html": "^15.0.1",
|
||||||
"remark-slug": "^6.0.0",
|
"remark-slug": "^7.0.1",
|
||||||
"remark-stringify": "^9.0.1"
|
"remark-stringify": "^10.0.2"
|
||||||
},
|
},
|
||||||
"types": "dist-types/index.d.ts"
|
"types": "dist-types/index.d.ts"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* @param {string} text
|
* @param {string} text
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
function isMdjsContent(text) {
|
export function isMdjsContent(text) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,3 @@ function isMdjsContent(text) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
isMdjsContent,
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
const { mdjsProcess } = require('./mdjsProcess.js');
|
import { mdjsProcess } from './mdjsProcess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} body
|
* @param {string} body
|
||||||
* @returns {Promise<string>}
|
* @returns {Promise<string>}
|
||||||
*/
|
*/
|
||||||
async function mdjsDocPage(body) {
|
export async function mdjsDocPage(body) {
|
||||||
const data = await mdjsProcess(body);
|
const data = await mdjsProcess(body);
|
||||||
return `
|
return `
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
@@ -92,7 +92,3 @@ async function mdjsDocPage(body) {
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
mdjsDocPage,
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
import { visit } from 'unist-util-visit';
|
||||||
const visit = require('unist-util-visit');
|
import { remove } from 'unist-util-remove';
|
||||||
// @ts-ignore
|
|
||||||
const remove = require('unist-util-remove');
|
|
||||||
|
|
||||||
/** @typedef {import('vfile').VFileOptions} VFileOptions */
|
/** @typedef {import('vfile').VFileOptions} VFileOptions */
|
||||||
/** @typedef {import('unist').Node} Node */
|
/** @typedef {import('unist').Node} Node */
|
||||||
|
|
||||||
function mdjsParse() {
|
export function mdjsParse() {
|
||||||
let jsCode = '';
|
let jsCode = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,26 +12,37 @@ function mdjsParse() {
|
|||||||
* @param {VFileOptions} file
|
* @param {VFileOptions} file
|
||||||
*/
|
*/
|
||||||
function transformer(tree, file) {
|
function transformer(tree, file) {
|
||||||
visit(tree, 'code', node => {
|
visit(
|
||||||
if (node.lang === 'js' && node.meta === 'script') {
|
tree,
|
||||||
jsCode += node.value;
|
'code',
|
||||||
}
|
/** @param {Node & {[key: string]: unknown;}} node */ node => {
|
||||||
if (node.lang === 'js' && node.meta === 'client') {
|
if (node.lang === 'js' && node.meta === 'script') {
|
||||||
jsCode += node.value;
|
jsCode += node.value;
|
||||||
}
|
}
|
||||||
});
|
if (node.lang === 'js' && node.meta === 'client') {
|
||||||
|
jsCode += node.value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
// we can only return/modify the tree but jsCode should not be part of the tree
|
// we can only return/modify the tree but jsCode should not be part of the tree
|
||||||
// so we attach it globally to the file.data
|
// so we attach it globally to the file.data
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
if (!file.data) {
|
||||||
|
file.data = {};
|
||||||
|
}
|
||||||
file.data.jsCode = jsCode;
|
file.data.jsCode = jsCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Node} node
|
* @param {Node} node
|
||||||
*/
|
*/
|
||||||
const removeFunction = node =>
|
const removeFunction = node => {
|
||||||
node.type === 'code' &&
|
const _node = /** @type {Node & {[key: string]: unknown;}} */ (node);
|
||||||
node.lang === 'js' &&
|
return (
|
||||||
(node.meta === 'script' || node.meta === 'client');
|
_node.type === 'code' &&
|
||||||
|
_node.lang === 'js' &&
|
||||||
|
(_node.meta === 'script' || _node.meta === 'client')
|
||||||
|
);
|
||||||
|
};
|
||||||
remove(tree, removeFunction);
|
remove(tree, removeFunction);
|
||||||
|
|
||||||
return tree;
|
return tree;
|
||||||
@@ -41,7 +50,3 @@ function mdjsParse() {
|
|||||||
|
|
||||||
return transformer;
|
return transformer;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
mdjsParse,
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -4,23 +4,19 @@
|
|||||||
/** @typedef {import('../types/code').ProcessResult} ProcessResult */
|
/** @typedef {import('../types/code').ProcessResult} ProcessResult */
|
||||||
/** @typedef {import('../types/code').MdjsProcessPlugin} MdjsProcessPlugin */
|
/** @typedef {import('../types/code').MdjsProcessPlugin} MdjsProcessPlugin */
|
||||||
|
|
||||||
const unified = require('unified');
|
import { unified } from 'unified';
|
||||||
const markdown = require('remark-parse');
|
import markdown from 'remark-parse';
|
||||||
const gfm = require('remark-gfm');
|
import gfm from 'remark-gfm';
|
||||||
const remark2rehype = require('remark-rehype');
|
import remark2rehype from 'remark-rehype';
|
||||||
const raw = require('rehype-raw');
|
import raw from 'rehype-raw';
|
||||||
const htmlStringify = require('rehype-stringify');
|
import htmlSlug from 'rehype-slug';
|
||||||
const htmlSlug = require('rehype-slug');
|
import htmlHeading from 'rehype-autolink-headings';
|
||||||
const htmlHeading = require('rehype-autolink-headings');
|
import rehypePrism from 'rehype-prism-plus';
|
||||||
// @ts-ignore
|
import htmlStringify from 'rehype-stringify';
|
||||||
const { executeSetupFunctions } = require('plugins-manager');
|
import { executeSetupFunctions } from 'plugins-manager';
|
||||||
const loadLanguages = require('prismjs/components/');
|
import { mdjsParse } from './mdjsParse.js';
|
||||||
|
import { mdjsStoryParse } from './mdjsStoryParse.js';
|
||||||
const { mdjsParse } = require('./mdjsParse.js');
|
import { mdjsSetupCode } from './mdjsSetupCode.js';
|
||||||
const { mdjsStoryParse } = require('./mdjsStoryParse.js');
|
|
||||||
const { mdjsSetupCode } = require('./mdjsSetupCode.js');
|
|
||||||
|
|
||||||
let prismLoaded = false;
|
|
||||||
|
|
||||||
/** @type {MdjsProcessPlugin[]} */
|
/** @type {MdjsProcessPlugin[]} */
|
||||||
const defaultMetaPlugins = [
|
const defaultMetaPlugins = [
|
||||||
@@ -37,6 +33,7 @@ const defaultMetaPlugins = [
|
|||||||
{ plugin: htmlSlug, options: {} },
|
{ plugin: htmlSlug, options: {} },
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
{ plugin: htmlHeading, options: {} },
|
{ plugin: htmlHeading, options: {} },
|
||||||
|
{ plugin: rehypePrism, options: {} },
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
{ plugin: htmlStringify, options: {} },
|
{ plugin: htmlStringify, options: {} },
|
||||||
];
|
];
|
||||||
@@ -52,15 +49,8 @@ const defaultMetaPlugins = [
|
|||||||
* @param {function[]} [options.setupUnifiedPlugins]
|
* @param {function[]} [options.setupUnifiedPlugins]
|
||||||
* @param {MdjsProcessPlugin[]} [options.plugins] deprecated option use setupUnifiedPlugins instead
|
* @param {MdjsProcessPlugin[]} [options.plugins] deprecated option use setupUnifiedPlugins instead
|
||||||
*/
|
*/
|
||||||
async function mdjsProcess(mdjs, { setupUnifiedPlugins = [] } = {}) {
|
export async function mdjsProcess(mdjs, { setupUnifiedPlugins = [] } = {}) {
|
||||||
const parser = unified();
|
const parser = unified();
|
||||||
if (!prismLoaded) {
|
|
||||||
prismLoaded = true;
|
|
||||||
const rehypePrism = (await import('rehype-prism/lib/src/index.js')).default;
|
|
||||||
loadLanguages(['md', 'shell', 'yml', 'diff']);
|
|
||||||
defaultMetaPlugins.splice(6, 0, { plugin: rehypePrism, options: {} });
|
|
||||||
}
|
|
||||||
|
|
||||||
const metaPlugins = executeSetupFunctions(setupUnifiedPlugins, defaultMetaPlugins);
|
const metaPlugins = executeSetupFunctions(setupUnifiedPlugins, defaultMetaPlugins);
|
||||||
|
|
||||||
for (const pluginObj of metaPlugins) {
|
for (const pluginObj of metaPlugins) {
|
||||||
@@ -74,9 +64,5 @@ async function mdjsProcess(mdjs, { setupUnifiedPlugins = [] } = {}) {
|
|||||||
|
|
||||||
const { stories, setupJsCode } = result.data;
|
const { stories, setupJsCode } = result.data;
|
||||||
|
|
||||||
return { stories, jsCode: setupJsCode, html: result.contents };
|
return { stories, jsCode: setupJsCode, html: result.value };
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
mdjsProcess,
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const path = require('path');
|
import path from 'path';
|
||||||
const slash = require('slash');
|
import slash from 'slash';
|
||||||
|
|
||||||
/** @typedef {import('vfile').VFileOptions} VFileOptions */
|
/** @typedef {import('vfile').VFileOptions} VFileOptions */
|
||||||
/** @typedef {import('unist').Node} Node */
|
/** @typedef {import('unist').Node} Node */
|
||||||
@@ -22,7 +22,7 @@ const slash = require('slash');
|
|||||||
* @param {rocketConfig} [options.rocketConfig]
|
* @param {rocketConfig} [options.rocketConfig]
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function mdjsSetupCode({
|
export function mdjsSetupCode({
|
||||||
rootNodeQueryCode = 'document',
|
rootNodeQueryCode = 'document',
|
||||||
simulationSettings = {},
|
simulationSettings = {},
|
||||||
rocketConfig = {},
|
rocketConfig = {},
|
||||||
@@ -43,11 +43,13 @@ function mdjsSetupCode({
|
|||||||
* @param {VFileOptions} file
|
* @param {VFileOptions} file
|
||||||
*/
|
*/
|
||||||
async function transformer(tree, file) {
|
async function transformer(tree, file) {
|
||||||
|
if (!file.data) {
|
||||||
|
file.data = {};
|
||||||
|
}
|
||||||
const { stories, jsCode } = file.data;
|
const { stories, jsCode } = file.data;
|
||||||
|
|
||||||
file.data.setupJsCode = jsCode;
|
file.data.setupJsCode = jsCode;
|
||||||
|
|
||||||
if (stories && stories.length > 0) {
|
if (Array.isArray(stories) && stories.length > 0) {
|
||||||
const storiesCode = stories.map(/** @param {Story} story */ story => story.code).join('\n');
|
const storiesCode = stories.map(/** @param {Story} story */ story => story.code).join('\n');
|
||||||
|
|
||||||
const invokeStoriesCode = [];
|
const invokeStoriesCode = [];
|
||||||
@@ -86,7 +88,3 @@ function mdjsSetupCode({
|
|||||||
|
|
||||||
return transformer;
|
return transformer;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
mdjsSetupCode,
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
/** @typedef {import('unist').Parent} UnistParent */
|
/** @typedef {import('unist').Parent} UnistParent */
|
||||||
/** @typedef {import('vfile').VFileOptions} VFileOptions */
|
/** @typedef {import('vfile').VFileOptions} VFileOptions */
|
||||||
|
|
||||||
const visit = require('unist-util-visit');
|
import { visit } from 'unist-util-visit';
|
||||||
const { init, parse } = require('es-module-lexer');
|
import { init, parse } from 'es-module-lexer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {object} MDJSNodeProperties
|
* @typedef {object} MDJSNodeProperties
|
||||||
@@ -50,7 +50,7 @@ function defaultPreviewStoryTag(name) {
|
|||||||
* @param {TagFunction} [arg.previewStoryTag]
|
* @param {TagFunction} [arg.previewStoryTag]
|
||||||
* @param {number} [arg.counter]
|
* @param {number} [arg.counter]
|
||||||
*/
|
*/
|
||||||
function mdjsStoryParse({
|
export function mdjsStoryParse({
|
||||||
storyTag = defaultStoryTag,
|
storyTag = defaultStoryTag,
|
||||||
previewStoryTag = defaultPreviewStoryTag,
|
previewStoryTag = defaultPreviewStoryTag,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
@@ -61,11 +61,12 @@ function mdjsStoryParse({
|
|||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {UnistNode} node
|
* @param {UnistNode} _node
|
||||||
* @param {number} index
|
* @param {number} index
|
||||||
* @param {UnistParent} parent
|
* @param {UnistParent} parent
|
||||||
*/
|
*/
|
||||||
const nodeCodeVisitor = (node, index, parent) => {
|
const nodeCodeVisitor = (_node, index, parent) => {
|
||||||
|
let node = /** @type {UnistNode & {[key: string]: unknown}} */ (_node);
|
||||||
if (node.lang === 'js' && node.meta === 'story' && typeof node.value === 'string') {
|
if (node.lang === 'js' && node.meta === 'story' && typeof node.value === 'string') {
|
||||||
const storyData = extractStoryData(node.value);
|
const storyData = extractStoryData(node.value);
|
||||||
node.type = 'html';
|
node.type = 'html';
|
||||||
@@ -80,12 +81,17 @@ function mdjsStoryParse({
|
|||||||
|
|
||||||
const inside = [node];
|
const inside = [node];
|
||||||
let skipAmount = 1;
|
let skipAmount = 1;
|
||||||
const next = parent.children[index + 1];
|
|
||||||
|
const next = /** @type {UnistNode & {[key: string]: unknown}} */ (
|
||||||
|
parent.children[index + 1]
|
||||||
|
);
|
||||||
if (next && next.type === 'code' && next.meta === 'story-code') {
|
if (next && next.type === 'code' && next.meta === 'story-code') {
|
||||||
inside.push(next);
|
inside.push(next);
|
||||||
skipAmount += 1;
|
skipAmount += 1;
|
||||||
|
|
||||||
const next2 = parent.children[index + 2];
|
const next2 = /** @type {UnistNode & {[key: string]: unknown}} */ (
|
||||||
|
parent.children[index + 2]
|
||||||
|
);
|
||||||
if (next2 && next2.type === 'code' && next2.meta === 'story-code') {
|
if (next2 && next2.type === 'code' && next2.meta === 'story-code') {
|
||||||
inside.push(next2);
|
inside.push(next2);
|
||||||
skipAmount += 1;
|
skipAmount += 1;
|
||||||
@@ -132,12 +138,16 @@ function mdjsStoryParse({
|
|||||||
const tagParts = newValue.split('[[CODE SLOT]]');
|
const tagParts = newValue.split('[[CODE SLOT]]');
|
||||||
const inside = [node];
|
const inside = [node];
|
||||||
let skipAmount = 1;
|
let skipAmount = 1;
|
||||||
const next = parent.children[index + 1];
|
const next = /** @type {UnistNode & {[key: string]: unknown}} */ (
|
||||||
|
parent.children[index + 1]
|
||||||
|
);
|
||||||
if (next && next.type === 'code' && next.meta === 'story-code') {
|
if (next && next.type === 'code' && next.meta === 'story-code') {
|
||||||
inside.push(next);
|
inside.push(next);
|
||||||
skipAmount += 1;
|
skipAmount += 1;
|
||||||
|
|
||||||
const next2 = parent.children[index + 2];
|
const next2 = /** @type {UnistNode & {[key: string]: unknown}} */ (
|
||||||
|
parent.children[index + 2]
|
||||||
|
);
|
||||||
if (next2 && next2.type === 'code' && next2.meta === 'story-code') {
|
if (next2 && next2.type === 'code' && next2.meta === 'story-code') {
|
||||||
inside.push(next2);
|
inside.push(next2);
|
||||||
skipAmount += 1;
|
skipAmount += 1;
|
||||||
@@ -176,6 +186,9 @@ function mdjsStoryParse({
|
|||||||
visit(tree, 'code', nodeCodeVisitor);
|
visit(tree, 'code', nodeCodeVisitor);
|
||||||
// we can only return/modify the tree but stories should not be part of the tree
|
// we can only return/modify the tree but stories should not be part of the tree
|
||||||
// so we attach it globally to the file.data
|
// so we attach it globally to the file.data
|
||||||
|
if (!file.data) {
|
||||||
|
file.data = {};
|
||||||
|
}
|
||||||
file.data.stories = stories;
|
file.data.stories = stories;
|
||||||
|
|
||||||
return tree;
|
return tree;
|
||||||
@@ -184,7 +197,3 @@ function mdjsStoryParse({
|
|||||||
return transformer;
|
return transformer;
|
||||||
/* eslint-enable no-param-reassign */
|
/* eslint-enable no-param-reassign */
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
mdjsStoryParse,
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
/* eslint-disable no-template-curly-in-string */
|
/* eslint-disable no-template-curly-in-string */
|
||||||
|
|
||||||
const unified = require('unified');
|
import { unified } from 'unified';
|
||||||
const markdown = require('remark-parse');
|
import markdown from 'remark-parse';
|
||||||
const remark2rehype = require('remark-rehype');
|
import remark2rehype from 'remark-rehype';
|
||||||
const htmlStringify = require('rehype-stringify');
|
import htmlStringify from 'rehype-stringify';
|
||||||
const htmlSlug = require('rehype-slug');
|
import htmlSlug from 'rehype-slug';
|
||||||
const htmlHeading = require('rehype-autolink-headings');
|
import htmlHeading from 'rehype-autolink-headings';
|
||||||
const raw = require('rehype-raw');
|
import raw from 'rehype-raw';
|
||||||
|
|
||||||
const mdSlug = require('remark-slug');
|
import mdSlug from 'remark-slug';
|
||||||
const mdHeadings = require('remark-autolink-headings');
|
import mdHeadings from 'remark-autolink-headings';
|
||||||
const mdStringify = require('remark-html');
|
import mdStringify from 'remark-html';
|
||||||
|
|
||||||
const chai = require('chai');
|
import { expect } from 'chai';
|
||||||
const { mdjsParse } = require('../src/mdjsParse.js');
|
import { mdjsParse } from '../src/mdjsParse.js';
|
||||||
const { mdjsStoryParse } = require('../src/mdjsStoryParse.js');
|
import { mdjsStoryParse } from '../src/mdjsStoryParse.js';
|
||||||
|
|
||||||
const { expect } = chai;
|
|
||||||
|
|
||||||
/** @typedef {import("../src/mdjsParse.js").MDJSVFileData} MDJSVFileData */
|
/** @typedef {import("../src/mdjsParse.js").MDJSVFileData} MDJSVFileData */
|
||||||
|
|
||||||
@@ -67,8 +65,8 @@ describe('Integration', () => {
|
|||||||
.use(htmlHeading)
|
.use(htmlHeading)
|
||||||
.use(htmlStringify);
|
.use(htmlStringify);
|
||||||
const result = await parser.process(input);
|
const result = await parser.process(input);
|
||||||
if (result.contents instanceof Buffer) throw new Error('contents should not be a buffer');
|
if (result.value instanceof Buffer) throw new Error('contents should not be a buffer');
|
||||||
expect(result.contents.split('\n')).to.deep.equal(expected);
|
expect(result.value.split('\n')).to.deep.equal(expected);
|
||||||
expect(/** @type {MDJSVFileData} */ (result.data).jsCode).to.equal('const bar = 22;');
|
expect(/** @type {MDJSVFileData} */ (result.data).jsCode).to.equal('const bar = 22;');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -108,7 +106,7 @@ describe('Integration', () => {
|
|||||||
.use(mdHeadings)
|
.use(mdHeadings)
|
||||||
.use(mdStringify, { sanitize: false });
|
.use(mdStringify, { sanitize: false });
|
||||||
const result = await parser.process(input);
|
const result = await parser.process(input);
|
||||||
expect(result.contents).to.equal(expected);
|
expect(result.value).to.equal(expected);
|
||||||
expect(/** @type {MDJSVFileData} */ (result.data).stories).to.deep.equal([
|
expect(/** @type {MDJSVFileData} */ (result.data).stories).to.deep.equal([
|
||||||
{
|
{
|
||||||
key: 'fooStory',
|
key: 'fooStory',
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user