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

@krutoo/showcase

v0.0.1

Published

Build tool agnostic Storybook alternative

Downloads

25

Readme

Showcase

Simple library for creating websites with examples of how your web oriented code works.

It is build tool agnostic alternative of Storybook.

Currently only React is supported.

MDX also supported as a story module.

Installation

npm add @krutoo/showcase

Usage

First of all you need to create your "story modules" - modules with example of usage of your library.

For example you can store all story modules in ./stories/ folder of your project.

A typical story module looks like this:

// ./stories/components/button/primary.jsx
import { Button } from 'my-ui-lib/button';

// export of meta needed for creating docs page with all stories
export const meta = {
  // "title" is the name of this example
  title: 'Simple example of Button',

  // roughly speaking "category" is the path in menu in docs page
  category: 'Components/Button',
};

export default function () {
  return (
    <>
      <Button onClick={() => alert('My button works!')}>Do something</Button>
    </>
  );
}

Next step is creating two entrypoints - for "sandbox" and for "showcase".

Sandbox entrypoint

Sandbox is the HTML page with result of selected story module.

Create sandbox entrypoint in your project, for example in ./src/sandbox.jsx:

// React bootstrap code
import { createRoot } from 'react-dom/client';

// util for validate story-modules
import { filterValidStories } from '@krutoo/showcase/runtime';

// React component for showing current story
import { SandboxApp } from '@krutoo/showcase/runtime-sandbox';

// "stories entrypoint" (this is an alias, more on that later)
import foundStories from '#found-stories';

// render your current story to the root element
createRoot(document.getElementById('root')).render(
  <SandboxApp stories={filterValidStories(foundStories).validStories} />,
);

Showcase entrypoint

Showcase is the HTML page with UI to find and display any of your story modules.

This page contains simple menu with all grouped stories and will render selected story in iframe.

Create showcase entrypoint in your project, for example in ./src/showcase.jsx:

// React bootstrap code
import { createRoot } from 'react-dom/client';

// util for validate story-modules
import { filterValidStories } from '@krutoo/showcase/runtime';

// React component for showing documentation with all stories
import { ShowcaseApp } from '@krutoo/showcase/runtime-showcase';

// "stories entrypoint" (this is an alias, more on that later)
import foundStories from '#found-stories';

// import styles bundle
import '@krutoo/showcase/runtime-showcase/styles.css';

// render documentation app to the root element
createRoot(document.getElementById('root')).render(
  <ShowcaseApp
    title='My UI Library'
    logoSrc='public/my-logo.svg'
    headerLinks={[
      {
        name: 'GitHub',
        href: 'https://github.com/my-team/my-ui-lib',
      },
      {
        name: 'Figma',
        href: 'https://www.figma.com/my-design-guides',
      },
    ]}
    stories={filterValidStories(foundStories).validStories}
  />,
);

Next step is configure your build tool...

Build with Webpack/Rspack

// webpack.config.js or rspack.config.js

const storiesConfig = {
  // where stories entrypoint will be emitted
  filename: './.generated/entries.js',

  // glob patter for find all story modules
  storiesGlob: './stories/**/*.story.{mdx,tsx}',

  // root dir of all story modules
  storiesRootDir: './stories/',

  // how sources of modules will be imported (it is not required for Vite by default)
  // but in Rspack it is required to disable other loaders by add leading "!"
  rawImport: mod => ({ importPath: `!${mod.importPath}?raw` }),
};

// emit stories entrypoint
await emitStoriesEntrypoint(storiesConfig);

// watch for changes in stories folder to update entrypoint (optional, suitable for local development)
if (isWatchOrServe) {
  watchStories(storiesConfig);
}

export default {
  entry: {
    sandbox: 'src/sandbox.jsx',
    showcase: 'src/showcase.jsx',
  },
  resolve: {
    alias: {
      '#found-stories': path.resolve(import.meta.dirname, storiesConfig.filename),
    },
  },
  module: {
    rules: [
      // since above we set "rawImport" option we need this rule
      // details: https://webpack.js.org/guides/asset-modules/#replacing-inline-loader-syntax
      // details: https://www.rspack.dev/guide/features/asset-module#replacing-raw-loader-with-type-assetsource
      {
        resourceQuery: /raw/,
        type: 'asset/source',
      },

      // ...your other rules
    ],
  },
  plugins: [
    // you need to emit "index.html" for showcase (for example by HtmlWebpackPlugin or HtmlRspackPlugin)
    // you also need to emit "sandbox.html" because ShowcaseApp is references it
  ],

  // ...your other config
};

Build with Vite

With Vite you need to configure it like this:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'node:path';
import { emitStoriesEntrypoint } from '@krutoo/showcase/build';

const storiesConfig = {
  filename: './.generated/entries.js',
  storiesGlob: './stories/**/*.story.{mdx,tsx}',
  storiesRootDir: './stories/',
};

export default defineConfig(async () => {
  await emitStoriesEntrypoint(storiesConfig).catch(console.error);

  return {
    build: {
      rollupOptions: {
        input: {
          main: path.resolve(process.cwd(), 'index.html'),
          sandbox: path.resolve(process.cwd(), 'sandbox/index.html'),
        },
      },
    },
    resolve: {
      alias: {
        '#found-stories': path.resolve(process.cwd(), '.generated/entries.js'),
      },
    },
    plugins: [react()],
  };
});

You also need to provide special option to ShowcaseApp:

<ShowcaseApp defineStoryUrl={story => `sandbox/?path=${story.pathname}`} />

To Do

  • Ability of localization
  • Search field of stories in menu
  • unit tests & e2e tests
  • working examples in repo (with Webpack, Rspack, Vite...)
  • ...