Files
Your Name 38652eb9b5 Initalize
2026-05-03 12:12:57 -04:00

239 lines
10 KiB
JavaScript

// mods
import {existsSync} from 'node:fs';
import {dirname, resolve} from 'node:path';
import {fileURLToPath} from 'node:url';
import isEmpty from 'lodash-es/isEmpty.js';
import merge from 'lodash-es/merge.js';
import Debug from 'debug';
import {defineConfigWithTheme} from 'vitepress';
// utils
import {default as createContainer} from './utils/create-container.js';
import {default as getBaseUrl} from './utils/get-base-url.js';
import {default as getContributors} from './utils/get-contributors.js';
import {default as getGaHeaders} from './utils/get-ga-headers.js';
import {default as getHubspotHeaders} from './utils/get-hubspot-headers.js';
import {default as getTags} from './utils/get-tags.js';
import {default as normalizeMVB} from './utils/normalize-mvb.js';
import {default as parseLayouts} from './utils/parse-layouts.js';
import {default as traverseUp} from './utils/traverse-up.js';
// node/plugins
import {default as addContributors} from './node/add-contributors.js';
import {default as addLayoutsPlugin} from './vite/add-layout-components-plugin.js';
import {default as addMetadata} from './node/add-metadata.js';
import {default as augmentAuthors} from './node/augment-authors.js';
import {default as buildCollections} from './node/build-collections.js';
import {default as normalizeFrontmatter} from './node/normalize-frontmatter.js';
import {default as normalizeLegacyFrontmatter} from './node/normalize-legacy-frontmatter.js';
import {default as parseCollections} from './node/parse-collections.js';
import {default as generateFeeds} from './node/generate-feeds.js';
import {default as generateRobotsTxt} from './node/generate-robots.js';
import {default as linkOverridePlugin} from './markdown/link-override-plugin.js';
import {tabsMarkdownPlugin} from 'vitepress-plugin-tabs';
import {default as tabsMarkdownOverridePlugin} from './markdown/tabs-override-plugin.js';
import {default as urlLoader} from './vite/url-loader.js';
// vitepress patches
import {default as patchVPMenuColumnsPlugin} from './vite/patch-vp-menu-columns-plugin.js';
import {default as patchVPUseSidebarControl} from './vite/patch-vp-use-sidebar-control.js';
// configsets
import {default as baseConfig} from './config/defaults.js';
import {default as lando3BaseConfig} from './config/landov3.js';
import {default as lando4BaseConfig} from './config/landov4.js';
export async function defineConfig(userConfig = {}, defaults = {}) {
const debug = Debug('@lando/vpltheme'); // eslint-disable-line
// theme root
userConfig.themeRoot = dirname(fileURLToPath(import.meta.url));
// prefer landov4 if defaults not set
if (isEmpty(userConfig.defaults) && userConfig.landoDocs === 4) {
debug('no user defaults set, using lando v4 defaults');
defaults = lando4BaseConfig(userConfig);
// ditto but for lando v3
} else if (isEmpty(userConfig.defaults) && userConfig.landoDocs === 3) {
debug('no user defaults set, using lando v3 defaults');
defaults = lando3BaseConfig(userConfig);
// Same as above but for legacy things
} else if (isEmpty(userConfig.defaults) && (userConfig.landoDocs || userConfig.lando)) {
debug('no user defaults set, using lando v3 defaults');
defaults = lando3BaseConfig(userConfig);
// Otherwise if we are empty then just set to defaults
} else if (isEmpty(userConfig.defaults)) {
debug('no user defaults set, using theme defaults');
defaults = baseConfig(userConfig);
}
// merge config sources
const config = merge({}, defaults, userConfig);
// log
debug('incoming vitepress configuration %O', config);
// normalize mvb stuff as needed
if (config?.themeConfig.multiVersionBuild) {
config.themeConfig.multiVersionBuild = normalizeMVB({...config.themeConfig.multiVersionBuild, siteBase: config.base});
debug('normalized mvb config to %o', config.themeConfig.multiVersionBuild);
}
// get git root if its not defined
if (!config.gitRoot) {
const gitDir = traverseUp(['.git'], resolve(config.themeRoot, '..')).find(dir => existsSync(dir));
config.gitRoot = gitDir ? resolve(gitDir, '..') : config.themeRoot;
debug('automatically set gitRoot to %o', config.gitRoot);
}
// If we want to show the shared navbar then lets add it to the begining of the navbar
if (Array.isArray(config?.themeConfig?.sharedNav)) {
config.themeConfig.nav = config.themeConfig.sharedNav.concat(config.themeConfig.nav);
debug('prepended shared navbar to user specified navbar with %o', config.themeConfig.sharedNav);
}
// explode
const {buildEnd, markdown, themeConfig, transformPageData, sitemap, vite} = config;
// normalize id
if (typeof themeConfig.internalDomain === 'string') themeConfig.internalDomain = [themeConfig.internalDomain];
if (typeof themeConfig.internalDomains === 'string') themeConfig.internalDomains = [themeConfig.internalDomains];
themeConfig.internalDomains = [...themeConfig.internalDomain, ...themeConfig.internalDomains];
// normalize contribs
if (themeConfig.contributors === true) themeConfig.contributors = baseConfig.themeConfig.contributors;
// normalize layouts
if (Object.keys(themeConfig.layouts).length > 0) themeConfig.layouts = parseLayouts(themeConfig.layouts);
// normalize sitemap
if (!sitemap.hostname && themeConfig?.autometa?.canonicalUrl) sitemap.hostname = themeConfig.autometa.canonicalUrl;
// attempt to set a baseurl
if (!config.baseUrl) config.baseUrl = getBaseUrl() ?? config.basethemeConfig?.autometa?.canonicalUrl ?? sitemap.hostname;
// extract
const {containers, contributors, ga, hubspot, internalDomains, layouts} = themeConfig;
// debug here so it doesnt print like 10 times
for (const [name, opts] of Object.entries(containers)) {
debug('added custom markdown container %o with config %o', name, opts);
}
// vite aliases
vite.resolve.alias.push(...[
{find: /^.*\/VPAlgoliaSearchBox\.vue$/, replacement: fileURLToPath(new URL('./components/VPLAlgoliaSearchBox.vue', import.meta.url))},
{find: /^.*\/VPDocFooter\.vue$/, replacement: fileURLToPath(new URL('./components/VPLDocFooter.vue', import.meta.url))},
{find: /^.*\/VPLink\.vue$/, replacement: fileURLToPath(new URL('./components/VPLLink.vue', import.meta.url))},
{find: /^.*\/VPMenuGroup\.vue$/, replacement: fileURLToPath(new URL('./components/VPLMenuGroup.vue', import.meta.url))},
{find: /^.*\/VPNavBarMenuGroup\.vue$/, replacement: fileURLToPath(new URL('./components/VPLNavBarMenuGroup.vue', import.meta.url))},
{find: /^.*\/VPTeamMembersItem\.vue$/, replacement: fileURLToPath(new URL('./components/VPLTeamMembersItem.vue', import.meta.url))},
]);
// plguins
vite.plugins.push(...[
addLayoutsPlugin(layouts, {debug: debug.extend('vite-plugin')}),
patchVPMenuColumnsPlugin({debug: debug.extend('vitepress-patcher')}),
patchVPUseSidebarControl({debug: debug.extend('vitepress-patcher')}),
urlLoader({debug: debug.extend('url-loader')}),
]);
// deps
vite.optimizeDeps.exclude.push('fsevents', '@lando/vitepress-theme-default-plus');
// ssr
vite.ssr.noExternal.push('@lando/vitepress-theme-default-plus');
// debug
debug('added vite resolver config %O', vite.resolve);
debug('added vite plugins %O', vite.plugins);
debug('added vite optimizeDeps config %O', vite.optimizeDeps);
debug('added vite ssr config %O', vite.ssr);
// markdown plugins
markdown.config = md => {
// add custom markdown containers, including tabs
for (const [name, opts] of Object.entries(containers)) {
md.use(...createContainer(name, opts, md));
}
// add tabs plugin
md.use(tabsMarkdownPlugin);
// override the tabs container so we can inject styling
md.use(tabsMarkdownOverridePlugin, {debug: debug.extend('markdown-plugin')});
// override the link plugin so it can handle internal domains
md.use(linkOverridePlugin, {
target: '_blank',
rel: 'noreferrer',
...markdown.externalLinks,
},
config.base,
internalDomains,
debug.extend('markdown-plugin'),
);
};
// add google analytics
if (ga !== false && ga.id) {
config.head.push(...getGaHeaders(ga.id));
debug('added google analytics/gtm tracking with %o', ga);
}
// add hubspot
if (hubspot !== false && hubspot.id) {
config.head.push(...getHubspotHeaders(hubspot.id));
debug('added hubspot tracking with %o', hubspot);
}
// get full team info
const copts = {debug: debug.extend('get-contribs'), paths: []};
const team = contributors !== false ? await getContributors(config.gitRoot, contributors, copts) : [];
debug('discovered full team info %o', team);
// get full version alias information but let this fail
try {
const tags = await getTags(config.gitRoot, undefined, {debug: debug.extend('get-tags')});
themeConfig.versions = tags.aliases ?? {};
debug('discovered version aliases %o', config.versions);
} catch (error) {
debug('unable to get version alias information with error %o', error);
}
// build robots.txt and rssfeed
config.buildEnd = async siteConfig => {
// generate robots txt
await generateRobotsTxt(siteConfig, {debug: debug.extend('generate-robots')});
// generate rss feeds
await generateFeeds(siteConfig, {debug: debug.extend('generate-feeds')});
// run any user specified transformPageData if its a function
if (buildEnd && typeof buildEnd === 'function') {
await buildEnd(siteConfig, {debug: debug.extend('user-build-end')});
}
};
// augment pages with additional data
config.transformPageData = async (pageData, {siteConfig}) => {
// make sure siteConfig.collections exists and is populated
await buildCollections(siteConfig, {debug: debug.extend('build-collections')});
// normalize legacy frontmatter
await normalizeLegacyFrontmatter(pageData, {siteConfig, debug: debug.extend('page-data')});
// normalize frontmatter
await normalizeFrontmatter(pageData, {siteConfig, debug: debug.extend('page-data')});
// add contributor information
await addContributors(pageData, {siteConfig, debug: debug.extend('page-data')});
// add metadata information
await addMetadata(pageData, {siteConfig, debug: debug.extend('page-data')});
// parse collections
await parseCollections(pageData, {siteConfig, debug: debug.extend('page-data')});
// normalize authors
await augmentAuthors(pageData, {team, debug: debug.extend('page-data')});
// run any user specified transformPageData if its a function
if (transformPageData && typeof transformPageData === 'function') {
await transformPageData(pageData, {siteConfig, debug: debug.extend('user-transform-page-data')});
}
};
return defineConfigWithTheme(config);
}