Skip to content

Commit

Permalink
Switch to Vite from Create React App (#1152)
Browse files Browse the repository at this point in the history
- CRA/Craco -> Vite + Vitest + eslint 
- TypeScript 4->5

npm audit issues are now at 0 🎉
bundle size slightly smaller with fewer total requests and quicker load time in Chrome

Notable changes:
- Use a Web Worker bundle per language to workaround Vite/Safari 14 limitations
    - I also renamed the main worker-side file to make it clearer what was what as I found it confusing to come back to.
- Fixed a dev-only API tab initialisation issue found by e2e tests
- Fixed a layout shift issue spotted in review that turned out to be due to useMediaQuery behaviour changes in the recent Chakra UI upgrade
- Adding updated eslint config caught a missing await in storage.ts. Should only have been significant when deleting files that don't exist which we never intend to do.

We'll run this on beta for a while (along with the Chakra UI upgrade) before considering a release.
  • Loading branch information
microbit-matt-hillsdon authored Mar 15, 2024
1 parent c16d50d commit 4425d16
Show file tree
Hide file tree
Showing 105 changed files with 8,525 additions and 21,406 deletions.
5 changes: 3 additions & 2 deletions .env
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
REACT_APP_VERSION=$npm_package_version
REACT_APP_NAME=$npm_package_name
VITE_VERSION=$npm_package_version
VITE_NAME=$npm_package_name
VITE_FULL_URL=/
63 changes: 63 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
"eslint:recommended",
// We should switch to recommended-type-checked but there are many issues to review
"plugin:@typescript-eslint/recommended",
//"plugin:@typescript-eslint/recommended-type-checked",
"plugin:react-hooks/recommended",
"plugin:react/recommended",
"plugin:react/jsx-runtime",
],
ignorePatterns: [
"dist",
".eslintrc.cjs",
"deployment.cjs",
"bin/**/*.js",
"bootstrap-template.js",
"playwright.config.ts",
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
project: ["./tsconfig.json", "./tsconfig.node.json"],
tsconfigRootDir: __dirname,
},
plugins: ["react-refresh"],
settings: {
react: {
version: "18",
},
},
rules: {
// More trouble than it's worth
"react/no-unescaped-entities": "off",
// False positives from library imports from Chakra UI
"@typescript-eslint/unbound-method": "off",
"@typescript-eslint/no-misused-promises": [
"error",
{
checksVoidReturn: false,
},
],
"@typescript-eslint/no-unused-vars": [
"error",
{
args: "all",
argsIgnorePattern: "^_",
caughtErrors: "all",
// Let's remove e from here
caughtErrorsIgnorePattern: "^_|e",
destructuredArrayIgnorePattern: "^_",
varsIgnorePattern: "^_",
ignoreRestSiblings: true,
},
],
// Temporary, new rules on Vite migration that are widely flouted
"@typescript-eslint/no-explicit-any": "off",
"prefer-const": "off",
"react/display-name": "off",
},
};
14 changes: 6 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
PRODUCTION_CLOUDFRONT_DISTRIBUTION_ID: E2ELTBTA2OFPY2
STAGING_CLOUDFRONT_DISTRIBUTION_ID: E2ELTBTA2OFPY2
REVIEW_CLOUDFRONT_DISTRIBUTION_ID: E3267W09ZJHQG9
REACT_APP_FOUNDATION_BUILD: ${{ github.repository_owner == 'microbit-foundation' }}
VITE_FOUNDATION_BUILD: ${{ github.repository_owner == 'microbit-foundation' }}

