v 0.1.15

Creating Pages in Ecopages

Pages are the core of your Ecopages project. They represent the different routes and content of your website. In this guide, we'll explore how to create pages using the ghtml integration.

Basic Page Structure

A typical page in Ecopages using the ghtml integration consists of a single TypeScript file. Here's a basic example:

import { BaseLayout } from '@/layouts/base-layout';
import { type EcoComponent, type GetMetadata, html } from '@ecopages/core';

export const getMetadata: GetMetadata = () => ({
    title: 'Home page',
    description: 'This is the homepage of the website',
    image: 'public/assets/images/default-og.png',
    keywords: ['typescript', 'framework', 'static'],
});

const HomePage: EcoComponent = () => html`${BaseLayout({
    class: 'main-content',
    children: html`
      <h1>Ecopages</h1>
      <p>Welcome to my Ecopages website!</p>
    `,
  })}`;

HomePage.config = {
    importMeta: import.meta,
    dependencies: {
      components: [BaseLayout],
    },
};

export default HomePage;

Let's break down the key elements of a page:

  1. Imports: Import necessary components and types from @ecopages/core and your project files.

  2. Metadata: Use the getMetadata function to define page-specific metadata.

  3. Page Component: Create your main page component as an EcoComponent.

  4. HTML Template: Use the html template literal to define your page's structure.

  5. Config: Always include the config object with importMeta and any necessary dependencies.

  6. Export: Export your page component as the default export.

Using Components in Pages

To use components in your pages, import them and include them in your HTML template:

import { RadiantCounter } from '@/components/radiant-counter';
import { BaseLayout } from '@/layouts/base-layout';
import { type EcoComponent, type GetMetadata, html, resolveComponentsScripts, removeComponentsScripts } from '@ecopages/core';

const HomePage: EcoComponent = () => html`${BaseLayout({
    class: 'main-content',
    children: html`
      <h1>Ecopages</h1>
      <scripts-injector
        on:interaction="mouseenter,focusin"
        scripts="${resolveComponentsScripts([RadiantCounter])}"
      >
        !${RadiantCounter({
          count: 5,
        })}
      </scripts-injector>
    `,
  })}`;

HomePage.config = {
    importMeta: import.meta,
    dependencies: {
      components: [BaseLayout, ...removeComponentsScripts([RadiantCounter])],
    },
};

You're absolutely right. Adding information about getMetadata, getStaticProps, and getStaticPaths is crucial for understanding how to work with data in Ecopages. I'll create a new section called "Working with Data" to cover these important concepts. Here's the addition we can make to the existing content:

Working with Data

Ecopages provides several powerful functions for working with data in your pages:

getMetadata

The getMetadata function allows you to define page-specific metadata. Please note that you can set defaultMetadata in the config to avoid repeating yourself. This is useful for SEO and social sharing:

import { type GetMetadata } from '@ecopages/core';

export const getMetadata: GetMetadata = () => ({
  title: 'My Page Title',
  description: 'A description of my page',
  image: 'path/to/og-image.jpg',
  keywords: ['ecopages', 'static site', 'typescript'],
});

getStaticProps

getStaticProps is used to fetch data at build time. This is ideal for data that do not depend on page parameters.

import { type GetStaticProps } from '@ecopages/core';

export const getStaticProps: GetStaticProps = async () => {
  const data = await fetchSomeData();
  return {
    props: {
      data,
    },
  };
};

const MyPage: EcoComponent<{ data: any }> = ({ data }) => html`
  <div>
    <h1>My Page</h1>
    <p>${data.someField}</p>
  </div>
`;

getStaticPaths

For dynamic routes, getStaticPaths is used to specify which paths will be pre-rendered at build time:

export const getMetadata: GetMetadata<BlogPostProps> = async ({ props: { title, slug } }) => {
  return {
    title,
    description: `This is a blog post with the slug ${slug}`,
  };
};

export const getStaticProps: GetStaticProps = async ({ params }) => {
  const data = await fetchDataForSlug(params.slug);
  return {
    props: {
      data,
    },
  };
};

export const getStaticPaths: GetStaticPaths = async () => {
 const paths = await fetchAvailablePaths();
  return {
    paths: paths.map(path => ({ params: { slug: path } })),
  };
};

export const getStaticProps: GetStaticProps<BlogPostProps> = async ({ pathname }) => {
  const data = await fetchDataForSlug(params.slug);
  return {
    props: {
      ...data,
    },
  };
};

const DynamicPage: EcoComponent<BlogPostProps> = (props) => html`
  <div>
    <h1>${props.title}</h1>
    <p>${props.content}</p>
  </div>
`;

Lazy Loading Components

Ecopages provides powerful tools for lazy loading components, which can significantly improve your site's performance.

The main tool for this is the custom component scripts-injector, which allows you to load scripts only when needed. Two key functions for this are resolveComponentsScripts and removeComponentScripts.

resolveComponentsScripts

This function is used to resolve the scripts associated with components for lazy loading. It's typically used with the scripts-injector component.

resolveComponentsScripts takes an array of components and returns a string of resolved script paths. This allows the scripts-injector to load these scripts only when needed (in this case, on mouse enter or focus).

removeComponentScripts

As you can see in the example above, removeComponentScripts is used to remove scripts from the initial page load, further optimizing performance:

This function removes the scripts associated with the specified components from the initial page load. The scripts will be loaded later when needed, typically through a scripts-injector.

By using these functions, you can create pages that are lightweight on initial load but still provide rich interactivity when needed. This approach is particularly useful for components that are not immediately visible or not used by all users.

Remember to always balance performance optimization with user experience. Some critical components might need to be loaded immediately, while others can be safely deferred.