ライブラリ / App Layout

App Layout

SPAアプリケーションで使用されるHTMLレイアウトジェネレーター。

@gravity-ui/app-layout · npm package CI

インストール

npm install --save-dev @gravity-ui/app-layout

使用方法

express を使用する場合:

import express from 'express';
import {createRenderFunction} from '@gravity-ui/app-layout';

const app = express();

const renderLayout = createRenderFunction();

app.get('/', function (req, res) {
  res.send(
    renderLayout({
      // RenderParams
      title: 'ホーム',
      bodyContent: {
        root: 'こんにちは、世界!',
      },
    }),
  );
});

app.listen(3000);

ここで

interface RenderParams<Data, Plugins> {
  // JSON互換の任意のデータ。ページ上の window.__DATA__ に設定されます。
  data?: Data;
  // ファビコン
  icon?: Icon;
  // タグに設定される nonce
  nonce?: string;
  // base タグの属性
  base?: Base;

  // 一般的なオプション
  // ページのタイトル
  title: string;
  // ページの言語。html タグに設定されます。
  lang?: string;
  isMobile?: boolean;

  // html 属性
  htmlAttributes?: string;
  // ヘッダータグの内容
  // meta タグ
  meta?: Meta[];
  // link タグ
  links?: Link[];
  // script タグ
  scripts?: Script[];
  // style タグ
  styleSheets?: Stylesheet[];
  // インラインコードを含む script タグ
  inlineScripts?: string[];
  // インラインスタイルを含む style タグ
  inlineStyleSheets?: string[];

  // body タグの内容
  bodyContent?: {
    // body タグのクラス名
    className?: string;
    // body 属性
    attributes?: string;
    // root div タグの前の body の内容
    beforeRoot?: string;
    // id="root" の div タグの内部 HTML コンテンツ
    root?: string;
    // root div タグの後の body の内容
    afterRoot?: string;
  };
  // プラグインオプション
  pluginsOptions?: Partial<PluginsOptions<Plugins>>;
}

Base

base タグを記述します:

interface Base {
  href?: string;
  target?: HTMLBaseElement['target'];
}

例:

renderLayout({
  title: 'ホーム',
  base: {target: '_top'},
});

次のようにレンダリングされます:

<base target="_top" />

Meta

meta タグを記述します:

interface Meta {
  name: string;
  content: string;
}

例:

const meta = [
  {name: 'description', content: 'some text'},
  {name: 'robots', content: 'noindex'},
  {name: 'og:title', content: 'Some title'},
];

次のようにレンダリングされます:

<meta name="description" content="some text" />
<meta name="robots" content="noindex" />
<meta property="og:title" content="Some title" />

Icon

ページのファビコンを記述します:

interface Icon {
  type?: string;
  sizes?: string;
  href?: string;
}

デフォルト値は次のとおりです:

const icon = {
  type: 'image/png',
  sizes: '16x16',
  href: '/favicon.png',
};

link タグを記述します:

interface Link {
  as?: string;
  href: string;
  rel?: string;
  type?: string;
  sizes?: string;
  title?: HTMLLinkElement['title'];
  crossOrigin?: '' | 'anonymous' | 'use-credentials';
}

例:

const link = {
  href: 'myFont.woff2',
  rel: 'preload',
  as: 'font',
  type: 'font/woff2',
  crossOrigin: 'anonymous',
};

次のようにレンダリングされます:

<link href="myFont.woff2" rel="preload" as="font" type="font/woff2" crossorigin="anonymous" />

Scripts

プリロード付きスクリプトへのリンクを記述します:

interface Script {
  src: string;
  defer?: boolean;
  async?: boolean;
  crossOrigin?: '' | 'anonymous' | 'use-credentials';
  type?: 'importmap' | 'module' | string;
}

例:

const script = {
  src: 'url/to/script',
  defer: true,
  async: false,
  crossOrigin: 'anonymous',
};

次のようにレンダリングされます:

<link href="url/to/script" rel="preload" as="script" crossorigin="anonymous" />

<script src="url/to/script" defer="true" async="false" crossorigin="anonymous" nonce="..."></script>

Style sheets

スタイルへのリンクを記述します:

interface Stylesheet {
  href: string;
}

例:

const styleSheet = {
  href: 'url/to/stylesheet',
};

次のようにレンダリングされます:

<link href="url/to/stylesheet" rel="stylesheet" />

プラグイン

レンダリング関数はプラグインで拡張できます。プラグインはユーザー定義のレンダリングコンテンツを書き換えることができます。 プラグインは nameapply プロパティを持つオブジェクトです:

interface Plugin<Options = any, Name = string> {
  name: Name;
  apply: (params: {
    options: Options | undefined; // `pluginsOptions` パラメータで `renderLayout` 関数を通じて渡されます。
    commonOptions: CommonOptions;
    renderContent: RenderContent;
    /** @deprecated `renderContent.helpers` を使用してください */
    utils: RenderHelpers;
  }) => void;
}

