Saltearse al contenido

Inicio Rápido + Frontend Next.JS

next_js_frontend.png

Puedes ver una demo de esta plantilla:

Puedes cambiar los datos en la demo y ver las actualizaciones, pero se reinicia cada hora.

Obtén una plantilla de frontend con vistas CRUD de muestra que incluyen:

  • Integración con Firebase y FireCMS. Reutiliza componentes tanto en el frontend como en el panel de administración.
  • Vista previa en tiempo real: ve cómo los cambios en el CMS se reflejarán en el sitio web, usando exactamente el mismo código.
  • Interfaz implementada con tailwindcss y componentes Radix UI.
  • Opciones de filtrado avanzadas
  • Obtención de datos al desplazarse.
  • Almacenamiento del estado de filtros en la URL.

Esta plantilla es extremadamente fácil de personalizar según tus necesidades.

La forma más sencilla de usar FireCMS con Next.js es usar la plantilla de inicio de FireCMS PRO. Esta plantilla incluye un proyecto Next.js con FireCMS ya configurado.

Puedes crear un nuevo proyecto usando la plantilla PRO de FireCMS ejecutando:

npx create-firecms-app

o

yarn create firecms-app

y selecciona la plantilla FireCMS PRO con frontend Next.js.

Luego sigue las instrucciones en pantalla para crear tu proyecto.

El código que se generará para ti es un proyecto Next.JS dividido en 3 partes:

  • Una instancia de FireCMS para gestionar tus datos.
  • Una aplicación frontend que implementa funcionalidad CRUD para una colección de productos, así como una vista de blog.
  • Una carpeta común con componentes compartidos.

Puedes usar FireCMS con Next.js. FireCMS es una biblioteca de React, por lo que puedes usarla con cualquier framework de React.

En el caso de Next.js, estás limitado a ejecutar FireCMS en el lado del cliente, ya que Next.js no admite el renderizado del lado del servidor de algunos de los componentes de React utilizados por FireCMS.

Construyamos una aplicación usando FireCMS y Next.js, con el app router configurado para delegar todas las rutas que comienzan con /cms a FireCMS.

Empieza creando tu proyecto Next.js:

npx create-next-app@latest

Selecciona:

  • TypeScript como lenguaje
  • ESLint como linter
  • Tailwind CSS como framework CSS
  • src como directorio raíz
  • Sí al prompt del app router
  • Sí para personalizar el alias de importación predeterminado (opcional)

Luego vamos a instalar FireCMS PRO. Ten en cuenta que no añadiremos todos los plugins como el editor de colecciones o la mejora de datos, pero puedes añadirlos según sea necesario.

Instala FireCMS y sus dependencias:

yarn add firebase@^10 @firecms/core@^3.0.0-beta @firecms/firebase@^3.0.0-beta react-router@^6 react-router-dom@^6 @tailwindcss/typography typeface-rubik @fontsource/jetbrains-mono

Ahora vamos a importar la configuración de tailwind de FireCMS. Añade el preset de FireCMS en tailwind.config.js, así como las rutas de contenido al código fuente de FireCMS, para que se incluyan las clases de tailwind correctas.

import fireCMSConfig from "@firecms/ui/tailwind.config.js";
import type { Config } from "tailwindcss";
const config: Config = {
presets: [fireCMSConfig],
content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
"./src/cms/**/*.{js,ts,jsx,tsx,mdx}",
"./node_modules/@firecms/**/*.{js,ts,jsx,tsx}"
]
};
export default config;

Preferimos deshabilitar yarn pnp para este proyecto. Puedes hacerlo creando el archivo .yarnrc en la raíz de tu proyecto con el siguiente contenido:

nodeLinker: node-modules

Next.js usa un enrutador basado en archivos. En esta guía, crearemos la aplicación FireCMS en la ruta /cms, pero puedes personalizar esto según tus necesidades.

FireCMS usa react-router, por lo que necesitamos configurar Next.js para delegar todas las rutas que comienzan con /cms a FireCMS.

