Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to Vite #2996

Draft
wants to merge 34 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
5df7d25
Install vite dependencies
RichDom2185 May 12, 2024
67740b0
Lock test dependencies
RichDom2185 May 12, 2024
a1be899
Create vite.config.ts
RichDom2185 May 12, 2024
5ccab84
Update server port and add dev script
RichDom2185 May 12, 2024
36238ea
Add SVGR plugin
RichDom2185 May 12, 2024
30d06e6
Update vite config
RichDom2185 May 12, 2024
be175c1
Move index.html to top-level
RichDom2185 May 12, 2024
be901e7
Add application entrypoint
RichDom2185 May 12, 2024
70ab372
Update tsconfig.json
RichDom2185 May 12, 2024
b1c5a6b
Update reference types
RichDom2185 May 12, 2024
616f90c
Add "type: module" to package.json
RichDom2185 May 12, 2024
4179b3e
Update styles import
RichDom2185 May 12, 2024
622963a
Replace require with import
RichDom2185 May 12, 2024
409f114
Add polyfills
RichDom2185 May 12, 2024
67ad4ee
Fix SASS warning
RichDom2185 May 12, 2024
5edbb04
Add hotfixes for compile errors
RichDom2185 May 12, 2024
2d835a9
Add test build script with Vite + rollup
RichDom2185 May 12, 2024
7969ecb
Fix Vite build command error
RichDom2185 May 12, 2024
e8022ee
Fix runtime errors in build
RichDom2185 May 12, 2024
ce5a1c6
Replace react-error-overlay with Vite's version
RichDom2185 May 12, 2024
ec805bd
Switch to ESM resolver for ace-builds
RichDom2185 May 12, 2024
4bb2028
Update ESLint config to CJS extension
RichDom2185 May 12, 2024
d42a9ea
Merge branch 'master' into 2024-vite
RichDom2185 May 12, 2024
451f135
Merge branch 'master' into 2024-vite
RichDom2185 May 13, 2024
318e25b
Merge branch 'master' into 2024-vite
RichDom2185 May 15, 2024
a0c3d44
Rename CRACO config to .cjs
RichDom2185 May 16, 2024
77b33fb
Fix type errors
RichDom2185 May 16, 2024
94ca65f
Switch build command to use Vite
RichDom2185 May 16, 2024
c6406fa
Bump vite to v5.3
RichDom2185 Jun 29, 2024
aed5188
Bump dependencies
RichDom2185 Jun 29, 2024
ec1acc9
Deduplicate dependencies
RichDom2185 Jun 29, 2024
01e3acd
Merge branch 'master' into 2024-vite
RichDom2185 Aug 6, 2024
c64a812
Merge branch 'master' into 2024-vite
RichDom2185 Aug 6, 2024
48711c0
Merge branch 'master' of https://github.com/source-academy/frontend i…
RichDom2185 Oct 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
2 changes: 1 addition & 1 deletion eslint.config.js → eslint.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const compat = new FlatCompat({
});

