@minissg/page
v2.0.2
Published
simple page organization management for Minissg
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/pageand 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_projectChange directory to the new directory and install all dependencies
by the npm command:
cd my_project
npm installThe following scripts are initially available:
npm run buildfor static site generation for production.npm run servefor preview of the build result.npm run devfor 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.globprovided by Vite, create aPageobject 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
urlparameter indicates the root URL of this website.pageshas the map from file names to dynamic import functions provided byimport.meta.glob.substitutePathremoves./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.mdxis associated with a webpage of URLfoo/bar/.Set
page.renderto a function indicating how to render a webpage component in a HTML file. The following example addsDOCTYPE,html, andbodytags tomodule.defaultcomponent and renders all of them bypages.jsx's renderer.import render from './pages.jsx?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
Pageobject dedicated to that MDX file throughprops.pageproperty.Export the root page through the
mainfunction:
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 Pages.
Page manages the following four kinds of paths:
moduleNameis the path of webpages. This is used to determine the URL of each webpage.stemidentifies a content of a webpage regardless of its variants, such as languages and formats.variantidentifies a variants of the content.fileNameis 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: thePageobject 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:
pagesof typePairs. Its key must be eitherstringorRelPath. Its value must be either a function returningobject,Page, orMainModule.loadof 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:
substitutePathof function taking astringand returning either astringorPromise<string>.assetsof typePairs. Its key must bestring. Its value must be either astringor function returningAssetModuleorPromise<AssetModule>. This can be used only withpagesproperty.urlof type eitherURLorstring.parsePathmethod taking astringand returning aParsePathorPromise<ParsePath>.rendermethod taking astringand returning aContentorPromise<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:
itemsof typeList. Its value may be arbitrary type.loadmethod that takesPaginateand returns either anobject,Page,MainModule, or promise of one of them.
The following are options:
pageSizeof integer. Its default is 10.paginatePathmethod taking anumberand returning aRelPathorPromise<RelPath>.url,parsePath, andrendercan 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
