MIT License
This is a port of the React Server Components "React Notes" demo for Azure Static Web Apps. React Server Components is currently an experimental project, and the code here to make it work in Azure is equally experimental. For demonstration purposes only!
Live demo: https://react-notes.anthonychu.com/
Azure services used:
See original README for license and other info.
Fork and clone this repo.
Start an instance of Postgres locally with the demo's default credentials. Docker works great:
docker run --name react-notes -p 5432:5432 -e POSTGRES_USER=notesadmin -e POSTGRES_PASSWORD=password -d postgres
Install Azure Functions Core Tools.
npm i -g azure-functions-core-tools@3 --unsafe-perm true
Update src/config.js
to use local Azure Functions URL:
module.exports = {
apiBaseUrl: '/api'
};
Build the app.
npm install
npm run build
Start the Azure Functions app.
func start
Serve the frontend with a web server. Using Python here but anything works.
python -m http.server
Create a Postgres Database in Azure
Seed database
DB_HOST
, DB_USER
, and DB_PASSWORD
environment variables to match how you configured your Azure Postgres instancenpm run seed
Create an Azure Static Web App
build
/
The workflow needs to be modified to build the app properly. Add an Action to the generated workflow:
- name: Build app and API
run: | # build and then remove package.json (so deploy step doesn't reinstall modules)
npm install
npm run build
npm prune --production
rm package.json package-lock.json
ls -la build
Save and push the file to trigger another deployment. See this file for an example.
In the Azure portal, go to the Static Web App and open Configuration. Enter the following settings:
name | value |
---|---|
BABEL_DISABLE_CACHE |
1 |
DB_HOST |
<server_name>.postgres.database.azure.com |
DB_USER |
your database username |
DB_PASSWORD |
your database password |
DB_SSL |
1 |
languageWorkers__node__arguments |
--conditions=react-server |
NODE_ENV |
production |
Save the settings. It may take a few seconds to take effect. If all goes well, go to the app's URL and you should see the app.
While it is fully functional, this is entirely experimental and for demonstration purposes only. Do not use for anything resembling production.
A few changes were made to the demo app to work better in Azure.
scripts/build.js
to combine the contents of build
and publish
folders.function_react/index.server.js
..server.js
to satisfy React Server Components conventions.fs/promises
, which is only in Node.js 14. Added a shim at fs/promises.js
to get around this.--conditions
flag to be set in the Node.js process. This flag is set with languageWorkers__node__arguments
app setting. Because Azure Functions starts the Node worker process before your app is loaded, you typically need to set an extra app setting (WEBSITE_USE_PLACEHOLDER=0
) to delay the start of the worker process. However, function apps in Static Web Apps are not allowed to configure app settings starting with WEBSITE_
. To get around this, if the conditions
flag isn't set, there is code in funcutil/babelregister.server.js
to cause a restart in the Node process. This is a huge hack and should never be used in a production app!pipeToNodeWritable
function in React Server Components requires writing to a stream. Like some other serverless platforms, Azure Functions is unable to stream responses. We use a memory-stream
for this.pipeToNodeWritable
looks up client components in a generated manifest. Because the manifest contains full paths from the build machine that are different than the paths in the Azure Functions environment, we use a proxy to select the file with the nearest matching name. See funcutil/react-utils.server.js
.X-Location
header, an additional 'Access-Control-Expose-Headers': 'X-Location'
must be added to responses.