interface CommonOptions {
  name: string;
  title: string;
  lang?: string;
  isMobile?: boolean;
}

export interface HeadContent {
  base?: Base;
  scripts: Script[];
  helpers: RenderHelpers;
  links: Link[];
  meta: Meta[];
  styleSheets: Stylesheet[];
  inlineStyleSheets: string[];
  inlineScripts: string[];
  title: string;
}

export interface BodyContent {
  attributes: Attributes;
  beforeRoot: string[];
  root?: string;
  afterRoot: string[];
}

export interface RenderContent extends HeadContent {
  htmlAttributes: Attributes;
  bodyContent: BodyContent;
}

export interface RenderHelpers {
  renderScript(script: Script): string;
  renderInlineScript(content: string): string;
  renderStyle(style: Stylesheet): string;
  renderInlineStyle(content: string): string;
  renderMeta(meta: Meta): string;
  renderLink(link: Link): string;
  attrs(obj: Attributes): string;
}

このパッケージにはいくつかのプラグインがあります:

Google Analytics

ページに Google Analytics カウンターを追加します。

使い方:

import {createRenderFunction, createGoogleAnalyticsPlugin} from '@gravity-ui/app-layout';

const renderLayout = createRenderFunction([createGoogleAnalyticsPlugin()]);

app.get((req, res) => {
  res.send(
    renderLayout({
      title: 'ホームページ',
      pluginsOptions: {
        googleAnalytics: {
          useBeaconTransport: true, // navigator.sendBeacon の使用を有効にします
          counter: {
            id: 'some id',
          },
        },
      },
    }),
  );
});

プラグインオプション:

interface GoogleAnalyticsCounter {
  id: string;
}

interface GoogleAnalyticsOptions {
  useBeaconTransport?: boolean;
  counter: GoogleAnalyticsCounter;
}

Yandex Metrika

ページに Yandex メトリカカウンターを追加します。

使い方:

import {createRenderFunction, createYandexMetrikaPlugin} from '@gravity-ui/app-layout';

const renderLayout = createRenderFunction([createYandexMetrikaPlugin()]);

app.get((req, res) => {
  res.send(
    renderLayout({
      title: 'ホームページ',
      pluginsOptions: {
        yandexMetrika: {
          counter: {
            id: 123123123,
            defer: true,
            clickmap: true,
            trackLinks: true,
            accurateTrackBounce: true,
          },
        },
      },
    }),
  );
});

プラグインオプション:

export type UserParams = {
  [x: string]: boolean | string | number | null | UserParams;
};

export interface MetrikaCounter {
  id: number;
  defer: boolean;
  clickmap: boolean;
  trackLinks: boolean;
  accurateTrackBounce: boolean | number;
  webvisor?: boolean;
  nonce?: string;
  encryptedExperiments?: string;
  triggerEvent?: boolean;
  trackHash?: boolean;
  ecommerce?: boolean | string;
  type?: number;
  userParams?: UserParams;
}

export type MetrikaOptions = {
  src?: string;
  counter: MetrikaCounter | MetrikaCounter[];
};

Layout

webpack アセットマニフェストファイルからスクリプトとスタイルを追加します。

使い方:

import {createRenderFunction, createLayoutPlugin} from '@gravity-ui/app-layout';

const renderLayout = createRenderFunction([
  createLayoutPlugin({manifest: 'path/to/assets-manifest.json', publicPath: '/build/'}),
]);

app.get((req, res) => {
  res.send(
    renderLayout({
      title: 'ホームページ',
      pluginsOptions: {
        layout: {
          name: 'home',
        },
      },
    }),
  );
});

プラグインオプション:

export interface LayoutOptions {
  name: string;
  prefix?: string;
}

@gravity-ui/uikit

body 属性を追加します。

使い方:

import {createRenderFunction, createUikitPlugin} from '@gravity-ui/app-layout';

const renderLayout = createRenderFunction([createUikitPlugin()]);

app.get((req, res) => {
  res.send(
    renderLayout({
      title: 'ホームページ',
      pluginsOptions: {
        uikit: {
          theme: 'dark',
          direction: 'ltr',
        },
      },
    }),
  );
});

プラグインオプション:

interface UikitPluginOptions {
  theme: string;
  direction?: 'ltr' | 'rtl';
}

Remote Versions

マイクロフロントエンドのバージョン情報をページに追加します。

このプラグインは、指定されたマイクロフロントエンドのバージョンを含むグローバルな window.__REMOTE_VERSIONS__ オブジェクトを作成します。これは、モジュールフェデレーションや同様のマイクロフロントエンドアーキテクチャが、ロードするリモートモジュールのバージョンを決定するために使用できます。

App Builder および moduleFederation.remotesRuntimeVersioning オプションと組み合わせて、対応するバージョンのリモートモジュールを自動的にロードするために使用できます。

使い方:

import {createRenderFunction, createRemoteVersionsPlugin} from '@gravity-ui/app-layout';

const renderLayout = createRenderFunction([createRemoteVersionsPlugin()]);

app.get((req, res) => {
  res.send(
    renderLayout({
      title: 'ホームページ',
      pluginsOptions: {
        remoteVersions: {
          header: '1.2.3',
          footer: '2.1.0',
          sidebar: '0.5.1',
        },
      },
    }),
  );
});

プラグインオプション:

type RemoteVersionsPluginOptions = Record<string, string>;

ヘルパー

すべてのプラグインを作成するためのヘルパーがあります。

import {createMiddleware, createDefaultPlugins} from '@gravity-ui/app-layout';

const renderLayout = createRenderFunction(
    createDefaultPlugins({layout: {manifest: 'path/to/assets-manifest.json'}})
);

app.get((req, res) => {
    res.send(renderLayout({
        title: 'ホームページ',
        pluginsOptions: {
            layout: {
                name: 'home'
            },
            googleAnalytics: {
                counter: {...}
            },
            yandexMetrika: {
                counter: {...}
            },
        },
    }));
})

代替の使い方

generateRenderContentrenderHeadContentrenderBodyContent のパーツレンダラーを HTML ストリーミング経由で使用します。

import express from 'express';
import htmlescape from 'htmlescape';
import {
  generateRenderContent,
  renderHeadContent,
  renderBodyContent,
  createDefaultPlugins,
} from '@gravity-ui/app-layout';

const app = express();

app.get('/', async function (req, res) {
  res.writeHead(200, {
    'Content-Type': 'text/html',
    'Transfer-Encoding': 'chunked',
  });

```markdown
# @gravity/uikit

このライブラリは、Reactアプリケーションのサーバーサイドレンダリング(SSR)を容易にするためのユーティリティを提供します。

## インストール

```bash
npm install @gravity/uikit
# または
yarn add @gravity/uikit

使用例

以下は、Express.jsアプリケーションでこのライブラリを使用して、基本的なSSRページをレンダリングする例です。

import express from 'express';
import { createDefaultPlugins, generateRenderContent, renderHeadContent, renderBodyContent } from '@gravity/uikit';
import htmlescape from 'htmlescape';

const app = express();

app.get('/', async (req, res) => {
  const plugins = createDefaultPlugins({ layout: { manifest: 'path/to/assets-manifest.json' } });

  const content = generateRenderContent(plugins, {
    title: 'ホーム',
  });

  const { htmlAttributes, helpers, bodyContent } = content;

  res.write(`
        <!DOCTYPE html>
        <html ${helpers.attrs({ ...htmlAttributes })}>
        <head>
            ${renderHeadContent(content)}
        </head>
        <body ${helpers.attrs(bodyContent.attributes)}>
            ${renderBodyContent(content)}
    `);

  const data = await getUserData();

  res.write(`
            ${content.renderHelpers.renderInlineScript(`
                window.__DATA__ = ${htmlescape(data)};
            `)}
        </body>
        </html>
    `);
  res.end();
});

app.listen(3000);

この例では、以下のことを行っています。

  1. createDefaultPlugins を使用して、SSRに必要なデフォルトのプラグインを作成します。layout.manifest は、アセットマニフェストファイルのパスを指定します。
  2. generateRenderContent を使用して、ページのレンダリングに必要なコンテンツを生成します。title はページのタイトルを設定します。
  3. 生成された content オブジェクトから htmlAttributeshelpersbodyContent を取得します。
  4. 基本的なHTML構造を構築し、helpers.attrs を使用して属性を適用します。
  5. renderHeadContent でヘッダー部分をレンダリングします。
  6. renderBodyContent でボディ部分をレンダリングします。
  7. getUserData で非同期にデータを取得します。
  8. content.renderHelpers.renderInlineScript を使用して、取得したデータをJavaScript変数 window.__DATA__ としてインラインスクリプトで埋め込みます。htmlescape は、データを安全にエスケープするために使用されます。
  9. レスポンスを終了します。

API

createDefaultPlugins(options)

SSRのためのデフォルトプラグインを作成します。

  • options:
    • layout:
      • manifest: アセットマニフェストファイルのパス (文字列)。

generateRenderContent(plugins, pageOptions)

ページのレンダリングに必要なコンテンツを生成します。

  • plugins: プラグインの配列。
  • pageOptions:
    • title: ページのタイトル (文字列)。
    • その他、プラグインが期待するオプション。

renderHeadContent(content)

HTMLの <head> セクションの内容をレンダリングします。

renderBodyContent(content)

HTMLの <body> セクションの内容をレンダリングします。

ライセンス

MITライセンスで提供されています。

ライブラリについて
スターでライブラリを応援
バージョン
2.4.0
最終更新日
07.04.2026
リポジトリ
github.com/gravity-ui/app-layout
ライセンス
MIT License
コントリビューター