En nuestra carpeta app, creamos una carpeta llamada cms y dentro de ella otra llamada [[...path]]. Esto coincidirá con cualquier ruta que comience con /cms.

Luego crea el archivo cms/[[...path]]/page.tsx con el siguiente contenido:

Si no estás ejecutando FireCMS en la ruta raíz de tu aplicación, necesitas establecer la prop basePath a la ruta donde lo estás ejecutando. En este caso, lo ejecutamos en /cms.

"use client";
import { FireCMSApp } from "@/cms/FireCMSApp";
import { FireCMSRouter } from "@firecms/core";
export default function CMS() {
return <FireCMSRouter basePath={"/cms"}>
<FireCMSApp/>
</FireCMSRouter>;
}

Ahora vamos a crear los componentes de FireCMS. Crea el archivo ./src/cms/FireCMSApp.tsx con el siguiente contenido. Recuerda reemplazar firebaseConfig con tu propia configuración de Firebase.

"use client";
import React, { useCallback } from "react";
import "./index.css";
import "typeface-rubik";
import "@fontsource/jetbrains-mono";
import {
AppBar,
buildCollection,
CircularProgressCenter,
Drawer,
FireCMS,
ModeControllerProvider,
NavigationRoutes,
Scaffold,
SideDialogs,
SnackbarProvider,
useBuildLocalConfigurationPersistence,
useBuildModeController,
useBuildNavigationController,
useValidateAuthenticator
} from "@firecms/core";
import {
FirebaseAuthController,
FirebaseLoginView,
FirebaseSignInProvider,
useFirebaseAuthController,
useFirebaseStorageSource,
useFirestoreDelegate,
useInitialiseFirebase,
} from "@firecms/firebase";
import { useImportPlugin } from "@firecms/data_import";
import { useExportPlugin } from "@firecms/data_export";
import { useBuildUserManagement, userManagementAdminViews, useUserManagementPlugin } from "@firecms/user_management";
import { useFirestoreCollectionsConfigController } from "@firecms/collection_editor_firebase";
import { mergeCollections, useCollectionEditorPlugin } from "@firecms/collection_editor";
//TODO: replace with your own Firebase config
export const firebaseConfig = {
//...
};
const categories = {
fiction: "Fiction",
drama: "Drama",
"fantasy-fiction": "Fantasy fiction",
history: "History",
religion: "Religion",
"self-help": "Self-Help",
"comics-graphic-novels": "Comics & Graphic Novels",
"juvenile-fiction": "Juvenile Fiction",
philosophy: "Philosophy",
fantasy: "Fantasy",
education: "Education",
science: "Science",
medical: "Medical",
cooking: "Cooking",
travel: "Travel"
};
const booksCollection = buildCollection({
name: "Books",
singularName: "Book",
id: "books",
path: "books",
icon: "MenuBook",
group: "Content",
textSearchEnabled: true,
description: "Example of a books collection that allows data enhancement through the use of the **OpenAI plugin**",
properties: {
title: {
name: "Title",
validation: { required: true },
dataType: "string"
},
authors: {
name: "Authors",
dataType: "string"
},
description: {
name: "Description",
dataType: "string",
multiline: true
},
spanish_description: {
name: "Spanish description",
dataType: "string",
multiline: true
},
thumbnail: {
name: "Thumbnail",
dataType: "string",
url: "image"
},
category: {
name: "Category",
dataType: "string",
enumValues: categories
},
tags: {
name: "Tags",
dataType: "array",
of: {
dataType: "string"
}
},
published_year: {
name: "Published Year",
dataType: "number",
validation: {
integer: true,
min: 0
}
},
num_pages: {
name: "Num pages",
dataType: "number"
},
created_at: {
name: "Created at",
dataType: "date",
autoValue: "on_create"
}
}
});
export function FireCMSApp() {
const {
firebaseApp,
firebaseConfigLoading,
configError
} = useInitialiseFirebase({
firebaseConfig
});
// Controller used to manage the dark or light color mode
const modeController = useBuildModeController();
const signInOptions: FirebaseSignInProvider[] = ["google.com"];
// Controller for saving some user preferences locally.
const userConfigPersistence = useBuildLocalConfigurationPersistence();
// Delegate used for fetching and saving data in Firestore
const firestoreDelegate = useFirestoreDelegate({
firebaseApp
});
// Controller used for saving and fetching files in storage
const storageSource = useFirebaseStorageSource({
firebaseApp
});
const collectionConfigController = useFirestoreCollectionsConfigController({
firebaseApp
});
// controller in charge of user management
const userManagement = useBuildUserManagement({
dataSourceDelegate: firestoreDelegate,
});
// Controller for managing authentication
const authController: FirebaseAuthController = useFirebaseAuthController({
firebaseApp,
signInOptions,
loading: userManagement.loading,
defineRolesFor: userManagement.defineRolesFor
});
const {
authLoading,
canAccessMainView,
notAllowedError
} = useValidateAuthenticator({
disabled: userManagement.loading,
authenticator: userManagement.authenticator,
authController,
// authenticator: myAuthenticator,
dataSourceDelegate: firestoreDelegate,
storageSource
});
const collectionsBuilder = useCallback(() => {
const collections = [
booksCollection,
// Your collections here
];
return mergeCollections(collections, collectionConfigController.collections ?? []);
}, [collectionConfigController.collections]);
const navigationController = useBuildNavigationController({
basePath: "/",
collections: collectionsBuilder,
collectionPermissions: userManagement.collectionPermissions,
adminViews: userManagementAdminViews,
authController,
dataSourceDelegate: firestoreDelegate
});
const userManagementPlugin = useUserManagementPlugin({ userManagement });
const importPlugin = useImportPlugin();
const exportPlugin = useExportPlugin();
const collectionEditorPlugin = useCollectionEditorPlugin({
collectionConfigController
});
if (firebaseConfigLoading || !firebaseApp) {
return <><CircularProgressCenter/></>;
}
if (configError) {
return <>{configError}</>;
}
return (
<SnackbarProvider>
<ModeControllerProvider value={modeController}>
<FireCMS
navigationController={navigationController}
authController={authController}
userConfigPersistence={userConfigPersistence}
dataSourceDelegate={firestoreDelegate}
storageSource={storageSource}
plugins={[importPlugin, exportPlugin, userManagementPlugin, collectionEditorPlugin]}
>
{({
context,
loading
}) => {
if (loading || authLoading) {
return <CircularProgressCenter size={"large"}/>;
}
if (!canAccessMainView) {
return <FirebaseLoginView authController={authController}
firebaseApp={firebaseApp}
signInOptions={signInOptions}
notAllowedError={notAllowedError}/>;
}
return <Scaffold
autoOpenDrawer={false}>
<AppBar title={"My demo app"}/>
<Drawer/>
<NavigationRoutes/>
<SideDialogs/>
</Scaffold>;
}}
</FireCMS>
</ModeControllerProvider>
</SnackbarProvider>
);
}

Importar los estilos predeterminados de FireCMS

Sección titulada «Importar los estilos predeterminados de FireCMS»

Crea un archivo llamado index.css en la carpeta ./src/cms con el siguiente contenido:

@import "@firecms/ui/index.css";
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--color-primary: #0070F4;
--color-secondary: #FF5B79;
}
a {
@apply text-blue-600 dark:text-blue-400 dark:hover:text-blue-600 hover:text-blue-800
}

Luego simplemente ejecuta:

yarn dev

y navega a http://localhost:3000/cms para ver tu aplicación FireCMS funcionando.

  • Las imágenes se cargan de forma diferente en Next.js. Obtienes un StaticImageData en lugar de la URL de la imagen (como en vite). Puedes usarlo en los componentes de FireCMS que esperan una URL usando la propiedad src:
import logo from "./logo.png";
<FirebaseLoginView
logo={logo.src}/>