From a3e58df594719dd853af94c78fbad13031cbe36d Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Sun, 21 May 2023 15:11:32 +0300 Subject: [PATCH] refactor: refactoring gatsby node --- www/gatsby-node.js | 197 +------------------ www/src/components/insights/SummaryUsage.tsx | 7 +- www/src/context/InsightsContext.jsx | 2 +- www/src/utils/getParagonComponentsTypes.js | 2 +- www/utils/createCssUtilityClassNodes.js | 65 ++++++ www/utils/createPages.js | 93 +++++++++ www/utils/onCreateNode.js | 28 +++ www/utils/onCreateWebpackConfig.js | 15 ++ 8 files changed, 214 insertions(+), 195 deletions(-) create mode 100644 www/utils/createCssUtilityClassNodes.js create mode 100644 www/utils/createPages.js create mode 100644 www/utils/onCreateNode.js create mode 100644 www/utils/onCreateWebpackConfig.js diff --git a/www/gatsby-node.js b/www/gatsby-node.js index 45ecaf8b76..525ea7fb38 100644 --- a/www/gatsby-node.js +++ b/www/gatsby-node.js @@ -4,199 +4,16 @@ * See: https://www.gatsbyjs.com/docs/node-apis/ */ -// You can delete this file if you're not using it -const path = require('path'); -const { createFilePath } = require('gatsby-source-filesystem'); -const sass = require('sass'); -const css = require('css'); +const createPages = require('./utils/createPages'); +const onCreateNode = require('./utils/onCreateNode'); +const onCreateWebpackConfig = require('./utils/onCreateWebpackConfig'); +const createCssUtilityClassNodes = require('./utils/createCssUtilityClassNodes'); -const fs = require('fs'); -const { INSIGHTS_PAGES } = require('./src/config'); -const { getThemesSCSSVariables, processComponentSCSSVariables } = require('./theme-utils'); -const componentsUsage = require('./src/utils/componentsUsage'); +exports.onCreateWebpackConfig = ({ actions }) => onCreateWebpackConfig(actions); -exports.onCreateWebpackConfig = ({ actions }) => { - actions.setWebpackConfig({ - resolve: { - alias: { - '~paragon-react': path.resolve(__dirname, '../src'), - '~paragon-style': path.resolve(__dirname, '../scss'), - '~paragon-icons': path.resolve(__dirname, '../icons'), - }, - }, - }); -}; - -exports.onCreateNode = ({ node, actions, getNode }) => { - const { createNodeField } = actions; - // you only want to operate on `Mdx` nodes. If you had content from a - // remote CMS you could also check to see if the parent node was a - // `File` node here - if (node.internal.type === 'Mdx') { - const value = createFilePath({ node, getNode }) - .split('README')[0] - .toLowerCase(); - - const isChangelogNode = node.fileAbsolutePath && node.fileAbsolutePath.endsWith('CHANGELOG.md'); - - createNodeField({ - // Name of the field you are adding - name: 'slug', - // Individual MDX node - node, - // Generated value based on filepath with 'components' prefix. you - // don't need a separating '/' before the value because - // createFilePath returns a path with the leading '/'. - value: isChangelogNode ? 'changelog' : `/components${value}`, - }); - } -}; - -exports.createPages = async ({ graphql, actions, reporter }) => { - // Destructure the createPage function from the actions object - const { createPage, createRedirect } = actions; - // MDX transforms markdown generated by gatsby-transformer-react-docgen - // This query filters out all of those markdown nodes and assumes all others - // are for page creation purposes. - const result = await graphql(` - query { - allMdx( - filter: { - parent: { - internal: { owner: { nin: "gatsby-transformer-react-docgen" } } - } - } - ) { - edges { - node { - id - fields { - slug - } - frontmatter { - components - } - slug - } - } - } - } - `); - if (result.errors) { - reporter.panicOnBuild('🚨 ERROR: Loading createPages query'); - } - // Create component detail pages. - const components = result.data.allMdx.edges; - - const themesSCSSVariables = await getThemesSCSSVariables(); - - // you'll call `createPage` for each result - // eslint-disable-next-line no-restricted-syntax - for (const { node } of components) { - const componentDir = node.slug.split('/')[0]; - const variablesPath = path.resolve(__dirname, `../src/${componentDir}/_variables.scss`); - let scssVariablesData = {}; - - if (fs.existsSync(variablesPath)) { - // eslint-disable-next-line no-await-in-loop - scssVariablesData = await processComponentSCSSVariables(variablesPath, themesSCSSVariables); - } - - createPage({ - // This is the slug you created before - // (or `node.frontmatter.slug`) - path: node.fields.slug, - // This component will wrap our MDX content - component: path.resolve('./src/templates/component-page-template.tsx'), - // You can use the values in this context in - // our page layout component - context: { - id: node.id, - components: node.frontmatter.components || [], - scssVariablesData, - componentsUsageInsights: Object.keys(componentsUsage), - }, - }); - } - - INSIGHTS_PAGES.forEach(({ path: pagePath, tab }) => { - createPage({ - path: pagePath, - component: require.resolve('./src/pages/insights.tsx'), - context: { tab }, - }); - }); - - createRedirect({ - fromPath: '/playroom', - toPath: '/playroom/index.html', - }); - - createRedirect({ - fromPath: '/playroom/preview', - toPath: '/playroom/preview/index.html', - }); -}; - -function createCssUtilityClassNodes({ - actions, - createNodeId, - createContentDigest, -}) { - const { createNode } = actions; - - // We convert to CSS first since we prefer the real values over tokens. - const compiledCSS = sass - .renderSync({ - file: path.resolve(__dirname, '../scss/core/utilities-only.scss'), - // Resolve tildes the way webpack would in our base npm project - importer(url) { - let resolvedUrl = url; - if (url[0] === '~') { - resolvedUrl = path.resolve(__dirname, '../node_modules', url.substr(1)); - } - return { file: resolvedUrl }; - }, - }) - .css.toString(); - - const sheet = css.parse(compiledCSS).stylesheet; - - sheet.rules.forEach(({ selectors, position, declarations }) => { - if (!selectors) { return; } - - selectors.forEach(selector => { - if (selector[0] !== '.') { return; } // classes only - - const classSelector = selector.substr(1); - - const nodeData = { - selector: classSelector, - declarations: declarations.map( - ({ property, value }) => `${property}: ${value};`, - ), - isUtility: - declarations.length === 1 - && declarations[0].value.includes('!important'), - }; - - const nodeMeta = { - id: createNodeId( - `rule-${classSelector}-${position.start.line}-${position.end.line}`, - ), - parent: null, - children: [], - internal: { - type: 'CssUtilityClasses', - contentDigest: createContentDigest(nodeData), - }, - }; +exports.onCreateNode = ({ node, actions, getNode }) => onCreateNode(node, actions, getNode); - const node = { ...nodeData, ...nodeMeta }; - createNode(node); - }); - }); -} +exports.createPages = ({ graphql, actions, reporter }) => createPages(graphql, actions, reporter); exports.sourceNodes = ({ actions, createNodeId, createContentDigest }) => { createCssUtilityClassNodes({ actions, createNodeId, createContentDigest }); diff --git a/www/src/components/insights/SummaryUsage.tsx b/www/src/components/insights/SummaryUsage.tsx index 1bde268483..076536bdef 100644 --- a/www/src/components/insights/SummaryUsage.tsx +++ b/www/src/components/insights/SummaryUsage.tsx @@ -9,7 +9,8 @@ import { import componentsUsage from '../../utils/componentsUsage'; import InsightsContext from '../../context/InsightsContext'; import SummaryUsageExamples, { ISummaryUsageExamples } from './SummaryUsageExamples'; -import { IComponentUsageData, IDependentUsage, IInsightsContext } from '../../types/types'; +import { IComponentUsageData, IInsightsContext } from '../../types/types'; +import getDependentProjectsUsages from '../../utils/getDependentProjectsUsages'; interface IFilterData { name: string, @@ -22,7 +23,7 @@ const round = (n: number) => Math.round(n * 10) / 10; const ICON_TYPE = 'Icon'; const TABLE_PAGE_SIZE = 10; const componentsInUsage = Object.keys(componentsUsage); -const dependentProjects: IDependentUsage[] = []; +const dependentProjects = getDependentProjectsUsages(); function SummaryUsage() { const { paragonTypes = {}, isParagonIcon = () => false } = useContext(InsightsContext) as IInsightsContext; @@ -72,7 +73,7 @@ function SummaryUsage() { const averageComponentsUsedPerProject = dependentProjects .reduce((accumulator, project) => accumulator + project.count, 0) / dependentProjects.length; - + console.log('dependentProjects', dependentProjects); return (
diff --git a/www/src/context/InsightsContext.jsx b/www/src/context/InsightsContext.jsx index 75a014fb9f..c4588f8a39 100644 --- a/www/src/context/InsightsContext.jsx +++ b/www/src/context/InsightsContext.jsx @@ -15,7 +15,7 @@ function InsightsContextProvider({ children }) { setParagonTypes(getParagonComponentsTypes(Components)); }, []); - const isParagonIcon = (name) => name in Icons; + const isParagonIcon = (name) => name in Icons || name.match('Icon'); const contextValue = useMemo(() => ({ paragonTypes, diff --git a/www/src/utils/getParagonComponentsTypes.js b/www/src/utils/getParagonComponentsTypes.js index 4fc2dccf1f..ef837d773e 100644 --- a/www/src/utils/getParagonComponentsTypes.js +++ b/www/src/utils/getParagonComponentsTypes.js @@ -17,7 +17,7 @@ const getParagonComponentsTypes = (components) => { case isFunctionComponent || isObjectComponent || isContext: componentType = 'Component'; break; - case component.constructor.name === 'Object': + case typeof component === 'object': componentType = 'Object'; break; case typeof component === 'function': diff --git a/www/utils/createCssUtilityClassNodes.js b/www/utils/createCssUtilityClassNodes.js new file mode 100644 index 0000000000..4074fadf40 --- /dev/null +++ b/www/utils/createCssUtilityClassNodes.js @@ -0,0 +1,65 @@ +const sass = require('sass'); +const path = require('path'); +const css = require('css'); + +function createCssUtilityClassNodes({ + actions, + createNodeId, + createContentDigest, +}) { + const { createNode } = actions; + + // We convert to CSS first since we prefer the real values over tokens. + const compiledCSS = sass + .renderSync({ + file: path.resolve(__dirname, '../../scss/core/utilities-only.scss'), + // Resolve tildes the way webpack would in our base npm project + importer(url) { + let resolvedUrl = url; + if (url[0] === '~') { + resolvedUrl = path.resolve(__dirname, '../../node_modules', url.substr(1)); + } + return { file: resolvedUrl }; + }, + }) + .css.toString(); + + const sheet = css.parse(compiledCSS).stylesheet; + + sheet.rules.forEach(({ selectors, position, declarations }) => { + if (!selectors) { return; } + + selectors.forEach(selector => { + if (selector[0] !== '.') { return; } // classes only + + const classSelector = selector.substr(1); + + const nodeData = { + selector: classSelector, + declarations: declarations.map( + ({ property, value }) => `${property}: ${value};`, + ), + isUtility: + declarations.length === 1 + && declarations[0].value.includes('!important'), + }; + + const nodeMeta = { + id: createNodeId( + `rule-${classSelector}-${position.start.line}-${position.end.line}`, + ), + parent: null, + children: [], + internal: { + type: 'CssUtilityClasses', + contentDigest: createContentDigest(nodeData), + }, + }; + + const node = { ...nodeData, ...nodeMeta }; + createNode(node); + }); + }); +} + +module.exports = createCssUtilityClassNodes; diff --git a/www/utils/createPages.js b/www/utils/createPages.js new file mode 100644 index 0000000000..e28cf61e57 --- /dev/null +++ b/www/utils/createPages.js @@ -0,0 +1,93 @@ +const path = require('path'); +const fs = require('fs'); +const { INSIGHTS_PAGES } = require('../src/config'); +const { getThemesSCSSVariables, processComponentSCSSVariables } = require('../theme-utils'); +const componentsUsage = require('../src/utils/componentsUsage'); + +async function createPages(graphql, actions, reporter) { + // Destructure the createPage function from the actions object + const { createPage, createRedirect } = actions; + // MDX transforms markdown generated by gatsby-transformer-react-docgen + // This query filters out all of those markdown nodes and assumes all others + // are for page creation purposes. + const result = await graphql(` + query { + allMdx( + filter: { + parent: { + internal: { owner: { nin: "gatsby-transformer-react-docgen" } } + } + } + ) { + edges { + node { + id + fields { + slug + } + frontmatter { + components + } + slug + } + } + } + } + `); + if (result.errors) { + reporter.panicOnBuild('🚨 ERROR: Loading createPages query'); + } + // Create component detail pages. + const components = result.data.allMdx.edges; + + const themesSCSSVariables = await getThemesSCSSVariables(); + + // you'll call `createPage` for each result + // eslint-disable-next-line no-restricted-syntax + for (const { node } of components) { + const componentDir = node.slug.split('/')[0]; + const variablesPath = path.resolve(__dirname, `../../src/${componentDir}/_variables.scss`); + let scssVariablesData = {}; + + if (fs.existsSync(variablesPath)) { + // eslint-disable-next-line no-await-in-loop + scssVariablesData = await processComponentSCSSVariables(variablesPath, themesSCSSVariables); + } + + createPage({ + // This is the slug you created before + // (or `node.frontmatter.slug`) + path: node.fields.slug, + // This component will wrap our MDX content + component: path.resolve(__dirname, '../src/templates/component-page-template.tsx'), + // You can use the values in this context in + // our page layout component + context: { + id: node.id, + components: node.frontmatter.components || [], + scssVariablesData, + componentsUsageInsights: Object.keys(componentsUsage), + }, + }); + } + + INSIGHTS_PAGES.forEach(({ path: pagePath, tab }) => { + createPage({ + path: pagePath, + component: require.resolve('../src/pages/insights.tsx'), + context: { tab }, + }); + }); + + createRedirect({ + fromPath: '/playroom', + toPath: '/playroom/index.html', + }); + + createRedirect({ + fromPath: '/playroom/preview', + toPath: '/playroom/preview/index.html', + }); +} + +module.exports = createPages; diff --git a/www/utils/onCreateNode.js b/www/utils/onCreateNode.js new file mode 100644 index 0000000000..5950d05518 --- /dev/null +++ b/www/utils/onCreateNode.js @@ -0,0 +1,28 @@ +const { createFilePath } = require('gatsby-source-filesystem'); + +function onCreateNode(node, actions, getNode) { + const { createNodeField } = actions; + // you only want to operate on `Mdx` nodes. If you had content from a + // remote CMS you could also check to see if the parent node was a + // `File` node here + if (node.internal.type === 'Mdx') { + const value = createFilePath({ node, getNode }) + .split('README')[0] + .toLowerCase(); + + const isChangelogNode = node.fileAbsolutePath && node.fileAbsolutePath.endsWith('CHANGELOG.md'); + + createNodeField({ + // Name of the field you are adding + name: 'slug', + // Individual MDX node + node, + // Generated value based on filepath with 'components' prefix. you + // don't need a separating '/' before the value because + // createFilePath returns a path with the leading '/'. + value: isChangelogNode ? 'changelog' : `/components${value}`, + }); + } +} + +module.exports = onCreateNode; diff --git a/www/utils/onCreateWebpackConfig.js b/www/utils/onCreateWebpackConfig.js new file mode 100644 index 0000000000..9b3171fe0e --- /dev/null +++ b/www/utils/onCreateWebpackConfig.js @@ -0,0 +1,15 @@ +const path = require('path'); + +function onCreateWebpackConfig(actions) { + actions.setWebpackConfig({ + resolve: { + alias: { + '~paragon-react': path.resolve(__dirname, '../../src'), + '~paragon-style': path.resolve(__dirname, '../../scss'), + '~paragon-icons': path.resolve(__dirname, '../../icons'), + }, + }, + }); +} + +module.exports = onCreateWebpackConfig;