We’ll be releasing another major version of Redwood soon. We plan to merge a few more fixes in before releasing the final version, but we have the first release candidate ready, and we’re excited for you to try it! You can upgrade to the release candidate using the yarn rw upgrade command
:
yarn rw upgrade --tag rc
This major version includes more breaking changes than the last (v2) since many of Redwood’s fundamental dependencies—like Fastify, Jest, and Prisma—released a major version of their own.
This major version is part of the same Redwood epochal version as v1 and v2, Arapaho Forest.
Breaking changes:
- Cell and Route-parameter Prerendering
- Access to the Fastify instance in the Api-server Configuration
- TypeScript Strict Mode
- Targeting Node.js 14
- Jest v29 and Improvements in Test Memory Usage and Performance
- Prisma v4
- Fixing the import-order rule
Breaking Changes
Cell and Route-parameter Prerendering
This change is more of a feature than a breaking change, but there’ s a few edge cases where it could be breaking.
v3 features a major new capability to Redwood’s prerendering: Cells and routes with parameters can now be prerendered! Given a set of route parameters, Redwood can now fetch data from your GraphQL API at build-time. This means you can use Redwood as a proper static site generator!
Before, Redwood couldn’t prerender routes with parameters:
<Route path="/blog-post/{id}" page={BlogPostPage} name="blogPost" prerender />
Here, the value of id
isn’t known at build-time. Before Redwood would just silently ignore this route (even though it has the prerender
prop). But now you can tell Redwood what id
s to prerender by creating a BlogPostPage.routeHooks.{js,ts}
file next to BlogPostPage.{js,ts}
:
// BlogPostPage.routesHooks.{js,ts}
export function routeParameters() {
return [{ id: 1 }, { id: 2 }, { id: 3 }]
}
In these *.routeHooks.{js,ts}
files, you have full access to your project’s api side—the database (via Prisma), services—should you need it. Just import { db } from '$api/src/lib/db'
. If you’re using TypeScript, your project’s web-side tsconfig will need a small edit to know about this path. We wrote a codemod to make this change for you:
Codemod Available
To implement this step via automated codemod, run:
npx @redwoodjs/codemods@canary tsconfig-for-route-hooks
That’s the gist of it for route parameters. You can read more in the new Dynamic routes & Route Hooks section of the prerender docs. To prerender Cells, you don’t need any special config, but you should note that prerendering always happens as an unauthenticated user. The new Cell prerendering section in the docs goes into more detail.
All together, while this feature probably won’t break your project, it could for one of the following reasons:
- if you were previously prerendering pages with route parameters, they used to just be silently ignored. Now they’ll fail and tell you that you need to create a
routeHooks
file. You can either implemented a routeHooks file, or addprerender={false}
to the route you wish to skip. - if you were previously prerendering pages that had Cells that need auth. Redwood used to just render the Loading component, but now it tries to execute the query and will error out
- your project already has a file that ends in
.routeHooks.{js,ts}
along side the page file that exports arouteParameters
function (this is pretty unlikely)
Access to the Fastify instance in the Api-server Configuration
This change affects all users and can be applied via a codemod, or by manually updating the
server.config.js
file found in your project’s api directory.
Previously, the api side’s server.config.js
file only exposed a limited number of Fastify settings. But you all told us that being able to enrich the Fastify instance with plug-ins would be really useful.
Agreed!
The server.config.js
file now exposes a hook to configure plug-ins on a per-side basis.
You’ll need to update your api side’s server.config.js
either via a codemod or manually.
Note that, ff your project does not currently have a 'server.config.js` file, one will be added.
To do so via codemod:
Codemod Available
To implement this step via automated codemod, run:
npx @redwoodjs/codemods@canary configure-fastify
If you choose to update manually, you’ll need to replace the api/server.config.js
with the latest version found here. Then, update the following config
to include any FastifyServerOptions
that your prior configuration used (such as a custom requestTimeout
value, etc):
/** @type {import('fastify').FastifyServerOptions} */
const config = {
requestTimeout: 15_000, // 👈 update these config settings to match your prior config
logger: {
// Note: If running locally using `yarn rw serve` you may want to adust
// the default non-development level to `info`
level: process.env.NODE_ENV === 'development' ? 'debug' : 'warn',
},
}
Want to see an example of what’s possible now? Expand the “Configuring the Fastify Instance” section below and follow along:
Configuring the Fastify Instance
For example, here you can register the compress
and rate-limit
Fastify plug-ins that will deflate or gzip your app’s responses and also enforce how many requests can be made to the api over a certain period of time. And, on the web-side, responses will have HTTP ETags generated.
This configuration does not apply in a serverless deploy, but will apply in local development.
// api/server.config.js
/** @type {import('@redwoodjs/api-server/dist/fastify').FastifySideConfigFn} */
const configureFastify = async (fastify, options) => {
if (options.side === 'api') {
fastify.log.info({ custom: { options } }, 'Configuring api side')
await fastify.register(import('@fastify/compress'), {
global: true,
threshold: 1_024,
encodings: ['deflate', 'gzip'],
})
await fastify.register(import('@fastify/rate-limit'), {
max: 100,
timeWindow: '5 minutes',
})
}
if (options.side === 'web') {
fastify.log.info({ custom: { options } }, 'Configuring web side')
fastify.register(import('@fastify/etag'))
}
return fastify
}
For complete configuration instructions, please see Register Custom Fastify Plug-ins.
TypeScript Strict Mode
This change only affects TypeScript users. There’s at least one change you’ll have to make (documented below) whether or not you’re using strict mode.
While Redwood has supported TypeScript for a while, if you’ve ever turned on strict mode before, you may have been overwhelmed by red squiggles. @danny and @Tobbe have spent a ton of time this release making sure that the TypeScript strict-mode experience in Redwood is red-squiggle free. And even if you’re not using strict mode, there’s still a lot to look forward to as they’ve improved the types across the board, especially for resolvers (i.e. your service functions).
Codemod Available
To implement this step via automated codemod, run:
npx @redwoodjs/codemods@canary update-resolver-types
Open to see manual steps
Let’s say you have a Post service, and Posts have an Author. At the bottom of the Posts service file, we usually define the “relation” or field resolvers. You’ll need to wrap the type in a Partial now, due to config changes for strict mode.
In essence PostResolvers
becomes Partial<PostResolvers>
:
// services/posts.ts
export const post: QueryResolvers['post'] = /**/
export const createPost: MutationResolvers['createPost'] = /**/
// 👇 these are your "relation" or field resolvers
- export const Post: PostResolvers = {
+ export const Post: Partial<PostResolvers> = {
author: (_obj, gqlArgs) => /**/
}
No feature is complete without docs. We revamped the TypeScript docs on redwoodjs.com. If you’re actually going to enable strict mode, there’s a few manual changes you’ll have to make after setting strict
to true. Start here in the introduction and follow along: https://redwoodjs.com/docs/canary/typescript/strict-mode#manual-tweaks-to-generated-code.
Remember to regenerate your types by running
yarn rw g types
at the end of your upgrade!
Targeting Node.js 14
This change affects all users, but there’s nothing you have to do.
Redwood apps now target Node.js 14 instead of 12. This is the main reason we’re releasing a major as the rest of the ecosystem has decided that it’s time to deprecate Node.js 12. Since we use Babel (and on the api-side, ESBuild) to transpile modern JS, you’ve been able to write code for Node.js 12+ all along, so you shouldn’t have to worry about this change. But let us know if anything comes up!
Jest v29 and Improvements in Test Memory Usage and Performance
This change affects all users. The least you have to do is update snapshots (
yarn rw test -u
), but there may be more—read on!
Redwood v3 upgrades Jest from v27 to v29. A breaking change introduced in v29 likely to affect all users is the change to the snapshot format. Jest changed the snapshot format making them more readable and copy-pasteable.
This should be an easy fix. Just update the snapshots! We recommend keeping your git history clean by doing this in its own commit:
# Provided your working directory is clean
yarn rw test -u
# Scan the changes; make sure everything looks ok
git add .
git commit -m "chore: update snapshot format"
Are you a fan of the older snapshot format?
If you’re a fan of the older snapshot format, you’re free to undo the changes. All you have to do is add this to the jest.setup.js
config file in the api and web side of your project:
// In `api/jest.config.js` and `web/jest.config.js`
const config = {
rootDir: '../',
preset: '@redwoodjs/testing/config/jest/api', // or web
+ snapshotFormat: {
+ escapeString: true,
+ printBasicPrototype: true,
+ }
}
module.exports = config
The rest of the breaking changes depend on your config and dependencies. The things that are most likely to affect you are:
- a configuration option was renamed (see https://jestjs.io/docs/upgrading-to-jest28#configuration-options)
- dependencies aren’t being resolved correctly (most likely in web-side tests)
If you think a dependency isn’t being resolved correctly (the error will probably be “Jest encountered an unexpected token”), expand the section below and follow along:
Did Jest encounter an unexpected token?
If Jest isn’t resolving a dependency correctly, your tests will fail with an error like this:
● Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
• If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation
Details:
C:\repos\accessibility-insights-web\node_modules\uuid\dist\esm-browser\index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export { default as v1 } from './v1.js';
^^^^^^
SyntaxError: Unexpected token 'export'
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
> 3 | import { v4 } from 'uuid';
| ^
4 |
5 | export type UUIDGenerator = () => string;
6 |
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1773:14)
at Object.<anonymous> (src/common/uid-generator.ts:3:26)
This may seem impossible to fix, but it’s actually somewhat straightforward:
- as a simple debugging step, try rebuilding your project’s
yarn.lock
file (sometimes that’s all it takes) - if you think it’s a problem with one of the Redwood framework’s dependencies (you could figure this out using
yarn why
), make an issue - if it’s a dependency that’s specific to your project, follow one of the strategies in this GitHub issue comment
That comment is long. To save you some time, we chose the resolver strategy, and if you do too, just copy our resolver and a check for your package:
// See https://github.com/redwoodjs/redwood/blob/main/packages/testing/config/jest/web/resolver.js
module.exports = (path, options) => {
return options.defaultResolver(path, {
...options,
packageFilter: (pkg) => {
+ if (pkg.name === 'uuid' || pkg.name === 'my-troublesome-dependency') {
delete pkg['exports']
delete pkg['module']
}
return pkg
},
})
}
This file should live next to the api or web side’s—whichever one has failing tests—jest.config.js
. You can name it whatever you want, just be sure to specify it in jest.config.js
:
// In `api/jest.config.js` and `web/jest.config.js`
const config = {
rootDir: '../',
preset: '@redwoodjs/testing/config/jest/api', // or web
+ resolver: path.resolve(__dirname, './my-custom-resolver.js'),
}
module.exports = config
If that still doesn’t work, definitely make an issue!
Prisma v4
This change affects all users, but there may be nothing actionable. Read on!
Redwood v3 bumps the version of Prisma from v3.15.2 to v4.3.1.
As with all Prisma upgrades, remember to regenerate your Prisma client after upgrading:
yarn rw prisma generate
Prisma v4 was breaking for both the framework and for projects because it dropped Node.js 12 support. But there are some changes that only break the framework and some that may (depending on your use of Prisma) only break projects.
On the framework’s side, v4 was breaking because it renamed @prisma/sdk
to prisma/internals
to better communicate that the package won’t be versioned with SemVer. (So if you happen to be using it in your project for some reason, note that every release could be breaking.)
On a project’s side, it depends on your use of Prisma. So there may be no breaking changes for you, but to know for sure, you’ll have to read through Prisma’s upgrade guide. We think the sections that are most likely to affect you are…
- Explicit
@unique
constraints on one-to-one relations - Enforced use of
@unique
or@id
attribute for one-to-one and one-to-many relations (MySQL and MongoDB) - Disallow
references
syntax for implicit many-to-many relations
Since Prisma v4.0.0 was released, a few minors have come out as well. Check out the release notes for all the new features:
- https://github.com/prisma/prisma/releases/tag/4.0.0
- Release 4.1.0 · prisma/prisma · GitHub
- Release 4.2.0 · prisma/prisma · GitHub
- Release 4.3.0 · prisma/prisma · GitHub
Fixing the import-order rule
This change affects all users and can be applied via
yarn rw lint --fix
.
Last major, we added an ESLint rule to Redwood projects that orders imports. (Read more about it here https://community.redwoodjs.com/t/redwood-v2-0-0-is-now-available/3299#linting-import-order-3.)
It turns out we overlooked one thing in the api/src/functions/graphql.js
file. Those “glob star” imports are special (Babel “expands” them as a part of the build step), and we want to highlight that by setting them apart:
// Actual behavior (two groups)
import { createGraphQLHandler } from '@redwoodjs/graphql-server'
import directives from 'src/directives/**/*.{js,ts}'
import sdls from 'src/graphql/**/*.sdl.{js,ts}'
import { db } from 'src/lib/db'
import { logger } from 'src/lib/logger'
import services from 'src/services/**/*.{js,ts}'
// Desired behavior (three groups)
import { createGraphQLHandler } from '@redwoodjs/graphql-server'
import directives from 'src/directives/**/*.{js,ts}'
import sdls from 'src/graphql/**/*.sdl.{js,ts}'
import services from 'src/services/**/*.{js,ts}'
import { db } from 'src/lib/db'
import { logger } from 'src/lib/logger'
So this major includes a fix to the import-order rule. That should be the only change, and it should be as easy as last time:
# After stashing, or at least when your working directory is clean
yarn rw lint --fix
git add .
git commit -m "style: fix graphql.js imports"
We know these kinds of changes can be annoying, and don’t take changes to linting lightly. We don’t want to bikeshed, and want to do less not more. Let us know what you think!
Want to turn this off? In the package.json in the root of your project:
...
"eslintConfig": {
"extends": "@redwoodjs/eslint-config",
"root": true
+ "rules": {
+ "import/order": "off"
+ }
},
Features
CLI Performance
The Redwood CLI can be painfully slow. There’s a lot we can do to improve performance, and we plan to do it. This release, we finished some preliminary work that should pave the way for real gains in the future. While it was just preliminary, you should experience faster startup times for the CLI overall already. Here’s an unscientific benchmark:
# v2.2.1
~/v2-rw-project> hyperfine --warmup 3 "yarn rw --help"
Benchmark 1: yarn rw --help
Time (mean ± σ): 1.489 s ± 0.015 s [User: 1.692 s, System: 0.213 s]
Range (min … max): 1.474 s … 1.528 s 10 runs
# v3.0.0
~/v3-rw-project> hyperfine --warmup 3 "yarn rw --help"
Benchmark 1: yarn rw --help
Time (mean ± σ): 741.5 ms ± 2.3 ms [User: 874.6 ms, System: 94.5 ms]
Range (min … max): 738.7 ms … 746.6 ms 10 runs
WebAuthn Support
Did you know that websites can make use of TouchID/FaceID/biometric devices, not just apps? We didn’t, until a couple of months ago! The experience is so nice that we added support for it to dbAuth. Now when a user comes to your site you can log them in the first time with username/password, then ask if they want to use TouchID/FaceID going forward. If they do, when they return to the site they can just scan their fingerprint to log in.
WebAuthn adds a new cookie, which has a separate expiration date from the regular session cookie. So you can set the session cookie to expire in, say, a day, but keep the WebAuthn cookie around for two weeks. If the user comes back after 24 hours they simply scan their fingerprint again. If they haven’t been to the site in two weeks then they’ll need to use their username/password.
If you’re starting a new app, you’ll be prompted during yarn rw setup auth dbAuth
and yarn rw generate dbAuth
asking if you want to enable WebAuthn support. If you do, just hit y
and follow the post-install instructions.
If you have an existing app, follow the exhaustive guide here for instructions on adding support to your current codebase. If you haven’t made a ton of changes to api/src/functions/auth.js
or the Login/Signup pages, it may be easier to just run the setup and generate commands again with the --force
option, then checking the diff of the changes to see what was added. Then just copy/paste your custom code back into the re-generated files.
Changelog
Unique contributors: 28
PRs merged: 99
Breaking
- Cell prerendering + Prerender routes with parameters #5600 by @Tobbe
- Configure Fastify Server with Custom Plugins + Fastify Upgrade #5903 by @dthyresson
- [Chore]: Upgrade prisma to v4 #5924 by @jtoar
- fix:
import/order
should treat “glob star” imports as their own group #6213 by @jtoar - [Build] Bump Node.js target from 12 to 14 #6229 by @jtoar
- update jest monorepo to v29.0.1 #6314
- update dependency fastify to v4.5.3 #6313
Features
- TypeScript strict mode support + docs #5491 by @dac09
- Adds Webauthn support (TouchID, FaceID) to dbAuth #5680 by @cannikin
cli/lib/merge
&setup ui mantine
#4900 by @nickpdemarco- Auto-generate GraphQL comments in SDL to support a self-documenting API #5824 by @dthyresson
- Provide a possibility to disable flows in dbAuth completely #5851 by @Morishiri
- feat(internal): generate proper types for cells with custom props #6014 by @codekrafter
- Adds flags to skip prompting of WebAuthn install for headless commands #6022 by @cannikin
- CLI responsiveness #6028 by @peterp
- Copy changes from “Make Jest Debugging a No-Brainer” (5296) #6070 by @jtoar
- feat(ts): Improves return types of QueryResolvers, MutationResolvers and Resolvers #6228 by @dac09
- More helpful prerender error message #6240 by @Tobbe
- feat(ts): Improve types for directives #6272 by @dac09
- feat(jest): Improve performance of jest #6281 by @dac09
- CodeGen: Try to generate prisma client if no models are found #6308 by @Tobbe
- Add Okta to auth providers #5088 by @NoahC5
Fixed
- Fix unused import in generator cell test template #5827 by @Philzen
- fix: Configure and Document GraphQL Health Check for GraphQL Yoga #5875 by @dthyresson
- fix: Adds defensive check for GraphQL Errors when rendering errors of other types in Forms #6007 by @dthyresson
- Switch WebAuthn requests to XMLHttpRequest instead of fetch to get around security limitations #6024 by @cannikin
- 5101: auth.ts: Update eslint-disable-next-line statement to be compatible with js files too #6037 by @standup75
- Amend import order in auth templates according to ESLint rules introduced in v2.0 #6059 by @Philzen
- Avoid typescript warning when no roles key is supplied #6060 by @Philzen
- fix(cli): Modify existence check of jest.config to check for both .js and .ts extensions in rw test #6074 by @dac09
- Update types used in scaffolds #6083 by @Tobbe
- Generate Prisma Client when prerendering #6093 by @Tobbe
- fix: Allow using requireAuth without roles parameters in templates #6110 by @dac09
- Added full qualified path and mockServiceWorker.js to webpack file copy globOptions #6117 by @standup75
- tailwindcss ui: Support yarn v1 while setting up #6119 by @Morishiri
- fix(codemods): Add typescript as a dependency of codemods package #6121 by @dac09
- fix: Use the GraphQL codegen add plugin to include the Prisma namespace needed for the web type generation #6123 by @dthyresson
- Force file paths computed during Baremetal deploy to always have forward slashes #6126 by @cannikin
- docs: Remove ‘W’ from from pm2 installation command #6130 by @talk2MeGooseman
- Include ./scripts and ./web/config folders when linting #6150 by @Philzen
- Setup exclude: Eagerly match all ‘setup’ in path #6168 by @Tobbe
- Leverage PROJECT_CWD to set cwd in yarn 3 bin “proxies” #6199 by @jtoar
- Add arg types to @requireAuth #6216 by @Tobbe
- Fix strict mode errors in Name and NameForm scaffold templates #6220 by @Tobbe
- fix(ts): Avoid using partial resolver return types in codegen #6222 by @dac09
- Improve typing on generated storybook components #6226 by @will-ks
- Set content-type header when prerendering #6241 by @Tobbe
- [Fix] Install
@emotion/react
with mantine packages #6257 by @jtoar - Fix DOM nesting warning in test project #6264 by @Tobbe
- [Fix] Swap
testURL
fortestEnvironmentOptions.url
in Jest web preset #6273 by @jtoar - [Fix] Try reverting
tough-cookie
patch change #6298 by @jtoar
Docs
- doc(graphql): GraphQL 101 section #5800 by @charlypoly
- Add section on VSCode folder-/watcher-ignore settings to “Project Configuration” docs (using
.yarn
-folder as an example) #5868 by @Philzen - Fix redwood root schema definition link on GraphQL docs page #5896 by @Philzen
- docs: add link to Prisma Data Proxy #6002 by @nikolasburk
- Corrects schema.prisma file path in Deployment section #6030 by @tommymarshall
- Update sending-emails.md #6031 by @justinkuntz
- small update to flightcontrol deploy doc #6035 by @flybayer
- Tutorial 6.2: Add generics type hint to CellSuccessProps #6042 by @Philzen
- Tutorial 6.2: Wrap JSX element array in fragment tag #6043 by @Philzen
- Tutorial 6.3: Condense highlighted section to actual changes #6044 by @Philzen
- Tutorial 6.3: Fix prisma type error on comment creation #6045 by @Philzen
- Tutorial 6.4: Add type generics to mockGraphQLMutation #6046 by @Philzen
- Doc: Move generate script up in list #6076 by @pantheredeye
- Handful of doc fixes - typos and light highlights #6077 by @exzachlyvv
- Remove prisma db seed from intermission.md #6079 by @dac09
- docs: Fix deploy serverless command #6085 by @ajcwebdev
- Update Azure auth docs #6086 by @Tobbe
- docs(ts): Update some TS links, and add a tip to the tutorial #6095 by @dac09
- docs: update netlify deployment settings #6102 by @payapula
- docs(tutorial): Adds more TS hints in the toturial #6115 by @dac09
- [Docs] Adds a doc about getting started with SSH and real servers #6118 by @cannikin
- testing.md: Update file path in code snippet #6145 by @makdeb
- Tutorial 4.1: Update lib/auth code & remove warning about non-existent TS error (fixed via #5856, shipped in v2.1) #6158 by @Philzen
- Fix a typo in TS docs (there is no hasRoles function) #6160 by @Philzen
- docs(ts): Add section on core concepts and reorg introduction #6202 by @dac09
- Tutorial Chapter 4: Miniscule typo fixup #6211 by @noccer
- Tutorial: Use curly braces and
return
in ArticleCell Success #6224 by @Tobbe - More SSH doc updates, finally adds nginx config details to Baremetal doc #6263 by @cannikin
- Adds a Deploy Keys section to server doc #6304 by @cannikin
- [Docs]: Update GraphiQL Paragraph #6305 by @sarmstead
- docs: fix typos #6310 by @irshadwanijk
Need help or having trouble upgrading?
See this forum topic for manual upgrade instructions and general upgrade help .