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

eleventy-react

v0.5.2

Published

Use React components in Eleventy

Downloads

53

Readme

eleventy-react

Use React components in Eleventy.

If you want a lighter version, without eleventy dependency, try pequeno

Demo

https://eleventy-react.netlify.app/

Why

Eleventy is a great static site generator, but I don’t like template engines. They introduce a lot of custom syntax, and it’s almost impossibile to convert them to a component-based dev flow.

Installation

1. Clone or download the repository

git clone [email protected]:signalkuppe/eleventy-react.git eleventy-react

2. Go to the working directory

cd eleventy-react

3. Install the project dependencies

npm install

3. Run development mode

npm run dev

Build you site for deploy

npm run build

Features

Integration with data file and custom template data

just add a data export to your jsx file

import React from 'react';
import DefaultLayout from '../components/layout/Default';
import P from '../components/primitives/P';
import Span from '../components/primitives/Span';
import H1 from '../components/primitives/H1';

// custom template data
export const data = {
    name: 'John Doe',
};

export default function Index({ site, name }) {
    // site comes from site.js data file in _data
    const { title } = site;

    return (
        <DefaultLayout>
            <H1>{title}</H1>
            <P>
                This name is from custom template data: <Span bold>{name}</Span>
            </P>
        </DefaultLayout>
    );
}

Support for pagination: you can generate pages from data

import React from 'react';
import { slug } from './utils/user';
import DefaultLayout from '../components/layout/Default';
import H1 from '../components/primitives/H1';

/**
 * A template that renders a page for each user in the users collection
 */

export const data = {
    pagination: {
        data: 'users',
        size: 1,
        alias: 'user',
    },
    permalink: function (data) {
        return slug(data.user);
    },
};

export default function User({ site, user }) {
    return (
        <DefaultLayout>
            <H1>{user.name}</H1>
        </DefaultLayout>
    );
}

Support for markdown content

Write your content in markdown format, and use .jsx files as layouts. Print html markup with a custom withHtml HOC that uses our primitives styles

_includes/layouts/post.jsx

import React from 'react';
import DefaultLayout from '../../../components/layout/Default';
import Section from '../../../components/primitives/Section';
import Img from '../../../components/primitives/Img';
import Span from '../../../components/primitives/Span';
import VerticalSpace from '../../../components/ui/VerticalSpace';
import withHtml from '../../../components/hoc/withHtml';
import { postSlug } from '../../../components/features/posts/utils';

/**
 * A template that renders a page for each post in the post collection (_posts/*.md)
 */

const PostBodySection = withHtml(Section);

export const data = {
    permalink: function (data) {
        return postSlug(data.page);
    },
};

export default function Post(data) {
    const { title, content, cover, tags } = data;
    return (
        <DefaultLayout>
            <Img src={cover} alt={title} />
            <PostBodySection>{content}</PostBodySection>
            {tags?.length && (
                <>
                    <VerticalSpace />
                    {tags.map((tag, i) => (
                        <Span key={i} italic>
                            {tag}
                            {i < tags.length - 1 && ', '}
                        </Span>
                    ))}
                </>
            )}
        </DefaultLayout>
    );
}

Integration with styled components

styles are extracted and inserted into the <head> tag

import React from 'react';
import styled from 'styled-components';

const StyledText = styled.span`
    font-weight: ${(props) => {
        if (props.bold) {
            return 700;
        } else {
            return 400;
        }
    }};
`;

export default function Span({ children, ...props }) {
    return <StyledText {...props}>{children}</StyledText>;
}

Integration with storybook

Develop your UI in isolation adding stories for your components and run storybook with

npm run storybook

Build storybook inside eleventy’s _site folder

npm run build-storybook

stories are written in .mdx format

Some basic scaffolding included

basic ui/primitives/features components included to give an idea of the approach

Inline svg parser included

import and use inline svgs in your react components

Babel plugins included

  • @babel/plugin-proposal-optional-chaining

Dealing with client-side js

React is not included in the build, so you can use any js approach on the client. I think that adding hydration would go against Eleventy’s philosophy.

Developers like to write code in a component-fashioned way so there’s a helper to deal with client-side js code.

Say you have a component that need some vanilla client-side js logic and maybe an external library, like an accordion. Just add the <Script> component in you code like this

import React, { Fragment } from 'react';
import Dl from '../../primitives/Dl';
import Dt from '../../primitives/Dt';
import Dd from '../../primitives/Dd';
import Button from '../../primitives/Button';
import Script, { outputLibDir } from '../Script';
import client from './index.client.js';

export default function Accordion({ items }) {
    return (
        <>
            <Dl reset id="accordion">
                {items.map((item, i) => (
                    <Fragment key={i}>
                        <Dt>
                            <Button>{item.title}</Button>
                        </Dt>
                        <Dd>{item.description}</Dd>
                    </Fragment>
                ))}
            </Dl>
            <Script
                libs={[
                    {
                        js: `/${outputLibDir}/fisarmonica/src/fisarmonica.js`,
                        css: `/${outputLibDir}/fisarmonica/src/fisarmonica.css`,
                    },
                ]}
            >
                {client}
            </Script>
        </>
    );
}

With the libs param you can add as many libraries as you want, adding the required js and css files. Write you logic in a .client.js file in the component folder, import it and place it as a children of the <Script> component.

Styles and scripts will be extracted at build time and placed in the right place in the DOM. There is also a Storybook decorator that adds the client-side logic to stories

Be sure to pass the libs installed via npm to the output folder in the .eleventy.js config file.

// add this client side js lib to our otuput dir

eleventyConfig.addPassthroughCopy({
    'node_modules/fisarmonica': `${config.outputLibDir}/fisarmonica`,
});

Theme variables are exposed to the client

Sometimes you have to use your theme variables in client-side logic. A global THEME variable containing our styled-components settings is exposed to the client.

const THEME = {
    colors: {
        background: '#282c34',
        backgroundDark: '#20232a',
        primary: '#61dafb',
        white: 'white',
        grey: '#32363e',
    },
    type: {
        fontSans: '-apple-system, “Segoe UI”, “Roboto”',
        fontMono: 'source-code-pro, Menlo, Monaco, Consolas, monospace',
        leading: 1.4,
        root: '112.5%',
        base: '1rem',
        headingsBase: 2,
        scale: 1.333,
    },
};

TODO

  • reduce storybook bundle site for production build
  • test other eleventy’s features
  • use React components in _data files

Warnings

⚠️ very much a work in progress

Requires experimental features in Eleventy, specifically: Custom File Extension Handlers feature from Eleventy