Redwood v8.0.0 Upgrade Guide

I’m seeing the same issue in tests since trying to upgrade. IDE resolves routes.whatever with no issues, but when testing a [TypeError: _router.routes.whatever is not a function] exception is thrown. I generated a brand new page using yarn rw generate page xxx and the generated test also fails. Running yarn rw g types did not change anything.

This all worked in 7.7.4 with no issues.

Sorry – meant to reply to Redwood v8.0.0 Upgrade Guide - #33 by Josh-Walker-GM

1 Like

Hey @klobetime! Awesome thanks for proving more information.

I just ran through the following:

  1. yarn create redwood-app test-project
  2. yarn rw g page whatever
  3. yarn rw test web

Everything has worked. I’m about to generate a v7 project, upgrade it and test the same thing.

Are you able to produce a reproduction of this issue on a repository that you could share?

I went through the same steps you did and also was met with success (mostly – more on that in a second). My next step will be to compare the config of the fresh project with mine and see where I find differences.

I did see a (harmless?) error when generating a new project:

$$$$ yarn create redwood-app test-project --typescript
➤ YN0000: · Yarn 4.4.1
➤ YN0000: ┌ Resolution step
➤ YN0085: │ + create-redwood-app@npm:8.1.1
➤ YN0000: └ Completed
➤ YN0000: ┌ Fetch step
➤ YN0013: │ A package was added to the project (+ 2.27 MiB).
➤ YN0000: └ Completed in 0s 262ms
➤ YN0000: ┌ Link step
➤ YN0000: │ ESM support for PnP uses the experimental loader API and is therefore experimental
➤ YN0000: └ Completed
➤ YN0000: · Done with warnings in 0s 366ms

------------------------------------------------------------------
                🌲⚡️ Welcome to RedwoodJS! ⚡️🌲
------------------------------------------------------------------
✔ Compatibility checks passed
✔ Creating your Redwood app in test-project based on command line argument
✔ Using TypeScript based on command line flag
✔ Do you want to initialize a git repo? · no / Yes
✔ Do you want to run yarn install? · no / Yes
✔ Project files created
✔ Installed node modules
✔ Generated types

Thanks for trying out Redwood!

 ⚡️ Get up and running fast with this Quick Start guide: https://redwoodjs.com/quick-start

Fire it up! 🚀

 > cd test-project
 > yarn rw dev

