fix(api, client): update Gatsby, webpack & related things (#41452)

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
Mrugesh Mohapatra
2021-03-26 00:43:43 +05:30
committed by GitHub
parent 92dfb3065c
commit ad9b1f89d8
71 changed files with 35182 additions and 9001 deletions

View File

@ -33,6 +33,7 @@
"import/no-duplicates": 2, "import/no-duplicates": 2,
"import/no-unresolved": [2, { "commonjs": true }], "import/no-unresolved": [2, { "commonjs": true }],
"import/unambiguous": 2, "import/unambiguous": 2,
"import/no-anonymous-default-export": 2,
"jsx-quotes": [2, "prefer-single"], "jsx-quotes": [2, "prefer-single"],
"jsx-a11y/accessible-emoji": "error", "jsx-a11y/accessible-emoji": "error",
"jsx-a11y/alt-text": "error", "jsx-a11y/alt-text": "error",

View File

@ -14,7 +14,7 @@ export function ensureLowerCaseEmail(profile) {
: ''; : '';
} }
export default function (UserIdent) { export default function initializeUserIdent(UserIdent) {
UserIdent.on('dataSourceAttached', () => { UserIdent.on('dataSourceAttached', () => {
UserIdent.findOne$ = observeMethod(UserIdent, 'findOne'); UserIdent.findOne$ = observeMethod(UserIdent, 'findOne');
}); });

View File

@ -1,6 +1,6 @@
import { Observable } from 'rx'; import { Observable } from 'rx';
export default function (Block) { export default function initializeBlock(Block) {
Block.on('dataSourceAttached', () => { Block.on('dataSourceAttached', () => {
Block.findOne$ = Observable.fromNodeCallback(Block.findOne, Block); Block.findOne$ = Observable.fromNodeCallback(Block.findOne, Block);
Block.findById$ = Observable.fromNodeCallback(Block.findById, Block); Block.findById$ = Observable.fromNodeCallback(Block.findById, Block);

View File

@ -152,7 +152,7 @@ function populateRequiredFields(user) {
return; return;
} }
export default function (User) { export default function initializeUser(User) {
// set salt factor for passwords // set salt factor for passwords
User.settings.saltWorkFactor = 5; User.settings.saltWorkFactor = 5;
// set user.rand to random number // set user.rand to random number

View File

@ -1,6 +1,6 @@
import csurf from 'csurf'; import csurf from 'csurf';
export default function () { export default function getCsurf() {
const protection = csurf({ const protection = csurf({
cookie: { cookie: {
domain: process.env.COOKIE_DOMAIN || 'localhost', domain: process.env.COOKIE_DOMAIN || 'localhost',

View File

@ -1,7 +1,7 @@
import qs from 'query-string'; import qs from 'query-string';
// add rx methods to express // add rx methods to express
export default function () { export default function getExpressExtensions() {
return function expressExtensions(req, res, next) { return function expressExtensions(req, res, next) {
res.redirectWithFlash = uri => { res.redirectWithFlash = uri => {
const flash = req.flash(); const flash = req.flash();

View File

@ -48,8 +48,11 @@ export function isAllowedPath(path, pathsAllowedREs = _pathsAllowedREs) {
return pathsAllowedREs.some(re => re.test(path)); return pathsAllowedREs.some(re => re.test(path));
} }
export default ({ jwtSecret = _jwtSecret, getUserById = _getUserById } = {}) => export default function getRequestAuthorisation({
function requestAuthorisation(req, res, next) { jwtSecret = _jwtSecret,
getUserById = _getUserById
} = {}) {
return function requestAuthorisation(req, res, next) {
const { origin } = getRedirectParams(req); const { origin } = getRedirectParams(req);
const { path } = req; const { path } = req;
if (!isAllowedPath(path)) { if (!isAllowedPath(path)) {
@ -102,3 +105,4 @@ export default ({ jwtSecret = _jwtSecret, getUserById = _getUserById } = {}) =>
} }
return Promise.resolve(next()); return Promise.resolve(next());
}; };
}

View File

@ -1,6 +1,6 @@
import { Observable } from 'rx'; import { Observable } from 'rx';
export default function (AuthToken) { export default function initializeAuthToken(AuthToken) {
AuthToken.on('dataSourceAttached', () => { AuthToken.on('dataSourceAttached', () => {
AuthToken.findOne$ = Observable.fromNodeCallback( AuthToken.findOne$ = Observable.fromNodeCallback(
AuthToken.findOne.bind(AuthToken) AuthToken.findOne.bind(AuthToken)

View File

@ -7,7 +7,7 @@ import InMemoryCache from '../utils/in-memory-cache';
const log = debug('fcc:boot:donate'); const log = debug('fcc:boot:donate');
const fiveMinutes = 1000 * 60 * 5; const fiveMinutes = 1000 * 60 * 5;
export default function (Donation) { export default function initializeDonation(Donation) {
let activeDonationUpdateInterval = null; let activeDonationUpdateInterval = null;
const activeDonationCountCacheTTL = fiveMinutes; const activeDonationCountCacheTTL = fiveMinutes;
const activeDonationCountCache = InMemoryCache(0, reportError); const activeDonationCountCache = InMemoryCache(0, reportError);

View File

@ -9,7 +9,7 @@ const failureRedirect = `${homeLocation}/signin`;
// TODO: can we remove passport-mock-strategy entirely in prod? That would let // TODO: can we remove passport-mock-strategy entirely in prod? That would let
// us make passport-mock-strategy a dev dep, as it should be. // us make passport-mock-strategy a dev dep, as it should be.
export default { const passportProviders = {
devlogin: { devlogin: {
authScheme: 'mock', authScheme: 'mock',
provider: 'dev', provider: 'dev',
@ -45,3 +45,5 @@ export default {
failureFlash: true failureFlash: true
} }
}; };
export default passportProviders;

View File

@ -1,19 +0,0 @@
export default {
bg9997c9c79feddfaeb9bdef: '56bbb991ad1ed5201cd392ca',
bg9995c9c69feddfaeb9bdef: '56bbb991ad1ed5201cd392cb',
bg9994c9c69feddfaeb9bdef: '56bbb991ad1ed5201cd392cc',
bg9996c9c69feddfaeb9bdef: '56bbb991ad1ed5201cd392cd',
bg9997c9c69feddfaeb9bdef: '56bbb991ad1ed5201cd392ce',
bg9997c9c89feddfaeb9bdef: '56bbb991ad1ed5201cd392cf',
bg9998c9c99feddfaeb9bdef: '56bbb991ad1ed5201cd392d0',
bg9999c9c99feddfaeb9bdef: '56bbb991ad1ed5201cd392d1',
bg9999c9c99feedfaeb9bdef: '56bbb991ad1ed5201cd392d2',
bg9999c9c99fdddfaeb9bdef: '56bbb991ad1ed5201cd392d3',
bb000000000000000000001: '56bbb991ad1ed5201cd392d4',
bc000000000000000000001: '56bbb991ad1ed5201cd392d5',
bb000000000000000000002: '56bbb991ad1ed5201cd392d6',
bb000000000000000000003: '56bbb991ad1ed5201cd392d7',
bb000000000000000000004: '56bbb991ad1ed5201cd392d8',
bb000000000000000000005: '56bbb991ad1ed5201cd392d9',
bb000000000000000000006: '56bbb991ad1ed5201cd392da'
};

View File

@ -1,17 +1,13 @@
const path = require('path'); const path = require('path');
const envData = require('../config/env.json');
const {
clientLocale,
curriculumLocale,
homeLocation
} = require('../config/env.json');
const { const {
buildChallenges, buildChallenges,
replaceChallengeNode, replaceChallengeNode,
localeChallengesRootDir localeChallengesRootDir
} = require('./utils/buildChallenges'); } = require('./utils/buildChallenges');
const { clientLocale, curriculumLocale, homeLocation } = envData;
const curriculumIntroRoot = path.resolve(__dirname, './src/pages'); const curriculumIntroRoot = path.resolve(__dirname, './src/pages');
const pathPrefix = const pathPrefix =
clientLocale === 'english' || clientLocale === 'chinese' clientLocale === 'english' || clientLocale === 'chinese'
@ -84,20 +80,20 @@ module.exports = {
} }
} }
}, },
{ // {
resolve: `gatsby-plugin-advanced-sitemap`, // resolve: `gatsby-plugin-advanced-sitemap`,
options: { // options: {
exclude: [ // exclude: [
`/dev-404-page`, // `/dev-404-page`,
`/404`, // `/404`,
`/404.html`, // `/404.html`,
`/offline-plugin-app-shell-fallback`, // `/offline-plugin-app-shell-fallback`,
`/learn`, // `/learn`,
/(\/)learn(\/)\S*/ // /(\/)learn(\/)\S*/
], // ],
addUncaughtPages: true // addUncaughtPages: true
} // }
}, // },
{ {
resolve: 'gatsby-plugin-manifest', resolve: 'gatsby-plugin-manifest',
options: { options: {

View File

@ -1,4 +1,5 @@
const env = require('../config/env'); const env = require('../config/env');
const webpack = require('webpack');
const { createFilePath } = require('gatsby-source-filesystem'); const { createFilePath } = require('gatsby-source-filesystem');
const uniq = require('lodash/uniq'); const uniq = require('lodash/uniq');
@ -184,6 +185,13 @@ exports.onCreateWebpackConfig = ({ stage, plugins, actions }) => {
process.env.HOME_PATH || 'http://localhost:3000' process.env.HOME_PATH || 'http://localhost:3000'
), ),
STRIPE_PUBLIC_KEY: JSON.stringify(process.env.STRIPE_PUBLIC_KEY || '') STRIPE_PUBLIC_KEY: JSON.stringify(process.env.STRIPE_PUBLIC_KEY || '')
}),
// We add the shims of the node globals to the global scope
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer']
}),
new webpack.ProvidePlugin({
process: 'process/browser'
}) })
]; ];
// The monaco editor relies on some browser only globals so should not be // The monaco editor relies on some browser only globals so should not be
@ -193,8 +201,17 @@ exports.onCreateWebpackConfig = ({ stage, plugins, actions }) => {
newPlugins.push(new MonacoWebpackPlugin()); newPlugins.push(new MonacoWebpackPlugin());
} }
actions.setWebpackConfig({ actions.setWebpackConfig({
node: { resolve: {
fs: 'empty' fallback: {
fs: false,
path: false,
assert: require.resolve('assert'),
crypto: require.resolve('crypto-browserify'),
util: false,
buffer: require.resolve('buffer'),
stream: require.resolve('stream-browserify'),
process: require.resolve('process/browser')
}
}, },
plugins: newPlugins plugins: newPlugins
}); });

View File

@ -1,9 +1,11 @@
import i18n from 'i18next'; import i18n from 'i18next';
import { initReactI18next } from 'react-i18next'; import { initReactI18next } from 'react-i18next';
const { clientLocale } = require('../../config/env.json'); const envData = require('../../config/env.json');
const { i18nextCodes } = require('../../config/i18n/all-langs'); const { i18nextCodes } = require('../../config/i18n/all-langs');
const { clientLocale } = envData;
const i18nextCode = i18nextCodes[clientLocale]; const i18nextCode = i18nextCodes[clientLocale];
i18n.use(initReactI18next).init({ i18n.use(initReactI18next).init({

43790
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -21,33 +21,37 @@
"@reach/router": "^1.3.4", "@reach/router": "^1.3.4",
"@stripe/react-stripe-js": "^1.4.0", "@stripe/react-stripe-js": "^1.4.0",
"algoliasearch": "^3.35.1", "algoliasearch": "^3.35.1",
"assert": "^2.0.0",
"axios": "^0.21.1", "axios": "^0.21.1",
"babel-plugin-prismjs": "^2.0.1", "babel-plugin-prismjs": "^2.0.1",
"bezier-easing": "^2.1.0", "bezier-easing": "^2.1.0",
"browser-cookies": "^1.2.0", "browser-cookies": "^1.2.0",
"buffer": "^6.0.3",
"chai": "^4.3.3", "chai": "^4.3.3",
"crypto-browserify": "^3.12.0",
"csrf": "^3.1.0", "csrf": "^3.1.0",
"date-fns": "^2.19.0", "date-fns": "^2.19.0",
"enzyme": "^3.10.0", "enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.15.6", "enzyme-adapter-react-16": "^1.15.6",
"final-form": "^4.20.2", "final-form": "^4.20.2",
"gatsby": "^2.32.9", "gatsby": "^3.1.2",
"gatsby-cli": "^2.19.1", "gatsby-cli": "^3.0.0",
"gatsby-plugin-advanced-sitemap": "^1.6.0", "gatsby-plugin-advanced-sitemap": "^1.6.0",
"gatsby-plugin-create-client-paths": "^2.10.0", "gatsby-plugin-create-client-paths": "^3.0.0",
"gatsby-plugin-manifest": "^2.12.1", "gatsby-plugin-manifest": "^3.0.0",
"gatsby-plugin-postcss": "^2.3.13", "gatsby-plugin-postcss": "^4.0.0",
"gatsby-plugin-react-helmet": "^3.10.0", "gatsby-plugin-react-helmet": "^4.0.0",
"gatsby-plugin-remove-serviceworker": "^1.0.0", "gatsby-plugin-remove-serviceworker": "^1.0.0",
"gatsby-remark-prismjs": "^3.13.0", "gatsby-remark-prismjs": "^4.0.0",
"gatsby-source-filesystem": "^2.11.1", "gatsby-source-filesystem": "^3.0.0",
"gatsby-transformer-remark": "^2.16.1", "gatsby-transformer-remark": "^3.0.0",
"i18next": "^19.9.1", "i18next": "^19.9.1",
"jquery": "^3.6.0", "jquery": "^3.6.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"monaco-editor": "^0.22.3", "monaco-editor": "^0.22.3",
"nanoid": "^3.1.20", "nanoid": "^3.1.20",
"prismjs": "^1.23.0", "prismjs": "^1.23.0",
"process": "^0.11.10",
"query-string": "^6.14.1", "query-string": "^6.14.1",
"react": "^16.14.0", "react": "^16.14.0",
"react-dom": "^16.14.0", "react-dom": "^16.14.0",
@ -77,6 +81,7 @@
"sanitize-html": "^2.3.2", "sanitize-html": "^2.3.2",
"sass.js": "^0.11.0", "sass.js": "^0.11.0",
"store": "^2.0.12", "store": "^2.0.12",
"stream-browserify": "^3.0.0",
"typescript": "^4.2.3", "typescript": "^4.2.3",
"validator": "^13.5.2" "validator": "^13.5.2"
}, },
@ -87,8 +92,8 @@
"scripts": { "scripts": {
"prebuild": "echo 'Client workers building...' && npm run build:workers && echo 'Client workers ready.' && node ../tools/scripts/build/ensure-env.js", "prebuild": "echo 'Client workers building...' && npm run build:workers && echo 'Client workers ready.' && node ../tools/scripts/build/ensure-env.js",
"build": "node --max_old_space_size=7168 node_modules/gatsby-cli build --prefix-paths", "build": "node --max_old_space_size=7168 node_modules/gatsby-cli build --prefix-paths",
"build:workers": "node --max_old_space_size=7168 node_modules/webpack-cli --env.production --config ./webpack-workers.js && echo", "build:workers": "node --max_old_space_size=7168 node_modules/webpack-cli/bin/cli --env production --config ./webpack-workers.js && echo",
"build:workers:debug": "node --max_old_space_size=7168 node_modules/webpack-cli --env.production --config ./webpack-workers.js --progress", "build:workers:debug": "node --max_old_space_size=7168 node_modules/webpack-cli/bin/cli --env production --config ./webpack-workers.js --progress",
"clean": "gatsby clean", "clean": "gatsby clean",
"predevelop": "npm run prebuild", "predevelop": "npm run prebuild",
"develop": "gatsby develop --inspect=9230", "develop": "gatsby develop --inspect=9230",
@ -115,8 +120,8 @@
"monaco-editor-webpack-plugin": "^3.0.0", "monaco-editor-webpack-plugin": "^3.0.0",
"react-test-renderer": "^16.14.0", "react-test-renderer": "^16.14.0",
"redux-saga-test-plan": "^4.0.1", "redux-saga-test-plan": "^4.0.1",
"webpack": "^4.46.0", "webpack": "^5.25.1",
"webpack-cli": "^3.3.12" "webpack-cli": "^4.5.0"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -1,3 +1,5 @@
export default { const analytics = {
event: () => {} event: () => {}
}; };
export default analytics;

View File

@ -1,4 +1,4 @@
export default [ const mockChallengeNodes = [
{ {
fields: { fields: {
slug: '/super-block-one/block-a/challenge-one', slug: '/super-block-one/block-a/challenge-one',
@ -133,3 +133,5 @@ export default [
dashedName: 'challenge-two' dashedName: 'challenge-two'
} }
]; ];
export default mockChallengeNodes;

View File

@ -1 +0,0 @@
export default ['a', 'c', 'g'];

View File

@ -4,7 +4,9 @@ const React = require('react');
const gatsby = jest.requireActual('gatsby'); const gatsby = jest.requireActual('gatsby');
const { clientLocale } = require('../../../config/env.json'); const envData = require('../../../config/env.json');
const { clientLocale } = envData;
module.exports = { module.exports = {
...gatsby, ...gatsby,

View File

@ -1,29 +0,0 @@
export default [
{
fields: {
slug: '/super-block-one/block-a'
},
frontmatter: {
block: 'Block A',
title: 'Introduction to Block A'
}
},
{
fields: {
slug: '/super-block-one/block-b'
},
frontmatter: {
block: 'Block B',
title: 'Introduction to Block B'
}
},
{
fields: {
slug: '/super-block-one/block-c'
},
frontmatter: {
block: 'Block C',
title: 'Introduction to Block C'
}
}
];

View File

@ -28,12 +28,14 @@ import { createFlashMessage } from '../components/Flash/redux';
import standardErrorMessage from '../utils/standardErrorMessage'; import standardErrorMessage from '../utils/standardErrorMessage';
import reallyWeirdErrorMessage from '../utils/reallyWeirdErrorMessage'; import reallyWeirdErrorMessage from '../utils/reallyWeirdErrorMessage';
import { langCodes } from '../../../config/i18n/all-langs'; import { langCodes } from '../../../config/i18n/all-langs';
import { clientLocale } from '../../../config/env.json'; import envData from '../../../config/env.json';
import RedirectHome from '../components/RedirectHome'; import RedirectHome from '../components/RedirectHome';
import { Loader, Spacer } from '../components/helpers'; import { Loader, Spacer } from '../components/helpers';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
const { clientLocale } = envData;
const localeCode = langCodes[clientLocale]; const localeCode = langCodes[clientLocale];
const propTypes = { const propTypes = {

View File

@ -5,7 +5,7 @@ import { createSelector } from 'reselect';
import { Grid, Button } from '@freecodecamp/react-bootstrap'; import { Grid, Button } from '@freecodecamp/react-bootstrap';
import Helmet from 'react-helmet'; import Helmet from 'react-helmet';
import { apiLocation } from '../../../config/env.json'; import envData from '../../../config/env.json';
import { import {
signInLoadingSelector, signInLoadingSelector,
userSelector, userSelector,
@ -27,6 +27,8 @@ import Certification from '../components/settings/Certification';
import DangerZone from '../components/settings/DangerZone'; import DangerZone from '../components/settings/DangerZone';
import { User } from '../redux/propTypes'; import { User } from '../redux/propTypes';
const { apiLocation } = envData;
const propTypes = { const propTypes = {
createFlashMessage: PropTypes.func.isRequired, createFlashMessage: PropTypes.func.isRequired,
isSignedIn: PropTypes.bool.isRequired, isSignedIn: PropTypes.bool.isRequired,

View File

@ -1,10 +1,12 @@
/* global jest, expect */ /* global jest, expect */
import React from 'react'; import React from 'react';
import ShallowRenderer from 'react-test-renderer/shallow'; import ShallowRenderer from 'react-test-renderer/shallow';
import { apiLocation } from '../../../config/env.json'; import envData from '../../../config/env.json';
import { ShowSettings } from './ShowSettings'; import { ShowSettings } from './ShowSettings';
const { apiLocation } = envData;
describe('<ShowSettings />', () => { describe('<ShowSettings />', () => {
it('renders to the DOM when user is logged in', () => { it('renders to the DOM when user is logged in', () => {
const shallow = new ShallowRenderer(); const shallow = new ShallowRenderer();

View File

@ -4,11 +4,11 @@ import { Grid, Panel, Button } from '@freecodecamp/react-bootstrap';
import Helmet from 'react-helmet'; import Helmet from 'react-helmet';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import env from '../../../config/env.json'; import envData from '../../../config/env.json';
import FullWidthRow from '../components/helpers/FullWidthRow'; import FullWidthRow from '../components/helpers/FullWidthRow';
import { Spacer } from '../components/helpers'; import { Spacer } from '../components/helpers';
const { apiLocation } = env; const { apiLocation } = envData;
function ShowUnsubscribed({ unsubscribeId }) { function ShowUnsubscribed({ unsubscribeId }) {
const { t } = useTranslation(); const { t } = useTranslation();

View File

@ -24,7 +24,7 @@ import {
donationUrls, donationUrls,
modalDefaultDonation modalDefaultDonation
} from '../../../../config/donation-settings'; } from '../../../../config/donation-settings';
import { stripePublicKey, deploymentEnv } from '../../../../config/env.json'; import envData from '../../../../config/env.json';
import { stripeScriptLoader } from '../../utils/scriptLoaders'; import { stripeScriptLoader } from '../../utils/scriptLoaders';
import Spacer from '../helpers/Spacer'; import Spacer from '../helpers/Spacer';
import PaypalButton from './PaypalButton'; import PaypalButton from './PaypalButton';
@ -44,6 +44,8 @@ import {
import './Donation.css'; import './Donation.css';
const { stripePublicKey, deploymentEnv } = envData;
const numToCommas = num => const numToCommas = num =>
num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'); num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');

View File

@ -7,13 +7,14 @@ import { createSelector } from 'reselect';
import PayPalButtonScriptLoader from './PayPalButtonScriptLoader'; import PayPalButtonScriptLoader from './PayPalButtonScriptLoader';
import { withTranslation } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import { paypalClientId, deploymentEnv } from '../../../../config/env.json'; import envData from '../../../../config/env.json';
import { import {
paypalConfigurator, paypalConfigurator,
paypalConfigTypes paypalConfigTypes
} from '../../../../config/donation-settings'; } from '../../../../config/donation-settings';
import { signInLoadingSelector, userSelector } from '../../redux'; import { signInLoadingSelector, userSelector } from '../../redux';
const { paypalClientId, deploymentEnv } = envData;
export class PaypalButton extends Component { export class PaypalButton extends Component {
constructor(props) { constructor(props) {
super(props); super(props);

View File

@ -6,7 +6,9 @@ import { UniversalNav } from './components/UniversalNav';
import { NavLinks } from './components/NavLinks'; import { NavLinks } from './components/NavLinks';
import AuthOrProfile from './components/AuthOrProfile'; import AuthOrProfile from './components/AuthOrProfile';
import { apiLocation, clientLocale } from '../../../../config/env.json'; import envData from '../../../../config/env.json';
const { apiLocation, clientLocale } = envData;
describe('<UniversalNav />', () => { describe('<UniversalNav />', () => {
const UniversalNavProps = { const UniversalNavProps = {

View File

@ -6,10 +6,12 @@ import { Button } from '@freecodecamp/react-bootstrap';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { isSignedInSelector } from '../../../redux'; import { isSignedInSelector } from '../../../redux';
import { apiLocation, homeLocation } from '../../../../../config/env.json'; import envData from '../../../../../config/env.json';
import './login.css'; import './login.css';
const { apiLocation, homeLocation } = envData;
const mapStateToProps = createSelector(isSignedInSelector, isSignedIn => ({ const mapStateToProps = createSelector(isSignedInSelector, isSignedIn => ({
isSignedIn isSignedIn
})); }));

View File

@ -12,14 +12,12 @@ import {
} from '@fortawesome/free-solid-svg-icons'; } from '@fortawesome/free-solid-svg-icons';
import { Link } from '../../helpers'; import { Link } from '../../helpers';
import { updateUserFlag } from '../../../redux/settings'; import { updateUserFlag } from '../../../redux/settings';
import { import envData from '../../../../../config/env.json';
clientLocale,
radioLocation,
apiLocation
} from '../../../../../config/env.json';
import createLanguageRedirect from '../../createLanguageRedirect'; import createLanguageRedirect from '../../createLanguageRedirect';
import createExternalRedirect from '../../createExternalRedirects'; import createExternalRedirect from '../../createExternalRedirects';
const { clientLocale, radioLocation, apiLocation } = envData;
const { const {
availableLangs, availableLangs,
i18nextCodes, i18nextCodes,

View File

@ -1,10 +1,11 @@
import React from 'react'; import React from 'react';
import { Link, Spacer } from '../../helpers'; import { Link, Spacer } from '../../helpers';
import { forumLocation } from '../../../../../config/env.json'; import envData from '../../../../../config/env.json';
import { Trans, useTranslation } from 'react-i18next'; import { Trans, useTranslation } from 'react-i18next';
import '../intro.css'; import '../intro.css';
const { forumLocation } = envData;
function IntroDescription() { function IntroDescription() {
const { t } = useTranslation(); const { t } = useTranslation();

View File

@ -8,7 +8,9 @@ import { Link, Spacer } from '../helpers';
import LinkButton from '../../assets/icons/LinkButton'; import LinkButton from '../../assets/icons/LinkButton';
import './map.css'; import './map.css';
import { isAuditedCert } from '../../../../utils/is-audited'; import { isAuditedCert } from '../../../../utils/is-audited';
import { curriculumLocale } from '../../../../config/env.json'; import envData from '../../../../config/env.json';
const { curriculumLocale } = envData;
const propTypes = { const propTypes = {
currentSuperBlock: PropTypes.string, currentSuperBlock: PropTypes.string,

View File

@ -1,4 +1,6 @@
import { forumLocation } from '../../../config/env.json'; import envData from '../../../config/env.json';
const { forumLocation } = envData;
const createExternalRedirect = (page, { clientLocale }) => { const createExternalRedirect = (page, { clientLocale }) => {
const isNotEnglish = clientLocale !== 'english'; const isNotEnglish = clientLocale !== 'english';

View File

@ -1,7 +1,9 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { apiLocation } from '../../../../config/env.json'; import envData from '../../../../config/env.json';
const { apiLocation } = envData;
const currentChallengeApi = '/challenges/current-challenge'; const currentChallengeApi = '/challenges/current-challenge';

View File

@ -1,4 +1,4 @@
export default ` const styles = `
.sprite-container { .sprite-container {
height: 100%; height: 100%;
@ -71,3 +71,5 @@ export default `
animation-direction: normal; animation-direction: normal;
} }
`; `;
export default styles;

View File

@ -2,7 +2,7 @@
import React from 'react'; import React from 'react';
import ShallowRenderer from 'react-test-renderer/shallow'; import ShallowRenderer from 'react-test-renderer/shallow';
import { IndexPage } from '../../pages'; import IndexPage from '../../pages';
import mockChallengeNodes from '../../__mocks__/challenge-nodes'; import mockChallengeNodes from '../../__mocks__/challenge-nodes';
describe('<Landing />', () => { describe('<Landing />', () => {

View File

@ -11,7 +11,9 @@ import HeatMap from './components/HeatMap';
import Certifications from './components/Certifications'; import Certifications from './components/Certifications';
import Portfolio from './components/Portfolio'; import Portfolio from './components/Portfolio';
import Timeline from './components/TimeLine'; import Timeline from './components/TimeLine';
import { apiLocation } from '../../../../config/env.json'; import envData from '../../../../config/env.json';
const { apiLocation } = envData;
const propTypes = { const propTypes = {
isSessionUser: PropTypes.bool, isSessionUser: PropTypes.bool,

View File

@ -16,8 +16,9 @@ import Link from '../../helpers/Link';
import './camper.css'; import './camper.css';
import { langCodes } from '../../../../../config/i18n/all-langs'; import { langCodes } from '../../../../../config/i18n/all-langs';
import { clientLocale } from '../../../../../config/env.json'; import envData from '../../../../../config/env.json';
const { clientLocale } = envData;
const localeCode = langCodes[clientLocale]; const localeCode = langCodes[clientLocale];
const propTypes = { const propTypes = {

View File

@ -16,7 +16,9 @@ import '@freecodecamp/react-calendar-heatmap/dist/styles.css';
import './heatmap.css'; import './heatmap.css';
import { langCodes } from '../../../../../config/i18n/all-langs'; import { langCodes } from '../../../../../config/i18n/all-langs';
import { clientLocale } from '../../../../../config/env.json'; import envData from '../../../../../config/env.json';
const { clientLocale } = envData;
const localeCode = langCodes[clientLocale]; const localeCode = langCodes[clientLocale];

View File

@ -25,7 +25,9 @@ import { maybeUrlRE } from '../../../utils';
import CertificationIcon from '../../../assets/icons/CertificationIcon'; import CertificationIcon from '../../../assets/icons/CertificationIcon';
import { langCodes } from '../../../../../config/i18n/all-langs'; import { langCodes } from '../../../../../config/i18n/all-langs';
import { clientLocale } from '../../../../../config/env.json'; import envData from '../../../../../config/env.json';
const { clientLocale } = envData;
const localeCode = langCodes[clientLocale]; const localeCode = langCodes[clientLocale];

View File

@ -15,10 +15,12 @@ import {
toggleSearchDropdown, toggleSearchDropdown,
updateSearchQuery updateSearchQuery
} from './redux'; } from './redux';
import { algoliaAppId, algoliaAPIKey } from '../../../../config/env.json'; import envData from '../../../../config/env.json';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
const { algoliaAppId, algoliaAPIKey } = envData;
const DEBOUNCE_TIME = 100; const DEBOUNCE_TIME = 100;
// If a key is missing, searches will fail, but the client will still render. // If a key is missing, searches will fail, but the client will still render.

View File

@ -3,6 +3,8 @@ import React from 'react';
import { Router } from '@reach/router'; import { Router } from '@reach/router';
import { navigate, withPrefix } from 'gatsby'; import { navigate, withPrefix } from 'gatsby';
import toLearnPath from '../utils/to-learn-path';
const Redirect = props => { const Redirect = props => {
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
navigate(toLearnPath(props)); navigate(toLearnPath(props));
@ -21,12 +23,4 @@ const Challenges = () => (
Challenges.displayName = 'Challenges'; Challenges.displayName = 'Challenges';
export function toLearnPath({ superBlock, block, challenge }) {
let path = withPrefix('/learn');
if (superBlock) path += `/${superBlock}`;
if (block) path += `/${block}`;
if (challenge) path += `/${challenge}`;
return path;
}
export default Challenges; export default Challenges;

View File

@ -1,5 +1,5 @@
/* global expect */ /* global expect */
import { toLearnPath } from './challenges'; import toLearnPath from '../utils/to-learn-path';
import { withPrefix } from 'gatsby'; import { withPrefix } from 'gatsby';
describe('toLearnPath', () => { describe('toLearnPath', () => {

View File

@ -42,7 +42,7 @@ const mapDispatchToProps = dispatch =>
dispatch dispatch
); );
export class DonatePage extends Component { class DonatePage extends Component {
constructor(...props) { constructor(...props) {
super(...props); super(...props);
this.state = { this.state = {

View File

@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
import Landing from '../components/landing'; import Landing from '../components/landing';
import { AllChallengeNode } from '../redux/propTypes'; import { AllChallengeNode } from '../redux/propTypes';
export const IndexPage = () => { const IndexPage = () => {
return <Landing />; return <Landing />;
}; };

View File

@ -47,7 +47,7 @@ const propTypes = {
}) })
}; };
export const LearnPage = ({ const LearnPage = ({
isSignedIn, isSignedIn,
fetchState: { pending, complete }, fetchState: { pending, complete },
user: { name = '', completedChallengeCount = 0 }, user: { name = '', completedChallengeCount = 0 },

View File

@ -9,7 +9,9 @@ import rootReducer from './rootReducer';
import rootSaga from './rootSaga'; import rootSaga from './rootSaga';
import { isBrowser } from '../../utils'; import { isBrowser } from '../../utils';
import { environment } from '../../../config/env.json'; import envData from '../../../config/env.json';
const { environment } = envData;
const clientSide = isBrowser(); const clientSide = isBrowser();

View File

@ -22,4 +22,6 @@ function* errorHandlerSaga({ payload: error }) {
yield put(createFlashMessage(reportedErrorMessage)); yield put(createFlashMessage(reportedErrorMessage));
} }
export default [takeEvery(errorActionSelector, errorHandlerSaga)]; const errorSagas = [takeEvery(errorActionSelector, errorHandlerSaga)];
export default errorSagas;

View File

@ -4,7 +4,9 @@ import PropTypes from 'prop-types';
import { first } from 'lodash'; import { first } from 'lodash';
import EditorTabs from './EditorTabs'; import EditorTabs from './EditorTabs';
import ActionRow from './ActionRow'; import ActionRow from './ActionRow';
import { showUpcomingChanges } from '../../../../../config/env.json'; import envData from '../../../../../config/env.json';
const { showUpcomingChanges } = envData;
const propTypes = { const propTypes = {
challengeFiles: PropTypes.object, challengeFiles: PropTypes.object,

View File

@ -8,9 +8,11 @@ import { createStructuredSelector } from 'reselect';
import { currentTabSelector, moveToTab } from '../redux'; import { currentTabSelector, moveToTab } from '../redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import EditorTabs from './EditorTabs'; import EditorTabs from './EditorTabs';
import { showUpcomingChanges } from '../../../../../config/env.json'; import envData from '../../../../../config/env.json';
import i18next from 'i18next'; import i18next from 'i18next';
const { showUpcomingChanges } = envData;
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
currentTab: currentTabSelector currentTab: currentTabSelector
}); });

View File

@ -7,10 +7,12 @@ import { Trans, withTranslation } from 'react-i18next';
import { createQuestion, closeModal, isHelpModalOpenSelector } from '../redux'; import { createQuestion, closeModal, isHelpModalOpenSelector } from '../redux';
import { executeGA } from '../../../redux'; import { executeGA } from '../../../redux';
import { forumLocation } from '../../../../../config/env.json'; import envData from '../../../../../config/env.json';
import './help-modal.css'; import './help-modal.css';
const { forumLocation } = envData;
const mapStateToProps = state => ({ isOpen: isHelpModalOpenSelector(state) }); const mapStateToProps = state => ({ isOpen: isHelpModalOpenSelector(state) });
const mapDispatchToProps = dispatch => const mapDispatchToProps = dispatch =>
bindActionCreators( bindActionCreators(

View File

@ -82,7 +82,7 @@ const mapDispatchToActions = {
updateSolutionFormValues updateSolutionFormValues
}; };
export class BackEnd extends Component { class BackEnd extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = {}; this.state = {};

View File

@ -62,7 +62,7 @@ const propTypes = {
updateSolutionFormValues: PropTypes.func.isRequired updateSolutionFormValues: PropTypes.func.isRequired
}; };
export class Project extends Component { class Project extends Component {
constructor() { constructor() {
super(); super();
this.handleSubmit = this.handleSubmit.bind(this); this.handleSubmit = this.handleSubmit.bind(this);

View File

@ -17,7 +17,9 @@ import createWorker from '../utils/worker-executor';
// the config files are created during the build, but not before linting // the config files are created during the build, but not before linting
// eslint-disable-next-line import/no-unresolved // eslint-disable-next-line import/no-unresolved
import { filename as sassCompile } from '../../../../../config/client/sass-compile'; import sassData from '../../../../../config/client/sass-compile.json';
const { filename: sassCompile } = sassData;
const protectTimeout = 100; const protectTimeout = 100;
const testProtectTimeout = 1500; const testProtectTimeout = 1500;

View File

@ -8,7 +8,9 @@ import {
projectFormValuesSelector projectFormValuesSelector
} from '../redux'; } from '../redux';
import { tap, mapTo } from 'rxjs/operators'; import { tap, mapTo } from 'rxjs/operators';
import { forumLocation } from '../../../../../config/env.json'; import envData from '../../../../../config/env.json';
const { forumLocation } = envData;
function filesToMarkdown(files = {}) { function filesToMarkdown(files = {}) {
const moreThenOneFile = Object.keys(files).length > 1; const moreThenOneFile = Object.keys(files).length > 1;

View File

@ -10,9 +10,12 @@ import {
// the config files are created during the build, but not before linting // the config files are created during the build, but not before linting
// eslint-disable-next-line import/no-unresolved // eslint-disable-next-line import/no-unresolved
import { filename as runner } from '../../../../../config/client/frame-runner'; import frameRunnerData from '../../../../../config/client/frame-runner.json';
// eslint-disable-next-line import/no-unresolved // eslint-disable-next-line import/no-unresolved
import { filename as testEvaluator } from '../../../../../config/client/test-evaluator'; import testEvaluatorData from '../../../../../config/client/test-evaluator.json';
const { filename: runner } = frameRunnerData;
const { filename: testEvaluator } = testEvaluatorData;
const frameRunner = [ const frameRunner = [
{ {

View File

@ -1,4 +1,6 @@
import { forumLocation } from '../../../../../config/env.json'; import envData from '../../../../../config/env.json';
const { forumLocation } = envData;
export function getGuideUrl({ forumTopicId, title = '' }) { export function getGuideUrl({ forumTopicId, title = '' }) {
title = encodeURIComponent(title); title = encodeURIComponent(title);

View File

@ -1,6 +1,8 @@
/* global expect */ /* global expect */
import { forumLocation } from '../../../../../config/env.json'; import envData from '../../../../../config/env.json';
const { forumLocation } = envData;
const { getGuideUrl } = require('./'); const { getGuideUrl } = require('./');

View File

@ -68,7 +68,7 @@ const propTypes = {
}; };
// Component // Component
export class Project extends Component { class Project extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {

View File

@ -71,7 +71,7 @@ const mapDispatchToProps = dispatch =>
dispatch dispatch
); );
export class SuperBlockIntroductionPage extends Component { class SuperBlockIntroductionPage extends Component {
componentDidMount() { componentDidMount() {
this.initializeExpandedState(); this.initializeExpandedState();

View File

@ -13,9 +13,11 @@ import Caret from '../../../assets/icons/Caret';
import GreenPass from '../../../assets/icons/GreenPass'; import GreenPass from '../../../assets/icons/GreenPass';
import GreenNotCompleted from '../../../assets/icons/GreenNotCompleted'; import GreenNotCompleted from '../../../assets/icons/GreenNotCompleted';
import { isAuditedCert } from '../../../../../utils/is-audited'; import { isAuditedCert } from '../../../../../utils/is-audited';
import { curriculumLocale } from '../../../../../config/env.json'; import envData from '../../../../../config/env.json';
import { Link } from '../../../components/helpers/'; import { Link } from '../../../components/helpers/';
const { curriculumLocale } = envData;
const mapStateToProps = (state, ownProps) => { const mapStateToProps = (state, ownProps) => {
const expandedSelector = makeExpandedBlockSelector(ownProps.blockDashedName); const expandedSelector = makeExpandedBlockSelector(ownProps.blockDashedName);

View File

@ -1,8 +1,10 @@
import { apiLocation } from '../../../config/env.json'; import envData from '../../../config/env.json';
import axios from 'axios'; import axios from 'axios';
import Tokens from 'csrf'; import Tokens from 'csrf';
import cookies from 'browser-cookies'; import cookies from 'browser-cookies';
const { apiLocation } = envData;
const base = apiLocation; const base = apiLocation;
const tokens = new Tokens(); const tokens = new Tokens();

View File

@ -1,4 +1,6 @@
import { clientLocale } from '../../../config/env.json'; import envData from '../../../config/env.json';
const { clientLocale } = envData;
const algoliaIndices = { const algoliaIndices = {
english: { english: {

View File

@ -27,9 +27,11 @@ const removeWhiteSpace = (str = '') => {
return str.replace(/\s/g, ''); return str.replace(/\s/g, '');
}; };
export default { const curriculumHelpers = {
removeHtmlComments, removeHtmlComments,
removeCssComments, removeCssComments,
removeJSComments, removeJSComments,
removeWhiteSpace removeWhiteSpace
}; };
export default curriculumHelpers;

View File

@ -1,4 +1,6 @@
export default { const reallyWeirdErrorMessage = {
type: 'danger', type: 'danger',
message: 'flash.really-weird' message: 'flash.really-weird'
}; };
export default reallyWeirdErrorMessage;

View File

@ -1,4 +1,6 @@
export default { const reportedErrorMessage = {
type: 'danger', type: 'danger',
message: 'flash.not-right' message: 'flash.not-right'
}; };
export default reportedErrorMessage;

View File

@ -1,4 +1,6 @@
export default { const standardErrorMessage = {
type: 'danger', type: 'danger',
message: 'flash.went-wrong' message: 'flash.went-wrong'
}; };
export default standardErrorMessage;

View File

@ -0,0 +1,9 @@
import { withPrefix } from 'gatsby';
export default function toLearnPath({ superBlock, block, challenge }) {
let path = withPrefix('/learn');
if (superBlock) path += `/${superBlock}`;
if (block) path += `/${block}`;
if (challenge) path += `/${challenge}`;
return path;
}

View File

@ -6,7 +6,9 @@ const {
challengesDir, challengesDir,
getChallengesDirForLang getChallengesDirForLang
} = require('../../curriculum/getChallenges'); } = require('../../curriculum/getChallenges');
const { curriculumLocale } = require('../../config/env.json'); const envData = require('../../config/env.json');
const { curriculumLocale } = envData;
exports.localeChallengesRootDir = getChallengesDirForLang(curriculumLocale); exports.localeChallengesRootDir = getChallengesDirForLang(curriculumLocale);

View File

@ -1,4 +1,5 @@
const path = require('path'); const path = require('path');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin');
const { writeFileSync } = require('fs'); const { writeFileSync } = require('fs');
@ -60,7 +61,21 @@ module.exports = (env = {}) => {
plugins: [ plugins: [
new CopyWebpackPlugin([ new CopyWebpackPlugin([
{ from: 'node_modules/sass.js/dist/sass.sync.js' } { from: 'node_modules/sass.js/dist/sass.sync.js' }
]) ]),
] new webpack.ProvidePlugin({
process: 'process/browser'
}),
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer']
})
],
resolve: {
fallback: {
buffer: require.resolve('buffer'),
util: false,
stream: false,
process: require.resolve('process/browser')
}
}
}; };
}; };

View File

@ -61,7 +61,8 @@ const TRANSLATABLE_COMMENTS = getTranslatableComments(
// the config files are created during the build, but not before linting // the config files are created during the build, but not before linting
// eslint-disable-next-line import/no-unresolved // eslint-disable-next-line import/no-unresolved
const testEvaluator = require('../../config/client/test-evaluator').filename; const testEvaluator = require('../../config/client/test-evaluator.json')
.filename;
const { inspect } = require('util'); const { inspect } = require('util');
const commentExtractors = { const commentExtractors = {