mirror of
https://github.com/facebook/docusaurus.git
synced 2025-08-06 02:08:55 +02:00
feat(v2): allow users to specify a custom ssr HTML template (#3387)
* feat(v2): allow users to specify a custom ssr HTML template * docs(v2): add ssrTemplate property to docusaurus.config.js page
This commit is contained in:
parent
9857f7b2b5
commit
3ace60043b
6 changed files with 60 additions and 8 deletions
2
packages/docusaurus-types/src/index.d.ts
vendored
2
packages/docusaurus-types/src/index.d.ts
vendored
|
@ -41,6 +41,7 @@ export interface DocusaurusConfig {
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
)[];
|
)[];
|
||||||
|
ssrTemplate?: string;
|
||||||
stylesheets?: (
|
stylesheets?: (
|
||||||
| string
|
| string
|
||||||
| {
|
| {
|
||||||
|
@ -110,6 +111,7 @@ export interface LoadContext {
|
||||||
siteConfig: DocusaurusConfig;
|
siteConfig: DocusaurusConfig;
|
||||||
outDir: string;
|
outDir: string;
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
|
ssrTemplate?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InjectedHtmlTags {
|
export interface InjectedHtmlTags {
|
||||||
|
|
|
@ -26,19 +26,18 @@ import {
|
||||||
createStatefulLinksCollector,
|
createStatefulLinksCollector,
|
||||||
ProvideLinksCollector,
|
ProvideLinksCollector,
|
||||||
} from './LinksCollector';
|
} from './LinksCollector';
|
||||||
import ssrTemplate from './templates/ssr.html.template';
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-restricted-imports
|
// eslint-disable-next-line no-restricted-imports
|
||||||
import {memoize} from 'lodash';
|
import {memoize} from 'lodash';
|
||||||
|
|
||||||
const getCompiledSSRTemplate = memoize(() => {
|
const getCompiledSSRTemplate = memoize((template) => {
|
||||||
return eta.compile(ssrTemplate.trim(), {
|
return eta.compile(template.trim(), {
|
||||||
rmWhitespace: true,
|
rmWhitespace: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function renderSSRTemplate(data) {
|
function renderSSRTemplate(ssrTemplate, data) {
|
||||||
const compiled = getCompiledSSRTemplate();
|
const compiled = getCompiledSSRTemplate(ssrTemplate);
|
||||||
return compiled(data, eta.defaultConfig);
|
return compiled(data, eta.defaultConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +50,7 @@ export default async function render(locals) {
|
||||||
postBodyTags,
|
postBodyTags,
|
||||||
onLinksCollected,
|
onLinksCollected,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
|
ssrTemplate,
|
||||||
} = locals;
|
} = locals;
|
||||||
const location = routesLocation[locals.path];
|
const location = routesLocation[locals.path];
|
||||||
await preload(routes, location);
|
await preload(routes, location);
|
||||||
|
@ -90,7 +90,7 @@ export default async function render(locals) {
|
||||||
const stylesheets = (bundles.css || []).map((b) => b.file);
|
const stylesheets = (bundles.css || []).map((b) => b.file);
|
||||||
const scripts = (bundles.js || []).map((b) => b.file);
|
const scripts = (bundles.js || []).map((b) => b.file);
|
||||||
|
|
||||||
const renderedHtml = renderSSRTemplate({
|
const renderedHtml = renderSSRTemplate(ssrTemplate, {
|
||||||
appHtml,
|
appHtml,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
htmlAttributes: htmlAttributes || '',
|
htmlAttributes: htmlAttributes || '',
|
||||||
|
|
|
@ -81,6 +81,7 @@ const ConfigSchema = Joi.object({
|
||||||
// See https://github.com/facebook/docusaurus/issues/3378
|
// See https://github.com/facebook/docusaurus/issues/3378
|
||||||
.unknown(),
|
.unknown(),
|
||||||
),
|
),
|
||||||
|
ssrTemplate: Joi.string(),
|
||||||
stylesheets: Joi.array().items(
|
stylesheets: Joi.array().items(
|
||||||
Joi.string(),
|
Joi.string(),
|
||||||
Joi.object({
|
Joi.object({
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import {generate} from '@docusaurus/utils';
|
import {generate} from '@docusaurus/utils';
|
||||||
import path, {join} from 'path';
|
import path, {join} from 'path';
|
||||||
|
import ssrDefaultTemplate from '../client/templates/ssr.html.template';
|
||||||
import {
|
import {
|
||||||
BUILD_DIR_NAME,
|
BUILD_DIR_NAME,
|
||||||
CONFIG_FILE_NAME,
|
CONFIG_FILE_NAME,
|
||||||
|
@ -43,7 +44,7 @@ export function loadContext(
|
||||||
const outDir = customOutDir
|
const outDir = customOutDir
|
||||||
? path.resolve(customOutDir)
|
? path.resolve(customOutDir)
|
||||||
: path.resolve(siteDir, BUILD_DIR_NAME);
|
: path.resolve(siteDir, BUILD_DIR_NAME);
|
||||||
const {baseUrl} = siteConfig;
|
const {baseUrl, ssrTemplate} = siteConfig;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
siteDir,
|
siteDir,
|
||||||
|
@ -51,6 +52,7 @@ export function loadContext(
|
||||||
siteConfig,
|
siteConfig,
|
||||||
outDir,
|
outDir,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
|
ssrTemplate,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +74,7 @@ export async function load(
|
||||||
): Promise<Props> {
|
): Promise<Props> {
|
||||||
// Context.
|
// Context.
|
||||||
const context: LoadContext = loadContext(siteDir, customOutDir);
|
const context: LoadContext = loadContext(siteDir, customOutDir);
|
||||||
const {generatedFilesDir, siteConfig, outDir, baseUrl} = context;
|
const {generatedFilesDir, siteConfig, outDir, baseUrl, ssrTemplate} = context;
|
||||||
|
|
||||||
// Plugins.
|
// Plugins.
|
||||||
const pluginConfigs: PluginConfig[] = loadPluginConfigs(context);
|
const pluginConfigs: PluginConfig[] = loadPluginConfigs(context);
|
||||||
|
@ -237,6 +239,7 @@ ${Object.keys(registry)
|
||||||
headTags,
|
headTags,
|
||||||
preBodyTags,
|
preBodyTags,
|
||||||
postBodyTags,
|
postBodyTags,
|
||||||
|
ssrTemplate: ssrTemplate || ssrDefaultTemplate,
|
||||||
};
|
};
|
||||||
|
|
||||||
return props;
|
return props;
|
||||||
|
|
|
@ -31,6 +31,7 @@ export default function createServerConfig({
|
||||||
headTags,
|
headTags,
|
||||||
preBodyTags,
|
preBodyTags,
|
||||||
postBodyTags,
|
postBodyTags,
|
||||||
|
ssrTemplate,
|
||||||
} = props;
|
} = props;
|
||||||
const config = createBaseConfig(props, true, minify);
|
const config = createBaseConfig(props, true, minify);
|
||||||
|
|
||||||
|
@ -70,6 +71,7 @@ export default function createServerConfig({
|
||||||
preBodyTags,
|
preBodyTags,
|
||||||
postBodyTags,
|
postBodyTags,
|
||||||
onLinksCollected,
|
onLinksCollected,
|
||||||
|
ssrTemplate,
|
||||||
},
|
},
|
||||||
paths: ssgPaths,
|
paths: ssgPaths,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -306,6 +306,50 @@ module.exports = {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `ssrTemplate`
|
||||||
|
|
||||||
|
An HTML template that will be used to render your application. This can be used to set custom attributes on the `body` tags, additional `meta` tags, customize the `viewport`, etc. Please note that Docusaurus will rely on the template to be correctly structured in order to function properly, once you do customize it, you will have to make sure that your template is compliant with the requirements from `upstream`.
|
||||||
|
|
||||||
|
- Type: `string`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```js title="docusaurus.config.js"
|
||||||
|
module.exports = {
|
||||||
|
ssrTemplate: `<!DOCTYPE html>
|
||||||
|
<html <%~ it.htmlAttributes %>>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=0.86, maximum-scale=3.0, minimum-scale=0.86">
|
||||||
|
<meta name="generator" content="Docusaurus v<%= it.version %>">
|
||||||
|
<%~ it.headTags %>
|
||||||
|
<% it.metaAttributes.forEach((metaAttribute) => { %>
|
||||||
|
<%~ metaAttribute %>
|
||||||
|
<% }); %>
|
||||||
|
<% it.stylesheets.forEach((stylesheet) => { %>
|
||||||
|
<link rel="stylesheet" type="text/css" href="<%= it.baseUrl %><%= stylesheet %>" />
|
||||||
|
<% }); %>
|
||||||
|
<% it.scripts.forEach((script) => { %>
|
||||||
|
<link rel="preload" href="<%= it.baseUrl %><%= script %>" as="script">
|
||||||
|
<% }); %>
|
||||||
|
</head>
|
||||||
|
<body <%~ it.bodyAttributes %> itemscope="" itemtype="http://schema.org/Organization">
|
||||||
|
<%~ it.preBodyTags %>
|
||||||
|
<div id="__docusaurus">
|
||||||
|
<%~ it.appHtml %>
|
||||||
|
</div>
|
||||||
|
<div id="outside-docusaurus">
|
||||||
|
<span>Custom markup</span>
|
||||||
|
</div>
|
||||||
|
<% it.scripts.forEach((script) => { %>
|
||||||
|
<script type="text/javascript" src="<%= it.baseUrl %><%= script %>"></script>
|
||||||
|
<% }); %>
|
||||||
|
<%~ it.postBodyTags %>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
### `stylesheets`
|
### `stylesheets`
|
||||||
|
|
||||||
An array of CSS sources to load. The values can be either strings or plain objects of attribute-value maps. The `<link>` tags will be inserted in the HTML `<head>`.
|
An array of CSS sources to load. The values can be either strings or plain objects of attribute-value maps. The `<link>` tags will be inserted in the HTML `<head>`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue