npm package: @rei/nuxt-layout-module
Description: A Nuxt module that handles sourcing of layout components and global scripts
Latest version: 1.11.4

# @rei/nuxt-layout-module

A Nuxt 3 module for dynamically injecting REI’s universal layout components into your application—centralized, configurable, and performance-conscious.

You can read more about this module in [the Wiki](https://gitlab.com/rei/internal/product-engineering/alpine-fe/configuration-driven-rendering/nuxt-layout-module/-/wikis/home).

## GitLab Pages

View the prerendered (SSG) playground showcasing the layout module:

[https://nuxt-layout-module-cdc738.gitlab.io](https://nuxt-layout-module-cdc738.gitlab.io)

## Overview

`@rei/nuxt-layout-module` is a Nuxt 3 module designed to streamline layout integration across REI nuxt applications. It fetches layout fragments (markup, styles, and scripts) from a centralized REST API and injects them into the app through runtime components, ensuring brand consistency while enabling modular, independently deployable teams.

This module handles:

- Global header and navigation
- Universal promotional messaging
- Footer scripts and markup
- Associated external stylesheets and inline styles
- Asynchronous layout hydration via `useLayout()`

## Features

- **Composable Injection** – Inject layout fragments via provided components (`<LayoutHeader>`, `<LayoutPMB>`, etc.)
- **Pinia-Powered Cache** – Store raw layout data using Pinia for optimal reuse and control
- **Configurable** – Toggle features using `runtimeConfig.public` environment variables
- **Static or Dynamic Support** – Use static JSON layout files or fetch live data from REST endpoints
- **Lightweight & Pluggable** – Easy to integrate, no global side effects

## Installation

```bash
npm install @rei/nuxt-layout-module @pinia/nuxt
```

### Peer Dependencies

This module requires the following Nuxt module to be installed:

- `@pinia/nuxt`

## Nuxt Configuration

Add the following to your `nuxt.config.ts` to configure the layout module. These options can also be supplied via environment variables in production.

```ts
import type { ModuleOptions as LayoutModuleOptions } from '@rei/nuxt-layout-module';

const NuxtLayoutModuleConfig: LayoutModuleOptions = {
  enabled: process.env.REI_LAYOUT_ENABLED === 'true',
  staticEnabled: process.env.REI_LAYOUT_STATIC_ENABLED === 'true',
  staticForceFetch: process.env.REI_LAYOUT_STATIC_FORCE_FETCH === 'true',
  endpoints: {
    universal: process.env.CCS_UNIVERSAL_URL || '',
    global: process.env.CCS_GLOBAL_URL || '',
    footer: process.env.CCS_FOOTER_URL || '',
    promo: process.env.CCS_PROMO_URL || '',
  },
  gvc: {
    js: process.env.GVC_MODULE_URL || '',
    css: process.env.GVC_STYLESHEET_URL || '',
  },
};

export default defineNuxtConfig({
  modules: ['@pinia/nuxt', '@rei/nuxt-layout-module'],
  nuxtLayoutModule: NuxtLayoutModuleConfig,
});
```

## Usage

```vue
<template>
  <LayoutHeader v-if="nuxtLayoutModule.enabled" />
  <LayoutPMB v-if="nuxtLayoutModule.enabled" />

  <NuxtPage />

  <LayoutFooter v-if="nuxtLayoutModule.enabled" />
  <LayoutScripts v-if="nuxtLayoutModule.enabled" />
</template>

<script lang="ts" setup>
const {
  public: { nuxtLayoutModule },
} = useRuntimeConfig();

if (nuxtLayoutModule.enabled) {
  await useLayout();
  useLayoutStyles();
  useLayoutData();
}
</script>
```

### Notes

- Ensure that `nuxtLayoutModule.enabled` is correctly set in `runtimeConfig.public` or via environment variables.
- When `staticEnabled` is `true`, the static layout file (`layout-data.ts`) must exist at runtime. If it does not exist, the module will attempt to generate it automatically during development.
- If you are fetching from live APIs (`staticEnabled: false`), ensure your endpoints are available and returning valid component payloads.
- The provided layout components (`<LayoutHeader>`, `<LayoutPMB>`, etc.) will render nothing if the fetched layout fragments are empty.

## Static vs Live API Mode

This module supports two modes of fetching layout data:

- **Static Mode** (`staticEnabled: true`)

The module will fetch the layout fragments at build time (or during development) and generate a static module (`layout-data.ts` by default). On runtime, the module will read the static layout data instead of making live API calls.  
**During development**, this file will be auto-generated if it doesn't exist.  
**In production**, make sure to generate and commit the file beforehand, or include generation in a prebuild step.

- **Live API Mode** (`staticEnabled: false`)

The module will fetch the layout fragments dynamically at runtime from the configured API endpoints. This ensures the latest content is always used but requires reliable API availability during user visits.

You can control this behavior by setting the `REI_LAYOUT_STATIC_ENABLED` environment variable (or configuring `staticEnabled` in `runtimeConfig`) to `true` or `false`.

## Troubleshooting

- **My layout components render empty:**  
  Ensure the API endpoints are reachable and returning valid component payloads, or that the `layout-data.ts` file exists in static mode.

- **Build fails due to missing static file:**  
  Set `staticForceFetch: true` during development or manually generate the static file before your production build.

- **Runtime error accessing config:**  
  Confirm that all required environment variables are defined, especially the endpoint and GVC asset URLs.

- **Pinia store not available:**  
  Check that `@pinia/nuxt` is installed and listed before this module in your Nuxt config `modules` array.

## Development

This repository includes a `playground/` Nuxt application to facilitate local development and testing of the module.

### Preparing the Playground

Before starting development — especially after making structural changes to the module (such as adding files, exports, or modifying types) — you should prepare the playground environment:

```bash
npm run dev:prepare
```

This script will:

- Build a stub version of the module
- Prepare types and runtime files
- Set up the playground for hot reload development

Running `dev:prepare` ensures that any changes to the module’s runtime logic or typings are properly reflected inside the playground.

### Running the Playground

After preparing the environment, you can start the playground in development mode:

```bash
npm run dev
```

This will launch a Nuxt app that loads the module directly from the local source, allowing you to validate integration, configuration, and runtime behavior changes without needing to publish the module.