Telemetry error
TT [OTLPExporterError]
    at IncomingMessage.<anonymous> (file:///private/var/folders/yw/vlr9zv8d4p9g7rrbx8dlc4ym0000gn/T/xfs-078f4e77/dlx-56972/.yarn/cache/create-redwood-app-npm-8.1.1-9db4d0013b-f01931964a.zip/node_modules/create-redwood-app/dist/create-redwood-app.js:147:72228)
    at IncomingMessage.emit (node:events:530:35)
    at endReadableNT (node:internal/streams/readable:1696:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  data: 'error code: 526',
  code: 526
}
$$$$ yarn --version
4.4.1
$$$$ node --version
v20.11.1
1 Like

Yeah that error is harmless and it’ll be gone in then next patch/minor

Went through a diff between my project and the newly generated test-project and didn’t find anything that would explain this behavior. There were minor changes, but even when I backed them out I saw the same error. (I did notice that in the fresh project, the module setting in web/tsconfig.json is set to ESNext rather than ES2022 as the upgrade process recommends. But that had no bearing on the error.)

Running the project with yarn rw dev shows that everything works just fine; it is only the tests that error out. I reworked my jest.config.js to exactly match the one in the fresh test-project, and the same error occurs so it isn’t that.

Debugging into the test, I find that the import is being auto-mocked to @redwoodjs/testing/dist/web/MockRouter.js as desired, but routes is always just {}, so routes.whatever() throws an error. Where should the routes get populated during a junit test?

Updating my test to use render(<Router><WhateverPage /></Router>); from just render(<WhateverPage />); fixes the issue. Not sure what changed in v8 to cause this behavior, or why it seems inconsistent with a fresh project, but at least I’m past it now!

1 Like

Well, that was dumb. :slight_smile: Adding <Router> didn’t solve the problems, it just masked them. The test passes, but <WhateverPage> isn’t ever actually rendered. So I’m back to not understanding why the MockRouter used by Jest never populates any routes.

2 Likes

Hi @Josh-Walker-GM ! I removed <LocationProvider> and stopped using useLocation in our code. This solved our issue with navigation for now.
There is definitely a regression in v8 with the LocationProvider but your new <NavLink> activeClass is a good substitute. Thanks!

I’ve got red squiggles in the Sentry implementation after upgrading from v7 –

Type '(props: { error?: ErrorWithRequestMeta; }) => Element' is not assignable to type 'ReactElement<any, string | JSXElementConstructor<any>> | FallbackRender'.
  Type '(props: { error?: ErrorWithRequestMeta; }) => Element' is not assignable to type 'FallbackRender'.
    Types of parameters 'props' and 'errorData' are incompatible.
      Type '{ error: Error; componentStack: string; eventId: string; resetError(): void; }' is not assignable to type '{ error?: ErrorWithRequestMeta; }'.
        Types of property 'error' are incompatible.
          Type 'Error' is not assignable to type 'ErrorWithRequestMeta'.
            Property 'graphQLErrors' is missing in type 'Error' but required in type '{ mostRecentRequest?: RequestDetails; graphQLErrors: EnhancedGqlError[]; mostRecentResponse?: any; }'.ts(2322)
DevFatalErrorPage.d.ts(14, 5): 'graphQLErrors' is declared here.
App.tsx(16, 34): Did you mean to call this expression?

Looks like it is an issue with a fresh setup as well:

➜  ~ yarn create redwood-app my-redwood-project
➜  ~ cd my-redwood-project
➜  my-redwood-project yarn rw setup monitoring sentry   
➜  my-redwood-project yarn rw type-check   
✔ Generating the Prisma client...
✔ Generating types
src/App.tsx:16:34 - error TS2322: Type '(props: { error?: ErrorWithRequestMeta; }) => Element' is not assignable to type 'ReactElement<any, string | JSXElementConstructor<any>> | FallbackRender'.
  Type '(props: { error?: ErrorWithRequestMeta; }) => Element' is not assignable to type 'FallbackRender'.
    Types of parameters 'props' and 'errorData' are incompatible.
      Type '{ error: Error; componentStack: string; eventId: string; resetError(): void; }' is not assignable to type '{ error?: ErrorWithRequestMeta; }'.
        Types of property 'error' are incompatible.
          Type 'Error' is not assignable to type 'ErrorWithRequestMeta'.
            Property 'graphQLErrors' is missing in type 'Error' but required in type '{ mostRecentRequest?: RequestDetails; graphQLErrors: EnhancedGqlError[]; mostRecentResponse?: any; }'.

16   <Sentry.ErrorBoundary fallback={FatalErrorPage}>
                                    ~~~~~~~~~~~~~~~~

  ../node_modules/@redwoodjs/web/dist/components/DevFatalErrorPage.d.ts:14:5
    14     graphQLErrors: EnhancedGqlError[];
           ~~~~~~~~~~~~~
    'graphQLErrors' is declared here.
  src/App.tsx:16:34
    16   <Sentry.ErrorBoundary fallback={FatalErrorPage}>
                                        ~~~~~~~~~~~~~~~~
    Did you mean to call this expression?


Found 1 error in src/App.tsx:16
1 Like

We just migrated to Redwood V8 on our main project. I am still working through some issues on module resolution. It looks like this is a topic that could be easy to get into the weeds on, so I’d like first to clarify what the intent for V8 is with respect to typescript and ESM builds on the API side. The recommended changes to the API side tsconfig are:

compilerOptions": {
-    "target": "esnext",
+    "target": "ES2023",
-    "module": "esnext",
+    "module": "Node16",
-    "moduleResolution": "node",
+    "moduleResolution": "Node16",
  }

The above settings generally work for most of the code, except for importing ESM packages. If trying to actually build to ESM by setting "type": "module", in package.json, (which is not a Redwood recommendation) then we start going down another whole rabbit hole…

As per Typescript Documentation, the Node16 module resolution will require file extensions on import statements…

"In Node.js, module specifiers in import statements and dynamic import() calls are not allowed to omit file extensions or /index.js suffixes, while module specifiers in require calls are.

