v 0.1.48

Understanding Ecopages Core

Before diving into the specifics of writing code for Ecopages, it's important to understand how the core of Ecopages works. This knowledge will help you make better decisions when structuring your project and writing your code.

Integration System

Ecopages uses a flexible integration system to extend its functionality. Each integration plugin can provide:

  1. Template extensions
  2. Custom loaders
  3. Build hooks

For example, the KitaJS integration might set up template extensions like this:

.setIncludesTemplates({
	head: 'head.kita.tsx',
	html: 'html.kita.tsx',
	seo: 'seo.kita.tsx',
})

This configuration tells Ecopages which files to use for specific parts of the page structure.

CSS Processing

By default, Ecopages uses plain css for styling. We currently provide a simple Postcss and Tailwind (v3) plugin that provides a powerful and flexible system for managing your styles. You can customize this in your eco.config.ts file:

const config = await new ConfigBuilder() 
	// ... other configurations
	.setProcessors([postcssProcessorPlugin()])
	.build();

Script and CSS Loading

Ecopages handles script and CSS loading efficiently by analyzing component dependencies.

Explicit Dependencies

To ensure that your components have the necessary scripts and styles, you must explicitly declare them in the component's config.dependencies property. This allows Ecopages to:

  1. Deduplicate: If multiple components share the same script, Ecopages only ships it once.
  2. Order: Dependencies are loaded in the correct order based on the component tree.
  3. Optimize: Only the code used on a specific page is sent to the browser.
import { BaseLayout } from '@/layouts/base-layout';
import { type EcoComponent, html } from '@ecopages/core';

const HomePage: EcoComponent = () => html`
  <div class="main-content">
    <h1>Welcome to Ecopages</h1>
  </div>
`;

HomePage.config = {
  dependencies: {
    // Scripts must be explicitly declared
    scripts: ['./home-page.script.ts'],
    // Stylesheets must be explicitly declared
    stylesheets: ['./home-page.css'],
    // Child components to crawl for their own dependencies
    components: [BaseLayout],
  },
};

[!NOTE] Ecopages does not automatically detect script files by name pattern. You must always include them in the dependencies.scripts array if you want them to be processed and included in the build.

Robots.txt Generation

Ecopages automatically generates a robots.txt file based on your configuration. You can customize this in your eco.config.ts file:

Loaders

Ecopages uses loaders to process your files. Each loader is responsible for processing a specific type of file.

In bun loaders are used to process your files. You can find more information about loaders in the bun documentation.

You can add it to your bunfig.toml file:

preload = ["@ecopages/bun-postcss-loader"]

Import CSS as String in JS Files

Ecopages provides a way to load CSS directly into your JavaScript files as strings using Bun's preload tools. This feature is available through the @ecopages/bun-postcss-loader package.

Import MDX as a Component

Ecopages allows you to import MDX files as components. This is useful for creating reusable content and components that can be used across your site.

This capability is provided by the MDX Integration, which automatically handles MDX transformations using @mdx-js/esbuild internally.

import Component from '@/components/mdx-component';

const MyPage = () => html`${Component()}`;

Project Structure

Ecopages expects a specific project structure:


my-project/
├── src/
│ ├── pages/
│ ├── layouts/
│ ├── components/
│ └── includes/
├── public/
├── eco.config.ts
└── package.json

This structure helps Ecopages efficiently process and build your site.

Runtime Origin and API Requests

When fetching data in getStaticPaths or getStaticProps, Ecopages provides different approaches. For most cases, calling your data functions directly is recommended for better performance and reliability.

Direct Function Calls (Recommended)

For the best performance during static generation, call your data layer functions directly:

import { getAllBlogPosts, getBlogPost } from '@/data/blog';

export const getStaticPaths: GetStaticPaths = async () => {
	const posts = getAllBlogPosts();

	return {
		paths: posts.map(post => ({
			params: { slug: post.slug }
		}))
	};
};

export const getStaticProps: GetStaticProps = async ({ pathname }) => {
	const slug = pathname.params.slug as string;
	const post = getBlogPost(slug);

	if (!post) {
		throw new Error(`Post not found: ${slug}`);
	}

	return { props: { post } };
};

HTTP Requests to External APIs

For external data sources, HTTP requests are necessary:

export const getStaticPaths: GetStaticPaths = async () => {
	const response = await fetch('https://external-api.com/posts');
	const posts = await response.json();
	
	return {
		paths: posts.map(post => ({
			params: { slug: post.slug }
		}))
	};
};

Runtime Support

Currently, Ecopages is designed to work exclusively with the Bun runtime. While the architecture supports multiple runtime adapters, at the moment only the Bun adapter is implemented and maintained.

This means you'll need to:

Server and API Handlers

Ecopages provides a simple and intuitive way to create API endpoints and handle server-side logic. You can find more details in the Server API documentation.

import { EcopagesApp } from '@ecopages/core/adapters/bun/create-app';
import appConfig from './eco.config';

const app = new EcopagesApp({ appConfig });

app.get('/api/hello', async () => {
	return new Response(JSON.stringify({ message: 'Hello world!' }));
});

await app.start();

Additional Features