mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat(tools): modularize browser-scripts (#65399)
This commit is contained in:
committed by
GitHub
parent
3152bff893
commit
e5cae6909c
@@ -12,7 +12,6 @@ yarn-error.log
|
|||||||
static/curriculum-data
|
static/curriculum-data
|
||||||
|
|
||||||
# Generated config
|
# Generated config
|
||||||
config/browser-scripts/*.json
|
|
||||||
i18n/locales/**/trending.json
|
i18n/locales/**/trending.json
|
||||||
i18n/locales/**/search-bar.json
|
i18n/locales/**/search-bar.json
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -21,7 +21,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "pnpm run common-setup && pnpm run build:scripts --env production",
|
"prebuild": "pnpm run common-setup && pnpm run build:scripts --env production",
|
||||||
"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",
|
||||||
"build:scripts": "pnpm run -F=browser-scripts compile",
|
"build:scripts": "pnpm run -F=browser-scripts compile && tsx ./tools/copy-browser-scripts.ts",
|
||||||
"build:external-curriculum": "tsx ./tools/external-curriculum/build",
|
"build:external-curriculum": "tsx ./tools/external-curriculum/build",
|
||||||
"clean": "gatsby clean",
|
"clean": "gatsby clean",
|
||||||
"common-setup": "pnpm -w turbo compile && pnpm run create:env && pnpm run create:trending && pnpm run create:search-placeholder",
|
"common-setup": "pnpm -w turbo compile && pnpm run create:env && pnpm run create:trending && pnpm run create:search-placeholder",
|
||||||
@@ -144,6 +144,7 @@
|
|||||||
"@freecodecamp/eslint-config": "workspace:*",
|
"@freecodecamp/eslint-config": "workspace:*",
|
||||||
"@freecodecamp/shared": "workspace:*",
|
"@freecodecamp/shared": "workspace:*",
|
||||||
"@freecodecamp/curriculum": "workspace:*",
|
"@freecodecamp/curriculum": "workspace:*",
|
||||||
|
"@freecodecamp/browser-scripts": "workspace:*",
|
||||||
"@testing-library/jest-dom": "^6.8.0",
|
"@testing-library/jest-dom": "^6.8.0",
|
||||||
"@testing-library/react": "12.1.5",
|
"@testing-library/react": "12.1.5",
|
||||||
"@testing-library/react-hooks": "^8.0.1",
|
"@testing-library/react-hooks": "^8.0.1",
|
||||||
|
|||||||
@@ -9,21 +9,20 @@ import {
|
|||||||
stubTrue
|
stubTrue
|
||||||
} from 'lodash-es';
|
} from 'lodash-es';
|
||||||
|
|
||||||
import sassData from '../../../../config/browser-scripts/sass-compile.json';
|
|
||||||
import {
|
import {
|
||||||
transformContents,
|
transformContents,
|
||||||
transformHeadTailAndContents,
|
transformHeadTailAndContents,
|
||||||
compileHeadTail,
|
compileHeadTail,
|
||||||
createSource
|
createSource
|
||||||
} from '@freecodecamp/shared/utils/polyvinyl';
|
} from '@freecodecamp/shared/utils/polyvinyl';
|
||||||
|
import { version } from '@freecodecamp/browser-scripts/package.json';
|
||||||
|
|
||||||
import { WorkerExecutor } from '../utils/worker-executor';
|
import { WorkerExecutor } from '../utils/worker-executor';
|
||||||
import {
|
import {
|
||||||
compileTypeScriptCode,
|
compileTypeScriptCode,
|
||||||
checkTSServiceIsReady
|
checkTSServiceIsReady
|
||||||
} from '../utils/typescript-worker-handler';
|
} from '../utils/typescript-worker-handler';
|
||||||
|
|
||||||
const { filename: sassCompile } = sassData;
|
|
||||||
|
|
||||||
const protectTimeout = 100;
|
const protectTimeout = 100;
|
||||||
const testProtectTimeout = 1500;
|
const testProtectTimeout = 1500;
|
||||||
const loopsPerTimeoutCheck = 100;
|
const loopsPerTimeoutCheck = 100;
|
||||||
@@ -209,7 +208,9 @@ function getBabelOptions(
|
|||||||
return presets;
|
return presets;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sassWorkerExecutor = new WorkerExecutor(sassCompile);
|
const sassWorkerExecutor = new WorkerExecutor(
|
||||||
|
`workers/${version}/sass-compile`
|
||||||
|
);
|
||||||
async function transformSASS(documentElement) {
|
async function transformSASS(documentElement) {
|
||||||
// we only teach scss syntax, not sass. Also the compiler does not seem to be
|
// we only teach scss syntax, not sass. Also the compiler does not seem to be
|
||||||
// able to deal with sass.
|
// able to deal with sass.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// TODO: This might be cleaner as a class.
|
import { version } from '@freecodecamp/browser-scripts/package.json';
|
||||||
import pythonWorkerData from '../../../../config/browser-scripts/python-worker.json';
|
|
||||||
|
|
||||||
const pythonWorkerSrc = `/js/${pythonWorkerData.filename}.js`;
|
// TODO: This might be cleaner as a class.
|
||||||
|
const pythonWorkerSrc = `/js/workers/${version}/python-worker.js`;
|
||||||
|
|
||||||
let worker: Worker | null = null;
|
let worker: Worker | null = null;
|
||||||
let listener: ((event: MessageEvent) => void) | null = null;
|
let listener: ((event: MessageEvent) => void) | null = null;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import typeScriptWorkerData from '../../../../config/browser-scripts/typescript-worker.json';
|
import { version } from '@freecodecamp/browser-scripts/package.json';
|
||||||
|
|
||||||
import { awaitResponse } from './awaitable-messenger';
|
import { awaitResponse } from './awaitable-messenger';
|
||||||
|
|
||||||
const typeScriptWorkerSrc = `/js/${typeScriptWorkerData.filename}.js`;
|
const typeScriptWorkerSrc = `/js/workers/${version}/typescript-worker.js`;
|
||||||
|
|
||||||
let worker: Worker | null = null;
|
let worker: Worker | null = null;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { cpSync, mkdirSync, rmSync } from 'node:fs';
|
||||||
|
|
||||||
|
import { resolve } from 'node:path';
|
||||||
|
|
||||||
|
const browserScriptDist = resolve(
|
||||||
|
__dirname,
|
||||||
|
'../../tools/client-plugins/browser-scripts/dist'
|
||||||
|
);
|
||||||
|
|
||||||
|
const destJsDir = resolve(__dirname, '../static/js');
|
||||||
|
|
||||||
|
// Everything is done synchronously to keep the script simple. There's no
|
||||||
|
// performance benefit to doing this asynchronously since it's already so fast.
|
||||||
|
rmSync(destJsDir, { recursive: true, force: true });
|
||||||
|
mkdirSync(destJsDir, { recursive: true });
|
||||||
|
|
||||||
|
cpSync(resolve(browserScriptDist, 'artifacts'), destJsDir, {
|
||||||
|
recursive: true
|
||||||
|
});
|
||||||
@@ -1 +1,2 @@
|
|||||||
generated
|
generated
|
||||||
|
src/test/stubs/js
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
"@babel/register": "7.23.7",
|
"@babel/register": "7.23.7",
|
||||||
"@freecodecamp/eslint-config": "workspace:*",
|
"@freecodecamp/eslint-config": "workspace:*",
|
||||||
"@freecodecamp/shared": "workspace:*",
|
"@freecodecamp/shared": "workspace:*",
|
||||||
|
"@freecodecamp/browser-scripts": "workspace:*",
|
||||||
"@total-typescript/ts-reset": "^0.6.1",
|
"@total-typescript/ts-reset": "^0.6.1",
|
||||||
"@types/debug": "^4.1.12",
|
"@types/debug": "^4.1.12",
|
||||||
"@types/js-yaml": "4.0.5",
|
"@types/js-yaml": "4.0.5",
|
||||||
|
|||||||
@@ -3,10 +3,8 @@ import path from 'node:path';
|
|||||||
import sirv from 'sirv';
|
import sirv from 'sirv';
|
||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import puppeteer from 'puppeteer';
|
import puppeteer from 'puppeteer';
|
||||||
|
import { cpSync, mkdirSync, rmSync } from 'node:fs';
|
||||||
import { helperVersion } from '../../../client/src/templates/Challenges/utils/frame';
|
import { version } from '@freecodecamp/browser-scripts/test-runner';
|
||||||
|
|
||||||
const clientPath = path.resolve(__dirname, '../../../client');
|
|
||||||
|
|
||||||
async function createBrowser() {
|
async function createBrowser() {
|
||||||
return puppeteer.launch({
|
return puppeteer.launch({
|
||||||
@@ -21,6 +19,20 @@ async function createBrowser() {
|
|||||||
|
|
||||||
let browser, server;
|
let browser, server;
|
||||||
|
|
||||||
|
function setupStubs() {
|
||||||
|
const browserScriptDist = path.resolve(
|
||||||
|
__dirname,
|
||||||
|
'../../../tools/client-plugins/browser-scripts/dist'
|
||||||
|
);
|
||||||
|
const destArtifactsDir = path.resolve(__dirname, 'stubs/js');
|
||||||
|
|
||||||
|
rmSync(destArtifactsDir, { recursive: true, force: true });
|
||||||
|
mkdirSync(destArtifactsDir, { recursive: true });
|
||||||
|
cpSync(path.resolve(browserScriptDist, 'artifacts'), destArtifactsDir, {
|
||||||
|
recursive: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function startServer() {
|
async function startServer() {
|
||||||
const host = '127.0.0.1';
|
const host = '127.0.0.1';
|
||||||
const port = 8080;
|
const port = 8080;
|
||||||
@@ -29,16 +41,16 @@ async function startServer() {
|
|||||||
|
|
||||||
// Mount static files used by the tests
|
// Mount static files used by the tests
|
||||||
app.use(
|
app.use(
|
||||||
'/dist',
|
'/dist', // the runner is mounted at dist so we don't need to specify the asset path when initializing
|
||||||
sirv(path.join(clientPath, `static/js/test-runner/${helperVersion}`))
|
sirv(path.resolve(__dirname, `stubs/js/test-runner/${version}`))
|
||||||
);
|
);
|
||||||
app.use('/js', sirv(path.join(clientPath, 'static/js')));
|
|
||||||
app.use('/', sirv(path.resolve(__dirname, 'stubs')));
|
app.use('/', sirv(path.resolve(__dirname, 'stubs')));
|
||||||
app.listen(port, host);
|
app.listen(port, host);
|
||||||
return app.server;
|
return app.server;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setup() {
|
export async function setup() {
|
||||||
|
setupStubs();
|
||||||
server = await startServer();
|
server = await startServer();
|
||||||
browser = await createBrowser();
|
browser = await createBrowser();
|
||||||
// Sharing the Websocket endpoint so that setup files can connect. This allows
|
// Sharing the Websocket endpoint so that setup files can connect. This allows
|
||||||
|
|||||||
Generated
+6
@@ -550,6 +550,9 @@ importers:
|
|||||||
'@babel/plugin-syntax-dynamic-import':
|
'@babel/plugin-syntax-dynamic-import':
|
||||||
specifier: 7.8.3
|
specifier: 7.8.3
|
||||||
version: 7.8.3(@babel/core@7.28.5)
|
version: 7.8.3(@babel/core@7.28.5)
|
||||||
|
'@freecodecamp/browser-scripts':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../tools/client-plugins/browser-scripts
|
||||||
'@freecodecamp/curriculum':
|
'@freecodecamp/curriculum':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../curriculum
|
version: link:../curriculum
|
||||||
@@ -710,6 +713,9 @@ importers:
|
|||||||
'@babel/register':
|
'@babel/register':
|
||||||
specifier: 7.23.7
|
specifier: 7.23.7
|
||||||
version: 7.23.7(@babel/core@7.23.7)
|
version: 7.23.7(@babel/core@7.23.7)
|
||||||
|
'@freecodecamp/browser-scripts':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../tools/client-plugins/browser-scripts
|
||||||
'@freecodecamp/eslint-config':
|
'@freecodecamp/eslint-config':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../packages/eslint-config
|
version: link:../packages/eslint-config
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
dist
|
||||||
@@ -8,6 +8,13 @@
|
|||||||
"node": ">=24",
|
"node": ">=24",
|
||||||
"pnpm": ">=10"
|
"pnpm": ">=10"
|
||||||
},
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"exports": {
|
||||||
|
"./test-runner": "./test-runner.ts",
|
||||||
|
"./package.json": "./package.json"
|
||||||
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/freeCodeCamp/freeCodeCamp.git"
|
"url": "git+https://github.com/freeCodeCamp/freeCodeCamp.git"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { version } from '@freecodecamp/browser-scripts/package.json';
|
||||||
// work around for SASS error in Edge
|
// work around for SASS error in Edge
|
||||||
// https://github.com/medialize/sass.js/issues/96#issuecomment-424386171
|
// https://github.com/medialize/sass.js/issues/96#issuecomment-424386171
|
||||||
interface WorkerWithSass extends Worker {
|
interface WorkerWithSass extends Worker {
|
||||||
@@ -20,7 +21,7 @@ if (!ctx.crypto) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.importScripts('/js/sass.sync.js');
|
ctx.importScripts(`/js/workers/${version}/sass.sync.js`);
|
||||||
|
|
||||||
ctx.onmessage = e => {
|
ctx.onmessage = e => {
|
||||||
const data: unknown = e.data;
|
const data: unknown = e.data;
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
const { writeFileSync } = require('fs');
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const {
|
const {
|
||||||
version: helperVersion
|
version: helperVersion
|
||||||
} = require('@freecodecamp/curriculum-helpers/package.json');
|
} = require('@freecodecamp/curriculum-helpers/package.json');
|
||||||
|
const { version } = require('./package.json');
|
||||||
|
|
||||||
module.exports = (env = {}) => {
|
module.exports = (env = {}) => {
|
||||||
const __DEV__ = env.production !== true;
|
const __DEV__ = env.production !== true;
|
||||||
const staticPath = path.join(__dirname, '../../../client/static/js');
|
|
||||||
const configPath = path.join(
|
|
||||||
__dirname,
|
|
||||||
'../../../client/config/browser-scripts/'
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
cache: __DEV__ ? { type: 'filesystem' } : false,
|
cache: __DEV__ ? { type: 'filesystem' } : false,
|
||||||
mode: __DEV__ ? 'development' : 'production',
|
mode: __DEV__ ? 'development' : 'production',
|
||||||
@@ -23,19 +19,9 @@ module.exports = (env = {}) => {
|
|||||||
},
|
},
|
||||||
devtool: __DEV__ ? 'inline-source-map' : 'source-map',
|
devtool: __DEV__ ? 'inline-source-map' : 'source-map',
|
||||||
output: {
|
output: {
|
||||||
publicPath: '/js/',
|
|
||||||
filename: chunkData => {
|
|
||||||
// construct and output the filename here, so the client can use the
|
|
||||||
// json to find the file.
|
|
||||||
const filename = `${chunkData.chunk.name}-${chunkData.chunk.contentHash.javascript}`;
|
|
||||||
writeFileSync(
|
|
||||||
path.join(configPath, `${chunkData.chunk.name}.json`),
|
|
||||||
`{"filename": "${filename}"}`
|
|
||||||
);
|
|
||||||
return filename + '.js';
|
|
||||||
},
|
|
||||||
chunkFilename: '[name]-[contenthash].js',
|
chunkFilename: '[name]-[contenthash].js',
|
||||||
path: staticPath
|
path: path.resolve(__dirname, `dist/artifacts/workers/${version}`),
|
||||||
|
clean: true
|
||||||
},
|
},
|
||||||
stats: {
|
stats: {
|
||||||
// Display bailout reasons
|
// Display bailout reasons
|
||||||
@@ -74,7 +60,7 @@ module.exports = (env = {}) => {
|
|||||||
'./node_modules/xterm/css/xterm.css',
|
'./node_modules/xterm/css/xterm.css',
|
||||||
{
|
{
|
||||||
from: './node_modules/@freecodecamp/curriculum-helpers/dist/test-runner',
|
from: './node_modules/@freecodecamp/curriculum-helpers/dist/test-runner',
|
||||||
to: `test-runner/${helperVersion}/`
|
to: `../../test-runner/${helperVersion}/`
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user