But before I get deeper into this, I’m trying to confirm what the intent was in V8 for the API side. Is it to support both CJS and ESM module imports and resolution but build to CJS, or are ESM module imports still unsupported (except dynamically)?

BTW, thanks to all for the good work on this release!

1 Like

There’s a section in the guides about changing your compiler options in tsconfig.json files… After this doing, the apps builds successfully but fails to serve… which means it’s failing silently in production after successful builds.

Has anybody encountered this?

There was no intended change regarding CJS/ESM support.
The reason for the change was that we wanted to “pin” our options. “esnext” can mean anything. Right now "module": "esnext" should be exactly the same as "module": "Node16". But no one knows for how long that’ll be true. Being explicit with both “target”, “module”, and “moduleResolution” makes things more predictable.
That was the goal at least.
Can you explain more about the issues you ran into?

1 Like

Hi @Tobbe Great work on the updates.

I believe my current issues is centered around this same moduleResolution thing with changing the tsconfig.json

Everything seems to work great after upgrade and api and web starts in dev mode, although building for production completes with no errors but when the app is served there’s a blank screen with a silent error in the console on the web side that feels more like the builds aren’t appropriately reducing bundle size so you end up with a large file.

Are there any recommended ways to go about fixing this?

Following up to @Tobbe’s answer which I agree with.

My main motivation in introducing the change was centred around the module resolution. The “node” option is valid for node v10 and doesn’t accurately reflect the module resolution behaviour in modern node versions that redwood relies on. An example of this is conditional exports - i.e. the “exports” field in the package.json file. Redwood has started to use those to direct how you import content from our packages. The problem is that without using the “Node16” module resolution typescript will not understand this and that can lead to situations where at build time you have no errors but at runtime your imports could fail because they aren’t truly valid. That sort of DX is pretty terrible and something I am keen to avoid but ofc if we’ve introduced problems then those need addressing.

2 Likes

Thanks @Tobbe and @Josh-Walker-GM .

My current problem relates to importing the open-source docx package (v 8.5.0). What is confusing me is that it worked fine with Redwood v7.x.x, but when I convert to Redwood v8.2.0, I get the following typescript error:

The current file is a CommonJS module whose imports will produce ‘require’ calls; however, the referenced file is an ECMAScript module and cannot be imported with ‘require’. Consider writing a dynamic ‘import(“docx”)’ call instead.
To convert this file to an ECMAScript module, change its file extension to ‘.mts’, or add the field "type": "module" to ‘c:/CENRIZE/cengys-r/api/package.json’.ts(1479)

OK … now that I know we’re not ready to truly support esm modules with Redwood V8, then I’ll avoid going down that rabbit hole, and I’ve tried to dynamically import the library. However, there is a bug in the exporting of types in the docx library. (It seems that maintenance on the library may be falling behind… not complaining … just a reality of using open-source).

So the long and the short of it is that I’m struggling to get typescript to work with dynamically importing the docX library due to a library issue, but what confuses me is that I could statically load the library just fine in Redwood v7.x.

As this relates to a non-Redwood library, I don’t expect you to put any time into figuring this all out, but I wouldn’t mind understanding why I could statically import in Redwood V7.xx and not in V8.xx if you can explain it off the top of your head!

Thanks as always for the awesome support!

1 Like

I’m afraid I can’t :frowning:
But if you gave me a repo to clone I’d be happy to take a look at the docx stuff and see if I can help with the types issue you’re having

2 Likes

Sounds like what I’m experiencing after upgrading as mentioned in my post above. I do have the module resolutions set as described in the docs for all tsconfig files.

App builds successfully in production but when it’s started, shows a blank page with an error in console:

Uncaught TypeError: Cannot read properties of undefined (reading 'defineProperty')

So I reckon some imports or exports might not be working as expected behind the scenes

@evansibok That might actually be a separate issue. Are you running into this by chance? https://github.com/redwoodjs/redwood/pull/11592

Hi @Tobbe I’ve been able to get this resolved… I did a fresh upgrade again and was able to get past this error… The issue now is with the authentication service…

I can log in during development without issues but when I build and serve, I notice the session doesn’t get sent to the client like it should, so login or logout auth doesn’t happen.