mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-06-05 21:04:28 +08:00
feat(tools): modularize browser-scripts (#65399)
This commit is contained in:
parent
3152bff893
commit
e5cae6909c
1
client/.gitignore
vendored
1
client/.gitignore
vendored
@ -12,7 +12,6 @@ yarn-error.log
|
||||
static/curriculum-data
|
||||
|
||||
# Generated config
|
||||
config/browser-scripts/*.json
|
||||
i18n/locales/**/trending.json
|
||||
i18n/locales/**/search-bar.json
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
"scripts": {
|
||||
"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: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",
|
||||
"clean": "gatsby clean",
|
||||
"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/shared": "workspace:*",
|
||||
"@freecodecamp/curriculum": "workspace:*",
|
||||
"@freecodecamp/browser-scripts": "workspace:*",
|
||||
"@testing-library/jest-dom": "^6.8.0",
|
||||
"@testing-library/react": "12.1.5",
|
||||
"@testing-library/react-hooks": "^8.0.1",
|
||||
|
||||
@ -9,21 +9,20 @@ import {
|
||||
stubTrue
|
||||
} from 'lodash-es';
|
||||
|
||||
import sassData from '../../../../config/browser-scripts/sass-compile.json';
|
||||
import {
|
||||
transformContents,
|
||||
transformHeadTailAndContents,
|
||||
compileHeadTail,
|
||||
createSource
|
||||
} from '@freecodecamp/shared/utils/polyvinyl';
|
||||
import { version } from '@freecodecamp/browser-scripts/package.json';
|
||||
|
||||
import { WorkerExecutor } from '../utils/worker-executor';
|
||||
import {
|
||||
compileTypeScriptCode,
|
||||
checkTSServiceIsReady
|
||||
} from '../utils/typescript-worker-handler';
|
||||
|
||||
const { filename: sassCompile } = sassData;
|
||||
|
||||
const protectTimeout = 100;
|
||||
const testProtectTimeout = 1500;
|
||||
const loopsPerTimeoutCheck = 100;
|
||||
@ -209,7 +208,9 @@ function getBabelOptions(
|
||||
return presets;
|
||||
}
|
||||
|
||||
const sassWorkerExecutor = new WorkerExecutor(sassCompile);
|
||||
const sassWorkerExecutor = new WorkerExecutor(
|
||||
`workers/${version}/sass-compile`
|
||||
);
|
||||
async function transformSASS(documentElement) {
|
||||
// we only teach scss syntax, not sass. Also the compiler does not seem to be
|
||||
// able to deal with sass.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// TODO: This might be cleaner as a class.
|
||||
import pythonWorkerData from '../../../../config/browser-scripts/python-worker.json';
|
||||
import { version } from '@freecodecamp/browser-scripts/package.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 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';
|
||||
|
||||
const typeScriptWorkerSrc = `/js/${typeScriptWorkerData.filename}.js`;
|
||||
const typeScriptWorkerSrc = `/js/workers/${version}/typescript-worker.js`;
|
||||
|
||||
let worker: Worker | null = null;
|
||||
|
||||
|
||||
19
client/tools/copy-browser-scripts.ts
Normal file
19
client/tools/copy-browser-scripts.ts
Normal file
@ -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
curriculum/.gitignore
vendored
1
curriculum/.gitignore
vendored
@ -1 +1,2 @@
|
||||
generated
|
||||
src/test/stubs/js
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"@babel/register": "7.23.7",
|
||||
"@freecodecamp/eslint-config": "workspace:*",
|
||||
"@freecodecamp/shared": "workspace:*",
|
||||
"@freecodecamp/browser-scripts": "workspace:*",
|
||||
"@total-typescript/ts-reset": "^0.6.1",
|
||||
"@types/debug": "^4.1.12",
|
||||
"@types/js-yaml": "4.0.5",
|
||||
|
||||
@ -3,10 +3,8 @@ import path from 'node:path';
|
||||
import sirv from 'sirv';
|
||||
import polka from 'polka';
|
||||
import puppeteer from 'puppeteer';
|
||||
|
||||
import { helperVersion } from '../../../client/src/templates/Challenges/utils/frame';
|
||||
|
||||
const clientPath = path.resolve(__dirname, '../../../client');
|
||||
import { cpSync, mkdirSync, rmSync } from 'node:fs';
|
||||
import { version } from '@freecodecamp/browser-scripts/test-runner';
|
||||
|
||||
async function createBrowser() {
|
||||
return puppeteer.launch({
|
||||
@ -21,6 +19,20 @@ async function createBrowser() {
|
||||
|
||||
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() {
|
||||
const host = '127.0.0.1';
|
||||
const port = 8080;
|
||||
@ -29,16 +41,16 @@ async function startServer() {
|
||||
|
||||
// Mount static files used by the tests
|
||||
app.use(
|
||||
'/dist',
|
||||
sirv(path.join(clientPath, `static/js/test-runner/${helperVersion}`))
|
||||
'/dist', // the runner is mounted at dist so we don't need to specify the asset path when initializing
|
||||
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.listen(port, host);
|
||||
return app.server;
|
||||
}
|
||||
|
||||
export async function setup() {
|
||||
setupStubs();
|
||||
server = await startServer();
|
||||
browser = await createBrowser();
|
||||
// Sharing the Websocket endpoint so that setup files can connect. This allows
|
||||
|
||||
@ -550,6 +550,9 @@ importers:
|
||||
'@babel/plugin-syntax-dynamic-import':
|
||||
specifier: 7.8.3
|
||||
version: 7.8.3(@babel/core@7.28.5)
|
||||
'@freecodecamp/browser-scripts':
|
||||
specifier: workspace:*
|
||||
version: link:../tools/client-plugins/browser-scripts
|
||||
'@freecodecamp/curriculum':
|
||||
specifier: workspace:*
|
||||
version: link:../curriculum
|
||||
@ -710,6 +713,9 @@ importers:
|
||||
'@babel/register':
|
||||
specifier: 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':
|
||||
specifier: workspace:*
|
||||
version: link:../packages/eslint-config
|
||||
|
||||
1
tools/client-plugins/browser-scripts/.gitignore
vendored
Normal file
1
tools/client-plugins/browser-scripts/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
dist
|
||||
@ -8,6 +8,13 @@
|
||||
"node": ">=24",
|
||||
"pnpm": ">=10"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"exports": {
|
||||
"./test-runner": "./test-runner.ts",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "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
|
||||
// https://github.com/medialize/sass.js/issues/96#issuecomment-424386171
|
||||
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 => {
|
||||
const data: unknown = e.data;
|
||||
|
||||
@ -1,18 +1,14 @@
|
||||
const { writeFileSync } = require('fs');
|
||||
const path = require('path');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const webpack = require('webpack');
|
||||
const {
|
||||
version: helperVersion
|
||||
} = require('@freecodecamp/curriculum-helpers/package.json');
|
||||
const { version } = require('./package.json');
|
||||
|
||||
module.exports = (env = {}) => {
|
||||
const __DEV__ = env.production !== true;
|
||||
const staticPath = path.join(__dirname, '../../../client/static/js');
|
||||
const configPath = path.join(
|
||||
__dirname,
|
||||
'../../../client/config/browser-scripts/'
|
||||
);
|
||||
|
||||
return {
|
||||
cache: __DEV__ ? { type: 'filesystem' } : false,
|
||||
mode: __DEV__ ? 'development' : 'production',
|
||||
@ -23,19 +19,9 @@ module.exports = (env = {}) => {
|
||||
},
|
||||
devtool: __DEV__ ? 'inline-source-map' : 'source-map',
|
||||
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',
|
||||
path: staticPath
|
||||
path: path.resolve(__dirname, `dist/artifacts/workers/${version}`),
|
||||
clean: true
|
||||
},
|
||||
stats: {
|
||||
// Display bailout reasons
|
||||
@ -74,7 +60,7 @@ module.exports = (env = {}) => {
|
||||
'./node_modules/xterm/css/xterm.css',
|
||||
{
|
||||
from: './node_modules/@freecodecamp/curriculum-helpers/dist/test-runner',
|
||||
to: `test-runner/${helperVersion}/`
|
||||
to: `../../test-runner/${helperVersion}/`
|
||||
}
|
||||
]
|
||||
}),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user