UNPKG

@newrelic/gatsby-theme-newrelic

Version:

[![Community Project header](https://github.com/newrelic/opensource-website/raw/master/src/images/categories/Community_Project.png)](https://opensource.newrelic.com/oss-category/#community-project)

483 lines (417 loc) 11.9 kB
const path = require('path'); const { createFilePath } = require('gatsby-source-filesystem'); const fs = require('fs'); const { withDefaults } = require('./src/utils/defaultOptions'); const createRelatedResourceNode = require('./src/utils/related-resources/createRelatedResourceNode'); const getRelatedResources = require('./src/utils/related-resources/fetchRelatedResources'); const { getResolvedEnv, getI18nConfig } = require('./src/utils/config'); const pageTransforms = require('./gatsby/page-transforms'); const { getFileRelativePath } = require('./gatsby/utils/fs'); const { SCHEMA_CUSTOMIZATION_TYPES } = require('./gatsby/type-defs'); const { SWIFTYPE_ENGINE_KEY } = require('./src/utils/constants'); let writeableRelatedResourceData = {}; const uniq = (arr) => [...new Set(arr)]; const is404Page = (page) => page.internalComponentName === 'Component/404.html' || page.internalComponentName === 'Component/dev-404-page/' || page.internalComponentName === 'Component/404/'; const ANNOUNCEMENTS_DIRECTORY = 'src/announcements'; const DEFAULT_BRANCH = 'main'; exports.onPreInit = (_, themeOptions) => { const { i18n, relatedResources = {}, signup } = themeOptions; if (i18n && !i18n.translationsPath) { throw new Error( "[@newrelic/gatsby-theme-newrelic] Please define an 'i18n.translationsPath' option" ); } if (relatedResources.swiftype) { validateSwiftypeOptions(relatedResources.swiftype); } if (signup) { validateSignupOptions(signup); } }; exports.onPreBootstrap = ({ reporter, store }, themeOptions) => { const { program } = store.getState(); const imagePath = path.join(program.directory, 'src/images'); const announcementsPath = path.join( program.directory, ANNOUNCEMENTS_DIRECTORY ); const { relatedResources = {} } = themeOptions; createDirectory(imagePath, { reporter, message: 'creating the images directory', }); createDirectory(announcementsPath, { reporter, message: 'creating the announcements directory', }); if (themeOptions.i18n) { const { locales, i18nextOptions, translationsPath, themeNamespace } = getI18nConfig(themeOptions); locales.forEach(({ locale }) => { i18nextOptions.ns .filter((ns) => ns !== themeNamespace) .forEach((ns) => { createFile(path.join(translationsPath, locale, `${ns}.json`), '{}', { reporter, message: `creating the ${locale}/${ns}.json file`, }); }); }); } if (relatedResources.swiftype) { const { resultsPath } = relatedResources.swiftype; createFile(resultsPath, '{}', { reporter, message: 'creating an empty related resources file', }); writeableRelatedResourceData = JSON.parse( fs.readFileSync(resultsPath, { encoding: 'utf-8' }) ); } }; exports.createSchemaCustomization = ({ actions }) => { const { createTypes } = actions; createTypes(SCHEMA_CUSTOMIZATION_TYPES); }; exports.sourceNodes = ( { actions, createNodeId, createContentDigest }, themeOptions ) => { const i18n = getI18nConfig(themeOptions); const { relatedResources } = withDefaults(themeOptions); const { createNode } = actions; const env = getResolvedEnv(themeOptions); i18n.locales.forEach((locale) => { createNode({ ...locale, id: createNodeId(`Locale-${locale.locale}`), parent: null, children: [], internal: { type: 'Locale', contentDigest: createContentDigest(locale), }, }); }); const config = { env, relatedResources: { labels: Object.entries(relatedResources.labels).map( ([baseUrl, label]) => ({ baseUrl, label, }) ), }, signup: themeOptions.signup, feedback: themeOptions.feedback, }; createNode({ ...config, id: createNodeId('@newrelic/gatsby-theme-newrelic:config'), parent: null, children: [], internal: { type: 'NewRelicThemeConfig', contentDigest: createContentDigest(config), content: JSON.stringify(config), }, }); }; exports.createResolvers = ({ createResolvers }, themeOptions) => { const { layout = {} } = themeOptions; const relatedResources = { args: { limit: { type: 'Int', defaultValue: 5, }, }, type: ['RelatedResource!'], resolve: (source, args, context) => { const { limit } = args; return context.nodeModel .getNodesByIds({ ids: source.children }) .slice(0, Math.max(limit, 0)); }, }; createResolvers({ Site: { layout: { type: 'SiteLayout', resolve: () => layout, }, }, SiteSiteMetadata: { branch: { resolve: ({ branch }) => branch || DEFAULT_BRANCH, }, contributingUrl: { resolve: ({ contributingUrl, branch, repository }) => { if (contributingUrl !== undefined) { return contributingUrl; } return repository ? `${repository}/blob/${branch || DEFAULT_BRANCH}/CONTRIBUTING.md` : null; }, }, }, Mdx: { relatedResources, }, Quickstarts: { relatedResources, }, }); }; exports.onCreateBabelConfig = ({ actions }, themeOptions) => { const { setBabelPlugin } = actions; const { prism = {} } = themeOptions; setBabelPlugin({ name: 'babel-plugin-prismjs', options: { languages: uniq([ 'markup', 'apacheconf', 'bash', 'clike', 'c', 'cpp', 'css', 'css-extras', 'javascript', 'jsx', 'js-extras', 'coffeescript', 'diff', 'git', 'go', 'graphql', 'handlebars', 'json', 'less', 'makefile', 'markdown', 'objectivec', 'ocaml', 'python', 'reason', 'sass', 'scss', 'sql', 'stylus', 'tsx', 'typescript', 'wasm', 'yaml', ...(prism.languages || []), ]), }, }); }; exports.onCreateNode = async (utils, themeOptions) => { const { relatedResources } = withDefaults(themeOptions); const { node, actions, store } = utils; const { createNodeField } = actions; const { program } = store.getState(); if (['Mdx', 'MarkdownRemark'].includes(node.internal.type)) { createNodeField({ node, name: 'fileRelativePath', value: getFileRelativePath(node.fileAbsolutePath, program.directory), }); } await createRelatedResources(utils, relatedResources); }; exports.onCreatePage = (helpers, themeOptions) => { const { page, actions } = helpers; const { createPage, deletePage } = actions; const { locales } = getI18nConfig(themeOptions); const additionalLocales = locales.filter((locale) => !locale.isDefault); const transformedPage = pageTransforms.reduce( (page, transform) => transform({ ...helpers, page }, themeOptions), page ); if (transformedPage !== page) { deletePage(page); createPage(transformedPage); } if ( !is404Page(page) && transformedPage.context.fileRelativePath.includes('src/pages/') && transformedPage.context.locale === 'en' ) { additionalLocales.forEach(({ locale }) => { createPage({ ...transformedPage, path: path.posix.join(`/${locale}`, transformedPage.path), context: { ...transformedPage.context, locale, }, }); }); } if (is404Page(page) && !page.context.layout) { deletePage(page); createPage({ ...page, context: { ...page.context, layout: 'basic', themeOptions, swiftypeEngineKey: SWIFTYPE_ENGINE_KEY, }, }); } }; exports.onCreateWebpackConfig = ({ actions, plugins }, themeOptions) => { const { i18n } = themeOptions; actions.setWebpackConfig({ plugins: [ plugins.define({ GATSBY_THEME_NEWRELIC_I18N_PATH: JSON.stringify( (i18n && i18n.translationsPath) || '' ), }), ], resolve: { alias: { path: require.resolve('path-browserify'), util: require.resolve('util'), stream: require.resolve('stream-browserify'), }, fallback: { fs: false, http: false, https: false, zlib: false, }, }, }); }; exports.onPostBootstrap = (_, themeOptions) => { const { relatedResources: { swiftype: { refetch, resultsPath }, }, } = withDefaults(themeOptions); if (refetch && resultsPath) { fs.writeFileSync( resultsPath, JSON.stringify(writeableRelatedResourceData, null, 2) ); } }; const createDirectory = (directory, { reporter, message } = {}) => { if (fs.existsSync(directory)) { return; } if (message) { reporter.info(`[@newrelic/gatsby-theme-newrelic] ${message}`); } fs.mkdirSync(directory, { recursive: true }); }; const createFile = (filepath, data, { reporter, message } = {}) => { if (fs.existsSync(filepath)) { return; } if (message) { reporter.info(`[@newrelic/gatsby-theme-newrelic] ${message}`); } createDirectory(path.dirname(filepath)); fs.writeFileSync(filepath, data, 'utf-8'); }; const createRelatedResources = async ( { node, actions, createContentDigest, getNodesByType, getNode, createNodeId, reporter, }, options ) => { const { swiftype } = options; const { createNode, createParentChildLink } = actions; if ( !['Mdx', 'Quickstarts'].includes(node.internal.type) || node.fileAbsolutePath?.includes(ANNOUNCEMENTS_DIRECTORY) ) { return; } const { frontmatter = {} } = node; const resources = frontmatter.resources || []; resources.forEach((resource) => { const child = createRelatedResourceNode({ parent: node.id, resource, createContentDigest, createNode, createNodeId, }); createParentChildLink({ parent: node, child: child }); }); const { getSlug, filter = () => true } = swiftype || {}; const slug = getSlug ? getSlug({ node }) : createFilePath({ node, getNode }); if (!swiftype || !filter({ node, slug })) { return; } const [ { siteMetadata: { siteUrl }, }, ] = getNodesByType('Site'); const swiftypeResources = await getRelatedResources( { node, slug, siteUrl, reporter }, swiftype ); writeableRelatedResourceData[slug] = swiftypeResources; swiftypeResources.forEach((resource) => { const child = createRelatedResourceNode({ parent: node.id, resource, createContentDigest, createNode, createNodeId, }); createParentChildLink({ parent: node, child: child }); }); }; const validateSwiftypeOptions = (swiftypeOptions) => { const { resultsPath, engineKey } = swiftypeOptions; if (!resultsPath) { throw new Error( "You have enabled swiftype searches, but the 'resultsPath' is not defined. Please define a 'relatedResources.swiftype.resultsPath' option" ); } if (!engineKey) { throw new Error( "You have enabled swiftype searches, but the 'engineKey' is missing. Please define a 'relatedResources.swiftype.engineKey' option" ); } }; const validateSignupOptions = (signupOptions) => { const { environment, reCaptchaToken, signupUrl } = signupOptions; if (!environment) { throw new Error( "You have enabled sign ups, but the 'environment' is missing. Please define a 'signup.environment' option" ); } if (!reCaptchaToken) { throw new Error( "You have enabled sign ups, but the 'reCaptchaToken' is missing. Please define a 'signup.reCaptchaToken' option" ); } if (!signupUrl) { throw new Error( "You have enabled sign ups, but the 'signupUrl' is missing. Please define a 'signup.signupUrl' option" ); } };