module.exports = tseslint.config(
{ ignores: ['eslint.config.js'] },
{ ignores: ['eslint.config.cjs'] },
// eslint.configs.recommended,
...tseslint.configs.recommended,
// TODO: Enable when ready
Expand Down
18 changes: 5 additions & 13 deletions public/index.html → index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,17 @@
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="theme-color" content="#000000" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.0/TweenMax.min.js"></script>
<script src="%PUBLIC_URL%/externalLibs/index.js"></script>
<script src="/externalLibs/index.js"></script>
<script type="text/javascript" src="https://apis.google.com/js/api.js"></script>
<script type="text/javascript" src="https://apis.google.com/js/client.js"></script>
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="shortcut icon" href="%PUBLIC_URL%/icons/favicon.ico?pr225" />
<link rel="apple-touch-icon" sizes="180x180" href="%PUBLIC_URL%/icons/apple-touch-icon.png">
<link rel="manifest" href="/manifest.json" />
<link rel="shortcut icon" href="/icons/favicon.ico?pr225" />
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png">
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Inconsolata&display=block" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.

Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Source Academy</title>
<meta name="description" content="Immersive experiential environment for learning programming, developed in the School of Computing at the National University of Singapore." />
</head>
Expand All @@ -35,6 +26,7 @@
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
Expand Down
20 changes: 18 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"private": true,
"type": "module",
"name": "frontend",
"version": "1.4.3",
"scripts-info": {
Expand All @@ -12,12 +13,16 @@
},
"scripts": {
"analyze": "yarn build --stats; webpack-bundle-analyzer build/bundle-stats.json",
"build": "cross-env DISABLE_ESLINT_PLUGIN=true NODE_OPTIONS=--max_old_space_size=8192 craco build",
"build-cra": "cross-env DISABLE_ESLINT_PLUGIN=true NODE_OPTIONS=--max_old_space_size=8192 craco build",
"//": "TODO: Add tsc --noEmit to check for type errors",
"build": "vite build",
"preview": "vite preview",
"coverage": "./scripts/coverage-fix.sh do && craco test --coverage && ./scripts/coverage-fix.sh undo",
"format": "eslint --fix src && prettier --write \"src/**/*.{js,jsx,ts,tsx}\" && prettier --write --parser scss \"src/**/*.scss\"",
"format:tsx": "prettier --list-different \"src/**/*.{js,jsx,ts,tsx}\"",
"format:scss": "prettier --list-different --parser scss \"src/**/*.scss\"",
"format:ci": "yarn run format:tsx && yarn run format:scss",
"dev": "vite",
"start": "cross-env DISABLE_ESLINT_PLUGIN=true BROWSER=none PORT=8000 craco start",
"test": "cross-env TZ=UTF-8 craco test",
"test-coveralls": "./scripts/test-coveralls.sh",
Expand Down Expand Up @@ -106,6 +111,8 @@
"@babel/runtime": "^7.24.5",
"@convergencelabs/ace-collab-ext": "^0.6.0",
"@craco/craco": "^7.1.0",
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
"@rollup/plugin-inject": "^5.0.5",
"@svgr/webpack": "^8.0.0",
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^15.0.6",
Expand All @@ -131,6 +138,7 @@
"@types/showdown": "^2.0.1",
"@types/uuid": "^9.0.0",
"@types/xml2js": "^0.4.11",
"@vitejs/plugin-react": "^4.2.1",
"babel-jest": "^29.7.0",
"buffer": "^6.0.3",
"canvas": "^2.11.2",
Expand All @@ -145,6 +153,9 @@
"eslint-plugin-simple-import-sort": "^12.1.1",
"https-browserify": "^1.0.0",
"husky": "^9.0.0",
"jest": "^27.4.3",
"jest-resolve": "^27.4.2",
"jest-watch-typeahead": "^1.0.0",
"npm-run-all2": "^6.0.0",
"os-browserify": "^0.3.0",
"path-browserify": "^1.0.1",
Expand All @@ -155,13 +166,18 @@
"react-test-renderer": "^18.2.0",
"redux-saga-test-plan": "^4.0.6",
"resize-observer-polyfill": "^1.5.1",
"sass": "^1.63.6",
"rollup-plugin-polyfill-node": "^0.13.0",
"sass": "^1.77.1",
"stream-browserify": "^3.0.0",
"stream-http": "^3.2.0",
"timers-browserify": "^2.0.12",
"typescript": "^5.5.3",
"typescript-eslint": "^8.1.0",
"url": "^0.11.1",
"vite": "^5.3.2",
"vite-plugin-svgr": "^4.2.0",
"vite-plugin-wasm": "^3.3.0",
"vite-tsconfig-paths": "^4.3.2",
"webpack-bundle-analyzer": "^4.9.0"
},
"resolutions": {
Expand Down
4 changes: 1 addition & 3 deletions src/commons/mocks/TeamFormationMocks.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { OptionType } from 'src/pages/academy/teamFormation/subcomponents/TeamFormationForm';
import XLSX from 'xlsx';

import { TeamFormationOverview } from '../../features/teamFormation/TeamFormationTypes';
import { Role } from '../application/ApplicationTypes';
import { mockFetchRole, mockFetchStudents } from './UserMocks';

// eslint-disable-next-line @typescript-eslint/no-require-imports
const XLSX = require('xlsx');

export const mockTeamFormationOverviews: TeamFormationOverview[] = [
{
teamId: 1,
Expand Down
13 changes: 7 additions & 6 deletions src/commons/redux/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import * as Sentry from '@sentry/browser';
import { SagaIterator } from 'redux-saga';
import { StrictEffect, takeEvery } from 'redux-saga/effects';
import type { ErrorPayload } from 'vite';

/**
* Creates actions, given a base name and base actions
Expand Down Expand Up @@ -87,12 +88,12 @@ export function saferTakeEvery<

function handleUncaughtError(error: any) {
if (process.env.NODE_ENV === 'development') {
// react-error-overlay is a "special" package that's automatically included
// in development mode by CRA

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import('react-error-overlay').then(reo => reo.reportRuntimeError(error));
const showErrorOverlay = (err: Partial<ErrorPayload['err']>) => {
const ErrorOverlay = customElements.get('vite-error-overlay');
if (ErrorOverlay == null) return;
document.body.appendChild(new ErrorOverlay(err));
};
showErrorOverlay(error);
}
Sentry.captureException(error);
console.error(error);
Expand Down
4 changes: 1 addition & 3 deletions src/commons/sagas/RequestsSaga.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { call } from 'redux-saga/effects';
import { backendParamsToProgressStatus } from 'src/features/grading/GradingUtils';
import { OptionType } from 'src/pages/academy/teamFormation/subcomponents/TeamFormationForm';
import XLSX from 'xlsx';

import {
AchievementGoal,
Expand Down Expand Up @@ -57,9 +58,6 @@ import Constants from '../utils/Constants';
import { showWarningMessage } from '../utils/notifications/NotificationsHelper';
import { request } from '../utils/RequestHelper';

// eslint-disable-next-line @typescript-eslint/no-require-imports
const XLSX = require('xlsx');

/**
* GET /
* (health check)
Expand Down
13 changes: 7 additions & 6 deletions src/commons/sagas/SafeEffects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,20 @@ import {
takeLatest,
takeLeading
} from 'redux-saga/effects';
import type { ErrorPayload } from 'vite';

// it's not possible to abstract the two functions into HOF over takeEvery and takeLatest
// without stepping out of TypeScript's type system because the type system does not support
// higher-kinded types (type parameters that take )

function handleUncaughtError(error: any) {
if (process.env.NODE_ENV === 'development') {
// react-error-overlay is a "special" package that's automatically included
// in development mode by CRA

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import('react-error-overlay').then(reo => reo.reportRuntimeError(error));
const showErrorOverlay = (err: Partial<ErrorPayload['err']>) => {
const ErrorOverlay = customElements.get('vite-error-overlay');
if (ErrorOverlay == null) return;
document.body.appendChild(new ErrorOverlay(err));
};
showErrorOverlay(error);
}
Sentry.captureException(error);
console.error(error);
Expand Down
86 changes: 44 additions & 42 deletions src/commons/sagas/WorkspaceSaga/helpers/evalCode.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { compileAndRun as compileAndRunCCode } from '@sourceacademy/c-slang/ctowasm/dist/index';
/* eslint-disable-file */
// import { compileAndRun as compileAndRunCCode } from '@sourceacademy/c-slang/ctowasm/dist/index';
import { tokenizer } from 'acorn';
import { Context, interrupt, Result, resume, runFilesInContext } from 'js-slang';
import { ACORN_PARSE_OPTIONS, TRY_AGAIN } from 'js-slang/dist/constants';
Expand All @@ -9,7 +10,6 @@ import { SagaIterator } from 'redux-saga';
import { call, put, race, select, take } from 'redux-saga/effects';
import * as Sourceror from 'sourceror';
import InterpreterActions from 'src/commons/application/actions/InterpreterActions';
import { makeCCompilerConfig, specialCReturnObject } from 'src/commons/utils/CToWasmHelper';
import { javaRun } from 'src/commons/utils/JavaHelper';
import StoriesActions from 'src/features/stories/StoriesActions';

Expand Down Expand Up @@ -209,46 +209,48 @@ export function* evalCodeSaga(
}

async function cCompileAndRun(cCode: string, context: Context) {
const cCompilerConfig = await makeCCompilerConfig(cCode, context);
return await compileAndRunCCode(cCode, cCompilerConfig)
.then(compilationResult => {
if (compilationResult.status === 'failure') {
// report any compilation failure
reportCCompilationError(
`Compilation failed with the following error(s):\n\n${compilationResult.errorMessage}`,
context
);
return {
status: 'error',
context
};
}
if (compilationResult.warnings.length > 0) {
return {
status: 'finished',
context,
value: {
toReplString: () =>
`Compilation and program execution successful with the following warning(s):\n${compilationResult.warnings.join(
'\n'
)}`
}
};
}
if (specialCReturnObject === null) {
return {
status: 'finished',
context,
value: { toReplString: () => 'Compilation and program execution successful.' }
};
}
return { status: 'finished', context, value: specialCReturnObject };
})
.catch((e: any): Result => {
console.log(e);
reportCRuntimeError(e.message, context);
return { status: 'error' };
});
// const cCompilerConfig = await makeCCompilerConfig(cCode, context);
// FIXME: Restore
return Promise.resolve({ status: 'error' });
// return await compileAndRunCCode(cCode, cCompilerConfig)
// .then(compilationResult => {
// if (compilationResult.status === 'failure') {
// // report any compilation failure
// reportCCompilationError(
// `Compilation failed with the following error(s):\n\n${compilationResult.errorMessage}`,
// context
// );
// return {
// status: 'error',
// context
// };
// }
// if (compilationResult.warnings.length > 0) {
// return {
// status: 'finished',
// context,
// value: {
// toReplString: () =>
// `Compilation and program execution successful with the following warning(s):\n${compilationResult.warnings.join(
// '\n'
// )}`
// }
// };
// }
// if (specialCReturnObject === null) {
// return {
// status: 'finished',
// context,
// value: { toReplString: () => 'Compilation and program execution successful.' }
// };
// }
// return { status: 'finished', context, value: specialCReturnObject };
// })
// .catch((e: any): Result => {
// console.log(e);
// reportCRuntimeError(e.message, context);
// return { status: 'error' };
// });
}

const isNonDet: boolean = context.variant === Variant.NON_DET;
Expand Down
3 changes: 2 additions & 1 deletion src/commons/utils/JavaHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ export async function javaRun(
const { proxy } = createModuleProxy(module, moduleFuncs[module]);
return { default: proxy };
}
return await import(`java-slang/dist/jvm/stdlib/${path}.js`);
// FIXME: Investigate
return await import(/* @vite-ignore */ `java-slang/dist/jvm/stdlib/${path}.js`);
};

const stdout = (str: string) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'ace-builds/webpack-resolver';
import 'ace-builds/esm-resolver';

import { Button, Classes, Tab, Tabs } from '@blueprintjs/core';
import { useState } from 'react';
Expand Down
1 change: 0 additions & 1 deletion src/react-app-env.d.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/styles/_achievementdashboard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@
color: white;
display: flex;
flex-direction: column;
height: $view-height / 3;
height: calc($view-height / 3);
justify-content: center;
margin: 1em auto;
width: $view-width;
Expand Down
20 changes: 10 additions & 10 deletions src/styles/index.scss
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
@use 'sass:math';

@import '~normalize.css/normalize.css';
@import '~@blueprintjs/core/lib/css/blueprint.css';
@import '~@blueprintjs/datetime/lib/css/blueprint-datetime.css';
@import '~@blueprintjs/select/lib/css/blueprint-select.css';
@import '~flexboxgrid/dist/flexboxgrid.css';
@import '~flexboxgrid-helpers/dist/flexboxgrid-helpers.min.css';
@import 'normalize.css/normalize.css';
@import '@blueprintjs/core/lib/css/blueprint.css';
@import '@blueprintjs/datetime/lib/css/blueprint-datetime.css';
@import '@blueprintjs/select/lib/css/blueprint-select.css';
@import 'flexboxgrid/dist/flexboxgrid.css';
@import 'flexboxgrid-helpers/dist/flexboxgrid-helpers.min.css';

// CSS styles for react-mde Markdown editor
// (currently this editor is only used for grading comments)
// react-mde-preview.css is excluded to avoid conflict with blueprintjs
// styles in the preview tab of the editor, providing a more accurate
// depiction of what the actual comment will look like
@import '~react-mde/lib/styles/css/react-mde-toolbar.css';
@import '~react-mde/lib/styles/css/react-mde-editor.css';
@import '~react-mde/lib/styles/css/react-mde.css';
@import 'react-mde/lib/styles/css/react-mde-toolbar.css';
@import 'react-mde/lib/styles/css/react-mde-editor.css';
@import 'react-mde/lib/styles/css/react-mde.css';

@import '../../node_modules/@blueprintjs/core/lib/scss/variables';
@import '@blueprintjs/core/lib/scss/variables';
@import 'global';

@import 'academy';
Expand Down
1 change: 1 addition & 0 deletions src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
14 changes: 12 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,18 @@
"baseUrl": ".",
"outDir": "build/dist",
"module": "esnext",
"target": "es2020",
"lib": ["dom", "dom.iterable", "esnext", "es6", "es2015", "es2017"],
"target": "ESNext",
"lib": ["dom", "dom.iterable", "esnext"],
"types": [
"vite/client",
"vite-plugin-svgr/client",
"jest",
"gapi",
"gapi.auth2",
"gapi.client",
"gapi.client.drive",
"google.picker"
],
"sourceMap": true,
"allowJs": true,
"jsx": "react-jsx",
Expand Down
Loading