@minissg/page
v1.0.1
Published
simple page organization management for Minissg
Downloads
1
Readme
@minissg/page
This library provides a feature to manage the set of webpages to be generated by Minissg.
Install
Install the package by
npm install @minissg/page
and import it in the root file of your project as follows:
import { Page } from "@minissg/page";
or
import Page from "@minissg/page";
Getting Started
Download a template project.
tiged uenob/minissg/template/page my_project
Change directory to the new directory and install all dependencies
by the npm
command:
cd my_project
npm install
The following scripts are initially available:
npm run build
for static site generation for production.npm run serve
for preview of the build result.npm run dev
for starting Vite's dev server.
Basic Usage
Each instance of the Page
class represents a set of webpages.
The typical usage of the Page
class is as follows:
Combined with
import.meta.glob
provided by Vite, create aPage
object of a set of webpage component modules byPage.create
. For example:const page = Page.create({ url: 'https://example.com/', pages: import.meta.glob('./pages/**/*.{md,mdx}'), substitutePath: s => s.slice('./pages/'.length) });
The
url
parameter indicates the root URL of this website.pages
has the map from file names to dynamic import functions provided byimport.meta.glob
.substitutePath
removes./pages/
prefix from each file name when making URL of each webpage. The URL of each webpage is obtained by transforming its file name after applyingsubstitutePath
. As a result, for example, a given modulepages/foo/bar.mdx
is associated with a webpage of URLfoo/bar/
.Set
page.render
to a function indicating how to render a webpage component in a HTML file. The following example addsDOCTYPE
,html
, andbody
tags tomodule.default
component and renders all of them byvirtual:minissg/self?renderer
.import render from 'virtual:minissg/self?renderer' page.render = async function (module) { const Webpage = () => ( <html> <body> <module.default page={this} /> </body> </html> ); return new Blob(['<!DOCTYPE html>\n', await render(Webpage)]); };
In each MDX file, you can access to the
Page
object dedicated to that MDX file throughprops.page
property.Export the root page through the
main
function:
export main = () => page;
The above three fragments of code is placed in the same JSX file, say
index.html.jsx
.
Set this file to the input of Vite in vite.config.js
and do vite build
.
Then you will find your website in dist
directory.
An example of vite.config.js
is given below:
import { defineConfig } from 'vite'
import mdx from '@mdx-js/rollup'
import preact from '@preact/preset-vite'
import minissg from 'vite-plugin-minissg'
import minissgPreact from '@minissg/render-preact'
export default defineConfig({
build: {
rollupOptions: {
input: './index.html.jsx'
}
},
plugins: [
minissg({
render: {
'**/*.jsx': minissgPreact()
},
plugins: () => [
preact(),
mdx({
mdxExtensions: ['.mdx', '.mdx?MINISSG-COPY'],
jsxImportSource: 'preact'
})
]
})
]
})
References
This package provides the Page
class having the following methods.
Types
Awaitable
type Awaitable<X> = X | PromiseLike<X>;
The type of values that can be passed to the await
construct.
Pairs
type Pairs<X, Y, This = void> =
| Awaitable<Record<string, Y>>
| Awaitable<Iterable<Awaitable<PairsItem<X, Y, This>>>>
| Awaitable<AsyncIterable<Awaitable<PairsItem<X, Y, This>>>>
| Awaitable<(this: This) => Awaitable<Pairs<X, Y, This>>>;
type PairsItem<X, Y, This> =
| [X, Y]
| Record<string, Y>
| ((this: This) => Pairs<X, Y, This>);
Pairs<Key, Value>
represents a sequence of key-value pairs.
It is either an array
, object
, promise of one of them,
or function returning Pairs<Key, Value>
.
If array
is given, each element must be either a pair
[Key, Value]
, object
, or function returning Pairs<Key, Value>
.
If object
is given as a Pairs<Key, Value>
, each property must be
of type Value
.
List
type List<X, This = void> =
| Awaitable<Iterable<X>>
| Awaitable<AsyncIterable<X>>
| Awaitable<(this: This) => List<X, This>>;
type Awaitable<X> = X | PromiseLike<X>;
List<Value>
represents a sequence of values.
It is either an Iterable<Value>
, AsyncIterable<Value>
, or promise
of one of them, or function returning List<Value>
.
RelPath
interface RelPath {
moduleName: string;
stem: string;
variant: string;
fileName: string;
}
RelPath
is the type of objects of the form
{ moduleName: string; stem: string; variant: string; fileName: string }
,
each of which represent relative paths between two Page
s.
Page
manages the following four kinds of paths:
moduleName
is the path of webpages. This is used to determine the URL of each webpage.stem
identifies a content of a webpage regardless of its variants, such as languages and formats.variant
identifies a variants of the content.fileName
is the path of source file.
Paginate
interface Paginate<Item, Page> {
pages: Array<Paginate<Item, Page>>;
page: Page;
pageIndex: number;
itemIndex: number;
items: Item[];
numAllItems: number;
}
Paginate<Item>
is a paginated fragment of a list of items of type Item
.
It consists of the following properties:
pages
: the array of all of the paginated fragments.page
: thePage
object corresponding to this paginated fragment.pageIndex
: the index of this fragment (starting from 0).itemIndex
: the index of the first item of this fragment in the given list of items.items
: the array of items in this fragment.numAllItems
: the number of all of the given items.
AssetModule
interface AssetModule {
default: string;
}
AssetModule
is the type of modules representing an asset.
Such modules must have a default export of type string
, which is the
path of the asset.
MainModule
interface MainModule {
main: (context: Context) => Awaitable<Module>
}
This is the type of modules having the main
function of Minissg.
See Minissg's document for details of main
.
Content
and Module
They are identical to Minissg's Content
and Module
type.
See Minissg's document for details.
Delay
Delay
is a promise that can be used with React Suspense.
See @minissg/async for details.
Class Methods
Page.create(options, args...) => Page
declare class Page {
static create<
Load,
Base extends Page<unknown, Base> = PageRec<unknown, PageRec>,
This extends Base = Base,
Args extends unknown[] = []
>(
this: {
new (...args: Args): This;
Base: abstract new (...args: never) => Base;
},
arg: PagesArg<Load, This> | LoadArg<Load, This>,
...args: Args
): This;
}
interface PagesArg<Load, This> {
pages: Pairs<string | RelPath, Loader<This, Load> | MainModule, This>;
substitutePath?: ((path: string) => Awaitable<string>) | Null;
assets?: Pairs<string, LoadAsset | string | Null, This> | Null;
url?: URL | string | Null;
parsePath?: ((this: This, path: string) => Awaitable<ParsePath>) | Null;
paginatePath?: ((this: This, index: number) => Awaitable<RelPath>) | Null;
render?: ((this: This, loaded: Load) => Awaitable<Content>) | Null;
}
interface LoadArg<Load, This> {
load: Loader<This, Load>;
url?: URL | string | Null;
parsePath?: ((this: This, path: string) => Awaitable<ParsePath>) | Null;
paginatePath?: ((this: This, index: number) => Awaitable<RelPath>) | Null;
render?: ((this: This, loaded: Load) => Awaitable<Content>) | Null;
}
type Null = null | undefined;
type Loader<This, Load> = (page: This) => Awaitable<Load | MainModule>;
Page.create
creates a new Page
object with its contents.
The options
argument specifies the contents and customizations.
The args
arguments are passed to constructor of Page
class, which does
not do anything by default and can be defined by creating a subclass.
The options
object must have one of the following properties:
pages
of typePairs
. Its key must be eitherstring
orRelPath
. Its value must be either a function returningobject
,Page
, orMainModule
.load
of function returningobject
,Page
,MainModule
, or promise of one of them.
They are exclusive: pages
is ignored if load
is specified, and vice versa.
The options
may have one of the following optional properties:
substitutePath
of function taking astring
and returning either astring
orPromise<string>
.assets
of typePairs
. Its key must bestring
. Its value must be either astring
or function returningAssetModule
orPromise<AssetModule>
. This can be used only withpages
property.url
of type eitherURL
orstring
.parsePath
method taking astring
and returning aParsePath
orPromise<ParsePath>
.render
method taking astring
and returning aContent
orPromise<Content>
.
Page.paginate(options, args...) => Page
declare class Page {
static paginate<
Item,
Load,
Base extends Page<unknown, Base> = PageRec<unknown, PageRec>,
This extends Base = Base,
Args extends unknown[] = []
>(
this: {
new (...args: Args): This;
Base: abstract new (...args: never) => Base;
},
arg: {
items: List<Item, This>;
load: (this: This, paginate: Paginate<Item, This>)
=> Awaitable<Load | MainModule>;
pageSize?: number | Null;
url?: URL | string | Null;
parsePath?: ((this: This, path: string) => Awaitable<ParsePath>) | Null;
paginatePath?: ((this: This, index: number) => Awaitable<RelPath>) | Null;
render?: ((this: This, loaded: Load) => Awaitable<Content>) | Null;
},
...args: Args
): This;
Page.paginate
creates a new Page
object with its contents by paginating
the given items.
Similarly to Page.create
, options
specifies the contents and args
are passed to constructor.
The options
object must have the following properties:
items
of typeList
. Its value may be arbitrary type.load
method that takesPaginate
and returns either anobject
,Page
,MainModule
, or promise of one of them.
The following are options:
pageSize
of integer. Its default is 10.paginatePath
method taking anumber
and returning aRelPath
orPromise<RelPath>
.url
,parsePath
, andrender
can be specified similarly toPage.create
.
Customization
The following methods can be overriden by either
specifying the corresponding options in Page.create
,
overwriting Page
object properties, or
creating a subclass of Page
.
Page.prototype.parsePath(fileName) => Awaitable<ParsePath>
This method translates a relative file path into ParsePath
, which
consists of three optional properties moduleName
, stem
, and variant
of type string
.
type ParsePath = Omit<Partial<RelPath>, 'fileName'>;
From the combination of fileName
and ParsePath
, a RelPath
is
generated.
Page.prototype.paginatePath(index) => Awaitable<RelPath>
This mehtod translates the index of a paginated fragment into a RelPath
.
Page.prototype.render(object) => Awaitable<Content>
This method transforms object
into a Content
, which is the content
of a webpage to be generated.
The argument object
is the object returned from the function given to
Page.create
or Page.paginate
through their pages
and load
option.
Page.Base
Base
is a constructor of the base class whose instances constitutes a
page tree.
When a Page object searches for its child node in the page tree,
the first object that is instance of Base
is regarded as the child.
Instance Methods
Page.prototype.moduleName => Delay<string>
Returns the URL path to this page.
Page.prototype.stem => Delay<string>
Returns the stem of URL path of this page.
Page.prototype.variant => Delay<string>
Returns the set of variants of this page.
Page.prototype.fileName => Delay<string>
Returns the source file name of this page.
Page.prototype.url => Delay<URL>
Returns the full URL of this page.
Page.prototype.parent => Delay<Page | undefined>
Returns the parent node of this page in the page tree.
Page.prototype.root => Delay<Page>
Return the root node in the page tree.
Page.prototype.loadThis() => Delay<object | undefined>
Loads the content object associated to this page.
Page.prototype.load() => Delay<object>
Searches for the content object associated to the path of this page.
Page.prototype.children() => Delay<Array<[RelPath, Page]>>
Returns the immediate children of this page.
Page.prototype.findByModuleName(path) => Delay<Page | undefined>
Searches for a page of the given relative path by its module name.
Page.prototype.findByFileName(path) => Delay<Page | undefined>
Searches for a page of the given relative path by its source file name.
Page.prototype.find(path) => Delay<Page | undefined>
Try findByModuleName
and findByFileName
in this order.
Page.prototype.findByStem(path) => Delay<Set<Page>>
Searches for all pages having the given stem path.
Page.prototype.variants() => Delay<Set<Base>>
Searches for all pages having the same stem path as this page.
License
MIT