mirror of
https://github.com/modernweb-dev/rocket.git
synced 2026-03-21 08:51:18 +00:00
Compare commits
28 Commits
@rocket/sp
...
feat/updat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ba487813a | ||
|
|
685e6fd9b4 | ||
|
|
ecfa631367 | ||
|
|
80ff4be34a | ||
|
|
3fd736c213 | ||
|
|
f3cc3b8050 | ||
|
|
a049a82141 | ||
|
|
a868ff13e4 | ||
|
|
5f4a86b1a8 | ||
|
|
79e6f0df33 | ||
|
|
04621c3f16 | ||
|
|
1cd9508384 | ||
|
|
c8082fbac8 | ||
|
|
68e05f4d4a | ||
|
|
660f64c320 | ||
|
|
97d5fb2040 | ||
|
|
0ca2bc6205 | ||
|
|
e53e0ebd6d | ||
|
|
87c10ec1d3 | ||
|
|
d7e461ca31 | ||
|
|
a12adf2cb5 | ||
|
|
acf84416dc | ||
|
|
a48dcd849b | ||
|
|
0ed3d6d0e9 | ||
|
|
57ec19fecc | ||
|
|
8b48fb9760 | ||
|
|
39206a1738 | ||
|
|
cbfb0f91e2 |
6
.changeset/big-meals-matter.md
Normal file
6
.changeset/big-meals-matter.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@rocket/building-rollup': minor
|
||||
'@rocket/cli': minor
|
||||
---
|
||||
|
||||
Update to Rollup v3 + all plugins that require it
|
||||
5
.changeset/real-moose-check.md
Normal file
5
.changeset/real-moose-check.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@rocket/building-rollup': patch
|
||||
---
|
||||
|
||||
fix json5 security vulnerability
|
||||
@@ -13,6 +13,10 @@ __output-dev
|
||||
|
||||
docs/_merged*
|
||||
*-mdjs-generated.js
|
||||
*-converted-md-source.js
|
||||
*-converted-md.js
|
||||
|
||||
__example_site-for-check-website
|
||||
|
||||
# sanity example has a separate backend that is unrelated to Rocket
|
||||
# therefore it does not need to follow it code rules
|
||||
|
||||
28
.github/workflows/release.yml
vendored
28
.github/workflows/release.yml
vendored
@@ -12,45 +12,29 @@ jobs:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: google/wireit@setup-github-actions-caching/v1
|
||||
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Node.js 14.x
|
||||
- name: Setup Node.js 18.x
|
||||
uses: actions/setup-node@master
|
||||
with:
|
||||
node-version: 14.x
|
||||
node-version: 18.x
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- uses: actions/cache@v2
|
||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: yarn --frozen-lockfile
|
||||
|
||||
- name: Build Packages
|
||||
run: yarn build:packages
|
||||
|
||||
- name: Build Types
|
||||
run: yarn types
|
||||
run: npm ci
|
||||
|
||||
- name: Create Release Pull Request or Publish to npm
|
||||
id: changesets
|
||||
uses: changesets/action@master
|
||||
with:
|
||||
# This expects you to have a script called release which does a build for your packages and calls changeset publish
|
||||
publish: yarn release
|
||||
publish: npm run release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
53
.github/workflows/verify.yml
vendored
53
.github/workflows/verify.yml
vendored
@@ -8,8 +8,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16.x]
|
||||
node-version: [18.x]
|
||||
steps:
|
||||
- uses: google/wireit@setup-github-actions-caching/v1
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Node ${{ matrix.node-version }}
|
||||
@@ -17,20 +18,8 @@ jobs:
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- uses: actions/cache@v2
|
||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn --frozen-lockfile
|
||||
run: npm ci
|
||||
|
||||
- name: Install Playwright dependencies
|
||||
run: npx playwright install-deps
|
||||
@@ -38,40 +27,8 @@ jobs:
|
||||
- name: Install Playwright
|
||||
run: npx playwright install
|
||||
|
||||
- name: Build Packages
|
||||
run: yarn build:packages
|
||||
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
run: npm run lint
|
||||
|
||||
- name: Test
|
||||
run: yarn test
|
||||
|
||||
# verify-windows:
|
||||
# name: Verify windows
|
||||
# runs-on: windows-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v2
|
||||
|
||||
# - name: Setup Node 12.x
|
||||
# uses: actions/setup-node@v1
|
||||
# with:
|
||||
# node-version: 12.x
|
||||
|
||||
# - name: Get yarn cache directory path
|
||||
# id: yarn-cache-dir-path
|
||||
# run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
# - uses: actions/cache@v2
|
||||
# id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||
# with:
|
||||
# path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
# key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
# restore-keys: |
|
||||
# ${{ runner.os }}-yarn-
|
||||
|
||||
# - name: Install dependencies
|
||||
# run: yarn --frozen-lockfile
|
||||
|
||||
# - name: Test
|
||||
# run: yarn test
|
||||
run: npm run test
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -12,21 +12,16 @@ coverage/
|
||||
## npm
|
||||
node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
## temp folders
|
||||
/.tmp/
|
||||
|
||||
## we prefer yarn.lock
|
||||
package-lock.json
|
||||
## lock files in packages we do not need to save
|
||||
packages/*/yarn.lock
|
||||
|
||||
## build output
|
||||
dist
|
||||
dist-types
|
||||
stats.html
|
||||
*.tsbuildinfo
|
||||
.wireit
|
||||
|
||||
# Rocket Search
|
||||
rocket-search-index.json
|
||||
@@ -49,3 +44,4 @@ docs_backup
|
||||
|
||||
## Local playground
|
||||
examples/testing
|
||||
__example_site-for-check-website
|
||||
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -8,5 +8,5 @@
|
||||
"**/*-mdjs-generated.js": true,
|
||||
"**/dist-types": true,
|
||||
},
|
||||
"editor.experimental.stickyScroll.enabled": true
|
||||
"editor.stickyScroll.enabled": true
|
||||
}
|
||||
|
||||
@@ -32,10 +32,10 @@ git checkout -b my-awesome-fix
|
||||
|
||||
## Preparing Your Local Environment for Development
|
||||
|
||||
Now that you have cloned the repository, ensure you have [yarn](https://classic.yarnpkg.com/lang/en/) installed, then run the following commands to set up the development environment.
|
||||
Now that you have cloned the repository, ensure you have [node](https://nodejs.org/) installed, then run the following commands to set up the development environment.
|
||||
|
||||
```shell
|
||||
yarn install
|
||||
npm install
|
||||
```
|
||||
|
||||
This will download and install all packages needed.
|
||||
@@ -50,7 +50,7 @@ If you're making cross-package changes, you need to compile the TypeScript code.
|
||||
|
||||
### Running Tests
|
||||
|
||||
To run the tests of a package, it's recommended to `cd` into the package directory and then using `yarn test` to run them. This way you're only running tests of that specific package.
|
||||
To run the tests of a package, it's recommended to `cd` into the package directory and then using `npm run test` to run them. This way you're only running tests of that specific package.
|
||||
|
||||
### Integration Testing
|
||||
|
||||
@@ -58,7 +58,7 @@ To see how your changes integrate with everything together you can use the `test
|
||||
|
||||
## Adding New Packages
|
||||
|
||||
For all projects the tsconfig/jsconfig configuration files are auto generated. You need to add an entry to the [./workspace-packages.ts](./workspace-packages.ts) to let it generate a config for you. After adding an entry, run `yarn update-package-configs` to generate the files for you.
|
||||
For all projects the tsconfig/jsconfig configuration files are auto generated. You need to add an entry to the [./workspace-packages.ts](./workspace-packages.ts) to let it generate a config for you. After adding an entry, run `npm run update-package-configs` to generate the files for you.
|
||||
|
||||
## Creating a Changeset
|
||||
|
||||
@@ -70,7 +70,7 @@ This documents your intent to release, and allows you to specify a message that
|
||||
Run
|
||||
|
||||
```shell
|
||||
yarn changeset
|
||||
npm run changeset
|
||||
```
|
||||
|
||||
And use the menu to select for which packages you need a release, and then select what kind of release. For the release type, we follow [Semantic Versioning](https://semver.org/), so please take a look if you're unfamiliar.
|
||||
|
||||
2
examples/01-hydration-starter/.gitignore
vendored
2
examples/01-hydration-starter/.gitignore
vendored
@@ -3,8 +3,6 @@ node_modules/
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"scripts": {
|
||||
"build": "rocket build",
|
||||
"dev": "npm start",
|
||||
"preview": "rocket preview",
|
||||
"preview": "rocket preview --open",
|
||||
"start": "NODE_DEBUG=engine:rendering rocket start --open"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
2
examples/02-blog-starter/.gitignore
vendored
2
examples/02-blog-starter/.gitignore
vendored
@@ -3,8 +3,6 @@ node_modules/
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"scripts": {
|
||||
"build": "rocket build",
|
||||
"dev": "npm start",
|
||||
"preview": "rocket preview",
|
||||
"preview": "rocket preview --open",
|
||||
"start": "NODE_DEBUG=engine:rendering rocket start --open"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"title": "Example Blog",
|
||||
"h1": "\n \n ",
|
||||
"h1": "My Blog",
|
||||
"name": "Example Blog",
|
||||
"menuLinkText": "\n \n ",
|
||||
"menuLinkText": "My Blog",
|
||||
"url": "/",
|
||||
"outputRelativeFilePath": "index.html",
|
||||
"sourceRelativeFilePath": "index.rocket.js",
|
||||
@@ -20,7 +20,7 @@
|
||||
"children": [
|
||||
{
|
||||
"title": "",
|
||||
"h1": "\n \n ",
|
||||
"h1": "My Blog",
|
||||
"headlinesWithId": [
|
||||
{
|
||||
"text": "About",
|
||||
@@ -28,8 +28,8 @@
|
||||
"level": 1
|
||||
}
|
||||
],
|
||||
"name": "\n \n ",
|
||||
"menuLinkText": "\n \n ",
|
||||
"name": "My Blog",
|
||||
"menuLinkText": "My Blog",
|
||||
"url": "/about/",
|
||||
"outputRelativeFilePath": "about/index.html",
|
||||
"sourceRelativeFilePath": "about.rocket.md",
|
||||
@@ -60,9 +60,9 @@
|
||||
"children": [
|
||||
{
|
||||
"title": "Hello world!",
|
||||
"h1": "\n \n ",
|
||||
"h1": "My Blog",
|
||||
"name": "Hello world!",
|
||||
"menuLinkText": "\n \n ",
|
||||
"menuLinkText": "My Blog",
|
||||
"url": "/blog/hello-world/",
|
||||
"outputRelativeFilePath": "blog/hello-world/index.html",
|
||||
"sourceRelativeFilePath": "blog/hello-world.rocket.md",
|
||||
@@ -82,9 +82,9 @@
|
||||
},
|
||||
{
|
||||
"title": "With Image!",
|
||||
"h1": "\n \n ",
|
||||
"h1": "My Blog",
|
||||
"name": "With Image!",
|
||||
"menuLinkText": "\n \n ",
|
||||
"menuLinkText": "My Blog",
|
||||
"url": "/blog/with-image/",
|
||||
"outputRelativeFilePath": "blog/with-image/index.html",
|
||||
"sourceRelativeFilePath": "blog/with-image.rocket.md",
|
||||
|
||||
2
examples/03-minimal-starter/.gitignore
vendored
2
examples/03-minimal-starter/.gitignore
vendored
@@ -3,8 +3,6 @@ node_modules/
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"scripts": {
|
||||
"build": "rocket build",
|
||||
"dev": "npm start",
|
||||
"preview": "rocket preview",
|
||||
"preview": "rocket preview --open",
|
||||
"start": "NODE_DEBUG=engine:rendering rocket start --open"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
/dist
|
||||
/node_modules
|
||||
|
||||
yarn.lock
|
||||
@@ -3,7 +3,6 @@
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "package.json",
|
||||
"author": "Jaydan Urwin <jaydan@jaydanurwin.com>",
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
|
||||
@@ -3,8 +3,6 @@ node_modules/
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"scripts": {
|
||||
"build": "rocket build",
|
||||
"dev": "rocket start --open",
|
||||
"preview": "rocket preview",
|
||||
"preview": "rocket preview --open",
|
||||
"start": "NODE_DEBUG=engine:rendering rocket start --open"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
2
examples/50-landing-theme-spark/.gitignore
vendored
2
examples/50-landing-theme-spark/.gitignore
vendored
@@ -3,8 +3,6 @@ node_modules/
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"scripts": {
|
||||
"build": "rocket build",
|
||||
"dev": "npm start",
|
||||
"preview": "rocket preview",
|
||||
"preview": "rocket preview --open",
|
||||
"start": "NODE_DEBUG=engine:rendering rocket start --open"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
24
examples/50-landing-theme-spark/site/pages/aliens.rocket.md
Normal file
24
examples/50-landing-theme-spark/site/pages/aliens.rocket.md
Normal file
@@ -0,0 +1,24 @@
|
||||
```js server
|
||||
/* START - Rocket auto generated - do not touch */
|
||||
export const sourceRelativeFilePath = 'aliens.rocket.md';
|
||||
import { layout, components } from './recursive.data.js';
|
||||
export { layout, components };
|
||||
export async function registerCustomElements() {
|
||||
// server-only components
|
||||
// prettier-ignore
|
||||
customElements.define('rocket-content-area', await import('@rocket/components/content-area.js').then(m => m.RocketContentArea));
|
||||
// prettier-ignore
|
||||
customElements.define('rocket-header-scroll-menu', await import('@rocket/components/header-scroll-menu.js').then(m => m.RocketHeaderScrollMenu));
|
||||
// prettier-ignore
|
||||
customElements.define('rocket-columns', await import('@rocket/components/columns.js').then(m => m.RocketColumns));
|
||||
}
|
||||
/* END - Rocket auto generated - do not touch */
|
||||
|
||||
export const title = 'Aliens';
|
||||
```
|
||||
|
||||
Vastness is bearable only through love Cambrian explosion a still more glorious dawn awaits Euclid consciousness extraordinary claims require extraordinary evidence. Realm of the galaxies invent the universe culture made in the interiors of collapsing stars Drake Equation with pretty stories for which there's little good evidence. Bits of moving fluff preserve and cherish that pale blue dot shores of the cosmic ocean the ash of stellar alchemy brain is the seed of intelligence courage of our questions.
|
||||
|
||||
With pretty stories for which there's little good evidence not a sunrise but a galaxyrise rich in heavy atoms consciousness the sky calls to us rings of Uranus. Shores of the cosmic ocean shores of the cosmic ocean a very small stage in a vast cosmic arena of brilliant syntheses laws of physics muse about? Invent the universe finite but unbounded extraordinary claims require extraordinary evidence made in the interiors of collapsing stars muse about invent the universe.
|
||||
|
||||
The ash of stellar alchemy Cambrian explosion how far away kindling the energy hidden in matter cosmic ocean descended from astronomers. The carbon in our apple pies a very small stage in a vast cosmic arena brain is the seed of intelligence the only home we've ever known the carbon in our apple pies the carbon in our apple pies? Corpus callosum muse about citizens of distant epochs finite but unbounded extraordinary claims require extraordinary evidence finite but unbounded and billions upon billions upon billions upon billions upon billions upon billions upon billions.
|
||||
30
examples/50-landing-theme-spark/site/pages/humans.rocket.md
Normal file
30
examples/50-landing-theme-spark/site/pages/humans.rocket.md
Normal file
@@ -0,0 +1,30 @@
|
||||
```js server
|
||||
/* START - Rocket auto generated - do not touch */
|
||||
export const sourceRelativeFilePath = 'humans.rocket.md';
|
||||
import { layout, components } from './recursive.data.js';
|
||||
export { layout, components };
|
||||
export async function registerCustomElements() {
|
||||
// server-only components
|
||||
// prettier-ignore
|
||||
customElements.define('rocket-content-area', await import('@rocket/components/content-area.js').then(m => m.RocketContentArea));
|
||||
// prettier-ignore
|
||||
customElements.define('rocket-header-scroll-menu', await import('@rocket/components/header-scroll-menu.js').then(m => m.RocketHeaderScrollMenu));
|
||||
// prettier-ignore
|
||||
customElements.define('rocket-columns', await import('@rocket/components/columns.js').then(m => m.RocketColumns));
|
||||
}
|
||||
/* END - Rocket auto generated - do not touch */
|
||||
|
||||
export const title = 'Humans';
|
||||
```
|
||||
|
||||
Astonishment dispassionate extraterrestrial observer Drake Equation radio telescope Hypatia of brilliant syntheses. Vastness is bearable only through love Vangelis a mote of dust suspended in a sunbeam rings of Uranus vanquish the impossible rings of Uranus? Emerged into consciousness a billion trillion laws of physics emerged into consciousness bits of moving fluff as a patch of light. Sea of Tranquility something incredible is waiting to be known permanence of the stars something incredible is waiting to be known network of wormholes invent the universe.
|
||||
|
||||
Orion's sword the carbon in our apple pies tesseract made in the interiors of collapsing stars take root and flourish Jean-François Champollion. The ash of stellar alchemy rich in heavy atoms tingling of the spine invent the universe shores of the cosmic ocean star stuff harvesting star light. Bits of moving fluff courage of our questions as a patch of light preserve and cherish that pale blue dot citizens of distant epochs concept of the number one.
|
||||
|
||||
Two ghostly white figures in coveralls and helmets are softly dancing dispassionate extraterrestrial observer tesseract finite but unbounded the sky calls to us shores of the cosmic ocean? Muse about tingling of the spine stirred by starlight muse about not a sunrise but a galaxyrise venture. Concept of the number one are creatures of the cosmos something incredible is waiting to be known courage of our questions the only home we've ever known rich in heavy atoms.
|
||||
|
||||
Across the centuries light years billions upon billions bits of moving fluff permanence of the stars consciousness. Shores of the cosmic ocean realm of the galaxies vastness is bearable only through love Sea of Tranquility network of wormholes are creatures of the cosmos? Extraordinary claims require extraordinary evidence finite but unbounded made in the interiors of collapsing stars network of wormholes finite but unbounded radio telescope. Invent the universe from which we spring with pretty stories for which there's little good evidence Euclid inconspicuous motes of rock and gas something incredible is waiting to be known.
|
||||
|
||||
Birth dream of the mind's eye prime number at the edge of forever a billion trillion permanence of the stars? Vanquish the impossible two ghostly white figures in coveralls and helmets are softly dancing vastness is bearable only through love citizens of distant epochs something incredible is waiting to be known hydrogen atoms. Two ghostly white figures in coveralls and helmets are softly dancing shores of the cosmic ocean the ash of stellar alchemy Apollonius of Perga vastness is bearable only through love network of wormholes.
|
||||
|
||||
Gathered by gravity Sea of Tranquility galaxies astonishment hearts of the stars venture. Citizens of distant epochs the carbon in our apple pies encyclopaedia galactica birth brain is the seed of intelligence permanence of the stars? A still more glorious dawn awaits concept of the number one a mote of dust suspended in a sunbeam dream of the mind's eye Euclid a very small stage in a vast cosmic arena and billions upon billions upon billions upon billions upon billions upon billions upon billions.
|
||||
@@ -128,30 +128,32 @@ export const needsLoader = true;
|
||||
|
||||
<rocket-columns>
|
||||
<rocket-card>
|
||||
<h4 slot="title">No astrophysicist</h4>
|
||||
<h4 slot="title">Life</h4>
|
||||
<p>
|
||||
would deny the possibility of life. I think we're not creative enough to imagine what life
|
||||
would be like on another planet. Show me a dead alien. Better yet, show me a live one!
|
||||
As a scientist, I want to go to Mars and back to asteroids and the Moon because I'm a
|
||||
scientist. But I can tell you, I'm not so naive a scientist to think that the nation might
|
||||
not have geopolitical reasons for going into space.
|
||||
</p>
|
||||
<a slot="cta" class="cta" href="./life.rocket.html">Details</a>
|
||||
<a slot="cta" class="cta" href="./life.rocket.md">Details</a>
|
||||
</rocket-card>
|
||||
|
||||
<rocket-card>
|
||||
<h4 slot="title">No astrophysicist</h4>
|
||||
<h4 slot="title">Aliens</h4>
|
||||
<p>
|
||||
would deny the possibility of life. I think we're not creative enough to imagine what life
|
||||
would be like on another planet. Show me a dead alien. Better yet, show me a live one!
|
||||
Vastness is bearable only through love Cambrian explosion a still more glorious dawn awaits
|
||||
Euclid consciousness extraordinary claims require extraordinary evidence.
|
||||
</p>
|
||||
<a slot="cta" class="cta" href="./life.rocket.html">Details</a>
|
||||
<a slot="cta" class="cta" href="./aliens.rocket.md">Details</a>
|
||||
</rocket-card>
|
||||
|
||||
<rocket-card>
|
||||
<h4 slot="title">No astrophysicist</h4>
|
||||
<h4 slot="title">Humans</h4>
|
||||
<p>
|
||||
would deny the possibility of life. I think we're not creative enough to imagine what life
|
||||
would be like on another planet. Show me a dead alien. Better yet, show me a live one!
|
||||
Astonishment dispassionate extraterrestrial observer Drake Equation radio telescope Hypatia
|
||||
of brilliant syntheses. Vastness is bearable only through love Vangelis a mote of dust
|
||||
suspended in a sunbeam rings of Uranus vanquish the impossible rings of Uranus?
|
||||
</p>
|
||||
<a slot="cta" class="cta" href="./life.rocket.html">Details</a>
|
||||
<a slot="cta" class="cta" href="./humans.rocket.md">Details</a>
|
||||
</rocket-card>
|
||||
</rocket-columns>
|
||||
</rocket-content-area>
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
{
|
||||
"title": "Spark Rocket Example Template",
|
||||
"h1": "\n \n \n ",
|
||||
"h1": "Home",
|
||||
"headlinesWithId": [
|
||||
{
|
||||
"text": "Home",
|
||||
"id": "home",
|
||||
"level": 1,
|
||||
"rawText": "\n \n \n "
|
||||
"rawText": "@keyframes textAnimIn {\n 0% {\n transform: translate3d(0, -120%, 0);\n }\n\n 100% {\n transform: translate3d(0, 0%, 0);\n }\n }\n\n @keyframes textAnimOut {\n 0% {\n transform: translate3d(0, 0%, 0);\n }\n\n 50% {\n transform: translate3d(0, -20%, 0);\n }\n\n 100% {\n transform: translate3d(0, 120%, 0);\n }\n }\n\n p {\n position: absolute;\n top: 0;\n margin: 0;\n transform: translate3d(0, -120%, 0);\n }\n\n .anim-static {\n transform: translate3d(0, 0, 0);\n }\n\n .anim-in {\n animation: textAnimIn 0.6s 0.3s forwards;\n }\n\n .anim-out {\n animation: textAnimOut 0.6s forwards;\n }\n\n :host {\n position: block;\n position: relative;\n overflow: hidden;\n display: block;\n height: 1.5em;\n }\n div {\n display: flex;\n max-width: 960px;\n margin: 0 auto;\n }\n slot {\n display: block;\n flex: 1;\n }\n \n Welcome\n \n Hello\n \n Aloa\n lit-part-->\n to the world of science."
|
||||
},
|
||||
{
|
||||
"text": "Credit",
|
||||
"id": "credit",
|
||||
"level": 2,
|
||||
"rawText": "\n People credit me for \n \n "
|
||||
"rawText": "People credit me for \n making the universe interesting,"
|
||||
},
|
||||
{
|
||||
"text": "Knowledge",
|
||||
"id": "knowledge",
|
||||
"level": 2,
|
||||
"rawText": "\n I've known from long ago \n \n "
|
||||
"rawText": "I've known from long ago \n that the universe was calling me"
|
||||
},
|
||||
{
|
||||
"text": "Sign Up",
|
||||
@@ -30,7 +30,7 @@
|
||||
"text": "Say",
|
||||
"id": "say",
|
||||
"level": 2,
|
||||
"rawText": "\n What others \n about us?\n "
|
||||
"rawText": "What others say \n about us?"
|
||||
},
|
||||
{
|
||||
"text": "FAQ",
|
||||
@@ -39,7 +39,7 @@
|
||||
}
|
||||
],
|
||||
"name": "Spark Rocket Example Template",
|
||||
"menuLinkText": "\n \n \n ",
|
||||
"menuLinkText": "Home",
|
||||
"url": "/",
|
||||
"outputRelativeFilePath": "index.html",
|
||||
"sourceRelativeFilePath": "index.rocket.html",
|
||||
@@ -69,6 +69,70 @@
|
||||
"description": "Everyone can code a website!",
|
||||
"needsLoader": true,
|
||||
"children": [
|
||||
{
|
||||
"title": "Aliens",
|
||||
"h1": "Aliens",
|
||||
"name": "Aliens",
|
||||
"menuLinkText": "Aliens",
|
||||
"url": "/aliens/",
|
||||
"outputRelativeFilePath": "aliens/index.html",
|
||||
"sourceRelativeFilePath": "aliens.rocket.md",
|
||||
"level": 1,
|
||||
"components": {
|
||||
"rocket-columns": "@rocket/components/columns.js::RocketColumns",
|
||||
"rocket-card": "@rocket/components/card.js::RocketCard",
|
||||
"rocket-content-area": "@rocket/components/content-area.js::RocketContentArea",
|
||||
"rocket-details": "@rocket/components/details.js::RocketDetails",
|
||||
"rocket-drawer": "@rocket/components/drawer.js::RocketDrawer",
|
||||
"rocket-feature-small": "@rocket/components/feature-small.js::RocketFeatureSmall",
|
||||
"rocket-header": "@rocket/components/header.js::RocketHeader",
|
||||
"rocket-header-scroll-menu": "@rocket/components/header-scroll-menu.js::RocketHeaderScrollMenu",
|
||||
"rocket-icon": "@rocket/components/icon.js::RocketIcon",
|
||||
"rocket-icon-card": "@rocket/components/icon-card.js::RocketIconCard",
|
||||
"rocket-main": "@rocket/components/main.js::RocketMain",
|
||||
"rocket-main-docs": "@rocket/components/main-docs.js::RocketMainDocs",
|
||||
"rocket-opengraph-overview": "@rocket/components/open-graph-overview.js::RocketOpenGraphOverview",
|
||||
"rocket-rotating-text": "@rocket/components/rotating-text.js::RocketRotatingText",
|
||||
"rocket-social-link": "@rocket/components/social-link.js::RocketSocialLink",
|
||||
"rocket-testimonial-small": "@rocket/components/testimonial-small.js::RocketTestimonialSmall",
|
||||
"inline-notification": "@rocket/components/inline-notification.js::InlineNotification",
|
||||
"permanent-notification": "@rocket/components/permanent-notification.js::PermanentNotification",
|
||||
"block-blue": "@rocket/spark/block-blue.js::BlockBlue",
|
||||
"block-features": "@rocket/spark/block-features.js::BlockFeatures"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Humans",
|
||||
"h1": "Humans",
|
||||
"name": "Humans",
|
||||
"menuLinkText": "Humans",
|
||||
"url": "/humans/",
|
||||
"outputRelativeFilePath": "humans/index.html",
|
||||
"sourceRelativeFilePath": "humans.rocket.md",
|
||||
"level": 1,
|
||||
"components": {
|
||||
"rocket-columns": "@rocket/components/columns.js::RocketColumns",
|
||||
"rocket-card": "@rocket/components/card.js::RocketCard",
|
||||
"rocket-content-area": "@rocket/components/content-area.js::RocketContentArea",
|
||||
"rocket-details": "@rocket/components/details.js::RocketDetails",
|
||||
"rocket-drawer": "@rocket/components/drawer.js::RocketDrawer",
|
||||
"rocket-feature-small": "@rocket/components/feature-small.js::RocketFeatureSmall",
|
||||
"rocket-header": "@rocket/components/header.js::RocketHeader",
|
||||
"rocket-header-scroll-menu": "@rocket/components/header-scroll-menu.js::RocketHeaderScrollMenu",
|
||||
"rocket-icon": "@rocket/components/icon.js::RocketIcon",
|
||||
"rocket-icon-card": "@rocket/components/icon-card.js::RocketIconCard",
|
||||
"rocket-main": "@rocket/components/main.js::RocketMain",
|
||||
"rocket-main-docs": "@rocket/components/main-docs.js::RocketMainDocs",
|
||||
"rocket-opengraph-overview": "@rocket/components/open-graph-overview.js::RocketOpenGraphOverview",
|
||||
"rocket-rotating-text": "@rocket/components/rotating-text.js::RocketRotatingText",
|
||||
"rocket-social-link": "@rocket/components/social-link.js::RocketSocialLink",
|
||||
"rocket-testimonial-small": "@rocket/components/testimonial-small.js::RocketTestimonialSmall",
|
||||
"inline-notification": "@rocket/components/inline-notification.js::InlineNotification",
|
||||
"permanent-notification": "@rocket/components/permanent-notification.js::PermanentNotification",
|
||||
"block-blue": "@rocket/spark/block-blue.js::BlockBlue",
|
||||
"block-features": "@rocket/spark/block-features.js::BlockFeatures"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Life",
|
||||
"h1": "Life",
|
||||
|
||||
@@ -21,7 +21,7 @@ export const layoutData = {
|
||||
Modern Web<br />
|
||||
Internet 12<br />
|
||||
0000 Web<br />
|
||||
<a href="#">office@modern-web.dev</a><br />
|
||||
<a href="#">hello@modern-web.dev</a><br />
|
||||
<a href="#">0000 / 11223344</a>
|
||||
</div>
|
||||
|
||||
|
||||
2
examples/51-docs-theme-launch/.gitignore
vendored
2
examples/51-docs-theme-launch/.gitignore
vendored
@@ -3,8 +3,6 @@ node_modules/
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"scripts": {
|
||||
"build": "rocket build",
|
||||
"dev": "npm start",
|
||||
"preview": "rocket preview",
|
||||
"preview": "rocket preview --open",
|
||||
"start": "NODE_DEBUG=engine:rendering rocket start --open"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -12,6 +12,10 @@ export async function registerCustomElements() {
|
||||
'rocket-header',
|
||||
await import('@rocket/components/header.js').then(m => m.RocketHeader),
|
||||
);
|
||||
customElements.define(
|
||||
'launch-blog-preview',
|
||||
await import('@rocket/launch/blog-preview.js').then(m => m.LaunchBlogPreview),
|
||||
);
|
||||
customElements.define(
|
||||
'launch-blog-overview',
|
||||
await import('@rocket/launch/blog-overview.js').then(m => m.LaunchBlogOverview),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"title": "Welcome to Rocket",
|
||||
"h1": "\n \n ",
|
||||
"name": "\n \n ",
|
||||
"menuLinkText": "\n \n ",
|
||||
"h1": "",
|
||||
"name": "Welcome to Rocket",
|
||||
"menuLinkText": "Welcome to Rocket",
|
||||
"url": "/",
|
||||
"outputRelativeFilePath": "index.html",
|
||||
"sourceRelativeFilePath": "index.rocket.js",
|
||||
|
||||
27216
package-lock.json
generated
Normal file
27216
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
49
package.json
49
package.json
@@ -10,8 +10,7 @@
|
||||
"scripts": {
|
||||
"analyze": "run-s analyze:* format:*",
|
||||
"analyze:analyze": "node scripts/workspaces-scripts-bin.mjs analyze",
|
||||
"build": "npm run build:packages && npm run rocket:build",
|
||||
"build:packages": "node scripts/workspaces-scripts-bin.mjs build:package",
|
||||
"build": "npm run rocket:build",
|
||||
"build:site": "run-s analyze:* rocket:build",
|
||||
"changeset": "changeset",
|
||||
"debug": "web-test-runner --watch --config web-test-runner-chrome.config.mjs",
|
||||
@@ -25,39 +24,34 @@
|
||||
"lint:prettier": "node node_modules/prettier/bin-prettier.js \"**/*.{ts,js,mjs,cjs,md}\" --check --ignore-path .eslintignore",
|
||||
"lint:types": "npm run types",
|
||||
"lint:versions": "node scripts/lint-versions.js",
|
||||
"postinstall": "npm run setup",
|
||||
"release": "changeset publish && yarn format",
|
||||
"postinstall": "npx patch-package",
|
||||
"preview": "node packages/cli/src/cli.js preview --open",
|
||||
"release": "changeset publish && npm run format",
|
||||
"rocket:build": "NODE_DEBUG=engine:rendering node --trace-warnings packages/cli/src/cli.js build",
|
||||
"rocket:upgrade": "node packages/cli/src/cli.js upgrade",
|
||||
"search": "node packages/cli/src/cli.js search",
|
||||
"setup": "npm run setup:ts-configs",
|
||||
"setup:patches": "npx patch-package",
|
||||
"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": "NODE_DEBUG=engine:rendering node --trace-warnings packages/cli/src/cli.js start --open",
|
||||
"test": "yarn test:node && yarn test:web",
|
||||
"start:experimental": "NODE_DEBUG=engine:rendering node --no-warnings --experimental-loader ./packages/engine/src/litCssLoader.js packages/cli/src/cli.js start --open",
|
||||
"test": "npm run test:node && npm run test:web",
|
||||
"test:integration": "playwright test packages/*/test-node/*.spec.js --retries=3",
|
||||
"test:node": "yarn test:unit && yarn test:integration",
|
||||
"test:node": "npm run test:unit && npm run test:integration",
|
||||
"test:unit": "node --trace-warnings ./node_modules/.bin/mocha --require ./scripts/testMochaGlobalHooks.js \"packages/*/test-node/**/*.test.{ts,js,mjs,cjs}\" -- --timeout 8000 --reporter dot --exit",
|
||||
"test:web": "web-test-runner",
|
||||
"types": "run-s types:clear types:copy types:build",
|
||||
"types:build": "tsc --build",
|
||||
"types:clear": "rimraf packages/*/dist-types/",
|
||||
"types:copy": "node scripts/workspaces-scripts-bin.mjs types:copy",
|
||||
"types": "npm run types --workspaces --if-present",
|
||||
"update-dependency": "node scripts/update-dependency.js",
|
||||
"update-esm-entrypoints": "node scripts/update-esm-entrypoints.mjs && yarn format",
|
||||
"update-package-configs": "node scripts/update-package-configs.mjs && yarn format",
|
||||
"xprestart": "yarn analyze"
|
||||
"update-esm-entrypoints": "node scripts/update-esm-entrypoints.mjs && npm run format",
|
||||
"update-package-configs": "node scripts/update-package-configs.mjs && npm run format",
|
||||
"xprestart": "npm run analyze"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.20.0",
|
||||
"@custom-elements-manifest/analyzer": "^0.4.12",
|
||||
"@playwright/test": "^1.18.1",
|
||||
"@open-wc/testing": "^3.1.2",
|
||||
"@rollup/plugin-commonjs": "^17.0.0",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-typescript": "^8.1.0",
|
||||
"@playwright/test": "^1.18.1",
|
||||
"@rollup/plugin-commonjs": "^25.0.0",
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
"@rollup/plugin-terser": "^0.4.0",
|
||||
"@rollup/plugin-typescript": "^11.1.0",
|
||||
"@types/chai": "^4.2.14",
|
||||
"@types/fs-extra": "^9.0.6",
|
||||
"@types/mocha": "^9.0.0",
|
||||
@@ -80,7 +74,7 @@
|
||||
"husky": "^4.3.7",
|
||||
"lint-staged": "^10.5.3",
|
||||
"mocha": "^9.1.3",
|
||||
"node-fetch": "^2.6.7",
|
||||
"node-fetch": "^3.0.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"onchange": "^7.1.0",
|
||||
"prettier": "^2.5.1",
|
||||
@@ -89,11 +83,11 @@
|
||||
"puppeteer": "^13.0.0",
|
||||
"remark-emoji": "^2.1.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^2.36.1",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"rollup": "^3.0.0",
|
||||
"sinon": "^9.2.3",
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.6.3"
|
||||
"typescript": "^4.8.4",
|
||||
"wireit": "^0.7.2"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"parser": "@typescript-eslint/parser",
|
||||
@@ -117,7 +111,8 @@
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-empty-interface": "off",
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/no-var-requires": "off"
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"@typescript-eslint/ban-ts-comment": "off"
|
||||
}
|
||||
},
|
||||
"husky": {
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
// /**
|
||||
// * @typedef {import('./src/types').BasicOptions} BasicOptions
|
||||
// * @typedef {import('./src/types').SpaOptions} SpaOptions
|
||||
// */
|
||||
|
||||
export { createBasicConfig, createBasicMetaConfig } from './src/createBasicConfig.js';
|
||||
export { createSpaConfig, createSpaMetaConfig } from './src/createSpaConfig.js';
|
||||
export { createMpaConfig, createMpaMetaConfig } from './src/createMpaConfig.js';
|
||||
export {
|
||||
createServiceWorkerConfig,
|
||||
createServiceWorkerMetaConfig,
|
||||
} from './src/createServiceWorkerConfig.js';
|
||||
@@ -13,10 +13,12 @@
|
||||
},
|
||||
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
|
||||
"homepage": "https://rocket.modern-web.dev/docs/tools/building-rollup/",
|
||||
"main": "./index.js",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./index.js"
|
||||
".": {
|
||||
"types": "./dist-types/src/index.d.ts",
|
||||
"default": "./src/index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build:babelrc": "rimraf dist && rollup -c demo/babelrc/rollup.config.js",
|
||||
@@ -27,6 +29,7 @@
|
||||
"build:spa-js-input": "rimraf dist && rollup -c demo/js/rollup.spa-js-input.config.js",
|
||||
"build:spa-nomodule": "rimraf dist && rollup -c demo/js/rollup.spa-nomodule.config.js",
|
||||
"build:ts": "rimraf dist && rollup -c demo/ts/rollup.spa.config.js",
|
||||
"prepublishOnly": "npm run types",
|
||||
"start:babelrc": "npm run build:babelrc && npm run start:build",
|
||||
"start:build": "web-dev-server --root-dir dist --compatibility none --open",
|
||||
"start:cjs": "npm run build:cjs && npm run start:build",
|
||||
@@ -38,33 +41,52 @@
|
||||
"start:ts": "npm run build:ts && npm run start:build",
|
||||
"start:watch": "npm run build:spa-nomodule -- --watch & npm run start:build",
|
||||
"test": "npm run test:node",
|
||||
"test:node": "mocha test-node/**/*.test.js --timeout 5000"
|
||||
"test:node": "mocha test-node/**/*.test.js --timeout 5000",
|
||||
"types": "wireit"
|
||||
},
|
||||
"files": [
|
||||
"*.js",
|
||||
"dist-types",
|
||||
"src"
|
||||
],
|
||||
"keywords": [
|
||||
"rollup"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"rollup": "^2.35.0"
|
||||
"rollup": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.12.10",
|
||||
"@babel/core": "^7.20.12",
|
||||
"@babel/preset-env": "^7.12.11",
|
||||
"@rollup/plugin-babel": "^5.2.2",
|
||||
"@rollup/plugin-node-resolve": "^11.0.1",
|
||||
"@rollup/plugin-replace": "^2.4.2",
|
||||
"@web/rollup-plugin-html": "^1.8.0",
|
||||
"@web/rollup-plugin-import-meta-assets": "^1.0.4",
|
||||
"@web/rollup-plugin-polyfills-loader": "^1.1.0",
|
||||
"@rollup/plugin-babel": "^6.0.0",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"@rollup/plugin-replace": "^5.0.1",
|
||||
"@rollup/plugin-terser": "^0.4.0",
|
||||
"@web/rollup-plugin-html": "^2.0.0",
|
||||
"@web/rollup-plugin-import-meta-assets": "^2.0.0",
|
||||
"@web/rollup-plugin-polyfills-loader": "^2.0.0",
|
||||
"browserslist": "^4.16.1",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"plugins-manager": "^0.3.1",
|
||||
"workbox-broadcast-update": "^6.1.5",
|
||||
"workbox-cacheable-response": "^6.1.5",
|
||||
"workbox-expiration": "^6.1.5",
|
||||
"workbox-routing": "^6.1.5",
|
||||
"workbox-strategies": "^6.1.5"
|
||||
},
|
||||
"wireit": {
|
||||
"types": {
|
||||
"command": "copyfiles \"./types/**/*.d.ts\" dist-types/ && tsc --build --pretty",
|
||||
"dependencies": [
|
||||
"../plugins-manager:types"
|
||||
],
|
||||
"clean": "if-file-deleted",
|
||||
"files": [
|
||||
"src/**/*.js",
|
||||
"tsconfig.json"
|
||||
],
|
||||
"output": [
|
||||
"dist-types/**",
|
||||
".tsbuildinfo"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import { terser } from 'rollup-plugin-terser';
|
||||
import babelPkg from '@rollup/plugin-babel';
|
||||
import terser from '@rollup/plugin-terser';
|
||||
import { babel } from '@rollup/plugin-babel';
|
||||
|
||||
import { applyPlugins } from 'plugins-manager';
|
||||
|
||||
const { babel } = babelPkg;
|
||||
/** @typedef {import('../types/main.js').BuildingRollupOptions} BuildingRollupOptions */
|
||||
|
||||
/**
|
||||
* @param {BuildingRollupOptions} [userConfig]
|
||||
*/
|
||||
export function createBasicConfig(userConfig) {
|
||||
const { config, metaPlugins } = createBasicMetaConfig(userConfig);
|
||||
return applyPlugins(config, metaPlugins);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BuildingRollupOptions} [userConfig]
|
||||
*/
|
||||
export function createBasicMetaConfig(userConfig = { output: {} }) {
|
||||
const developmentMode =
|
||||
typeof userConfig.developmentMode !== 'undefined'
|
||||
@@ -37,8 +43,12 @@ export function createBasicMetaConfig(userConfig = { output: {} }) {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {import('plugins-manager').MetaPlugin<any>[]}
|
||||
*/
|
||||
let metaPlugins = [
|
||||
{
|
||||
// @ts-ignore
|
||||
plugin: resolve,
|
||||
options: {
|
||||
moduleDirectories: ['node_modules', 'web_modules'],
|
||||
@@ -71,7 +81,9 @@ export function createBasicMetaConfig(userConfig = { output: {} }) {
|
||||
},
|
||||
},
|
||||
{
|
||||
// @ts-ignore
|
||||
plugin: terser,
|
||||
options: {},
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import { createSpaMetaConfig } from './createSpaConfig.js';
|
||||
import { adjustPluginOptions, applyPlugins } from 'plugins-manager';
|
||||
// @ts-ignore
|
||||
import { rollupPluginHTML } from '@web/rollup-plugin-html';
|
||||
|
||||
/** @typedef {import('../types/main.js').BuildingRollupOptions} BuildingRollupOptions */
|
||||
|
||||
/**
|
||||
* @param {BuildingRollupOptions} [userConfig]
|
||||
*/
|
||||
export function createMpaConfig(userConfig) {
|
||||
const { config, metaPlugins } = createMpaMetaConfig(userConfig);
|
||||
|
||||
@@ -9,6 +15,9 @@ export function createMpaConfig(userConfig) {
|
||||
return final;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BuildingRollupOptions} userConfig
|
||||
*/
|
||||
export function createMpaMetaConfig(userConfig = { output: {}, setupPlugins: [] }) {
|
||||
const { config, metaPlugins } = createSpaMetaConfig(userConfig);
|
||||
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import { terser } from 'rollup-plugin-terser';
|
||||
import babelPkg from '@rollup/plugin-babel';
|
||||
import terser from '@rollup/plugin-terser';
|
||||
import { babel } from '@rollup/plugin-babel';
|
||||
import replace from '@rollup/plugin-replace';
|
||||
|
||||
import { applyPlugins } from 'plugins-manager';
|
||||
|
||||
const { babel } = babelPkg;
|
||||
/** @typedef {import('../types/main.js').BuildingRollupOptions} BuildingRollupOptions */
|
||||
|
||||
/**
|
||||
* @param {BuildingRollupOptions} userConfig
|
||||
*/
|
||||
export function createServiceWorkerConfig(userConfig) {
|
||||
const { config, metaPlugins } = createServiceWorkerMetaConfig(userConfig);
|
||||
return applyPlugins(config, metaPlugins);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BuildingRollupOptions} userConfig
|
||||
*/
|
||||
export function createServiceWorkerMetaConfig(userConfig = { output: {} }) {
|
||||
const developmentMode =
|
||||
typeof userConfig.developmentMode !== 'undefined'
|
||||
@@ -31,14 +37,19 @@ export function createServiceWorkerMetaConfig(userConfig = { output: {} }) {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {import('plugins-manager').MetaPlugin<any>[]}
|
||||
*/
|
||||
let metaPlugins = [
|
||||
{
|
||||
// @ts-ignore
|
||||
plugin: resolve,
|
||||
options: {
|
||||
moduleDirectories: ['node_modules', 'web_modules'],
|
||||
},
|
||||
},
|
||||
{
|
||||
// @ts-ignore
|
||||
plugin: replace,
|
||||
options: {
|
||||
'process.env.NODE_ENV': JSON.stringify(developmentMode ? 'development' : 'production'),
|
||||
@@ -72,6 +83,7 @@ export function createServiceWorkerMetaConfig(userConfig = { output: {} }) {
|
||||
},
|
||||
},
|
||||
{
|
||||
// @ts-ignore
|
||||
plugin: terser,
|
||||
options: {
|
||||
mangle: {
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
// @ts-ignore
|
||||
import { rollupPluginHTML } from '@web/rollup-plugin-html';
|
||||
// @ts-ignore
|
||||
import { importMetaAssets } from '@web/rollup-plugin-import-meta-assets';
|
||||
// @ts-ignore
|
||||
import { polyfillsLoader } from '@web/rollup-plugin-polyfills-loader';
|
||||
import { applyPlugins } from 'plugins-manager';
|
||||
|
||||
import { createBasicMetaConfig } from './createBasicConfig.js';
|
||||
|
||||
/** @typedef {import('../types/main.js').BuildingRollupOptions} BuildingRollupOptions */
|
||||
|
||||
/**
|
||||
* @param {BuildingRollupOptions} [userConfig]
|
||||
*/
|
||||
export function createSpaConfig(userConfig) {
|
||||
const { config, metaPlugins } = createSpaMetaConfig(userConfig);
|
||||
return applyPlugins(config, metaPlugins);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BuildingRollupOptions} userConfig
|
||||
*/
|
||||
export function createSpaMetaConfig(userConfig = { output: {} }) {
|
||||
const { config, metaPlugins, developmentMode } = createBasicMetaConfig(userConfig);
|
||||
|
||||
@@ -27,8 +38,13 @@ export function createSpaMetaConfig(userConfig = { output: {} }) {
|
||||
}
|
||||
delete config.absoluteBaseUrl;
|
||||
|
||||
/**
|
||||
* @type {import('plugins-manager').MetaPlugin<any>[]}
|
||||
*/
|
||||
const spaMetaPlugins = [
|
||||
// @ts-ignore
|
||||
...metaPlugins,
|
||||
// @ts-ignore
|
||||
{
|
||||
plugin: rollupPluginHTML,
|
||||
options: {
|
||||
@@ -36,9 +52,11 @@ export function createSpaMetaConfig(userConfig = { output: {} }) {
|
||||
absoluteBaseUrl,
|
||||
},
|
||||
},
|
||||
// @ts-ignore
|
||||
{
|
||||
plugin: importMetaAssets,
|
||||
},
|
||||
// @ts-ignore
|
||||
{
|
||||
plugin: polyfillsLoader,
|
||||
options: {
|
||||
|
||||
11
packages/building-rollup/src/index.js
Normal file
11
packages/building-rollup/src/index.js
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @typedef {import('../types/main.js').BuildingRollupOptions} BuildingRollupOptions
|
||||
*/
|
||||
|
||||
export { createBasicConfig, createBasicMetaConfig } from './createBasicConfig.js';
|
||||
export { createSpaConfig, createSpaMetaConfig } from './createSpaConfig.js';
|
||||
export { createMpaConfig, createMpaMetaConfig } from './createMpaConfig.js';
|
||||
export {
|
||||
createServiceWorkerConfig,
|
||||
createServiceWorkerMetaConfig,
|
||||
} from './createServiceWorkerConfig.js';
|
||||
@@ -1,6 +1,6 @@
|
||||
import chai from 'chai';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { readFile } from 'fs/promises';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { rollup } from 'rollup';
|
||||
|
||||
@@ -8,7 +8,7 @@ const { expect } = chai;
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
/**
|
||||
* @param {object} config
|
||||
* @param {import('@rocket/building-rollup').BuildingRollupOptions} config
|
||||
*/
|
||||
async function buildAndWrite(config) {
|
||||
const bundle = await rollup(config);
|
||||
@@ -16,21 +16,27 @@ async function buildAndWrite(config) {
|
||||
if (Array.isArray(config.output)) {
|
||||
await bundle.write(config.output[0]);
|
||||
await bundle.write(config.output[1]);
|
||||
} else {
|
||||
} else if (config.output) {
|
||||
await bundle.write(config.output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} configString
|
||||
* @returns
|
||||
*/
|
||||
async function execute(configString) {
|
||||
const configPath = path.join(__dirname, 'fixtures', configString.split('/').join(path.sep));
|
||||
const config = (await import(configPath)).default;
|
||||
await buildAndWrite(config);
|
||||
|
||||
/**
|
||||
* @param {string} fileName
|
||||
*/
|
||||
return async (fileName, { stripToBody = false, stripStartEndWhitespace = true } = {}) => {
|
||||
let text = await fs.promises.readFile(
|
||||
path.join(config.output.dir, fileName.split('/').join(path.sep)),
|
||||
);
|
||||
text = text.toString();
|
||||
let text = (
|
||||
await readFile(path.join(config.output.dir, fileName.split('/').join(path.sep)))
|
||||
).toString();
|
||||
if (stripToBody) {
|
||||
const bodyOpenTagEnd = text.indexOf('>', text.indexOf('<body') + 1) + 1;
|
||||
const bodyCloseTagStart = text.indexOf('</body>');
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import puppeteer from 'puppeteer';
|
||||
import chai from 'chai';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
// @ts-ignore
|
||||
import rimraf from 'rimraf';
|
||||
import { rollup } from 'rollup';
|
||||
// @ts-ignore
|
||||
import { startDevServer } from '@web/dev-server';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
@@ -14,6 +15,7 @@ const rootDir = path.resolve(__dirname, '..', 'dist');
|
||||
const { expect } = chai;
|
||||
|
||||
describe('spa integration tests', () => {
|
||||
// @ts-ignore
|
||||
let server;
|
||||
/** @type {import('puppeteer').Browser} */
|
||||
let browser;
|
||||
@@ -27,6 +29,7 @@ describe('spa integration tests', () => {
|
||||
readCliArgs: false,
|
||||
readFileConfig: false,
|
||||
logStartMessage: false,
|
||||
// @ts-ignore
|
||||
clearTerminalOnReload: false,
|
||||
});
|
||||
browser = await puppeteer.launch();
|
||||
@@ -35,6 +38,7 @@ describe('spa integration tests', () => {
|
||||
|
||||
after(async () => {
|
||||
await browser.close();
|
||||
// @ts-ignore
|
||||
await server.stop();
|
||||
});
|
||||
|
||||
@@ -45,6 +49,7 @@ describe('spa integration tests', () => {
|
||||
].forEach(testCase => {
|
||||
describe(`testcase ${testCase}`, function describe() {
|
||||
this.timeout(30000);
|
||||
// @ts-ignore
|
||||
let page;
|
||||
|
||||
before(async () => {
|
||||
|
||||
15
packages/building-rollup/tsconfig.json
Normal file
15
packages/building-rollup/tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"extends": "../../tsconfig.node-base.json",
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"outDir": "./dist-types",
|
||||
"rootDir": ".",
|
||||
"composite": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"moduleResolution": "NodeNext"
|
||||
},
|
||||
"include": ["src", "types", "test-node"],
|
||||
"exclude": ["dist-types"]
|
||||
}
|
||||
8
packages/building-rollup/types/main.d.ts
vendored
Normal file
8
packages/building-rollup/types/main.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { RollupOptions } from 'rollup';
|
||||
|
||||
interface BuildingRollupOptions extends RollupOptions {
|
||||
developmentMode?: boolean;
|
||||
rootDir?: string;
|
||||
absoluteBaseUrl?: string;
|
||||
setupPlugins?: function[];
|
||||
}
|
||||
@@ -1,5 +1,21 @@
|
||||
# check-html-links
|
||||
|
||||
## 0.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 97d5fb2: Add external links validation via the flag `--validate-externals`.
|
||||
|
||||
You can/should provide an optional `--absolute-base-url` to handle urls starting with it as internal.
|
||||
|
||||
```bash
|
||||
# check external urls
|
||||
npx check-html-links _site --validate-externals
|
||||
|
||||
# check external urls but treat links like https://rocket.modern-web.dev/about/ as internal
|
||||
npx check-html-links _site --validate-externals --absolute-base-url https://rocket.modern-web.dev
|
||||
```
|
||||
|
||||
## 0.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -14,7 +14,7 @@ npm i -D check-html-links
|
||||
npx check-html-links _site
|
||||
```
|
||||
|
||||
For docs please see our homepage [https://rocket.modern-web.dev/docs/tools/check-html-links/](https://rocket.modern-web.dev/docs/tools/check-html-links/).
|
||||
For docs please see our homepage [https://rocket.modern-web.dev/tools/check-html-links/overview/](https://rocket.modern-web.dev/tools/check-html-links/overview/).
|
||||
|
||||
## Comparison
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "check-html-links",
|
||||
"version": "0.2.3",
|
||||
"version": "0.2.4",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
@@ -37,6 +37,7 @@
|
||||
"command-line-args": "^5.1.1",
|
||||
"glob": "^7.0.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"node-fetch": "^3.0.0",
|
||||
"sax-wasm": "^2.0.0",
|
||||
"slash": "^4.0.0"
|
||||
},
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
|
||||
/** @typedef {import('../types/main').CheckHtmlLinksCliOptions} CheckHtmlLinksCliOptions */
|
||||
|
||||
import path from 'path';
|
||||
import chalk from 'chalk';
|
||||
|
||||
import commandLineArgs from 'command-line-args';
|
||||
import { validateFiles } from './validateFolder.js';
|
||||
import { prepareFiles, validateFiles } from './validateFolder.js';
|
||||
import { formatErrors } from './formatErrors.js';
|
||||
import { listFiles } from './listFiles.js';
|
||||
|
||||
@@ -18,7 +16,9 @@ export class CheckHtmlLinksCli {
|
||||
const mainDefinitions = [
|
||||
{ name: 'ignore-link-pattern', type: String, multiple: true },
|
||||
{ name: 'root-dir', type: String, defaultOption: true },
|
||||
{ name: 'continue-on-error', type: Boolean, defaultOption: false },
|
||||
{ name: 'continue-on-error', type: Boolean },
|
||||
{ name: 'validate-externals', type: Boolean },
|
||||
{ name: 'absolute-base-url', type: String },
|
||||
];
|
||||
const options = commandLineArgs(mainDefinitions, {
|
||||
stopAtFirstUnknown: true,
|
||||
@@ -29,6 +29,8 @@ export class CheckHtmlLinksCli {
|
||||
continueOnError: options['continue-on-error'],
|
||||
rootDir: options['root-dir'],
|
||||
ignoreLinkPatterns: options['ignore-link-pattern'],
|
||||
validateExternals: options['validate-externals'],
|
||||
absoluteBaseUrl: options['absolute-base-url'],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -43,22 +45,47 @@ export class CheckHtmlLinksCli {
|
||||
}
|
||||
|
||||
async run() {
|
||||
const { ignoreLinkPatterns, rootDir: userRootDir } = this.options;
|
||||
const {
|
||||
ignoreLinkPatterns,
|
||||
rootDir: userRootDir,
|
||||
validateExternals,
|
||||
absoluteBaseUrl,
|
||||
} = this.options;
|
||||
const rootDir = userRootDir ? path.resolve(userRootDir) : process.cwd();
|
||||
const performanceStart = process.hrtime();
|
||||
|
||||
console.log('👀 Checking if all internal links work...');
|
||||
const files = await listFiles('**/*.html', rootDir);
|
||||
|
||||
console.log('Check HTML Links');
|
||||
|
||||
const filesOutput =
|
||||
files.length == 0
|
||||
? '🧐 No files to check. Did you select the correct folder?'
|
||||
: `🔥 Found a total of ${chalk.green.bold(files.length)} files to check!`;
|
||||
? ' 🧐 No files to check. Did you select the correct folder?'
|
||||
: ` 📖 Found ${chalk.green.bold(files.length)} files containing`;
|
||||
console.log(filesOutput);
|
||||
|
||||
const { errors, numberLinks } = await validateFiles(files, rootDir, { ignoreLinkPatterns });
|
||||
const { numberLinks, checkLocalFiles, checkExternalLinks } = await prepareFiles(
|
||||
files,
|
||||
rootDir,
|
||||
{
|
||||
ignoreLinkPatterns,
|
||||
validateExternals,
|
||||
absoluteBaseUrl,
|
||||
},
|
||||
);
|
||||
|
||||
console.log(`🔗 Found a total of ${chalk.green.bold(numberLinks)} links to validate!\n`);
|
||||
console.log(` 🔗 ${chalk.green.bold(numberLinks)} internal links`);
|
||||
if (validateExternals) {
|
||||
console.log(` 🌐 ${chalk.green.bold(checkExternalLinks.length)} external links`);
|
||||
}
|
||||
|
||||
console.log(' 👀 Checking...');
|
||||
|
||||
const { errors } = await validateFiles({
|
||||
checkLocalFiles,
|
||||
validateExternals,
|
||||
checkExternalLinks,
|
||||
});
|
||||
|
||||
const performance = process.hrtime(performanceStart);
|
||||
/** @type {string[]} */
|
||||
@@ -70,7 +97,7 @@ export class CheckHtmlLinksCli {
|
||||
referenceCount += error.usage.length;
|
||||
}
|
||||
output = [
|
||||
`❌ Found ${chalk.red.bold(
|
||||
` ❌ Found ${chalk.red.bold(
|
||||
errors.length.toString(),
|
||||
)} missing reference targets (used by ${referenceCount} links) while checking ${
|
||||
files.length
|
||||
@@ -78,7 +105,7 @@ export class CheckHtmlLinksCli {
|
||||
...formatErrors(errors)
|
||||
.split('\n')
|
||||
.map(line => ` ${line}`),
|
||||
`Checking links duration: ${performance[0]}s ${performance[1] / 1000000}ms`,
|
||||
` 🕑 Checking links duration: ${performance[0]}s ${performance[1] / 1000000}ms`,
|
||||
];
|
||||
message = output.join('\n');
|
||||
if (this.options.printOnError === true) {
|
||||
@@ -89,7 +116,7 @@ export class CheckHtmlLinksCli {
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
`✅ All internal links are valid. (executed in ${performance[0]}s ${
|
||||
` ✅ All tested links are valid. (executed in ${performance[0]}s ${
|
||||
performance[1] / 1000000
|
||||
}ms)`,
|
||||
);
|
||||
|
||||
63
packages/check-html-links/src/checkLinks.js
Normal file
63
packages/check-html-links/src/checkLinks.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
/**
|
||||
* @type {Map<string,boolean>}
|
||||
*/
|
||||
const resultsMap = new Map();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} url
|
||||
* @param {boolean} result
|
||||
* @returns {boolean}
|
||||
*/
|
||||
const memorizeCheckup = (url, result) => {
|
||||
resultsMap.set(url, result);
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} url
|
||||
* @param {string} method
|
||||
* @returns
|
||||
*/
|
||||
const fetchWrap = async (url, method = 'GET') => {
|
||||
return Promise.race([
|
||||
fetch(url, { method })
|
||||
.then(response => response.ok)
|
||||
.catch(() => false),
|
||||
new Promise(resolve => setTimeout(resolve, 10000, false)),
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} url
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
const fetchHead = async url => fetchWrap(url, 'HEAD');
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} url - URL object to check
|
||||
* @returns {Promise<boolean>} true if url is alive or false if not
|
||||
*/
|
||||
const checkUrl = async url =>
|
||||
(fetchHead(url) || fetchWrap(url)).then(result => memorizeCheckup(url, result));
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} link - link string to check
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
export const checkLink = async link => {
|
||||
const url = link.startsWith('//') ? `https:${link}` : link;
|
||||
return resultsMap.get(url) ?? checkUrl(url);
|
||||
};
|
||||
/**
|
||||
* Check an array of links and return an object with
|
||||
*
|
||||
* @param {string[]} links Links to check
|
||||
*/
|
||||
export const checkLinks = async links => Promise.all(links.map(checkLink));
|
||||
@@ -15,7 +15,7 @@ export function formatErrors(errors, relativeFrom = process.cwd()) {
|
||||
const filePath = path.relative(relativeFrom, error.filePath);
|
||||
if (error.onlyAnchorMissing === true) {
|
||||
output.push(
|
||||
`${number}. missing ${chalk.red.bold(
|
||||
` ${number}. missing ${chalk.red.bold(
|
||||
`id="${error.usage[0].anchor}"`,
|
||||
)} in ${chalk.cyanBright(filePath)}`,
|
||||
);
|
||||
@@ -24,7 +24,7 @@ export function formatErrors(errors, relativeFrom = process.cwd()) {
|
||||
const title =
|
||||
firstAttribute === 'src' || firstAttribute === 'srcset' ? 'file' : 'reference target';
|
||||
|
||||
output.push(`${number}. missing ${title} ${chalk.red.bold(filePath)}`);
|
||||
output.push(` ${number}. missing ${title} ${chalk.red.bold(filePath)}`);
|
||||
}
|
||||
const usageLength = error.usage.length;
|
||||
|
||||
@@ -34,11 +34,11 @@ export function formatErrors(errors, relativeFrom = process.cwd()) {
|
||||
const clickAbleLink = chalk.cyanBright(`${usagePath}:${usage.line + 1}:${usage.character}`);
|
||||
const attributeStart = chalk.gray(`${usage.attribute}="`);
|
||||
const attributeEnd = chalk.gray('"');
|
||||
output.push(` from ${clickAbleLink} via ${attributeStart}${usage.value}${attributeEnd}`);
|
||||
output.push(` from ${clickAbleLink} via ${attributeStart}${usage.value}${attributeEnd}`);
|
||||
}
|
||||
if (usageLength > 3) {
|
||||
const more = chalk.red((usageLength - 3).toString());
|
||||
output.push(` ... ${more} more references to this target`);
|
||||
output.push(` ... ${more} more references to this target`);
|
||||
}
|
||||
output.push('');
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import fs from 'fs';
|
||||
import saxWasm from 'sax-wasm';
|
||||
import minimatch from 'minimatch';
|
||||
import { createRequire } from 'module';
|
||||
|
||||
import { listFiles } from './listFiles.js';
|
||||
import path from 'path';
|
||||
import slash from 'slash';
|
||||
import { listFiles } from './listFiles.js';
|
||||
import { checkLinks } from './checkLinks.js';
|
||||
|
||||
/** @typedef {import('../types/main').Link} Link */
|
||||
/** @typedef {import('../types/main').LocalFile} LocalFile */
|
||||
@@ -28,6 +27,9 @@ const parserIds = new SAXParser(SaxEventType.Attribute, streamOptions);
|
||||
/** @type {Error[]} */
|
||||
let checkLocalFiles = [];
|
||||
|
||||
/** @type {Error[]} */
|
||||
let checkExternalLinks = [];
|
||||
|
||||
/** @type {Error[]} */
|
||||
let errors = [];
|
||||
|
||||
@@ -151,6 +153,26 @@ function addLocalFile(filePath, anchor, usageObj) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} filePath
|
||||
* @param {Usage} usageObj
|
||||
*/
|
||||
function addExternalLink(filePath, usageObj) {
|
||||
const foundIndex = checkExternalLinks.findIndex(item => {
|
||||
return item.filePath === filePath;
|
||||
});
|
||||
|
||||
if (foundIndex === -1) {
|
||||
checkExternalLinks.push({
|
||||
filePath,
|
||||
onlyAnchorMissing: false,
|
||||
usage: [usageObj],
|
||||
});
|
||||
} else {
|
||||
checkExternalLinks[foundIndex].usage.push(usageObj);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} inValue
|
||||
*/
|
||||
@@ -200,11 +222,16 @@ function isNonHttpSchema(url) {
|
||||
* @param {object} options
|
||||
* @param {string} options.htmlFilePath
|
||||
* @param {string} options.rootDir
|
||||
* @param {string} options.absoluteBaseUrl
|
||||
* @param {function(string): boolean} options.ignoreUsage
|
||||
*/
|
||||
async function resolveLinks(links, { htmlFilePath, rootDir, ignoreUsage }) {
|
||||
async function resolveLinks(links, { htmlFilePath, rootDir, ignoreUsage, absoluteBaseUrl }) {
|
||||
for (const hrefObj of links) {
|
||||
const { value, anchor } = getValueAndAnchor(hrefObj.value);
|
||||
const { value: rawValue, anchor } = getValueAndAnchor(hrefObj.value);
|
||||
|
||||
const value = rawValue.startsWith(absoluteBaseUrl)
|
||||
? rawValue.substring(absoluteBaseUrl.length)
|
||||
: rawValue;
|
||||
|
||||
const usageObj = {
|
||||
attribute: hrefObj.attribute,
|
||||
@@ -229,8 +256,7 @@ async function resolveLinks(links, { htmlFilePath, rootDir, ignoreUsage }) {
|
||||
} else if (valueFile === '' && anchor !== '') {
|
||||
addLocalFile(htmlFilePath, anchor, usageObj);
|
||||
} else if (value.startsWith('//') || value.startsWith('http')) {
|
||||
// TODO: handle external urls
|
||||
// external url - we do not handle that (yet)
|
||||
addExternalLink(htmlFilePath, usageObj);
|
||||
} else if (value.startsWith('/')) {
|
||||
const filePath = path.join(rootDir, valueFile);
|
||||
addLocalFile(filePath, anchor, usageObj);
|
||||
@@ -244,7 +270,7 @@ async function resolveLinks(links, { htmlFilePath, rootDir, ignoreUsage }) {
|
||||
}
|
||||
}
|
||||
|
||||
return { checkLocalFiles: [...checkLocalFiles] };
|
||||
return { checkLocalFiles: [...checkLocalFiles], checkExternalLinks: [...checkExternalLinks] };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,17 +309,34 @@ async function validateLocalFiles(checkLocalFiles) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Error[]} checkExternalLinks
|
||||
*/
|
||||
async function validateExternalLinks(checkExternalLinks) {
|
||||
for await (const localFileObj of checkExternalLinks) {
|
||||
const links = localFileObj.usage.map(usage => usage.value);
|
||||
const results = await checkLinks(links);
|
||||
localFileObj.usage = localFileObj.usage.filter((link, index) => !results[index]);
|
||||
if (localFileObj.usage.length > 0) {
|
||||
errors.push(localFileObj);
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} files
|
||||
* @param {string} rootDir
|
||||
* @param {Options} opts?
|
||||
*/
|
||||
export async function validateFiles(files, rootDir, opts) {
|
||||
export async function prepareFiles(files, rootDir, opts) {
|
||||
await parserReferences.prepareWasm(saxWasmBuffer);
|
||||
await parserIds.prepareWasm(saxWasmBuffer);
|
||||
|
||||
errors = [];
|
||||
checkLocalFiles = [];
|
||||
checkExternalLinks = [];
|
||||
idCache = new Map();
|
||||
let numberLinks = 0;
|
||||
|
||||
@@ -309,11 +352,27 @@ export async function validateFiles(files, rootDir, opts) {
|
||||
for (const htmlFilePath of files) {
|
||||
const { links } = await extractReferences(htmlFilePath);
|
||||
numberLinks += links.length;
|
||||
await resolveLinks(links, { htmlFilePath, rootDir, ignoreUsage });
|
||||
await resolveLinks(links, {
|
||||
htmlFilePath,
|
||||
rootDir,
|
||||
ignoreUsage,
|
||||
absoluteBaseUrl: opts?.absoluteBaseUrl,
|
||||
});
|
||||
}
|
||||
await validateLocalFiles(checkLocalFiles);
|
||||
return { checkLocalFiles, checkExternalLinks, numberLinks };
|
||||
}
|
||||
|
||||
return { errors: errors, numberLinks: numberLinks };
|
||||
/**
|
||||
* @param {*} param0
|
||||
* @returns
|
||||
*/
|
||||
export async function validateFiles({ checkLocalFiles, validateExternals, checkExternalLinks }) {
|
||||
await validateLocalFiles(checkLocalFiles);
|
||||
if (validateExternals) {
|
||||
await validateExternalLinks(checkExternalLinks);
|
||||
}
|
||||
|
||||
return { errors };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -323,6 +382,14 @@ export async function validateFiles(files, rootDir, opts) {
|
||||
export async function validateFolder(inRootDir, opts) {
|
||||
const rootDir = path.resolve(inRootDir);
|
||||
const files = await listFiles('**/*.html', rootDir);
|
||||
const { errors } = await validateFiles(files, rootDir, opts);
|
||||
|
||||
const { checkLocalFiles, checkExternalLinks } = await prepareFiles(files, rootDir, opts);
|
||||
|
||||
const { errors } = await validateFiles({
|
||||
checkLocalFiles,
|
||||
validateExternals: opts?.validateExternals,
|
||||
checkExternalLinks,
|
||||
});
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<!-- ignore known subsystems -->
|
||||
<a href="/docs/"></a>
|
||||
<a href="/developer/getting-started.html#js"></a>
|
||||
<a href="/developer/language-guides/"></a>
|
||||
<a href="/developer/javascript.html"></a>
|
||||
<!-- valid -->
|
||||
<a href="//rocket.modern-web.dev/"></a>
|
||||
<a href="http://rocket.modern-web.dev/"></a>
|
||||
<a href="https://rocket.modern-web.dev/"></a>
|
||||
|
||||
<!-- invalid -->
|
||||
<a href="//rocket.modern-web.dev/unexists-page/"></a>
|
||||
<a href="http://rocket.modern-web.dev/unexists-page/"></a>
|
||||
<a href="https://rocket.modern-web.dev/unexists-page/"></a>
|
||||
|
||||
@@ -5,8 +5,5 @@
|
||||
<a href="./page.html"></a>
|
||||
<a href=" ./page.html "></a>
|
||||
<a href=" /page.html "></a>
|
||||
<a href="//domain.com/something/"></a>
|
||||
<a href="http://domain.com/something/"></a>
|
||||
<a href="https://domain.com/something/"></a>
|
||||
<a href=""></a>
|
||||
<a href=":~:text=put%20your%20labels%20above%20your%20inputs">Sign-in form best practices</a>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
About
|
||||
@@ -0,0 +1,2 @@
|
||||
<a href="about.html">About</a>
|
||||
<a href="http://localhost/about.html">About Absolute</a>
|
||||
@@ -20,19 +20,19 @@ describe('formatErrors', () => {
|
||||
const result = await executeAndFormat('fixtures/test-case');
|
||||
expect(result.trim().split('\n')).to.deep.equal([
|
||||
'1. missing id="my-teams" in fixtures/test-case/price/index.html',
|
||||
' from fixtures/test-case/history/index.html:1:9 via href="/price/#my-teams"',
|
||||
' from fixtures/test-case/history/index.html:1:9 via href="/price/#my-teams"',
|
||||
'',
|
||||
'2. missing file fixtures/test-case/about/images/team.png',
|
||||
' from fixtures/test-case/about/index.html:3:10 via src="./images/team.png"',
|
||||
' 2. missing file fixtures/test-case/about/images/team.png',
|
||||
' from fixtures/test-case/about/index.html:3:10 via src="./images/team.png"',
|
||||
'',
|
||||
'3. missing reference target fixtures/test-case/aboot',
|
||||
' from fixtures/test-case/about/index.html:6:11 via href="/aboot"',
|
||||
' from fixtures/test-case/history/index.html:4:11 via href="/aboot"',
|
||||
' from fixtures/test-case/index.html:4:11 via href="/aboot"',
|
||||
' ... 2 more references to this target',
|
||||
' 3. missing reference target fixtures/test-case/aboot',
|
||||
' from fixtures/test-case/about/index.html:6:11 via href="/aboot"',
|
||||
' from fixtures/test-case/history/index.html:4:11 via href="/aboot"',
|
||||
' from fixtures/test-case/index.html:4:11 via href="/aboot"',
|
||||
' ... 2 more references to this target',
|
||||
'',
|
||||
'4. missing reference target fixtures/test-case/prce',
|
||||
' from fixtures/test-case/index.html:1:9 via href="./prce"',
|
||||
' 4. missing reference target fixtures/test-case/prce',
|
||||
' from fixtures/test-case/index.html:1:9 via href="./prce"',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -66,6 +66,74 @@ describe('validateFolder', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('validates external links', async () => {
|
||||
const { errors, cleanup } = await execute('fixtures/external-link', {
|
||||
validateExternals: true,
|
||||
});
|
||||
expect(cleanup(errors)).to.deep.equal([
|
||||
{
|
||||
filePath: 'fixtures/external-link/index.html',
|
||||
onlyAnchorMissing: false,
|
||||
usage: [
|
||||
{
|
||||
attribute: 'href',
|
||||
value: '//rocket.modern-web.dev/unexists-page/',
|
||||
file: 'fixtures/external-link/index.html',
|
||||
line: 6,
|
||||
character: 9,
|
||||
anchor: '',
|
||||
},
|
||||
{
|
||||
attribute: 'href',
|
||||
value: 'http://rocket.modern-web.dev/unexists-page/',
|
||||
file: 'fixtures/external-link/index.html',
|
||||
line: 7,
|
||||
character: 9,
|
||||
anchor: '',
|
||||
},
|
||||
{
|
||||
attribute: 'href',
|
||||
value: 'https://rocket.modern-web.dev/unexists-page/',
|
||||
file: 'fixtures/external-link/index.html',
|
||||
line: 8,
|
||||
character: 9,
|
||||
anchor: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('validates links with own absolute base url as internal', async () => {
|
||||
const { errors, cleanup } = await execute('fixtures/internal-own-absolute-base-path', {
|
||||
validateExternals: true,
|
||||
absoluteBaseUrl: 'http://localhost',
|
||||
});
|
||||
expect(cleanup(errors)).to.deep.equal([]);
|
||||
});
|
||||
|
||||
it('validates all full urls if there is no absoluteBaseUrl provided', async () => {
|
||||
const { errors, cleanup } = await execute('fixtures/internal-own-absolute-base-path', {
|
||||
validateExternals: true,
|
||||
});
|
||||
expect(cleanup(errors)).to.deep.equal([
|
||||
{
|
||||
filePath: 'fixtures/internal-own-absolute-base-path/index.html',
|
||||
onlyAnchorMissing: false,
|
||||
usage: [
|
||||
{
|
||||
anchor: '',
|
||||
attribute: 'href',
|
||||
character: 9,
|
||||
file: 'fixtures/internal-own-absolute-base-path/index.html',
|
||||
line: 1,
|
||||
value: 'http://localhost/about.html',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('groups multiple usage of the same missing file', async () => {
|
||||
const { errors, cleanup } = await execute('fixtures/internal-links-to-same-file');
|
||||
expect(cleanup(errors)).to.deep.equal([
|
||||
|
||||
8
packages/check-html-links/types/main.d.ts
vendored
8
packages/check-html-links/types/main.d.ts
vendored
@@ -26,13 +26,15 @@ export interface Error {
|
||||
usage: Usage[];
|
||||
}
|
||||
|
||||
interface Options {
|
||||
export interface Options {
|
||||
ignoreLinkPatterns: string[] | null;
|
||||
validateExternals: boolean;
|
||||
absoluteBaseUrl: string;
|
||||
}
|
||||
|
||||
export interface CheckHtmlLinksCliOptions {
|
||||
export interface CheckHtmlLinksCliOptions extends Options {
|
||||
printOnError: boolean;
|
||||
rootDir: string;
|
||||
ignoreLinkPatterns: string[] | null;
|
||||
continueOnError: boolean;
|
||||
absoluteBaseUrl: string;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# @rocket/cli
|
||||
|
||||
## 0.20.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 68e05f4: `rocket lint` can now validate external links.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
rocket lint --validate-externals
|
||||
```
|
||||
|
||||
- Updated dependencies [97d5fb2]
|
||||
- check-html-links@0.2.4
|
||||
|
||||
## 0.20.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- a48dcd8: Introducing `rocket lint` to verify if all your links are correct.
|
||||
|
||||
There are two modes:
|
||||
|
||||
```bash
|
||||
# check existing production build in _site (need to execute "rocket build" before)
|
||||
rocket lint
|
||||
|
||||
# run a fast html only build and then check it
|
||||
rocket lint --build-html
|
||||
```
|
||||
|
||||
- Updated dependencies [0ed3d6d]
|
||||
- @rocket/engine@0.2.7
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@rocket/cli",
|
||||
"version": "0.20.1",
|
||||
"version": "0.20.4",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
@@ -13,7 +13,6 @@
|
||||
},
|
||||
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
|
||||
"homepage": "https://rocket.modern-web.dev/",
|
||||
"main": "./src/index.js",
|
||||
"bin": {
|
||||
"rocket": "src/cli.js"
|
||||
},
|
||||
@@ -30,12 +29,13 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm run rocket:build",
|
||||
"prepublishOnly": "npm run types",
|
||||
"rocket:build": "node src/cli.js build -c demo",
|
||||
"rocket:start": "node src/cli.js start -c demo",
|
||||
"start": "npm run rocket:start",
|
||||
"test": "mocha --require ../../scripts/testMochaGlobalHooks.js test-node/**/*.test.{js,cjs} test-node/*.test.{js,cjs} --timeout 8000",
|
||||
"test:watch": "onchange 'src/**/*.{js,cjs}' 'test-node/**/*.{js,cjs}' -- npm test",
|
||||
"types:copy": "copyfiles \"./types/**/*.d.ts\" dist-types/",
|
||||
"types": "wireit",
|
||||
"xtest:watch": "mocha test/**/*.test.js --parallel --watch"
|
||||
},
|
||||
"files": [
|
||||
@@ -52,9 +52,9 @@
|
||||
"rollup"
|
||||
],
|
||||
"dependencies": {
|
||||
"@rocket/building-rollup": "^0.4.0",
|
||||
"@rocket/engine": "^0.2.6",
|
||||
"@web/rollup-plugin-copy": "^0.3.0",
|
||||
"@rocket/building-rollup": "^0.4.1",
|
||||
"@rocket/engine": "^0.2.7",
|
||||
"check-html-links": "^0.2.4",
|
||||
"colorette": "^2.0.16",
|
||||
"commander": "^9.0.0",
|
||||
"fs-extra": "^9.0.1",
|
||||
@@ -67,14 +67,22 @@
|
||||
"@types/ip": "^1.1.0",
|
||||
"koa-proxy": "^1.0.0-alpha.3"
|
||||
},
|
||||
"types": "./dist-types/src/index.d.ts",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"./dist-types/src/index.d.ts"
|
||||
"wireit": {
|
||||
"types": {
|
||||
"command": "copyfiles \"./types/**/*.d.ts\" dist-types/ && tsc --build --pretty",
|
||||
"dependencies": [
|
||||
"../plugins-manager:types",
|
||||
"../engine:types",
|
||||
"../building-rollup:types"
|
||||
],
|
||||
"test-helpers": [
|
||||
"./dist-types/test-helpers/index.d.ts"
|
||||
"clean": "if-file-deleted",
|
||||
"files": [
|
||||
"src/**/*.js",
|
||||
"tsconfig.json"
|
||||
],
|
||||
"output": [
|
||||
"dist-types/**",
|
||||
".tsbuildinfo"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +1,17 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
// @ts-nocheck
|
||||
|
||||
import { Engine } from '@rocket/engine/server';
|
||||
import { gatherFiles } from '@rocket/engine';
|
||||
|
||||
import { fromRollup } from '@web/dev-server-rollup';
|
||||
|
||||
import { rollup } from 'rollup';
|
||||
import path from 'path';
|
||||
import { rollupPluginHTML } from '@web/rollup-plugin-html';
|
||||
|
||||
import { createMpaConfig, createServiceWorkerConfig } from '@rocket/building-rollup';
|
||||
import { adjustPluginOptions } from 'plugins-manager';
|
||||
import { existsSync } from 'fs';
|
||||
import { readFile, unlink, writeFile } from 'fs/promises';
|
||||
import { readFile, writeFile } from 'fs/promises';
|
||||
|
||||
import puppeteer from 'puppeteer';
|
||||
|
||||
/**
|
||||
* @param {object} config
|
||||
*/
|
||||
async function buildAndWrite(config) {
|
||||
const bundle = await rollup(config);
|
||||
|
||||
if (Array.isArray(config.output)) {
|
||||
await bundle.write(config.output[0]);
|
||||
await bundle.write(config.output[1]);
|
||||
} else {
|
||||
await bundle.write(config.output);
|
||||
}
|
||||
}
|
||||
|
||||
async function productionBuild(config) {
|
||||
const defaultSetupPlugins = [];
|
||||
if (config.pathPrefix) {
|
||||
defaultSetupPlugins.push(
|
||||
adjustPluginOptions(rollupPluginHTML, { absolutePathPrefix: config.pathPrefix }),
|
||||
);
|
||||
}
|
||||
|
||||
const mpaConfig = createMpaConfig({
|
||||
input: '**/*.html',
|
||||
output: {
|
||||
dir: config.outputDir,
|
||||
},
|
||||
// custom
|
||||
rootDir: path.resolve(config.outputDevDir),
|
||||
absoluteBaseUrl: config.absoluteBaseUrl,
|
||||
setupPlugins: [
|
||||
...defaultSetupPlugins,
|
||||
...config.setupDevServerAndBuildPlugins,
|
||||
...config.setupBuildPlugins,
|
||||
],
|
||||
});
|
||||
const finalConfig =
|
||||
typeof config.adjustBuildOptions === 'function'
|
||||
? config.adjustBuildOptions(mpaConfig)
|
||||
: mpaConfig;
|
||||
await buildAndWrite(finalConfig);
|
||||
|
||||
const { serviceWorkerSourcePath } = config;
|
||||
if (existsSync(serviceWorkerSourcePath)) {
|
||||
const serviceWorkerConfig = createServiceWorkerConfig({
|
||||
input: serviceWorkerSourcePath,
|
||||
output: {
|
||||
file: path.join(path.resolve(config.outputDir), config.serviceWorkerName),
|
||||
},
|
||||
});
|
||||
|
||||
await buildAndWrite(serviceWorkerConfig);
|
||||
}
|
||||
}
|
||||
import { buildHtml } from './build/buildHtml.js';
|
||||
import { buildOpenGraphImages } from './build/buildOpenGraphImages.js';
|
||||
import { buildJavaScriptOptimizedOutput } from './build/buildJavaScriptOptimizedOutput.js';
|
||||
|
||||
export class RocketBuild {
|
||||
/**
|
||||
* @param {import('commander').Command} program
|
||||
* @param {import('./RocketCli.js').RocketCli} cli
|
||||
*/
|
||||
async setupCommand(program, cli) {
|
||||
this.cli = cli;
|
||||
|
||||
@@ -87,30 +26,30 @@ export class RocketBuild {
|
||||
}
|
||||
|
||||
async build() {
|
||||
await this.cli.events.dispatchEventDone('build-start');
|
||||
|
||||
this.engine = new Engine();
|
||||
this.engine.setOptions({
|
||||
docsDir: this.cli.options.inputDir,
|
||||
outputDir: this.cli.options.outputDevDir,
|
||||
setupPlugins: this.cli.options.setupEnginePlugins,
|
||||
longFileHeaderWidth: this.cli.options.longFileHeaderWidth,
|
||||
longFileHeaderComment: this.cli.options.longFileHeaderComment,
|
||||
renderMode: 'production',
|
||||
clearOutputDir: this.cli.options.clearOutputDir,
|
||||
});
|
||||
console.log('Engine building...');
|
||||
await this.engine.build({ autoStop: this.cli.options.buildAutoStop });
|
||||
|
||||
if (this.cli.options.buildOpenGraphImages) {
|
||||
console.log('Generating Open Graph Images...');
|
||||
await this.buildOpenGraphImages();
|
||||
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.outputDir !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.cli.options.buildOptimize) {
|
||||
await this.cli.events.dispatchEventDone('build-start');
|
||||
|
||||
// 1. build html
|
||||
this.engine = await buildHtml(this.cli);
|
||||
|
||||
// 2. build open graph images
|
||||
if (this.cli.options.buildOpenGraphImages) {
|
||||
console.log('Generating Open Graph Images...');
|
||||
await buildOpenGraphImages(this.cli);
|
||||
}
|
||||
|
||||
// 3. build optimized output
|
||||
if (this.cli.options.buildOptimize && this.engine) {
|
||||
console.log('Optimize Production Build...');
|
||||
await productionBuild(this.cli.options);
|
||||
await this.engine.copyPublicFilesTo(this.cli.options.outputDir);
|
||||
await buildJavaScriptOptimizedOutput(this.cli, this.engine);
|
||||
}
|
||||
|
||||
// hackfix 404.html by making all asset urls absolute (rollup always makes them relative) which will break if netlify serves the content form a different url
|
||||
@@ -128,87 +67,4 @@ export class RocketBuild {
|
||||
|
||||
await this.cli.events.dispatchEventDone('build-end');
|
||||
}
|
||||
|
||||
async buildOpenGraphImages() {
|
||||
const openGraphFiles = await gatherFiles(this.cli.options.outputDevDir, {
|
||||
fileEndings: ['.opengraph.html'],
|
||||
});
|
||||
if (openGraphFiles.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: enable URL support in the Engine and remove this "workaround"
|
||||
if (
|
||||
typeof this.cli.options.inputDir !== 'string' ||
|
||||
typeof this.cli.options.outputDevDir !== 'string'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const withWrap = this.cli.options.setupDevServerAndBuildPlugins
|
||||
? this.cli.options.setupDevServerAndBuildPlugins.map(modFunction => {
|
||||
modFunction.wrapPlugin = fromRollup;
|
||||
return modFunction;
|
||||
})
|
||||
: [];
|
||||
|
||||
this.engine = new Engine();
|
||||
this.engine.setOptions({
|
||||
docsDir: this.cli.options.inputDir,
|
||||
outputDir: this.cli.options.outputDevDir,
|
||||
setupPlugins: this.cli.options.setupEnginePlugins,
|
||||
open: false,
|
||||
clearOutputDir: false,
|
||||
adjustDevServerOptions: this.cli.options.adjustDevServerOptions,
|
||||
setupDevServerMiddleware: this.cli.options.setupDevServerMiddleware,
|
||||
setupDevServerPlugins: [...this.cli.options.setupDevServerPlugins, ...withWrap],
|
||||
});
|
||||
try {
|
||||
await this.engine.start();
|
||||
|
||||
const browser = await puppeteer.launch();
|
||||
const page = await browser.newPage();
|
||||
|
||||
// In 2022 Twitter & Facebook recommend a size of 1200x628 - we capture with 2 dpr for retina displays
|
||||
await page.setViewport({
|
||||
width: 1200,
|
||||
height: 628,
|
||||
deviceScaleFactor: 2,
|
||||
});
|
||||
|
||||
for (const openGraphFile of openGraphFiles) {
|
||||
const relUrl = path.relative(this.cli.options.outputDevDir, openGraphFile);
|
||||
const imagePath = openGraphFile.replace('.opengraph.html', '.opengraph.png');
|
||||
const htmlPath = openGraphFile.replace('.opengraph.html', '.html');
|
||||
const relImageUrl = path.basename(imagePath);
|
||||
|
||||
let htmlString = await readFile(htmlPath, 'utf8');
|
||||
if (!htmlString.includes('<meta property="og:image"')) {
|
||||
if (htmlString.includes('</head>')) {
|
||||
htmlString = htmlString.replace(
|
||||
'</head>',
|
||||
[
|
||||
' <meta property="og:image:width" content="2400">',
|
||||
' <meta property="og:image:height" content="1256">',
|
||||
` <meta property="og:image" content="./${relImageUrl}">`,
|
||||
' </head>',
|
||||
].join('\n'),
|
||||
);
|
||||
}
|
||||
}
|
||||
const url = `http://localhost:${this.engine.devServer.config.port}/${relUrl}`;
|
||||
await page.goto(url, { waitUntil: 'networkidle0' });
|
||||
await page.screenshot({ path: imagePath });
|
||||
|
||||
await unlink(openGraphFile);
|
||||
await writeFile(htmlPath, htmlString);
|
||||
}
|
||||
await browser.close();
|
||||
|
||||
await this.engine.stop();
|
||||
} catch (e) {
|
||||
console.log('Could not start dev server to generate open graph images');
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import { Command } from 'commander';
|
||||
import { RocketStart } from './RocketStart.js';
|
||||
import { RocketBuild } from './RocketBuild.js';
|
||||
import { RocketInit } from './RocketInit.js';
|
||||
import { RocketLint } from './RocketLint.js';
|
||||
import { RocketUpgrade } from './RocketUpgrade.js';
|
||||
import { RocketPreview } from './RocketPreview.js';
|
||||
// import { ignore } from './images/ignore.js';
|
||||
|
||||
import path from 'path';
|
||||
@@ -34,7 +34,7 @@ export class RocketCli {
|
||||
open: false,
|
||||
cwd: process.cwd(),
|
||||
inputDir: 'FALLBACK',
|
||||
outputDir: '_site',
|
||||
outputDir: 'FALLBACK',
|
||||
outputDevDir: '_site-dev',
|
||||
|
||||
serviceWorkerSourcePath: '',
|
||||
@@ -53,6 +53,10 @@ export class RocketCli {
|
||||
absoluteBaseUrl: '',
|
||||
clearOutputDir: true,
|
||||
|
||||
lint: {
|
||||
buildHtml: false,
|
||||
},
|
||||
|
||||
// /** @type {{[key: string]: ImagePreset}} */
|
||||
// imagePresets: {
|
||||
// responsive: {
|
||||
@@ -93,6 +97,9 @@ export class RocketCli {
|
||||
if (this.options.inputDir === 'FALLBACK') {
|
||||
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) {
|
||||
this.options.inputDir = this.options.inputDir.pathname;
|
||||
}
|
||||
@@ -122,7 +129,6 @@ export class RocketCli {
|
||||
}
|
||||
|
||||
async prepare() {
|
||||
await this.clearOutputDirs();
|
||||
if (!this.options.presets) {
|
||||
return;
|
||||
}
|
||||
@@ -177,9 +183,9 @@ export class RocketCli {
|
||||
let pluginsMeta = [
|
||||
{ plugin: RocketStart, options: {} },
|
||||
{ plugin: RocketBuild, options: {} },
|
||||
{ plugin: RocketInit, options: {} },
|
||||
// { plugin: RocketLint },
|
||||
{ plugin: RocketLint, options: {} },
|
||||
{ plugin: RocketUpgrade, options: {} },
|
||||
{ plugin: RocketPreview, options: {} },
|
||||
];
|
||||
|
||||
if (Array.isArray(this.options.setupCliPlugins)) {
|
||||
@@ -230,10 +236,13 @@ export class RocketCli {
|
||||
}
|
||||
}
|
||||
|
||||
async clearOutputDirs() {
|
||||
async clearOutputDir() {
|
||||
if (this.options.outputDir && existsSync(this.options.outputDir)) {
|
||||
await rm(this.options.outputDir, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
async clearOutputDevDir() {
|
||||
if (this.options.outputDevDir && existsSync(this.options.outputDevDir)) {
|
||||
await rm(this.options.outputDevDir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
export class RocketInit {
|
||||
/**
|
||||
* @param {import('commander').Command} program
|
||||
* @param {import('./RocketCli.js').RocketCli} cli
|
||||
*/
|
||||
async setupCommand(program, cli) {
|
||||
this.cli = cli;
|
||||
|
||||
program
|
||||
.command('init')
|
||||
.option(
|
||||
'-o, --output-dir <path>',
|
||||
'path to where to put the source files [default to current directory]',
|
||||
)
|
||||
.action(async cliOptions => {
|
||||
// cli.setOptions(cliOptions);
|
||||
this.outputDir = cliOptions.outputDir ? path.resolve(cliOptions.outputDir) : process.cwd();
|
||||
|
||||
await this.init();
|
||||
});
|
||||
}
|
||||
|
||||
async init() {
|
||||
if (!this.outputDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const initFilesDir = path.join(moduleDir, 'init-files');
|
||||
const packageJsonPath = path.join(this.outputDir, 'package.json');
|
||||
|
||||
if (!(await fs.pathExists(packageJsonPath))) {
|
||||
await fs.writeJson(packageJsonPath, {});
|
||||
}
|
||||
|
||||
await fs.copy(initFilesDir, this.outputDir, {
|
||||
errorOnExist: true,
|
||||
filter: file => !(file.endsWith('_gitignore') || file.endsWith('README.md')),
|
||||
});
|
||||
|
||||
const packageJson = await fs.readJson(packageJsonPath);
|
||||
|
||||
await fs.writeJson(
|
||||
packageJsonPath,
|
||||
{
|
||||
...packageJson,
|
||||
type: 'module',
|
||||
scripts: {
|
||||
...packageJson.scripts,
|
||||
start: 'NODE_DEBUG=engine:rendering rocket start --open',
|
||||
build: 'NODE_DEBUG=engine:rendering rocket build',
|
||||
},
|
||||
imports: {
|
||||
'#images/*': './docs/__shared/*',
|
||||
},
|
||||
exports: {
|
||||
'.': './src/index.js',
|
||||
},
|
||||
},
|
||||
{ spaces: 2 },
|
||||
);
|
||||
|
||||
const gitignorePath = path.join(this.outputDir, '.gitignore');
|
||||
await fs.ensureFile(gitignorePath);
|
||||
await fs.appendFile(
|
||||
gitignorePath,
|
||||
await fs.readFile(path.join(initFilesDir, '_gitignore'), 'utf8'),
|
||||
);
|
||||
|
||||
const readmePath = path.join(this.outputDir, 'README.md');
|
||||
await fs.ensureFile(readmePath);
|
||||
await fs.appendFile(
|
||||
readmePath,
|
||||
await fs.readFile(path.join(initFilesDir, '_gitignore'), 'utf8'),
|
||||
);
|
||||
|
||||
console.log('All files have been created 🎉');
|
||||
console.log('Start developing by running `npm start`');
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
@@ -1,81 +1,85 @@
|
||||
// /* eslint-disable */
|
||||
// // @ts-nocheck
|
||||
// @ts-ignore
|
||||
import { CheckHtmlLinksCli } from 'check-html-links';
|
||||
import { bold, gray } from 'colorette';
|
||||
import { existsSync } from 'fs';
|
||||
import path from 'path';
|
||||
import { buildHtml } from './build/buildHtml.js';
|
||||
|
||||
// /** @typedef {import('../types/main').RocketCliOptions} RocketCliOptions */
|
||||
export class RocketLint {
|
||||
options = {
|
||||
buildHtml: false,
|
||||
};
|
||||
|
||||
// import { CheckHtmlLinksCli } from 'check-html-links';
|
||||
/**
|
||||
* @param {import('commander').Command} program
|
||||
* @param {import('./RocketCli.js').RocketCli} cli
|
||||
*/
|
||||
async setupCommand(program, cli) {
|
||||
this.cli = cli;
|
||||
this.active = true;
|
||||
|
||||
// export class RocketLint {
|
||||
// static pluginName = 'RocketLint';
|
||||
// commands = ['start', 'build', 'lint'];
|
||||
program
|
||||
.command('lint')
|
||||
.option('-i, --input-dir <path>', 'path to where to search for source files')
|
||||
.option('-b, --build-html', 'do a quick html only build and then check links')
|
||||
.option('-e, --validate-externals', 'validate external links')
|
||||
.action(async options => {
|
||||
const { cliOptions, ...lintOptions } = options;
|
||||
cli.setOptions({
|
||||
...cliOptions,
|
||||
lint: lintOptions,
|
||||
});
|
||||
this.options = { ...this.options, ...cli.options.lint };
|
||||
cli.activePlugin = this;
|
||||
|
||||
// /**
|
||||
// * @param {RocketCliOptions} config
|
||||
// */
|
||||
// setupCommand(config) {
|
||||
// if (config.command === 'lint') {
|
||||
// config.watch = false;
|
||||
// }
|
||||
// return config;
|
||||
// }
|
||||
await this.lint();
|
||||
});
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @param {object} options
|
||||
// * @param {RocketCliOptions} options.config
|
||||
// * @param {any} options.argv
|
||||
// */
|
||||
// async setup({ config, argv, eleventy }) {
|
||||
// this.__argv = argv;
|
||||
// this.config = {
|
||||
// lintInputDir: config.outputDevDir,
|
||||
// lintExecutesEleventyBefore: true,
|
||||
// ...config,
|
||||
// };
|
||||
// this.eleventy = eleventy;
|
||||
// }
|
||||
async lint() {
|
||||
if (!this.cli) {
|
||||
return;
|
||||
}
|
||||
|
||||
// async lintCommand() {
|
||||
// if (this.config.lintExecutesEleventyBefore) {
|
||||
// await this.eleventy.write();
|
||||
// // updated will trigger linting
|
||||
// } else {
|
||||
// await this.__lint();
|
||||
// }
|
||||
// }
|
||||
// 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.outputDevDir !== 'string' ||
|
||||
typeof this.cli.options.outputDir !== 'string'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// async __lint() {
|
||||
// if (this.config?.pathPrefix) {
|
||||
// console.log('INFO: RocketLint currently does not support being used with a pathPrefix');
|
||||
// return;
|
||||
// }
|
||||
if (this.options.buildHtml) {
|
||||
await buildHtml(this.cli);
|
||||
}
|
||||
|
||||
// const checkLinks = new CheckHtmlLinksCli();
|
||||
// checkLinks.setOptions({
|
||||
// ...this.config.checkLinks,
|
||||
// rootDir: this.config.lintInputDir,
|
||||
// printOnError: false,
|
||||
// continueOnError: true,
|
||||
// });
|
||||
const folderToCheck = this.options.buildHtml
|
||||
? this.cli.options.outputDevDir
|
||||
: this.cli.options.outputDir;
|
||||
|
||||
// const { errors, message } = await checkLinks.run();
|
||||
// if (errors.length > 0) {
|
||||
// if (this.config.command === 'start') {
|
||||
// console.log(message);
|
||||
// } else {
|
||||
// throw new Error(message);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
const rootIndexHtml = path.join(folderToCheck, 'index.html');
|
||||
if (!existsSync(rootIndexHtml)) {
|
||||
console.log(`${bold(`👀 Linting 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;
|
||||
}
|
||||
|
||||
// async postCommand() {
|
||||
// if (this.config.watch === false) {
|
||||
// await this.__lint();
|
||||
// }
|
||||
// }
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { buildHtml: _drop, ...userCheckHtmlLinksOptions } = this.options;
|
||||
|
||||
// async updated() {
|
||||
// if (this.config.watch === true) {
|
||||
// await this.__lint();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
const checkLinks = new CheckHtmlLinksCli();
|
||||
checkLinks.setOptions({
|
||||
rootDir: folderToCheck,
|
||||
printOnError: true,
|
||||
continueOnError: false,
|
||||
absoluteBaseUrl: this.cli.options.absoluteBaseUrl,
|
||||
...userCheckHtmlLinksOptions,
|
||||
});
|
||||
|
||||
await checkLinks.run();
|
||||
}
|
||||
}
|
||||
|
||||
79
packages/cli/src/RocketPreview.js
Executable file
79
packages/cli/src/RocketPreview.js
Executable file
@@ -0,0 +1,79 @@
|
||||
import { logPreviewMessage } from './preview/logPreviewMessage.js';
|
||||
import { startDevServer } from '@web/dev-server';
|
||||
import path from 'path';
|
||||
import { existsSync } from 'fs';
|
||||
import { gray, bold } from 'colorette';
|
||||
|
||||
export class RocketPreview {
|
||||
/**
|
||||
* @param {import('commander').Command} program
|
||||
* @param {import('./RocketCli.js').RocketCli} cli
|
||||
*/
|
||||
async setupCommand(program, cli) {
|
||||
this.cli = cli;
|
||||
this.active = true;
|
||||
|
||||
program
|
||||
.command('preview')
|
||||
.option('-i, --input-dir <path>', 'path to the folder with the build html files')
|
||||
.option('-o, --open', 'automatically open the browser')
|
||||
.action(async cliOptions => {
|
||||
cli.setOptions(cliOptions);
|
||||
cli.activePlugin = this;
|
||||
|
||||
await this.preview();
|
||||
});
|
||||
}
|
||||
|
||||
async preview() {
|
||||
if (!this.cli) {
|
||||
return;
|
||||
}
|
||||
|
||||
// for typescript as `this.cli.options.outputDir` supports other inputs as well
|
||||
// but the cli will normalize it to a string before calling plugins
|
||||
if (
|
||||
typeof this.cli.options.inputDir !== 'string' ||
|
||||
typeof this.cli.options.outputDir !== 'string'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rootIndexHtml = path.join(this.cli.options.outputDir, 'index.html');
|
||||
if (!existsSync(rootIndexHtml)) {
|
||||
console.log(`${bold(`👀 Previewing Production Build`)}`);
|
||||
console.log('');
|
||||
console.log(` 🛑 No index.html found in the build directory ${gray(`${rootIndexHtml}`)}`);
|
||||
console.log(' 🤔 Did you forget to run `rocket build` before?');
|
||||
console.log('');
|
||||
return;
|
||||
}
|
||||
|
||||
/** @type {import('@web/dev-server').DevServerConfig} */
|
||||
const config = {
|
||||
open: this.cli.options.open,
|
||||
rootDir: this.cli.options.outputDir,
|
||||
clearTerminalOnReload: false,
|
||||
};
|
||||
|
||||
try {
|
||||
this.devServer = await startDevServer({
|
||||
config,
|
||||
logStartMessage: false,
|
||||
readCliArgs: false,
|
||||
readFileConfig: false,
|
||||
// argv: this.__argv,
|
||||
});
|
||||
logPreviewMessage({ devServerOptions: this.devServer.config }, console);
|
||||
} catch (e) {
|
||||
console.log('🛑 Starting preview server failed');
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async stop() {
|
||||
if (this.devServer) {
|
||||
await this.devServer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,11 +31,12 @@ export class RocketStart {
|
||||
if (!this.cli) {
|
||||
return;
|
||||
}
|
||||
await this.cli.clearOutputDevDir();
|
||||
|
||||
// TODO: enable URL support in the Engine and remove this "workaround"
|
||||
if (
|
||||
typeof this.cli.options.inputDir !== 'string' ||
|
||||
typeof this.cli.options.outputDir !== 'string'
|
||||
typeof this.cli.options.outputDevDir !== 'string'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@@ -50,7 +51,7 @@ export class RocketStart {
|
||||
this.engine = new Engine();
|
||||
this.engine.setOptions({
|
||||
docsDir: this.cli.options.inputDir,
|
||||
outputDir: this.cli.options.outputDir,
|
||||
outputDir: this.cli.options.outputDevDir,
|
||||
setupPlugins: this.cli.options.setupEnginePlugins,
|
||||
open: this.cli.options.open,
|
||||
longFileHeaderWidth: this.cli.options.longFileHeaderWidth,
|
||||
|
||||
28
packages/cli/src/build/buildHtml.js
Normal file
28
packages/cli/src/build/buildHtml.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Engine } from '@rocket/engine/server';
|
||||
|
||||
/**
|
||||
* @param {import('../RocketCli.js').RocketCli} cli
|
||||
* @returns
|
||||
*/
|
||||
export async function buildHtml(cli) {
|
||||
// TODO: enable URL support in the Engine and remove this typescript "workaround"
|
||||
if (typeof cli.options.inputDir !== 'string' || typeof cli.options.outputDevDir !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
await cli.clearOutputDevDir();
|
||||
const engine = new Engine();
|
||||
engine.setOptions({
|
||||
docsDir: cli.options.inputDir,
|
||||
outputDir: cli.options.outputDevDir,
|
||||
setupPlugins: cli.options.setupEnginePlugins,
|
||||
longFileHeaderWidth: cli.options.longFileHeaderWidth,
|
||||
longFileHeaderComment: cli.options.longFileHeaderComment,
|
||||
renderMode: 'production',
|
||||
clearOutputDir: cli.options.clearOutputDir,
|
||||
});
|
||||
console.log('Engine building...');
|
||||
await engine.build({ autoStop: cli.options.buildAutoStop });
|
||||
|
||||
return engine;
|
||||
}
|
||||
86
packages/cli/src/build/buildJavaScriptOptimizedOutput.js
Normal file
86
packages/cli/src/build/buildJavaScriptOptimizedOutput.js
Normal file
@@ -0,0 +1,86 @@
|
||||
import path from 'path';
|
||||
import { existsSync } from 'fs';
|
||||
import { rollup } from 'rollup';
|
||||
|
||||
import { createMpaConfig, createServiceWorkerConfig } from '@rocket/building-rollup';
|
||||
|
||||
// import { rollupPluginHTML } from '@web/rollup-plugin-html';
|
||||
// import { adjustPluginOptions } from 'plugins-manager';
|
||||
|
||||
/**
|
||||
* @param {import('rollup').RollupOptions} config
|
||||
*/
|
||||
async function buildAndWrite(config) {
|
||||
if (!config.output) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bundle = await rollup(config);
|
||||
|
||||
if (Array.isArray(config.output)) {
|
||||
await bundle.write(config.output[0]);
|
||||
await bundle.write(config.output[1]);
|
||||
} else {
|
||||
await bundle.write(config.output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('../RocketCli.js').RocketCli} cli
|
||||
* @param {import('@rocket/engine/server').Engine} engine
|
||||
* @returns
|
||||
*/
|
||||
export async function buildJavaScriptOptimizedOutput(cli, engine) {
|
||||
const config = cli.options;
|
||||
|
||||
// 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 config.outputDir !== 'string' || typeof config.outputDevDir !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
await cli.clearOutputDir();
|
||||
|
||||
// TODO: pathPrefix is currently not supported
|
||||
// const defaultSetupPlugins = [];
|
||||
// if (config.pathPrefix) {
|
||||
// defaultSetupPlugins.push(
|
||||
// adjustPluginOptions(rollupPluginHTML, { absolutePathPrefix: config.pathPrefix }),
|
||||
// );
|
||||
// }
|
||||
|
||||
const mpaConfig = createMpaConfig({
|
||||
input: '**/*.html',
|
||||
output: {
|
||||
dir: config.outputDir,
|
||||
},
|
||||
// custom
|
||||
rootDir: path.resolve(config.outputDevDir),
|
||||
absoluteBaseUrl: config.absoluteBaseUrl,
|
||||
setupPlugins: [
|
||||
// ...defaultSetupPlugins,
|
||||
...config.setupDevServerAndBuildPlugins,
|
||||
...config.setupBuildPlugins,
|
||||
],
|
||||
});
|
||||
const finalConfig =
|
||||
typeof config.adjustBuildOptions === 'function'
|
||||
? config.adjustBuildOptions(mpaConfig)
|
||||
: mpaConfig;
|
||||
await buildAndWrite(finalConfig);
|
||||
|
||||
const { serviceWorkerSourcePath } = config;
|
||||
if (existsSync(serviceWorkerSourcePath)) {
|
||||
const serviceWorkerConfig = createServiceWorkerConfig({
|
||||
input: serviceWorkerSourcePath,
|
||||
output: {
|
||||
file: path.join(path.resolve(config.outputDir), config.serviceWorkerName),
|
||||
},
|
||||
});
|
||||
|
||||
await buildAndWrite(serviceWorkerConfig);
|
||||
}
|
||||
|
||||
// copy static files over
|
||||
await engine.copyPublicFilesTo(config.outputDir);
|
||||
}
|
||||
95
packages/cli/src/build/buildOpenGraphImages.js
Normal file
95
packages/cli/src/build/buildOpenGraphImages.js
Normal file
@@ -0,0 +1,95 @@
|
||||
import { gatherFiles } from '@rocket/engine';
|
||||
import { Engine } from '@rocket/engine/server';
|
||||
import { fromRollup } from '@web/dev-server-rollup';
|
||||
|
||||
import { readFile, unlink, writeFile } from 'fs/promises';
|
||||
|
||||
import puppeteer from 'puppeteer';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* @param {import('../RocketCli.js').RocketCli} cli
|
||||
* @returns
|
||||
*/
|
||||
export async function buildOpenGraphImages(cli) {
|
||||
const openGraphFiles = await gatherFiles(cli.options.outputDevDir, {
|
||||
fileEndings: ['.opengraph.html'],
|
||||
});
|
||||
if (openGraphFiles.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: enable URL support in the Engine and remove this typescript "workaround"
|
||||
if (typeof cli.options.inputDir !== 'string' || typeof cli.options.outputDevDir !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
const withWrap = cli.options.setupDevServerAndBuildPlugins
|
||||
? cli.options.setupDevServerAndBuildPlugins.map(modFunction => {
|
||||
modFunction.wrapPlugin = fromRollup;
|
||||
return modFunction;
|
||||
})
|
||||
: [];
|
||||
|
||||
const engine = new Engine();
|
||||
engine.setOptions({
|
||||
docsDir: cli.options.inputDir,
|
||||
outputDir: cli.options.outputDevDir,
|
||||
setupPlugins: cli.options.setupEnginePlugins,
|
||||
open: false,
|
||||
clearOutputDir: false,
|
||||
adjustDevServerOptions: cli.options.adjustDevServerOptions,
|
||||
setupDevServerMiddleware: cli.options.setupDevServerMiddleware,
|
||||
setupDevServerPlugins: [...cli.options.setupDevServerPlugins, ...withWrap],
|
||||
});
|
||||
try {
|
||||
await engine.start();
|
||||
if (!engine?.devServer?.config.port) {
|
||||
return;
|
||||
}
|
||||
|
||||
const browser = await puppeteer.launch();
|
||||
const page = await browser.newPage();
|
||||
|
||||
// In 2022 Twitter & Facebook recommend a size of 1200x628 - we capture with 2 dpr for retina displays
|
||||
await page.setViewport({
|
||||
width: 1200,
|
||||
height: 628,
|
||||
deviceScaleFactor: 2,
|
||||
});
|
||||
|
||||
for (const openGraphFile of openGraphFiles) {
|
||||
const relUrl = path.relative(cli.options.outputDevDir, openGraphFile);
|
||||
const imagePath = openGraphFile.replace('.opengraph.html', '.opengraph.png');
|
||||
const htmlPath = openGraphFile.replace('.opengraph.html', '.html');
|
||||
const relImageUrl = path.basename(imagePath);
|
||||
|
||||
let htmlString = await readFile(htmlPath, 'utf8');
|
||||
if (!htmlString.includes('<meta property="og:image"')) {
|
||||
if (htmlString.includes('</head>')) {
|
||||
htmlString = htmlString.replace(
|
||||
'</head>',
|
||||
[
|
||||
' <meta property="og:image:width" content="2400">',
|
||||
' <meta property="og:image:height" content="1256">',
|
||||
` <meta property="og:image" content="./${relImageUrl}">`,
|
||||
' </head>',
|
||||
].join('\n'),
|
||||
);
|
||||
}
|
||||
}
|
||||
const url = `http://localhost:${engine.devServer.config.port}/${relUrl}`;
|
||||
await page.goto(url, { waitUntil: 'networkidle0' });
|
||||
await page.screenshot({ path: imagePath });
|
||||
|
||||
await unlink(openGraphFile);
|
||||
await writeFile(htmlPath, htmlString);
|
||||
}
|
||||
await browser.close();
|
||||
|
||||
await engine.stop();
|
||||
} catch (e) {
|
||||
console.log('Could not start dev server to generate open graph images');
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
// @ts-nocheck
|
||||
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const EleventyImage = require('@11ty/eleventy-img');
|
||||
|
||||
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) {
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
// @ts-nocheck
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"gitdoc.enabled": false,
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"files.exclude": {
|
||||
"**/*-mdjs-generated.js": true,
|
||||
},
|
||||
"search.exclude": {
|
||||
"**/*-mdjs-generated.js": true,
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
# Welcome to Rocket
|
||||
|
||||
Get started with
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
Create new pages by calling them `my-page.rocket.md` and by putting them into `docs/`.
|
||||
@@ -1,8 +0,0 @@
|
||||
## npm
|
||||
node_modules
|
||||
npm-debug.log
|
||||
|
||||
## Rocket ignore files
|
||||
*-mdjs-generated.js
|
||||
_site
|
||||
_site-dev
|
||||
@@ -1,6 +0,0 @@
|
||||
import { rocketLaunch } from '@rocket/launch';
|
||||
|
||||
export default /** @type {import('@rocket/cli').RocketCliOptions} */ ({
|
||||
absoluteBaseUrl: 'http://localhost:8080',
|
||||
presets: [rocketLaunch()],
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
```js server
|
||||
/* START - Rocket auto generated - do not touch */
|
||||
export const sourceRelativeFilePath = '10--guides/10--first-pages/10--getting-started.rocket.md';
|
||||
import { pageTree, layout, html } from '../../recursive.data.js';
|
||||
export { pageTree, layout, html };
|
||||
/* END - Rocket auto generated - do not touch */
|
||||
```
|
||||
|
||||
# Getting Started
|
||||
|
||||
Rocket has the following prerequisites:
|
||||
|
||||
- [Node 14+](https://nodejs.org/en/)
|
||||
|
||||
Make sure they are installed before proceeding.
|
||||
|
||||
## Setup
|
||||
|
||||
The fastest way to get started is by using an existing preset like the launch preset.
|
||||
|
||||
<inline-notification type="warning">
|
||||
|
||||
If you don't want to use the `module` package type, make sure to rename the generated config file to `rocket.config.mjs`.
|
||||
|
||||
</inline-notification>
|
||||
|
||||
```js script
|
||||
import '@rocket/launch/inline-notification/inline-notification.js';
|
||||
```
|
||||
@@ -1,24 +0,0 @@
|
||||
```js server
|
||||
/* START - Rocket auto generated - do not touch */
|
||||
export const sourceRelativeFilePath = '10--guides/10--first-pages/20--custom-layout.rocket.md';
|
||||
import { pageTree } from '../../recursive.data.js';
|
||||
export { pageTree };
|
||||
/* END - Rocket auto generated - do not touch */
|
||||
|
||||
import { html } from 'lit';
|
||||
|
||||
export const layout = data => html`
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<p>A FULLY custom layout</p>
|
||||
${data.content()}
|
||||
<a href="../index.rocket.md">Go back to Guides</a>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
```
|
||||
|
||||
# Custom Layout
|
||||
|
||||
Here is my markdown content.
|
||||
@@ -1,43 +0,0 @@
|
||||
```js server
|
||||
/* START - Rocket auto generated - do not touch */
|
||||
export const sourceRelativeFilePath = '10--guides/10--first-pages/20--images.rocket.md';
|
||||
import { pageTree, layout, html } from '../../recursive.data.js';
|
||||
export { pageTree, layout, html };
|
||||
/* END - Rocket auto generated - do not touch */
|
||||
```
|
||||
|
||||
# Images
|
||||
|
||||
We can add a private package import to your
|
||||
|
||||
👉 `package.json`
|
||||
|
||||
```json
|
||||
"imports": {
|
||||
"#images/*": "./docs/__shared/*"
|
||||
},
|
||||
```
|
||||
|
||||
With that we can then use `resolve:[[npm resolve name]]` in our urls.
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
<div style="width: 50%">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
You can also include images from dependencies.
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
<div style="width: 50%">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
@@ -1,12 +0,0 @@
|
||||
/* START - Rocket auto generated - do not touch */
|
||||
export const sourceRelativeFilePath = '10--guides/10--first-pages/index.rocket.js';
|
||||
import { pageTree, layout } from '../../recursive.data.js';
|
||||
export { pageTree, layout };
|
||||
/* END - Rocket auto generated - do not touch */
|
||||
|
||||
import { html } from 'lit';
|
||||
|
||||
export default () => html`
|
||||
<h1>First Pages</h1>
|
||||
<meta name="menu:exclude" content="true" />
|
||||
`;
|
||||
@@ -1,17 +0,0 @@
|
||||
```js server
|
||||
/* START - Rocket auto generated - do not touch */
|
||||
export const sourceRelativeFilePath = '10--guides/index.rocket.md';
|
||||
import { pageTree, layout, html } from '../recursive.data.js';
|
||||
export { pageTree, layout, html };
|
||||
/* END - Rocket auto generated - do not touch */
|
||||
|
||||
import { ChildListMenu } from '@rocket/engine';
|
||||
```
|
||||
|
||||
# Learning Rocket
|
||||
|
||||
<meta name="menu:link.text" content="Guides">
|
||||
|
||||
Rocket helps you generate static pages from Markdown files while giving you the flexibility to sprinkle in some JavaScript where needed.
|
||||
|
||||
${pageTree.renderMenu(new ChildListMenu(), sourceRelativeFilePath)}
|
||||
@@ -1,16 +0,0 @@
|
||||
/* START - Rocket auto generated - do not touch */
|
||||
export const sourceRelativeFilePath = '20--docs/index.rocket.js';
|
||||
import { pageTree, layout, html } from '../recursive.data.js';
|
||||
export { pageTree, layout, html };
|
||||
/* END - Rocket auto generated - do not touch */
|
||||
|
||||
import { ChildListMenu } from '@rocket/engine';
|
||||
|
||||
export default () => html`
|
||||
<meta name="menu:link.text" content="Docs" />
|
||||
|
||||
<h1>Documentation</h1>
|
||||
|
||||
<p>Here you will find all the details for each of the packages/systems we offer.</p>
|
||||
${pageTree.renderMenu(new ChildListMenu(), sourceRelativeFilePath)}
|
||||
`;
|
||||
@@ -1,21 +0,0 @@
|
||||
/* START - Rocket auto generated - do not touch */
|
||||
export const sourceRelativeFilePath = '20--docs/star-wars.rocket.js';
|
||||
import { pageTree, layout, html } from '../recursive.data.js';
|
||||
export { pageTree, layout, html };
|
||||
/* END - Rocket auto generated - do not touch */
|
||||
|
||||
import cache from '@11ty/eleventy-cache-assets';
|
||||
|
||||
const films = await cache('https://swapi.dev/api/films/', {
|
||||
duration: '1d',
|
||||
type: 'json',
|
||||
});
|
||||
|
||||
export default () => html`
|
||||
<h1>Star Wars</h1>
|
||||
|
||||
<h2>Films:</h2>
|
||||
<ul>
|
||||
${films.results.map(film => html`<li>${film.title} (${film.release_date})</li>`)}
|
||||
</ul>
|
||||
`;
|
||||
@@ -1,11 +0,0 @@
|
||||
/* START - Rocket auto generated - do not touch */
|
||||
export const sourceRelativeFilePath = '404.html.rocket.js';
|
||||
import { pageTree, html } from './recursive.data.js';
|
||||
export { pageTree, html };
|
||||
/* END - Rocket auto generated - do not touch */
|
||||
|
||||
import { Layout404 } from '@rocket/launch';
|
||||
|
||||
export const layout = new Layout404();
|
||||
|
||||
export default () => '';
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 12 KiB |
@@ -1,45 +0,0 @@
|
||||
export const footerMenu = [
|
||||
{
|
||||
name: 'Discover',
|
||||
children: [
|
||||
{
|
||||
text: 'Blog',
|
||||
href: '/blog/',
|
||||
},
|
||||
{
|
||||
text: 'Help and Feedback',
|
||||
href: 'https://github.com/modernweb-dev/rocket/issues',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Follow',
|
||||
children: [
|
||||
{
|
||||
text: 'GitHub',
|
||||
href: 'https://github.com/modernweb-dev/rocket',
|
||||
},
|
||||
{
|
||||
text: 'Twitter',
|
||||
href: 'https://twitter.com/modern_web_dev',
|
||||
},
|
||||
{
|
||||
text: 'Slack',
|
||||
href: '/about/slack/',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Support',
|
||||
children: [
|
||||
{
|
||||
text: 'Sponsor',
|
||||
href: '/about/sponsor/',
|
||||
},
|
||||
{
|
||||
text: 'Contribute',
|
||||
href: 'https://github.com/modernweb-dev/rocket/blob/main/CONTRIBUTING.md',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 178 KiB |
@@ -1,52 +0,0 @@
|
||||
/* START - Rocket auto generated - do not touch */
|
||||
export const sourceRelativeFilePath = 'index.rocket.js';
|
||||
import { pageTree } from './recursive.data.js';
|
||||
export { pageTree };
|
||||
/* END - Rocket auto generated - do not touch */
|
||||
|
||||
import { html } from 'lit';
|
||||
|
||||
import { LayoutHome } from '@rocket/launch';
|
||||
import { footerMenu } from './__shared/footerMenu.js';
|
||||
|
||||
export const layout = new LayoutHome({
|
||||
pageTree,
|
||||
footerMenu,
|
||||
slogan: 'The modern web setup for static sites with a sprinkle of JavaScript.',
|
||||
callToActionItems: [
|
||||
{ text: 'Follow Guides', href: '/guides/' },
|
||||
{ text: 'Browse Docs', href: '/docs/' },
|
||||
],
|
||||
background: '/home-background.svg',
|
||||
reasonHeader: 'Why Rocket?',
|
||||
reasons: [
|
||||
{
|
||||
header: 'Small',
|
||||
text: 'No overblown tools or frontend frameworks, add JavaScript and/or Web Components only on pages where needed.',
|
||||
},
|
||||
{
|
||||
header: 'Pre-Rendered',
|
||||
text: 'Statically generated content means less JavaScript to ship and process.',
|
||||
},
|
||||
{
|
||||
header: 'Zero Configuration',
|
||||
text: 'Automatic code splitting, filesystem based routing, and JavaScript in Markdown.',
|
||||
},
|
||||
{
|
||||
header: 'Meta Framework',
|
||||
text: html`Build on top of giants like <a href="https://www.11ty.dev/">Eleventy</a>,
|
||||
<a href="https://rollupjs.org/">Rollup</a>, and
|
||||
<a href="https://www.modern-web.dev/">Modern Web</a>.`,
|
||||
},
|
||||
{
|
||||
header: 'Powerful Default Template',
|
||||
text: 'Provide content and you are ready to go.',
|
||||
},
|
||||
{
|
||||
header: 'Ready for Production',
|
||||
text: 'Optimized for a smaller build size, faster dev compilation and dozens of other improvements.',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export default () => '';
|
||||
@@ -1,121 +0,0 @@
|
||||
{
|
||||
"title": "Rocket | Rocket",
|
||||
"h1": "Rocket",
|
||||
"name": "Rocket",
|
||||
"menuLinkText": "Rocket",
|
||||
"url": "/",
|
||||
"outputRelativeFilePath": "index.html",
|
||||
"sourceRelativeFilePath": "index.rocket.js",
|
||||
"level": 0,
|
||||
"children": [
|
||||
{
|
||||
"title": "Learning Rocket | Rocket",
|
||||
"h1": "Learning Rocket",
|
||||
"headlinesWithId": [
|
||||
{
|
||||
"text": "Learning Rocket",
|
||||
"id": "learning-rocket",
|
||||
"level": 1
|
||||
}
|
||||
],
|
||||
"menuLinkText": "Guides",
|
||||
"name": "Learning Rocket",
|
||||
"url": "/guides/",
|
||||
"outputRelativeFilePath": "guides/index.html",
|
||||
"sourceRelativeFilePath": "10--guides/index.rocket.md",
|
||||
"level": 1,
|
||||
"children": [
|
||||
{
|
||||
"title": "First Pages | Rocket",
|
||||
"h1": "First Pages",
|
||||
"menuNoLink": true,
|
||||
"name": "First Pages",
|
||||
"menuLinkText": "First Pages",
|
||||
"url": "/guides/first-pages/",
|
||||
"outputRelativeFilePath": "guides/first-pages/index.html",
|
||||
"sourceRelativeFilePath": "10--guides/10--first-pages/index.rocket.js",
|
||||
"level": 2,
|
||||
"children": [
|
||||
{
|
||||
"title": "Getting Started | Rocket",
|
||||
"h1": "Getting Started",
|
||||
"headlinesWithId": [
|
||||
{
|
||||
"text": "Getting Started",
|
||||
"id": "getting-started",
|
||||
"level": 1
|
||||
},
|
||||
{
|
||||
"text": "Setup",
|
||||
"id": "setup",
|
||||
"level": 2
|
||||
}
|
||||
],
|
||||
"name": "Getting Started",
|
||||
"menuLinkText": "Getting Started",
|
||||
"url": "/guides/first-pages/getting-started/",
|
||||
"outputRelativeFilePath": "guides/first-pages/getting-started/index.html",
|
||||
"sourceRelativeFilePath": "10--guides/10--first-pages/10--getting-started.rocket.md",
|
||||
"level": 3
|
||||
},
|
||||
{
|
||||
"h1": "Custom Layout",
|
||||
"headlinesWithId": [
|
||||
{
|
||||
"text": "Custom Layout",
|
||||
"id": "custom-layout",
|
||||
"level": 1
|
||||
}
|
||||
],
|
||||
"name": "Custom Layout",
|
||||
"menuLinkText": "Custom Layout",
|
||||
"url": "/guides/first-pages/custom-layout/",
|
||||
"outputRelativeFilePath": "guides/first-pages/custom-layout/index.html",
|
||||
"sourceRelativeFilePath": "10--guides/10--first-pages/20--custom-layout.rocket.md",
|
||||
"level": 3
|
||||
},
|
||||
{
|
||||
"title": "Images | Rocket",
|
||||
"h1": "Images",
|
||||
"headlinesWithId": [
|
||||
{
|
||||
"text": "Images",
|
||||
"id": "images",
|
||||
"level": 1
|
||||
}
|
||||
],
|
||||
"name": "Images",
|
||||
"menuLinkText": "Images",
|
||||
"url": "/guides/first-pages/images/",
|
||||
"outputRelativeFilePath": "guides/first-pages/images/index.html",
|
||||
"sourceRelativeFilePath": "10--guides/10--first-pages/20--images.rocket.md",
|
||||
"level": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Documentation | Rocket",
|
||||
"menuLinkText": "Docs",
|
||||
"h1": "Documentation",
|
||||
"name": "Documentation",
|
||||
"url": "/docs/",
|
||||
"outputRelativeFilePath": "docs/index.html",
|
||||
"sourceRelativeFilePath": "20--docs/index.rocket.js",
|
||||
"level": 1,
|
||||
"children": [
|
||||
{
|
||||
"title": "Star Wars | Rocket",
|
||||
"h1": "Star Wars",
|
||||
"name": "Star Wars",
|
||||
"menuLinkText": "Star Wars",
|
||||
"url": "/docs/star-wars/",
|
||||
"outputRelativeFilePath": "docs/star-wars/index.html",
|
||||
"sourceRelativeFilePath": "20--docs/star-wars.rocket.js",
|
||||
"level": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { PageTree } from '@rocket/engine';
|
||||
import { LayoutSidebar } from '@rocket/launch';
|
||||
import { footerMenu } from './__shared/footerMenu.js';
|
||||
import { html } from 'lit';
|
||||
|
||||
export const pageTree = new PageTree({
|
||||
inputDir: new URL('./', import.meta.url),
|
||||
outputDir: new URL('../_site', import.meta.url),
|
||||
});
|
||||
await pageTree.restore();
|
||||
|
||||
export const layout = new LayoutSidebar({ pageTree, footerMenu });
|
||||
|
||||
export { html };
|
||||
|
||||
// export const openGraphLayout = new OpenGraphLayoutLogo();
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "esnext",
|
||||
"outDir": "./dist-types",
|
||||
"rootDir": ".",
|
||||
"composite": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"target": "esnext",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"downlevelIteration": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "Node",
|
||||
"typeRoots": ["@types", "./types"],
|
||||
"types": ["node"],
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"lib": [
|
||||
"DOM",
|
||||
"DOM.Iterable",
|
||||
"ES6",
|
||||
"ES2017",
|
||||
// Allows array.flatMap. import `array-flat-polyfill` to cover node10
|
||||
"ES2019.array",
|
||||
"ScriptHost"
|
||||
]
|
||||
}
|
||||
}
|
||||
33
packages/cli/src/preview/logPreviewMessage.js
Normal file
33
packages/cli/src/preview/logPreviewMessage.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { white, bold, cyan, gray } from 'colorette';
|
||||
import { createAddress, logNetworkAddress } from '../helpers/infoMessages.js';
|
||||
|
||||
/** @typedef {import('@web/dev-server').DevServerConfig} DevServerConfig */
|
||||
|
||||
/**
|
||||
* @param {{ devServerOptions: DevServerConfig}} options
|
||||
* @param {console} logger
|
||||
*/
|
||||
export function logPreviewMessage({ devServerOptions }, logger) {
|
||||
const prettyHost = devServerOptions.hostname ?? 'localhost';
|
||||
let openPath = typeof devServerOptions.open === 'string' ? devServerOptions.open : '/';
|
||||
if (!openPath.startsWith('/')) {
|
||||
openPath = `/${openPath}`;
|
||||
}
|
||||
|
||||
logger.log(`${bold(`👀 Previewing Production Build`)}`);
|
||||
logger.log('');
|
||||
logger.log(
|
||||
`${white(' 🚧 Local:')} ${cyan(createAddress(devServerOptions, prettyHost, openPath))}`,
|
||||
);
|
||||
logNetworkAddress(devServerOptions, logger, openPath);
|
||||
const sourceDir = devServerOptions.rootDir;
|
||||
if (sourceDir) {
|
||||
logger.log(`${white(' 📝 Source:')} ${cyan(sourceDir)}`);
|
||||
}
|
||||
logger.log('');
|
||||
logger.log(
|
||||
gray(
|
||||
'If what you see works as expected then you can upload "source" to your production web server.',
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1,38 +1,8 @@
|
||||
import ip from 'ip';
|
||||
import { white, bold, cyan, gray } from 'colorette';
|
||||
import { createAddress, logNetworkAddress } from '../helpers/infoMessages.js';
|
||||
|
||||
/** @typedef {import('@web/dev-server').DevServerConfig} DevServerConfig */
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {DevServerConfig} devServerOptions
|
||||
* @param {string} host
|
||||
* @param {string} path
|
||||
* @returns {string}
|
||||
*/
|
||||
function createAddress(devServerOptions, host, path) {
|
||||
return `http${devServerOptions.http2 ? 's' : ''}://${host}:${devServerOptions.port}${path}`;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {DevServerConfig} devServerOptions
|
||||
* @param {console} logger
|
||||
* @param {string} openPath
|
||||
*/
|
||||
function logNetworkAddress(devServerOptions, logger, openPath) {
|
||||
try {
|
||||
const address = ip.address();
|
||||
if (typeof address === 'string') {
|
||||
logger.log(
|
||||
`${white(' 🌐 Network:')} ${cyan(createAddress(devServerOptions, address, openPath))}`,
|
||||
);
|
||||
}
|
||||
} catch (_a) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ devServerOptions: DevServerConfig, engine: import('@rocket/engine/server').Engine}} options
|
||||
* @param {console} logger
|
||||
|
||||
@@ -74,7 +74,7 @@ describe('Config', () => {
|
||||
testOptions: { captureLogs: true },
|
||||
});
|
||||
await build();
|
||||
const inlineModule = await readOutput('e97af63d.js', { format: false });
|
||||
const inlineModule = await readOutput('ddcef8d1.js', { format: false });
|
||||
expect(inlineModule).to.equal('var a={test:"data"};console.log(a);\n');
|
||||
});
|
||||
|
||||
|
||||
49
packages/cli/test-node/06-preview.test.js
Normal file
49
packages/cli/test-node/06-preview.test.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import chai from 'chai';
|
||||
import { white, bold, gray } from 'colorette';
|
||||
|
||||
import { setupTestCli } from './test-helpers.js';
|
||||
|
||||
const { expect } = chai;
|
||||
|
||||
describe('Preview', () => {
|
||||
it('01: Preview Message', async () => {
|
||||
const { cli, capturedLogs, cleanup } = await setupTestCli({
|
||||
cwd: 'fixtures/06-preview/01-preview-message',
|
||||
cliOptions: ['preview'],
|
||||
testOptions: { captureLogs: true },
|
||||
});
|
||||
|
||||
await cli.start();
|
||||
await cleanup();
|
||||
|
||||
expect(capturedLogs[0]).to.equal(`${bold(`👀 Previewing Production Build`)}`);
|
||||
expect(capturedLogs[1]).to.equal('');
|
||||
expect(capturedLogs[2].startsWith(`${white(' 🚧 Local:')}`)).to.be.true;
|
||||
expect(capturedLogs[3].startsWith(`${white(' 🌐 Network:')}`)).to.be.true;
|
||||
expect(capturedLogs[4].startsWith(`${white(' 📝 Source:')}`)).to.be.true;
|
||||
expect(capturedLogs[5]).to.equal('');
|
||||
expect(capturedLogs[6]).to.equal(
|
||||
`${gray(
|
||||
'If what you see works as expected then you can upload "source" to your production web server.',
|
||||
)}`,
|
||||
);
|
||||
});
|
||||
|
||||
it('02: Error Message if there is no build output', async () => {
|
||||
const { cli, capturedLogs, cleanup } = await setupTestCli({
|
||||
cwd: 'fixtures/06-preview/02-error-no-build',
|
||||
cliOptions: ['preview'],
|
||||
testOptions: { captureLogs: true },
|
||||
});
|
||||
|
||||
await cli.start();
|
||||
await cleanup();
|
||||
|
||||
expect(capturedLogs[0]).to.equal(`${bold(`👀 Previewing Production Build`)}`);
|
||||
expect(capturedLogs[1]).to.equal('');
|
||||
expect(capturedLogs[2].startsWith(` 🛑 No index.html found in the build directory`)).to.be
|
||||
.true;
|
||||
expect(capturedLogs[3]).to.equal(' 🤔 Did you forget to run `rocket build` before?');
|
||||
expect(capturedLogs[4]).to.equal('');
|
||||
});
|
||||
});
|
||||
1
packages/cli/test-node/fixtures/06-preview/01-preview-message/.gitignore
vendored
Normal file
1
packages/cli/test-node/fixtures/06-preview/01-preview-message/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!__output
|
||||
@@ -0,0 +1 @@
|
||||
so preview does not stop
|
||||
@@ -1,5 +1,3 @@
|
||||
// Don't edit this file directly. It is generated by /scripts/update-package-configs.ts
|
||||
|
||||
{
|
||||
"extends": "../../tsconfig.node-base.json",
|
||||
"compilerOptions": {
|
||||
@@ -9,27 +7,9 @@
|
||||
"composite": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"emitDeclarationOnly": true
|
||||
"emitDeclarationOnly": true,
|
||||
"moduleResolution": "NodeNext"
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "../plugins-manager/tsconfig.json"
|
||||
},
|
||||
{
|
||||
"path": "../mdjs-core/tsconfig.json"
|
||||
},
|
||||
{
|
||||
"path": "../engine/tsconfig.json"
|
||||
}
|
||||
],
|
||||
"include": [
|
||||
"src",
|
||||
"*.js",
|
||||
"types"
|
||||
],
|
||||
"exclude": [
|
||||
"dist",
|
||||
"dist-types",
|
||||
"src/init-files/"
|
||||
]
|
||||
}
|
||||
"include": ["src", "types"],
|
||||
"exclude": ["dist-types", "**/__output/**", "**/__output-dev/**"]
|
||||
}
|
||||
|
||||
5
packages/cli/types/main.d.ts
vendored
5
packages/cli/types/main.d.ts
vendored
@@ -47,6 +47,11 @@ export interface FullRocketCliOptions extends Pick<FullRocketPreset, PresetKeys>
|
||||
// rarely used
|
||||
configFile: string;
|
||||
outputDevDir: URL | string;
|
||||
|
||||
lint: {
|
||||
buildHtml: boolean;
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
export type RocketCliOptions = Partial<FullRocketCliOptions>;
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
},
|
||||
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
|
||||
"homepage": "https://rocket.modern-web.dev/",
|
||||
"main": "./exports/index.js",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
@@ -26,9 +25,10 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"prepublishOnly": "npm run types",
|
||||
"test": "mocha --require ../../scripts/testMochaGlobalHooks.js test-node/**/*.test.{js,cjs} test-node/*.test.{js,cjs}",
|
||||
"test:watch": "onchange 'src/**/*.{js,cjs}' 'test-node/**/*.{js,cjs}' -- npm test",
|
||||
"types:copy": "copyfiles \"./types/**/*.d.ts\" dist-types/",
|
||||
"types": "wireit",
|
||||
"xtest:watch": "mocha test/**/*.test.js --parallel --watch"
|
||||
},
|
||||
"files": [
|
||||
@@ -47,10 +47,17 @@
|
||||
},
|
||||
"devDependencies": {},
|
||||
"types": "./dist-types/exports/index.d.ts",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"./dist-types/exports/index.d.ts"
|
||||
"wireit": {
|
||||
"types": {
|
||||
"command": "copyfiles \"./types/**/*.d.ts\" dist-types/ && tsc --build --pretty",
|
||||
"clean": "if-file-deleted",
|
||||
"files": [
|
||||
"src/**/*.js",
|
||||
"tsconfig.json"
|
||||
],
|
||||
"output": [
|
||||
"dist-types/**",
|
||||
".tsbuildinfo"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user