npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@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:

  1. Combined with import.meta.glob provided by Vite, create a Page object of a set of webpage component modules by Page.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 by import.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 applying substitutePath. As a result, for example, a given module pages/foo/bar.mdx is associated with a webpage of URL foo/bar/.

  2. Set page.render to a function indicating how to render a webpage component in a HTML file. The following example adds DOCTYPE, html, and body tags to module.default component and renders all of them by virtual: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 through props.page property.

  3. 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 Pages.

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: the Page 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 type Pairs. Its key must be either string or RelPath. Its value must be either a function returning object, Page, or MainModule.
  • load of function returning object, 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 a string and returning either a string or Promise<string>.
  • assets of type Pairs. Its key must be string. Its value must be either a string or function returning AssetModule or Promise<AssetModule>. This can be used only with pages property.
  • url of type either URL or string.
  • parsePath method taking a string and returning a ParsePath or Promise<ParsePath>.
  • render method taking a string and returning a Content or Promise<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 type List. Its value may be arbitrary type.
  • load method that takes Paginate and returns either an object, Page, MainModule, or promise of one of them.

The following are options:

  • pageSize of integer. Its default is 10.
  • paginatePath method taking a number and returning a RelPath or Promise<RelPath>.
  • url, parsePath, and render can be specified similarly to Page.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