mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat: allow configuration of the typescript-compiler (#66241)
This commit is contained in:
committed by
GitHub
parent
c94fe2d40e
commit
2972485a87
@@ -41,7 +41,7 @@ vi.mock(
|
|||||||
await compiler.setup({ useNodeModules: true });
|
await compiler.setup({ useNodeModules: true });
|
||||||
return {
|
return {
|
||||||
...actual,
|
...actual,
|
||||||
checkTSServiceIsReady: () => Promise.resolve(true),
|
setupTSCompiler: () => Promise.resolve(true),
|
||||||
compileTypeScriptCode: code => {
|
compileTypeScriptCode: code => {
|
||||||
const { result, error } = compiler.compile(code, 'index.tsx');
|
const { result, error } = compiler.compile(code, 'index.tsx');
|
||||||
if (error) throw error;
|
if (error) throw error;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import { version } from '@freecodecamp/browser-scripts/package.json';
|
|||||||
import { WorkerExecutor } from './worker-executor';
|
import { WorkerExecutor } from './worker-executor';
|
||||||
import {
|
import {
|
||||||
compileTypeScriptCode,
|
compileTypeScriptCode,
|
||||||
checkTSServiceIsReady
|
setupTSCompiler
|
||||||
} from './typescript-worker-handler';
|
} from './typescript-worker-handler';
|
||||||
|
|
||||||
const protectTimeout = 100;
|
const protectTimeout = 100;
|
||||||
@@ -148,7 +148,7 @@ const getJSXModuleTranspiler = loopProtectOptions => async challengeFile => {
|
|||||||
|
|
||||||
const getTSTranspiler = loopProtectOptions => async challengeFile => {
|
const getTSTranspiler = loopProtectOptions => async challengeFile => {
|
||||||
await loadBabel();
|
await loadBabel();
|
||||||
await checkTSServiceIsReady();
|
await setupTSCompiler();
|
||||||
const babelOptions = getBabelOptions(presetsJS, loopProtectOptions);
|
const babelOptions = getBabelOptions(presetsJS, loopProtectOptions);
|
||||||
return flow(
|
return flow(
|
||||||
partial(transformHeadTailAndContents, compileTypeScriptCode),
|
partial(transformHeadTailAndContents, compileTypeScriptCode),
|
||||||
@@ -159,7 +159,7 @@ const getTSTranspiler = loopProtectOptions => async challengeFile => {
|
|||||||
const getTSXModuleTranspiler = loopProtectOptions => async challengeFile => {
|
const getTSXModuleTranspiler = loopProtectOptions => async challengeFile => {
|
||||||
await loadBabel();
|
await loadBabel();
|
||||||
await loadPresetReact();
|
await loadPresetReact();
|
||||||
await checkTSServiceIsReady();
|
await setupTSCompiler();
|
||||||
const baseOptions = getBabelOptions(presetsJSX, loopProtectOptions);
|
const baseOptions = getBabelOptions(presetsJSX, loopProtectOptions);
|
||||||
const babelOptions = {
|
const babelOptions = {
|
||||||
...baseOptions,
|
...baseOptions,
|
||||||
|
|||||||
@@ -31,10 +31,12 @@ export function compileTypeScriptCode(code: string): Promise<string> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkTSServiceIsReady(): Promise<boolean> {
|
export function setupTSCompiler(
|
||||||
|
compilerOptions?: Record<string, unknown>
|
||||||
|
): Promise<boolean> {
|
||||||
return awaitResponse({
|
return awaitResponse({
|
||||||
messenger: getTypeScriptWorker(),
|
messenger: getTypeScriptWorker(),
|
||||||
message: { type: 'check-is-ready' },
|
message: { type: 'setup', ...(compilerOptions && { compilerOptions }) },
|
||||||
onMessage: (data, onSuccess) => {
|
onMessage: (data, onSuccess) => {
|
||||||
if (data.type === 'ready') {
|
if (data.type === 'ready') {
|
||||||
onSuccess(true);
|
onSuccess(true);
|
||||||
|
|||||||
@@ -16,10 +16,15 @@ export class Compiler {
|
|||||||
this.tsvfs = tsvfs;
|
this.tsvfs = tsvfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
async setup(opts?: { useNodeModules: boolean }) {
|
async setup(opts?: { useNodeModules?: boolean; compilerOptions?: unknown }) {
|
||||||
const ts = this.ts;
|
const ts = this.ts;
|
||||||
const tsvfs = this.tsvfs;
|
const tsvfs = this.tsvfs;
|
||||||
|
|
||||||
|
const parsedOptions = ts.convertCompilerOptionsFromJson(
|
||||||
|
opts?.compilerOptions ?? {},
|
||||||
|
'/'
|
||||||
|
);
|
||||||
|
|
||||||
const compilerOptions: CompilerOptions = {
|
const compilerOptions: CompilerOptions = {
|
||||||
target: ts.ScriptTarget.ES2024,
|
target: ts.ScriptTarget.ES2024,
|
||||||
module: ts.ModuleKind.Preserve, // Babel is handling module transformation, so TS should leave them alone.
|
module: ts.ModuleKind.Preserve, // Babel is handling module transformation, so TS should leave them alone.
|
||||||
@@ -28,7 +33,8 @@ export class Compiler {
|
|||||||
// sync with TypeScript over time. It was last synced with TypeScript
|
// sync with TypeScript over time. It was last synced with TypeScript
|
||||||
// 3.8.0-rc."
|
// 3.8.0-rc."
|
||||||
jsx: ts.JsxEmit.Preserve, // Babel will handle JSX,
|
jsx: ts.JsxEmit.Preserve, // Babel will handle JSX,
|
||||||
allowUmdGlobalAccess: true // Necessary because React is loaded via a UMD script.
|
allowUmdGlobalAccess: true, // Necessary because React is loaded via a UMD script.
|
||||||
|
...parsedOptions.options
|
||||||
};
|
};
|
||||||
|
|
||||||
const fsMap = opts?.useNodeModules
|
const fsMap = opts?.useNodeModules
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { CompilerOptions } from 'typescript';
|
||||||
import { Compiler } from './modules/typescript-compiler';
|
import { Compiler } from './modules/typescript-compiler';
|
||||||
|
|
||||||
// Most of the ts types are only a guideline. This is because we're not bundling
|
// Most of the ts types are only a guideline. This is because we're not bundling
|
||||||
@@ -23,9 +24,10 @@ interface TSCompiledMessage {
|
|||||||
error: string;
|
error: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CheckIsReadyRequestEvent extends MessageEvent {
|
interface SetupEvent extends MessageEvent {
|
||||||
data: {
|
data: {
|
||||||
type: 'check-is-ready';
|
type: 'setup';
|
||||||
|
compilerOptions?: CompilerOptions;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,12 +61,10 @@ function importTS(version: string) {
|
|||||||
cachedVersion = version;
|
cachedVersion = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.onmessage = (
|
ctx.onmessage = (e: TSCompileEvent | SetupEvent | CancelEvent) => {
|
||||||
e: TSCompileEvent | CheckIsReadyRequestEvent | CancelEvent
|
|
||||||
) => {
|
|
||||||
const { data, ports } = e;
|
const { data, ports } = e;
|
||||||
if (data.type === 'check-is-ready') {
|
if (data.type === 'setup') {
|
||||||
void handleCheckIsReadyRequest(ports[0]);
|
void handleSetupRequest(data, ports[0]);
|
||||||
} else if (data.type === 'cancel') {
|
} else if (data.type === 'cancel') {
|
||||||
handleCancelRequest(data);
|
handleCancelRequest(data);
|
||||||
} else {
|
} else {
|
||||||
@@ -75,15 +75,16 @@ ctx.onmessage = (
|
|||||||
importTS(TS_VERSION);
|
importTS(TS_VERSION);
|
||||||
|
|
||||||
const compiler = new Compiler(ts, tsvfs);
|
const compiler = new Compiler(ts, tsvfs);
|
||||||
const isSetup = compiler.setup();
|
|
||||||
|
|
||||||
// This lets the client know that there is nothing to cancel.
|
// This lets the client know that there is nothing to cancel.
|
||||||
function handleCancelRequest({ value }: { value: number }) {
|
function handleCancelRequest({ value }: { value: number }) {
|
||||||
postMessage({ type: 'is-alive', text: value });
|
postMessage({ type: 'is-alive', text: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleCheckIsReadyRequest(port: MessagePort) {
|
async function handleSetupRequest(data: SetupEvent['data'], port: MessagePort) {
|
||||||
await isSetup;
|
await compiler.setup({
|
||||||
|
compilerOptions: data.compilerOptions
|
||||||
|
});
|
||||||
// We freeze this to prevent learners from getting the worker into a weird
|
// We freeze this to prevent learners from getting the worker into a weird
|
||||||
// state.
|
// state.
|
||||||
Object.freeze(self);
|
Object.freeze(self);
|
||||||
|
|||||||
Reference in New Issue
Block a user