refactor(client): migrate Gatsby setup files to TypeScript (#66367)

This commit is contained in:
Sem Bauke
2026-03-23 10:28:04 +01:00
committed by GitHub
parent fe421a03c6
commit 08db6f8258
6 changed files with 58 additions and 45 deletions
@@ -1,6 +1,6 @@
import type { GatsbyBrowser } from 'gatsby';
import { LocationProvider } from '@gatsbyjs/reach-router'; import { LocationProvider } from '@gatsbyjs/reach-router';
import cookies from 'browser-cookies'; import cookies from 'browser-cookies';
import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import { I18nextProvider } from 'react-i18next'; import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
@@ -15,7 +15,9 @@ import GrowthBookProvider from './src/components/growth-book/growth-book-wrapper
const store = createStore(); const store = createStore();
export const wrapRootElement = ({ element }) => { export const wrapRootElement: GatsbyBrowser['wrapRootElement'] = ({
element
}) => {
return ( return (
<LocationProvider> <LocationProvider>
<Provider store={store}> <Provider store={store}>
@@ -31,19 +33,16 @@ export const wrapRootElement = ({ element }) => {
); );
}; };
wrapRootElement.propTypes = { export const wrapPageElement: GatsbyBrowser['wrapPageElement'] = layoutSelector;
element: PropTypes.any
};
export const wrapPageElement = layoutSelector; export const disableCorePrefetching: GatsbyBrowser['disableCorePrefetching'] =
() => true;
export const disableCorePrefetching = () => true; export const onRouteUpdate: GatsbyBrowser['onRouteUpdate'] = () => {
export const onRouteUpdate = () => {
store.dispatch({ type: 'app.routeUpdated' }); store.dispatch({ type: 'app.routeUpdated' });
}; };
export const onClientEntry = () => { export const onClientEntry: GatsbyBrowser['onClientEntry'] = () => {
// Letting the users' browsers expire the cookie seems to have caused issues // Letting the users' browsers expire the cookie seems to have caused issues
// for some users. Until we have time to investigate further, we should remove // for some users. Until we have time to investigate further, we should remove
// the cookie on every page load. // the cookie on every page load.
@@ -1,15 +1,17 @@
const path = require('path'); import path from 'path';
const envData = require('./config/env.json'); import type { GatsbyConfig } from 'gatsby';
const {
import envData from './config/env.json';
import {
buildChallenges, buildChallenges,
replaceChallengeNodes, replaceChallengeNodes,
localeChallengesRootDir localeChallengesRootDir
} = require('./utils/build-challenges'); } from './utils/build-challenges';
const { pathPrefix } = require('./utils/gatsby/path-prefix'); import { pathPrefix } from './utils/gatsby/path-prefix';
const { curriculumLocale, homeLocation } = envData; const { homeLocation } = envData;
module.exports = { const config: GatsbyConfig = {
flags: { flags: {
DEV_SSR: false DEV_SSR: false
}, },
@@ -43,13 +45,14 @@ module.exports = {
} }
}, },
{ {
resolve: require.resolve( resolve: path.resolve(
__dirname,
'../tools/client-plugins/gatsby-source-challenges' '../tools/client-plugins/gatsby-source-challenges'
), ),
options: { options: {
name: 'challenges', name: 'challenges',
source: buildChallenges, source: buildChallenges,
onSourceChange: replaceChallengeNodes(curriculumLocale), onSourceChange: replaceChallengeNodes(),
curriculumPath: localeChallengesRootDir curriculumPath: localeChallengesRootDir
} }
}, },
@@ -63,3 +66,5 @@ module.exports = {
} }
] ]
}; };
export default config;
+19 -14
View File
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const webpack = require('webpack'); const webpack = require('webpack');
@@ -8,7 +9,7 @@ exports.createPages = async function createPages({
actions, actions,
graphql, graphql,
reporter reporter
}) { }: any) {
if (!env.algoliaAPIKey || !env.algoliaAppId) { if (!env.algoliaAPIKey || !env.algoliaAppId) {
if (process.env.FREECODECAMP_NODE_ENV === 'production') { if (process.env.FREECODECAMP_NODE_ENV === 'production') {
throw new Error( throw new Error(
@@ -45,13 +46,15 @@ exports.createPages = async function createPages({
} }
`); `);
const superBlocks = allSuperBlockStructure.nodes.map(node => node.superBlock); const superBlocks = allSuperBlockStructure.nodes.map(
superBlocks.forEach(superBlock => { (node: { superBlock: string }) => node.superBlock
);
superBlocks.forEach((superBlock: string) => {
createSuperBlockIntroPages(createPage)({ superBlock }); createSuperBlockIntroPages(createPage)({ superBlock });
}); });
}; };
exports.onCreateWebpackConfig = ({ stage, actions }) => { exports.onCreateWebpackConfig = ({ stage, actions }: any) => {
const newPlugins = [ const newPlugins = [
// We add the shims of the node globals to the global scope // We add the shims of the node globals to the global scope
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
@@ -73,18 +76,18 @@ exports.onCreateWebpackConfig = ({ stage, actions }) => {
resolve: { resolve: {
fallback: { fallback: {
fs: false, fs: false,
path: require.resolve('path-browserify'), path: 'path-browserify',
assert: require.resolve('assert'), assert: 'assert',
crypto: require.resolve('crypto-browserify'), crypto: 'crypto-browserify',
util: require.resolve('util/util'), util: 'util/util',
buffer: require.resolve('buffer'), buffer: 'buffer',
stream: require.resolve('stream-browserify'), stream: 'stream-browserify',
process: require.resolve('process/browser') process: 'process/browser'
} }
}, },
plugins: newPlugins, plugins: newPlugins,
ignoreWarnings: [ ignoreWarnings: [
warning => { (warning: Error) => {
if (warning instanceof Error) { if (warning instanceof Error) {
if (warning.message.includes('mini-css-extract-plugin')) { if (warning.message.includes('mini-css-extract-plugin')) {
return true; return true;
@@ -96,7 +99,7 @@ exports.onCreateWebpackConfig = ({ stage, actions }) => {
}); });
}; };
exports.onCreateBabelConfig = ({ actions }) => { exports.onCreateBabelConfig = ({ actions }: any) => {
actions.setBabelPlugin({ actions.setBabelPlugin({
name: '@babel/plugin-proposal-function-bind' name: '@babel/plugin-proposal-function-bind'
}); });
@@ -105,7 +108,7 @@ exports.onCreateBabelConfig = ({ actions }) => {
}); });
}; };
exports.createSchemaCustomization = ({ actions }) => { exports.createSchemaCustomization = ({ actions }: any) => {
const { createTypes } = actions; const { createTypes } = actions;
// This hook is supported by the test runner, but is not currently used by the // This hook is supported by the test runner, but is not currently used by the
// client, so we have to tell Gatsby that it exists. // client, so we have to tell Gatsby that it exists.
@@ -116,3 +119,5 @@ exports.createSchemaCustomization = ({ actions }) => {
`; `;
createTypes(typeDefs); createTypes(typeDefs);
}; };
export {};
+13 -11
View File
@@ -1,4 +1,4 @@
import PropTypes from 'prop-types'; import type { GatsbySSR } from 'gatsby';
import React from 'react'; import React from 'react';
import { I18nextProvider } from 'react-i18next'; import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
@@ -18,7 +18,7 @@ import GrowthBookProvider from './src/components/growth-book/growth-book-wrapper
const store = createStore(); const store = createStore();
export const wrapRootElement = ({ element }) => { export const wrapRootElement: GatsbySSR['wrapRootElement'] = ({ element }) => {
return ( return (
<Provider store={store}> <Provider store={store}>
<I18nextProvider i18n={i18n}> <I18nextProvider i18n={i18n}>
@@ -30,13 +30,9 @@ export const wrapRootElement = ({ element }) => {
); );
}; };
wrapRootElement.propTypes = { export const wrapPageElement: GatsbySSR['wrapPageElement'] = layoutSelector;
element: PropTypes.any
};
export const wrapPageElement = layoutSelector; export const onRenderBody: GatsbySSR['onRenderBody'] = ({
export const onRenderBody = ({
pathname, pathname,
setHeadComponents, setHeadComponents,
setPreBodyComponents, setPreBodyComponents,
@@ -47,15 +43,21 @@ export const onRenderBody = ({
setPostBodyComponents(getPostBodyComponents(pathname)); setPostBodyComponents(getPostBodyComponents(pathname));
}; };
export const onPreRenderHTML = ({ export const onPreRenderHTML: GatsbySSR['onPreRenderHTML'] = ({
getHeadComponents, getHeadComponents,
replaceHeadComponents replaceHeadComponents
}) => { }) => {
const isBootstrapScript = (key: React.Key | null) =>
key === 'bootstrap-min-preload' || key === 'bootstrap-min';
const headComponents = getHeadComponents(); const headComponents = getHeadComponents();
headComponents.sort((x, y) => { headComponents.sort((x, y) => {
if (x.key === 'bootstrap-min-preload' || x.key === 'bootstrap-min') { const xKey = React.isValidElement(x) ? x.key : null;
const yKey = React.isValidElement(y) ? y.key : null;
if (isBootstrapScript(xKey)) {
return -1; return -1;
} else if (y.key === 'bootstrap-min-preload' || y.key === 'bootstrap-min') { } else if (isBootstrapScript(yKey)) {
return 1; return 1;
} }
return 0; return 0;
+1 -1
View File
@@ -17,7 +17,7 @@
}, },
"homepage": "https://github.com/freeCodeCamp/freeCodeCamp#readme", "homepage": "https://github.com/freeCodeCamp/freeCodeCamp#readme",
"author": "freeCodeCamp <team@freecodecamp.org>", "author": "freeCodeCamp <team@freecodecamp.org>",
"main": "none", "main": "index.js",
"scripts": { "scripts": {
"build": "NODE_OPTIONS=\"--max-old-space-size=7168 --no-deprecation\" gatsby build --prefix-paths", "build": "NODE_OPTIONS=\"--max-old-space-size=7168 --no-deprecation\" gatsby build --prefix-paths",
"clean": "gatsby clean", "clean": "gatsby clean",
+2
View File
@@ -16,6 +16,8 @@
"skipLibCheck": true "skipLibCheck": true
}, },
"include": [ "include": [
"gatsby-*.ts",
"gatsby-*.tsx",
"i18n/**/*", "i18n/**/*",
"plugins/**/*", "plugins/**/*",
"src/**/*", "src/**/*",