This is a technical guide for setting up a local development workflow for the Smart Forms app and the renderer component. More information will be added as necessary, i.e. more debugging tips, common issues, or even guides for the other packages in the monorepo.
smart-forms is a monorepo that contains the following:
Apps
apps/smart-forms-app- The main Smart Forms web React app https://smartforms.csiro.auapps/demo-renderer-app- A demo React app to validate if the renderer component runs properly outside the NPM workspace.
Packages
packages/smart-forms-renderer- A TypeScript implementation of the SDC questionnaire renderer library https://www.npmjs.com/package/@aehrc/smart-forms-rendererpackages/sdc-populate- A TypeScript implementation of SDC populate https://www.npmjs.com/package/@aehrc/sdc-populatepackages/sdc-assemble- A TypeScript implementation of SDC assemble https://www.npmjs.com/package/@aehrc/sdc-assemblepackages/sdc-template-extract- A TypeScript implementation of SDC extract https://www.npmjs.com/package/@aehrc/sdc-template-extract
Services
services/populate-express- A ExpressJS service to hold thepackages/sdc-populateimplementation that can be deployed.services/assemble-express- A ExpressJS service to hold thepackages/sdc-assembleimplementation that can be deployed.services/extract-express- A ExpressJS service to hold a .NET implementation of the SDC extract operation that can be deployed.
Deployment
deployment/*- Directories containing AWS CDK scripts for deploying apps and services.
Documentation
docs- Documentation for this project https://smartforms.csiro.au/docs
Except for apps/demo-renderer-app, all entities listed above are part of the NPM workspace.
NPM workspace allows working on multiple packages in a single repository. This brings benefits such as shared dependencies and a more streamlined workflow handling linked packages from the local filesystem.
However, it has its own set of complexities to watch out for, such as dependencies working even when they are located in different directories, which causes confusion and can lead to unexpected behaviour.
Install Node v20 via [https://nodejs.org/en/download]
# Install Node.js via nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash\n
# Install v20 of Node
nvm install 20
# Make this as default
nvm alias default node
# Verify installation
node -v
npm -v-
Clone this Git source repository onto your local machine from https://github.com/aehrc/smart-forms.
git clone https://github.com/aehrc/smart-forms
-
Navigate to the cloned directory and install dependencies. You can run
npm iin any folder as long as it is part of the NPM workspace (https://github.com/aehrc/smart-forms/blob/main/package.json#L16-L23).cd smart-forms npm install
Before any local development, it is important to configure the Smart Forms app correctly. If you are happy with the default configuration, you can skip directly to Running locally.
The Smart Forms app uses a config.json file for configuration, fetched at runtime. This allows configuration to be modified without rebuilding the app, which is particularly useful for containers.
-
Navigate to the directory containing the Smart Forms app.
cd apps/smart-forms-app -
The configuration is stored in
/public/config.json. Adjust the configuration based on your setup. Below is the TypeScript interface for the configuration:export interface ConfigFile { // FHIR Terminology Server for ValueSet expansion and terminology validation terminologyServerUrl: string; // Questionnaire-hosting FHIR server formsServerUrl: string; // Default/fallback SMART App Launch client ID, preferably client IDs should be assigned by the server and stored in a separate JSON file to be fetched at runtime (because there is no persistent backend on this SPA) defaultClientId: string; // SMART App Launch scopes, space-separated launchScopes: string; // URL link to a JS object of a key-value map of issuers to registered client IDs <issuer, client_id>. See https://hl7.org/fhir/smart-app-launch/app-launch.html#step-1-register on SMART registration recommended practices. // If this URL doesn't exist, the app will fallback to using `defaultClientId`. // Example URL: https://smartforms.csiro.au/smart-config/config.json // Example JSON response (`RegisteredClientIdsConfig`): // { // "https://proxy.smartforms.io/v/r4/fhir": "a57d90e3-5f69-4b92-aa2e-2992180863c1", // "https://example.com/fhir": "6cc9bccb-3ae2-40d7-9660-22c99534520b" // } registeredClientIdsUrl: string | null; }
Example
config.jsonstructure:{ "terminologyServerUrl": "https://tx.ontoserver.csiro.au/fhir", "formsServerUrl": "https://smartforms.csiro.au/api/fhir", "defaultClientId": "a57d90e3-5f69-4b92-aa2e-2992180863c1", "launchScopes": "launch openid fhirUser online_access patient/AllergyIntolerance.cs patient/Condition.cs patient/Encounter.r patient/Immunization.cs patient/Medication.r patient/MedicationStatement.cs patient/Observation.cs patient/Patient.r patient/QuestionnaireResponse.crus user/Practitioner.r launch/questionnaire?role=http://ns.electronichealth.net.au/smart/role/new", "registeredClientIdsUrl": "https://smartforms.csiro.au/smart-config/config.json" } -
The app includes a configuration checker that validates your
config.jsonfile before the app fully loads.
If you are using SMART App Launch, you need to ensure that the app can resolve a valid client_id during the launch sequence.
The app supports three different methods for resolving a SMART App Launch client_id. This ensures client_id registration flexibility.
You can embed the client_id directly in the launch URL.
Format: https://smartforms.csiro.au/<client_id>/launch?iss=<fhir_server_url>&launch=<launch>
Example URL: https://smartforms.csiro.au/a57d90e3-5f69-4b92-aa2e-2992180863c1/launch?iss=https://proxy.smartforms.io/v/r4/fhir
Based on guidance from the SMART App Launch spec, servers should assign a client_id to the client app during app registration. Because Smart Forms is a static SPA without a persistent backend, it stores this information in a JSON file hosted elsewhere, and is fetched at runtime.
Based on the issuer (iss parameter in the launch URL), the app will look up the corresponding client_id from this JSON file and use during the launch sequence.
This file's location can be configured in registeredClientIdsUrl in config.json.
Example URL: https://smartforms.csiro.au/smart-config/config.json
Example JSON response (RegisteredClientIdsConfig):
{
"https://proxy.smartforms.io/v/r4/fhir": "a57d90e3-5f69-4b92-aa2e-2992180863c1",
"https://example.com/fhir": "6cc9bccb-3ae2-40d7-9660-22c99534520b"
}If neither the launch URL nor the registered clients JSON provide a client_id, the app will fall back to a predefined default client_id.
This default client_id can be configured in defaultClientId in config.json.
Once configuration is set up, let's look at running the various apps and packages locally.
This is a monorepo, so you can run multiple packages/apps simultaneously in different terminal windows. Ensure that package versions and dependency versions are the same across the monorepo to prevent unexpected issues. Example: If you are making changes to the sdc-populate package and it is on 4.6.2, ensure that the Smart Forms app is using the same version (4.6.2) of sdc-populate.
-
Ensure you have run
npm installin the main folder to install all dependencies. -
Build all packages in the /packages directory.
npm run build-all-deps-first-run
Or individually:
npm run build -w packages/sdc-populate npm run build -w packages/sdc-assemble npm run build -w packages/sdc-template-extract npm run build -w packages/smart-forms-renderer
-
Open a new terminal window and navigate to the Smart Forms app directory.
cd apps/smart-forms-app -
Start the Smart Forms app on localhost. It defaults to port 5173.
npm start
-
Code changes in the Smart Forms app will trigger a live reload.
-
If you're using the Smart Forms app as a visual debug tool, the Playground (/playground) is a great way to view changes made to the other packages.
Most of the time, you will be making changes to the renderer component located in packages/smart-forms-renderer instead of the Smart Forms app.
You might also be making changes to the SDC packages such as sdc-populate, sdc-assemble or sdc-template-extract. In some cases, you may need to work on multiple packages simultaneously, which requires running multiple terminal windows.
-
Open a new terminal window and navigate to the package directory.
cd packages/smart-forms-renderer # or cd packages/sdc-* etc.
-
Start the renderer in watch mode to watch for live code changes. If there are any errors, your code will not compile properly until you resolve all errors. Errors will be displayed in the terminal.
npm run watch
-
At this stage, the TypeScript complier has complied the renderer's source code, but we need to visualise changes. You can either run Smart Forms Playground (more straightforward) or Storybook to visualise your changes.
- If running Smart Forms Playground:
- Follow the steps in Running Smart Forms locally to start the Smart Forms app.
- Go to http://localhost:5173/playground to view renderer changes
- Renderer changes will force the Smart Forms app to empty its state. Therefore you will see this "Questionnaire does not have any items or something has gone wrong. Try rebuilding the form." message every time the renderer is rebuilt.
Every time the renderer is re-built, the Smart Forms app will automatically reload to reflect changes. If it is not reloading as expected, the most common issue is that the package's version doesn't match the dependency version in the Smart Forms app.
- If running Renderer Storybook:
- Open a new terminal window, navigate to the renderer package directory and run
npm run storybookto start Storybook. It defaults to port 6006. - If using this method, refer to Create a Questionnaire story test case to create a Storybook test case for your changes.
- An alternative command is
npm run storybook-watch, which watches for changes concurrently without needing to runnpm run watchseparately.
- Open a new terminal window, navigate to the renderer package directory and run
- If running Smart Forms Playground:
The above two methods should be sufficient for local development. However, if you prefer to do local development in Docker containers, you can follow the steps below.
-
Install Docker and Docker Compose from https://www.docker.com.
-
In the main folder, build the docker container
docker-compose --env-file ./apps/smart-forms-app/.env.local build
-
Once the container is built, you can run both Smart Forms and Storyboard at the same time
docker-compose --env-file ./apps/smart-forms-app/.env.local up
-
Go to http://localhost:5173/ for Smart Forms app.
-
Go to http://localhost:6006/ for Renderer StoryBook.
NOTE: In the Docker setup, the current source code folder is shared as a volume to the Docker container. This allows live code reload to work.
To ensure your changes are properly tested and do not introduce regressions, it is important to create test cases for your changes and run existing tests to verify everything works as before.
Each package contains its own set of unit (and potentially integration) tests located in their respective src/test folders.
The Smart Forms app contains unit tests in src/test and src/feature/*/test.
Our GitHub CI workflow is also set up to run unit tests and check coverage on every push.
To run unit tests for a specific package or app, navigate to its directory and run:
npm run testWhen adding new features or fixing bugs, it is important to add relevant unit tests.
Jest is used as the unit testing framework. The coverage requirements are as below:
| Metric | Coverage (%) |
|---|---|
| Statements | 80 |
| Branches | 75 |
| Functions | 80 |
| Lines | 80 |
To add new unit tests, create a new file in the src/test folder (or src/feature/*/test for Smart Forms app) with the .test.ts or .test.tsx extension, using the same file name as the source code file you have modified.
If you need make any changes to Jest's config, they are located in the jest.config.ts file in the respective package or app directory.
We use Storybook primarily as pseudo-documentation for the FHIR community to view various Questionnaire examples and how they are rendered.
Besides that, the Smart Forms renderer also uses Storybook for questionnaire-based testing.
Coverage for this is fairly minimal and basic at the moment, but it is a good idea to create a Story + test case for any new components or significant changes. Otherwise, creating a Story (without any interactive tests) is sufficient.
Our GitHub CI workflow is also set up to run storybook-based tests on every push.
-
To run existing Storybook tests, navigate to the renderer package directory.
cd packages/smart-forms-renderer -
Run Storybook CI tests
npm run test-storybook-ci
Based on this issue storybookjs/storybook#25011, Storybook tests always have autoplay on, which can result in a jarring experience for users using Storybook as documentation.
We use a CI=true flag to conditionally enable the play field in Storybook test cases only during CI runs (or when you run npm run test-storybook-ci).
This means that running Storybook locally via npm run storybook will not trigger Storybook tests from running.
To explicitly enable Storybook tests while running Storybook locally, you can run:
CI=true npm run storybookStories are great for visualising Questionnaire rendering scenarios. They serve a similar purpose to rendering a Questionnaire in the Playground, but also act as concrete, reusable examples that can be referred to later.
Below are the steps to create a new Storybook story for a Questionnaire test case.
-
Identify where this new story fits in the existing Storybook structure. The categories are:
- Item Types - Basic Questionnaire item types such as
string,choice,groupetc. - SDC - Structured Data Capture-specific extensions such as
preferredTerminologyServer,initialExpression, etc. - Custom Extensions - CSIRO-specific custom extensions such as
https://smartforms.csiro.au/ig/StructureDefinition/GroupHideAddItemButton. - Testing - Any test cases that don't fit into the above categories.
- Item Types - Basic Questionnaire item types such as
-
Create a new TypeScript object of
Questionnairetype inpackages/smart-forms-renderer/src/stories/assets/questionnairesin a new or existing file depending on the issue you are working on.- This object holds a FHIR Questionnaire resource in TypeScript format. You can convert it back to JSON if needed using https://www.convertsimple.com/convert-javascript-to-json/.
- A good naming convention is to prefix the file name with
qfollowed by the story's title. - You can refer to existing Questionnaire examples for structure reference. Below is a minimal example:
export const qDecimalCalculation: Questionnaire = { resourceType: 'Questionnaire', status: 'draft', item: [ // <snipped for brevity> ] };
- Ensure that the Questionnaire object is exported.
-
Based on the category identified in step 1, open or create a new Storybook story file in
packages/smart-forms-renderer/src/stories/<category>.- A good naming convention is
<Story subcategory>.stories.tsx, e.g.Decimal.stories.tsx. - Refer to the below minimal story example:
const meta = { title: 'ItemType/Decimal', component: BuildFormWrapperForStorybook, tags: [] } satisfies Meta<typeof BuildFormWrapperForStorybook>; export default meta; type Story = StoryObj<typeof meta>; export const DecimalBasic: Story = createStory({ args: { questionnaire: qDecimalBasic } }) as Story;
meta.titledefines where this story appears in Storybook's sidebar. Each level is separated by a/.meta.componentshould contains a wrapper and it acts as the entry point into the renderer.BuildFormWrapperForStorybookis the standard wrapper used for Questionnaire stories.- Supply the component with necessary
args. At a minimum, you need to provide thequestionnairearg with the Questionnaire object created in step 2. - The story itself is defined as an exported constant.
- A good naming convention is
-
You should see your new story appear in Storybook's sidebar!
-
If you need make any changes to Storybook's config, Storybook holds its config in three files:
packages/smart-forms-renderer/vite.config.ts- Vite config for Storybookpackages/smart-forms-renderer/.storybook/main.ts- Main Storybook configpackages/smart-forms-renderer/.storybook/preview.ts- Storybook preview config
Storybook provides you a way to add interactive tests to your story using the play field. It has similar syntax to React Testing Library.
There are some testing utils provided in packages/smart-forms-renderer/src/stories/testUtils.ts to help with common tasks such as inputting or querying text for Questionnaire items.
This file contains examples of a Storybook tests: https://github.com/aehrc/smart-forms/blob/main/packages/smart-forms-renderer/src/stories/itemTypes/Decimal.stories.tsx
After adding a new Story test case, ensure that it runs correctly by running Storybook CI tests as described in Run existing Storybook tests.
If you are make changes to story names, ensure that they don’t break the docs!
There isn’t a CI process to do this, but you can check if the storyId exists in any documentation, e.g. sdc-9-1-4-rendering-other--read-only
We use Chromatic in CI to catch for any UI layout changes on the deployed Storybook instance https://smartforms.csiro.au/storybook/.
If Chromatic detects any layout changes, they have to be approved them in the Chromatic dashboard. Access the dashboard via the "Details" button next to "UI Tests" in GitHub Actions CI or use this link. You will need to sign in with your GitHub account.
Our GitHub CI workflow is set up to run Chromatic visual regression on every push to main. We are on the free plan, which has a limit of 5000 snapshots per month. When the limit is hit, Chromatic tests will be skipped until the next month.
Besides unit tests and Storybook tests, we also have questionnaire behaviour tests for specific questionnaires, such as the Aboriginal and Torres Strait Islander Health Check (MBS715).
These tests are located in apps/smart-forms-app/src/test/questionnaireRenderer.test.tsx and are run as part of the Smart Forms app's unit test CI workflow. These tests use Vitest instead of Jest.
This work was initiated by Beda Software, and no additional tests are required unless explicitly requested.
We use Playwright for end-to-end testing of the Smart Forms app. These tests focus on SMART App Launch + QuestionnaireResponse saving back to the FHIR server.
These tests are located in apps/smart-forms-app/e2e and are run as part of the Smart Forms app's e2e test CI workflow.
These end-to-end tests use MBS715 and BitOfEverything as test data. They can be fairly flaky, so we try to keep them to a minimum. Currently, there are no plans to add more tests unless explicitly requested. If CI e2e tests are failing, try running them again via the "sync" button on GitHub Actions.
For the MBS715, the version is currently set to
0.4.0in the tests. When the version inevitably changes,smart-forms-app/e2e/globals.tsneeds to be updated otherwise the tests will fail to find the Questionnaire.E.g.
'{"role":"http://ns.electronichealth.net.au/smart/role/new","canonical":"http://www.health.gov.au/assessments/mbs/715|0.3.0-assembled","type":"Questionnaire"}'
A common failure point for these tests is the SMART App Launch sequence, which relies on actual FHIR servers:
- SMART App Launch + Patient Data FHIR API: https://proxy.smartforms.io/v/r4/fhir
- Forms Server: https://smartforms.csiro.au/api/fhir
These servers get cleared out every 60 or 90 days when the AWS instances restarts, which may cause tests to fail if the expected test data is missing. In that case, follow this guide https://confluence.csiro.au/spaces/eHealth/pages/1952331307/Restoring+Smart+Forms+test+data+on+EHR+and+Forms+HAPI+instances to restore the test data.
The documentation site is located in the documentation folder and is built using Docusaurus https://docusaurus.io/. It is deployed automatically to https://smartforms.csiro.au/docs/ via GitHub Actions CI on every push to main and dev.
If you are running the documentation site locally, you can run:
cd documentation
npm startIt leverages Docusaurus' MDX feature to embed React components (i.e. Storybook iframe) directly into the documentation pages, and will require Storybook to be running locally on port 6006 to view the examples.
The search function is powered by Algolia DocSearch. If you are adding new documentation pages, ensure that they are indexed properly by following the steps in https://docsearch.algolia.com/docs/run-your-own/.
While it is optional to contribute to the documentation, it is highly encouraged to add or update relevant documentation pages when making significant changes.
We use Prettier and ESLint to enforce code style and quality. The most efficient way to enforce them is to install the relevant extensions in your IDE and enable settings that runs them "on save". Our CI workflow is also set up to run linting checks on every push.
One of the most common pitfalls in React is the overuse of useEffect. It might be worth reading this great article https://react.dev/learn/you-might-not-need-an-effect to understand when to use useEffect and when not to.
The Airbnb JavaScript style guide at https://github.com/airbnb/javascript is a great reference for writing clean and consistent JavaScript/TypeScript code.
We use a simple branching strategy with main as the main branch. All feature/bugfix branches should be created from main and merged back into main via pull requests.
If the branch is long-lived (i.e. more than a week), it is a good idea to regularly sync with main to prevent large merge conflicts.
It is good practice to have small and focused pull requests to make code reviews easier.
P.S. We had alpha as a pre-release branch before the recent v1.0.0 release. This branch is now deprecated and will be removed in the future. On now onwards, all changes should be merged directly into main.
- Create a new branch from
mainfor your feature or bugfix. A good convention is to useissue/<issue-number>if it's tied to an issue.- If it's not tied to an issue, create an issue first to track the work.
- If it's not tied to an issue and is a relatively quick fix (< 5 mins), use a descriptive name such as
feature/<feature-name>orfix/<bug-description>.
- Follow the steps in Running locally to setup your local development environment.
- Make your code changes.
- Run existing tests to ensure everything is working.
- Add new tests (unit tests, Storybook tests, etc.). Refer to Creating Test Cases.
- If applicable, update documentation. Refer to Documentation.
- Create a pull request to merge your branch into
main. - Ensure that all CI checks pass (build, tests, linting, etc.).
- Merge
maininto your branch to ensure you have the latest changes. - Update TypeDoc documentation by running
npm run buildin/documentation. - Request for a code review from a team member (or review it yourself). Once approved, you can proceed to the next steps.
- Merge your branch into
main. - Ensure the CI passes on
mainafter the merge. If you added any Storybook stories or if story layout in Chromatic changes, those have to be reviewed and approved in Chromatic.
Remember to merge main into your branch regularly throughout the development process.
- Create a fork of the repository.
- If not already done, create an issue to track the work.
- Create a new branch from
mainfor your feature or bugfix. A good convention is to useissue/<issue-number>. - Make your code changes.
- Run existing tests to ensure everything is working.
- Add new tests (unit tests, Storybook tests, etc.). Refer to Creating Test Cases.
- If applicable, update documentation. Refer to Documentation.
- Create a pull request to merge your branch into
aehrc/main. - Ensure that all CI checks pass (build, tests, linting, etc.).
- Merge
maininto your branch to ensure you have the latest changes. - Update TypeDoc documentation by running
npm run buildin/documentation. - Request for a code review from an internal team member.
- For the reviewing internal team member:
- Review the code changes.
- Once approved, merge the pull request into
aehrc/main. - If there are package version bumps, create a new PR referencing the issue and follow the steps in Release process to publish new package versions.
Publishing is automated via GitHub Actions. Creating a GitHub release with the appropriate tag triggers the build, test, lint, and publish pipeline.
Publishing uses npm trusted publishing via OIDC — no long-lived npm tokens are needed. Set up the following once:
GitHub environment:
- Go to Settings > Environments > New environment, name it
npm. - Optionally add a required reviewer as an approval gate before publish.
npm trusted publishers:
For each package, configure a trusted publisher on npmjs.com. Note that for
scoped packages under @aehrc, you must be a member of a team with write
access to the package — being an org owner alone is not sufficient to see the
Settings tab.
- Go to the package page on npmjs.com and click Settings.
- Under Trusted Publisher, click GitHub Actions.
- Enter the organisation (
aehrc), repository (smart-forms), the workflow filename (see table below), and the environment name (npm). - Click Set up connection.
| Package | Workflow filename |
|---|---|
@aehrc/sdc-assemble |
publish_sdc_assemble.yml |
@aehrc/sdc-populate |
publish_sdc_populate.yml |
@aehrc/sdc-template-extract |
publish_sdc_template_extract.yml |
@aehrc/smart-forms-renderer |
publish_smart_forms_renderer.yml |
- Bump the version in
package.jsonfor each package being released, following semantic versioning. - If releasing
@aehrc/sdc-populateor@aehrc/sdc-template-extract, also bump@aehrc/smart-forms-rendererand update its dependency versions. Update the Smart Forms app's dependency on the renderer as well. - Update the changelog in the respective package directory:
@aehrc/smart-forms-renderer—CHANGELOG.md(repo root)@aehrc/sdc-populate—packages/sdc-populate/CHANGELOG.md@aehrc/sdc-assemble—packages/sdc-assemble/CHANGELOG.md@aehrc/sdc-template-extract—packages/sdc-template-extract/CHANGELOG.md
- Run
npm installto updatepackage-lock.json. - Commit and merge the version bumps and changelog updates into main.
Create a new release on GitHub with the tag matching the package:
| Package | Tag format | Example |
|---|---|---|
@aehrc/smart-forms-renderer |
v<version> |
v1.3.0 |
@aehrc/sdc-assemble |
sdc-assemble@<version> |
sdc-assemble@2.0.2 |
@aehrc/sdc-populate |
sdc-populate@<version> |
sdc-populate@4.6.3 |
@aehrc/sdc-template-extract |
sdc-template-extract@<version> |
sdc-template-extract@1.0.15 |
The tag version must match the version in the package's package.json.
- The publish workflow runs the full build, test, and lint suite first. If any check fails, the package will not be published.
- If the
npmenvironment has a required reviewer, approve the deployment when prompted. - Once complete, verify the new version on npm (e.g.
npm view @aehrc/sdc-assemble version).
When releasing packages that depend on each other, publish them in dependency order:
@aehrc/sdc-assemble(independent, can be published any time)@aehrc/sdc-populate(independent)@aehrc/sdc-template-extract(independent)@aehrc/smart-forms-renderer(depends on sdc-populate and sdc-template-extract — publish after its dependencies)
Create a separate GitHub release for each package.
- Workflow did not trigger: Check that the tag matches the expected pattern exactly.
- Build or test failure: Fix the issue on main, then create a new release with the same tag (delete the failed release and tag first).
- npm authentication error: Verify that the trusted publisher is configured correctly on npmjs.com for the package, matching the workflow filename and environment name exactly.
- Provenance error: Ensure the repository's GitHub Actions settings allow
id-token: writepermissions (Settings > Actions > General > Workflow permissions).
date-fnswith version "^4.1.0" inapps/smart-forms-app/package.jsonis not used in the source code. It is used to prevent CommonJS issues when building the Smart Forms app in docker.html-react-parsershould be kept at version "4.2.10" inapps/smart-forms-app/package.json. Version 5.x breaks QuestionnaireResponse -> HTML parsing.react-router-domshould be kept at version "6.11.2" inapps/smart-forms-app/package.json. Version 7.x breaks useBlocker usage when switching from renderer to renderer/preview routes.
NPM workspaces can be a bit inconsistent at times, so it is a good idea to merge main back to your branch first, then run npm install in the directory you are working on to ensure dependencies are installed correctly.
If npm install doesn't resolve the issue, try deleting the node_modules directory (or package-lock.json at times) and running npm install again.
Sometimes packages in the monorepo can have different versions of the same dependency, which may cause issues. Ensure that the package/app you are working on have the same dependency versions as the other packages in the monorepo.
Perform a npm install in the directory you are working on every time you change package versions.
e.g. Smart Forms app running v1.0.0-alpha.15 of @aehrc/smart-forms-renderer while the documentation app is running v0.44.3.
Sometimes dependencies will work even when they are not installed. That is because NPM workspaces allow packages to work even when they are located in different directories. Ensure that the new dependency you are using is installed in the directory you are working on.
Sometimes your changes aren't reflected due to of compilation errors. Go back to the watching terminal tab and check if there are any errors.
When running the Smart Forms app locally, if you are getting errors like "Uncaught TypeError: undefined is not a function e.g. Grid2.js", it is likely that Vite is caching a previous (failing) build.
Try deleting the apps/smart-forms-app/node_modules/.vite directory and run npm start again.