Snippets Collections
FROM node:16-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install

# Rebuild the source code only when needed
FROM node:16-alpine AS builder
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN rm -f next.config.js
COPY ./next.config.local.js ./next.config.js
RUN rm -f .env.production && mv .env.local .env.production
RUN npm run build

# Production image, copy all the files and run next
FROM node:16-alpine AS runner

RUN apk --update --no-cache --virtual build-dependencies add \
  nginx

RUN npm install -g pm2

WORKDIR /app

ENV NODE_ENV production
ENV APP_ENV local
ENV NEXT_TELEMETRY_DISABLED 1

COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/pages ./pages
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/ecosystem.config.js ./ecosystem.config.js
# RUN cd /app/data/en-gb/products && cp me-888-marathon-ultra.json me-888-marathon-ultra-oth.json

COPY docker/nginx.conf /etc/nginx/nginx.conf

COPY docker/entrypoint.sh /usr/local/bin/entrypoint
RUN chmod +x /usr/local/bin/entrypoint

ENTRYPOINT [ "entrypoint" ]

CMD ["nginx"]


# Create a file app/docker/entrypoint.sh
# ------------------------------------------
#!/bin/sh

set -e

# pm2-docker --max-memory-restart 300M --deep-monitoring start "npm start" & nginx

pm2-runtime ecosystem.config.js & nginx


## Create a file in app/ecosystem.config.js

module.exports = {
  apps: [
    {
      name: "app",
      cwd: "/app",
      script: "node_modules/next/dist/bin/next",
      args: "start",
      max_memory_restart: "900M"
    }
  ]
};
import PlausibleProvider from "next-plausible";

function MyApp({ Component, pageProps }) {
  return 
  	<PlausibleProvider domain="<Your domain>">
  		<Component {...pageProps} />
  	</PlausibleProvider>
}

export default MyApp
import Document, {Html, Head, Main, NextScript} from 'next/document'

class MyDocument extends Document {
    render() {
        return (
            <Html>
                <Head>
                    <base href="/"></base>
                    <script async defer data-domain="<your-domain.com>" src="https://plausible.io/js/plausible.js"></script>

                </Head>
                <body>
                <Main/>
                <NextScript/>
                </body>
            </Html>
        )
    }
}

export default MyDocument
import client, { previewClient } from "./sanity";

const getUniquePosts = (posts) => {
  const slugs = new Set();
  return posts.filter((post) => {
    if (slugs.has(post.slug)) {
      return false;
    } else {
      slugs.add(post.slug);
      return true;
    }
  });
};

const postFields = `
  _id,
  name,
  title,
  'date': publishedAt,
  excerpt,
  'slug': slug.current,
  'coverImage': mainImage.asset->url,
  'author': author->{name, 'picture': image.asset->url},
`;

const getClient = (preview) => (preview ? previewClient : client);

export async function getPreviewPostBySlug(slug) {
  const data = await getClient(true).fetch(
    `*[_type == "post" && slug.current == $slug] | order(dpublishedAtate desc){
      ${postFields}
      body
    }`,
    { slug }
  );
  return data[0];
}

export async function getAllPostsWithSlug() {
  const data = await client.fetch(`*[_type == "post"]{ 'slug': slug.current }`);
  return data;
}

export async function getAllPostsForHome(preview) {
  const results = await getClient(preview)
    .fetch(`*[_type == "post"] | order(date desc, _updatedAt desc){
      ${postFields}
    }`);
  return getUniquePosts(results);
}

/* Relación Post-Author */
export async function getPostAndAuthors() {
  const data = await client.fetch(
    `*[_type == "post"]{title, publishedAt,'author': *[_type == "author" && _id == ^.author._ref && genre== 'comedia']{genre,name, 'picture': image.asset->url} }`
  );

  return data;
}

export async function getPostAndMorePosts(slug, preview) {
  const curClient = getClient(preview);
  const [post, morePosts] = await Promise.all([
    curClient
      .fetch(
        `*[_type == "post" && slug.current == $slug] | order(_updatedAt desc) {
        ${postFields}
        body,
        'comments': *[_type == "comment" && post._ref == ^._id]{name, text, _createdAt}
      }`,
        { slug }
      )
      .then((res) => res?.[0]),
    curClient.fetch(
      `*[_type == "post" && slug.current != $slug] | order(publishedAt desc, _updatedAt desc){
        ${postFields}
        body,
      }[0...2]`,
      { slug }
    ),
  ]);
  return { post, morePosts: getUniquePosts(morePosts) };
}
import styles from "../styles/Home.module.css";
//import imageUrlBuilder from "@sanity/image-url";
import { useState, useEffect } from "react";
import { getPostAndAuthors } from "../lib/api";

