next-composition
    TypeScript icon, indicating that this package has built-in type declarations

    1.0.0 • Public • Published

    next-composition

    npm CI codecov

    Next.js utility for reusing getServerSideProps, getStaticProps and getInitialProps logics.

    How does it different from _middleware.js?

    Next.js introduces a feature called middleware since v12.x which allows you to handle shared server side logic in a single module.

    It's goal is kind of similar to next-composition: sharing common logic among multiple pages. However, since _middleware designed to be executed as edge function, it has some limitations such as it does not allow you to pass props to page components.

    next-composition is just a utility and it's entity is just a getServerSideProps and getStaticProps so you can use it just like other APIs.

    Install

    You can install it via npm

    npm install --save next-composition
    

    APIs

    composeServerSideProps(params): GetServerSideProps

    composeServerSideProps takes multiple getServerSideProps and composes them into a single function.

    • params.use - Array of getServerSideProps to compose. Object returned from them will be shallow merged and returned from it.

    • params.resolver (optional, default: x => x) - A callback function that takes composite props and returns interpolated props.

    import { composeServerSideProps } from 'next-composition';
    
    const withAccount: GetServerSideProps = async (ctx) => {
      const data = await fetch('/account');
      return { props: { account: data } };
    };
    
    const withPosts: GetServerSideProps = async (ctx) => {
      const data = await fetch('/posts');
      return { props: { posts: data } };
    };
    
    export const getServerSideProps = composeServerSideProps({
      use: [withAccount, withPosts],
      resolver: (props) => ({
        ...props,
        title: `${props.posts.length} posts - My blog`,
      }),
    });
    
    export default function Page(props) {
      // Results are available here
      const { account, posts } = props;
    }

    If any of the functions in the head return an object that contains either notFound or redirect, the first result will be prioritized.

    composeStaticProps(params): GetStaticProps

    composeStaticProps takes multiple getStaticProps functions and composes them into a single function. Behaves like composeServerSideProps but you can additionally specify revalidate.

    • params.use - Array of getStaticProps to compose. Object returned from them will be shallow merged and returned from it.

    • params.resolver (optional, default: x => x) - A callback function that takes composite props and returns interpolated props.

    • params.revalidate (optional, default: min) - Could be one of min max or number. If you specify numbers, it will be used as revalidate. If you specify min (or max), the minimal number from revalidate returned from use will be used.

    import { composeStaticProps } from 'next-composition';
    
    const withAccount: GetStaticProps = async (ctx) => {
      const data = await fetch('/account');
      return { props: { account: data }, revalidate: 60 };
    };
    
    const withPosts: GetStaticProps = async (ctx) => {
      const data = await fetch('/posts');
      return { props: { posts: data }, revalidate: 30 };
    };
    
    export const getStaticProps = composeStaticProps({
      use: [withAccount, withPosts],
      resolver: (props) => ({
        ...props,
        title: `${props.posts.length} posts - My blog`,
      }),
      revalidate: 'min', // `30` will be used in this case
    });
    
    export default function Page(props) {
      // Results are available here
      const { account, posts } = props;
    }

    composeInitialProps(params): GetInitialProps (for Next.js < 9.x)

    composeInitialProps takes multiple getInitialProps functions and composes them into a single function.

    • params.use - Array of getInitialProps to compose. Object returned from them will be shallow merged and returned from it.

    • params.resolver (optional, default: x => x) - A callback function that takes composite props and returns interpolated props.

    import { composeInitialProps } from 'next-composition';
    
    const withAccount = async (ctx) => {
      const data = await fetch('/account');
      return { account: data };
    };
    
    const withPosts = async (ctx) => {
      const data = await fetch('/posts');
      return { posts: data };
    };
    
    export default function Page(props) {
      // Results are available here
      const { account, posts } = props;
    }
    
    Page.getInitialProps = composeInitialProps({
      use: [withAccount, withPosts],
      resolver: (props) => ({
        ...props,
        title: `${props.posts.length} posts - My blog`,
      }),
    });

    How to handle 404 and redirect

    composeServerSideProps and composeStaticProps can handle redirects and not found in the same way as the Next.js API.

    Multiple functions can be specified in use even if one of the arguments returns a redirect, in which case the other results will be ignored.

    If more than one of the functions specified in use returns a redirect, the first one specified will be used in priority.

    const withAccount: GetServerSideProps = async (ctx) => {
      const data = await fetch('/account');
    
      // If no account found, redirect to the login page
      if (!data) {
        return {
          redirect: {
            destination: '/login',
          },
        };
      }
    
      return { props: { account: data } };
    };
    
    // If you pass withAccount to the composeServerSideProps,
    // other props will be ignored and redirects to the login page
    export const getStaticProps = composeServerSideProps({
      use: [withAccount, withPosts],
    });

    Keywords

    none

    Install

    npm i next-composition

    DownloadsWeekly Downloads

    5

    Version

    1.0.0

    License

    MIT

    Unpacked Size

    34.3 kB

    Total Files

    7

    Last publish

    Collaborators

    • neetshin