steps:
# Note: This workflow disables deployment steps and micro:bit branding installation on forks.
Expand All @@ -36,20 +36,18 @@ jobs:
- run: npm ci
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: npm install --no-save @microbit-foundation/python-editor-v3-microbit@0.2.0-dev.31 @microbit-foundation/website-deploy-aws@0.3.0 @microbit-foundation/website-deploy-aws-config@0.7.1 @microbit-foundation/circleci-npm-package-versioner@1
- run: npm install --no-save @microbit-foundation/python-editor-v3-microbit@0.2.0-vite.35 @microbit-foundation/website-deploy-aws@0.6.0 @microbit-foundation/website-deploy-aws-config@0.9.0 @microbit-foundation/circleci-npm-package-versioner@1
if: github.repository_owner == 'microbit-foundation'
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: node ./bin/print-ci-env-stage.js >> $GITHUB_ENV
- run: node ./bin/print-ci-env-public-url.js >> $GITHUB_ENV
- run: node ./bin/print-ci-env-stage.cjs >> $GITHUB_ENV
- run: node ./bin/print-ci-env-public-url.cjs >> $GITHUB_ENV
- run: npm run ci:update-version
if: github.repository_owner == 'microbit-foundation'
- run: npm run ci
env:
REACT_APP_GA_COOKIE_PREFIX: ${{ secrets.REACT_APP_GA_COOKIE_PREFIX }}
REACT_APP_GA_MEASUREMENT_ID: ${{ secrets.GA_MEASUREMENT_ID }}
REACT_APP_SENTRY_DSN: ${{ secrets.REACT_APP_SENTRY_DSN }}
- run: mkdir -p /tmp/app${PUBLIC_URL} && cp -r build/* /tmp/app${PUBLIC_URL} && npx serve --no-clipboard -l 3000 /tmp/app &
VITE_SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
- run: mkdir -p /tmp/app${BASE_URL} && cp -r build/* /tmp/app${BASE_URL} && npx serve --no-clipboard -l 3000 /tmp/app &
if: env.STAGE == 'REVIEW' || env.STAGE == 'STAGING'
- run: curl --insecure -4 --retry 7 --retry-connrefused http://localhost:3000 1>/dev/null
if: env.STAGE == 'REVIEW' || env.STAGE == 'STAGING'
Expand Down
19 changes: 9 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,18 @@ Getting up and running:

### `npm start`

Runs the app in the development mode.\
Runs the app in the development mode.

Open [http://localhost:3000](http://localhost:3000) to view it in the browser.

The page will reload if you make edits.\
You will also see any lint errors in the console.
The page will reload if you make edits.

This does not show TypeScript or lint errors.
Use the eslint plugin for your editor and consider also running `npm run typecheck:watch` to see full type checking errors.

### `npm test`

Launches the test runner in the interactive watch mode.\
Launches the [test runner](https://vitest.dev/) in interactive mode (unless the `CI` environment variable is defined).
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.

If you have a connected micro:bit device, then setting the environment variable `TEST_MODE_DEVICE=1` will enable additional tests that will connect to your micro:bit. The tests will overwrite programs and data on the micro:bit.
Expand All @@ -55,10 +58,6 @@ We use [Puppeteer](https://pptr.dev/) and the helpers provided by [Testing Libra

The CI tests run these end-to-end tests against a production build.

### `npm run test:all --testPathPattern autocomplete`

An example of how to use jest options to filter to a specific subset of the tests (e2e or unit).

### `npm run build`

Builds the app for production to the `build` folder.\
Expand All @@ -68,11 +67,11 @@ It correctly bundles React in production mode and optimizes the build for the be

Most users should use the supported Foundation deployment at https://python.microbit.org/

The editor is deployed by [CircleCI](https://circleci.com/gh/microbit-foundation/python-editor-v3).
The editor is deployed by [GitHub actions](https://github.com/microbit-foundation/python-editor-v3/actions).

The `main` branch is deployed to https://python.microbit.org/v/beta on each push.

Other branches (e.g. for PRs) are deployed to https://review-python-editor-v3.microbit.org/{branch}. Special characters in the branch name are replaced by hyphens.
Other branches (e.g. for PRs) are deployed to https://review-python-editor-v3.microbit.org/{branch}. Special characters in the branch name are replaced by hyphens. Deployments will not run in forks.

## License

Expand Down
File renamed without changes.
File renamed without changes.
17 changes: 17 additions & 0 deletions bin/print-ci-env-public-url.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env node
let baseUrl;
if (process.env.GITHUB_REPOSITORY_OWNER === "microbit-foundation") {
// STAGE must be defined before this is imported
const { bucketPrefix, bucketName } = require("../deployment.cjs");
baseUrl = `/${bucketPrefix}/`;

const fullUrl = `https://${bucketName}${baseUrl}`;
// This is used for og:url and similar. Not quite right for review domain but we don't really care.
console.log(`VITE_FULL_URL=${fullUrl}`);
} else {
baseUrl = "/";
}

// Two env vars as BASE_URL seems to be blank when running jest even if we set it.
console.log(`BASE_URL=${baseUrl}`);
console.log(`E2E_BASE_URL=${baseUrl}`);
12 changes: 0 additions & 12 deletions bin/print-ci-env-public-url.js

This file was deleted.

2 changes: 1 addition & 1 deletion bin/print-ci-env-stage.js → bin/print-ci-env-stage.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ if (ref === "refs/heads/main") {
}

console.log(`STAGE=${stage}`);
console.log(`REACT_APP_STAGE=${stage}`);
console.log(`VITE_STAGE=${stage}`);
File renamed without changes.
File renamed without changes.
10 changes: 6 additions & 4 deletions docs/tech-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,21 @@ The document assumes some familiarity with the app as a user. [Try it out](http:

## User interface

The editor is written in [TypeScript](https://www.typescriptlang.org/) using [React](https://reactjs.org/). The best documentation for React at the time of writing is their [beta documentation](https://beta.reactjs.org/).
The editor is written in [TypeScript](https://www.typescriptlang.org/) using [React](https://reactjs.org/).

We use the [Chakra UI component library](https://chakra-ui.com/docs/getting-started) which provides a base set of accessible components. We're currently using Chakra UI 1.x.
We use the [Chakra UI component library](https://chakra-ui.com/docs/getting-started) which provides a base set of accessible components. We're currently using Chakra UI 2.x.

The project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). We're using [Craco](https://github.com/dilanx/craco) to override some parts of the Create React App configuration.
The project is bundled using [Vite](https://vitejs.dev/). The test runner is [Vitest](https://vitest.dev/) and we're using [eslint](https://eslint.org/).

We use Prettier to format code. Please set this up to format before committing changes, ideally on save (there's [a VS Code plugin](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)).

The UI is split into different areas by the [workbench component](../src/workbench/Workbench.tsx). This component manages layout including expand/collapse of the sidebar and simulator and is a good starting point to navigate the codebase. The main areas are:

1. The sidebar on the left, with Reference, Ideas, API and Project tabs as well as settings and help menus.
2. The main editing area with the text editor for the current file, header with the project title and the project action bar with buttons for key interactions. When a micro:bit device is connected over WebUSB, the serial area appears between the text editor and the project actions.
3. The simulator on the right, with its own serial area and controls.

The branding that you see on the [Foundation deployment](https://python.microbit.org/v/3) is not Open Source and is managed in a private GitHub project. This is swapped in via a webpack alias for `theme-package` configured by Craco.
The branding that you see on the [Foundation deployment](https://python.microbit.org/v/3) is not Open Source and is managed in a private GitHub project. This is swapped in via an alias for `theme-package` in the Vite config.

## Connecting to the micro:bit via WebUSB, flashing and hex files

Expand Down
30 changes: 18 additions & 12 deletions public/index.html → index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="icon" href="%BASE_URL%favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#6c4bc1" />
<title>micro:bit Python Editor</title>
Expand All @@ -11,26 +11,32 @@
property="og:description"
content="Built by the Micro:bit Educational Foundation and the global Python Community."
/>
<meta
property="og:image"
content="https://python.microbit.org%PUBLIC_URL%/social.png"
/>
<meta name="twitter:card" content="summary_large_image" />
<meta
name="twitter:description"
content="A Python Editor for the BBC micro:bit, built by the Micro:bit Educational Foundation and the global Python Community."
/>
<% if (process.env.REACT_APP_FOUNDATION_BUILD === 'true') { %>
<script src="https://shared-assets.microbit.org/common/v1/common.js" async></script>
<link rel="stylesheet" href="https://shared-assets.microbit.org/common/v1/main.css"></link>
<meta property="og:image" content="%VITE_FULL_URL%social.png" />
<% if (typeof VITE_FOUNDATION_BUILD !== 'undefined' && VITE_FOUNDATION_BUILD
=== 'true') { %>
<script
src="https://shared-assets.microbit.org/common/v1/common.js"
async
></script>
<link
rel="stylesheet"
href="https://shared-assets.microbit.org/common/v1/main.css"
/>
<script>
// GA config itself is via the common assets config depending on consent.
window.dataLayer = window.dataLayer || [];
window.gtag = window.gtag || function() {
window.dataLayer.push(arguments);
};
window.gtag =
window.gtag ||
function () {
window.dataLayer.push(arguments);
};
</script>
<% } %>
<script type="module" src="/src/index.tsx"></script>
</head>
<body>
<noscript
Expand Down
Loading

0 comments on commit 4425d16

Please sign in to comment.