export default function Home({ posts }) {
  const [mappedPosts, setMappedPosts] = useState([]);
  console.log("mappedPosts2: ", mappedPosts);
  /*  console.log(
    "mappedPosts: ",
    mappedPosts.map((p, index) => console.log(p[index]))
  );
 */
  useEffect(() => {
    if (posts.length) {
      setMappedPosts(
        posts.map((p) => {
          return {
            ...p,
          };
        })
      );
    } else {
      setMappedPosts([]);
    }
  }, [posts]);

  return (
    <div>
      <div>
        <h3>Recent Posts:</h3>
        {/* Sin  _id == ^.author._ref no te va a hacer la relaciòn */}
        {/* 
          `*[_type == "post"]{
            title, 
            publishedAt,
            'author': *[_type == "author" && _id == ^.author._ref && genre== 'comedia']{
              genre,name, 'picture': image.asset->url} 
            }` 
        */}
        {/* Out:
        [
  {
    "author": [
      {
        "genre": "comedia",
        "name": "Cezar",
        "picture": "https://cdn.sanity.io/images/9w4ss8xn/production/48ef72edee2dd89a71e272beea5721e40281d5a0-340x317.jpg"
      }
    ],
    "publishedAt": "2022-05-05T02:37:00.000Z",
    "title": "Cuentos"
  },
  {
    "author": [
      {
        "genre": "comedia",
        "name": "Cezar",
        "picture": "https://cdn.sanity.io/images/9w4ss8xn/production/48ef72edee2dd89a71e272beea5721e40281d5a0-340x317.jpg"
      }
    ],
    "publishedAt": "2022-05-06T02:36:00.000Z",
    "title": "Tormenta"
  },
  {
    "author": [],
    "publishedAt": "2022-05-04T02:38:00.000Z",
    "title": "Rios del Desierto"
  }
]
           
        */}
        <div>
          {mappedPosts.map((p, index) => (
            <div className={styles.post} key={index}>
              <h4>{p.author.length > 0 ? p.title : null}</h4>
              {p.author.map((a, index) => (
                <p key={index}>{a.name}</p>
              ))}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

export const getServerSideProps = async () => {
  const posts = await getPostAndAuthors();
  return {
    props: {
      posts,
    },
  };
};

/* export async function getStaticPaths() {
  const allPosts = await getAllPostsWithSlug();
  return {
    paths:
      allPosts?.map((post) => ({
        params: {
          slug: post.slug,
        },
      })) || [],
    fallback: true,
  };
} */
import Head from "next/head";
import styles from "../styles/Home.module.css";
import { Toolbar } from "../components/toolbar";
import imageUrlBuilder from "@sanity/image-url";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";

export default function Home({ posts, authors }) {
  const router = useRouter();
  const [mappedPosts, setMappedPosts] = useState([]);
  const [mappedAuthors, setMappedAuthors] = useState([]);
  console.log(mappedAuthors);
  console.log("mappedPosts: ", mappedPosts);

  useEffect(() => {
    if (posts.length && authors.length) {
      const imgBuilder = imageUrlBuilder({
        projectId: "9w4ss8xn",
        dataset: "production",
      });

      setMappedPosts(
        posts.map((p) => {
          return {
            ...p,
            mainImage: imgBuilder.image(p.mainImage).width(500).height(250),
          };
        })
      );
      setMappedAuthors(
        authors.map((a) => {
          return {
            ...a,
            image: imgBuilder.image(a.image).width(100).height(100),
          };
        })
      );
    } else {
      setMappedPosts([]);
    }
  }, [posts, authors]);

  return (
    <div>
      <Toolbar />
      <div className={styles.main}>
        <h1>Welcome To My Blog</h1>

        <h3>Recent Posts:</h3>

        <div className={styles.feed}>
          {mappedPosts.length ? (
            mappedPosts.map((p, index) => (
              <div key={index} className={styles.post}>
                <div
                  onClick={() => router.push(`/post/${p.slug.current}`)}
                  key={index}
                  className={styles.post}
                >
                  <h3>{p.title}</h3>
                  <img className={styles.mainImage} src={p.mainImage} />
                </div>
                {mappedAuthors
                  .filter((a) => a._id === p.author._ref)
                  .map((a, index) => (
                    <div key={index}>
                      <img src={a.image} />
                      <h4>{a.name}</h4>
                    </div>
                  ))}
              </div>
            ))
          ) : (
            <>No Posts Yet</>
          )}
        </div>
      </div>
    </div>
  );
}

export const getServerSideProps = async (pageContext) => {
  const query = encodeURIComponent('*[ _type == "post" ]');
  const qauthors = encodeURIComponent('*[ _type == "author" ]');
  const url = `https://9w4ss8xn.api.sanity.io/v1/data/query/production?query=${query}`;
  const urlauthors = `https://9w4ss8xn.api.sanity.io/v1/data/query/production?query=${qauthors}`;
  const result = await fetch(url).then((res) => res.json());
  const resultauthors = await fetch(urlauthors).then((res) => res.json());

  if (
    !result.result ||
    !result.result.length ||
    !resultauthors.result ||
    !resultauthors.result.length
  ) {
    return {
      props: {
        posts: [],
        authors: [],
      },
    };
  } else {
    return {
      props: {
        posts: result.result,
        authors: resultauthors.result,
      },
    };
  }
};

Save snippets that work with our extensions

Available in the Chrome Web Store Get Firefox Add-on Get VS Code extension