-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support React 18 #22437
feat: support React 18 #22437
Conversation
Thanks for taking the time to open a PR!
|
Test summaryRun details
View run in Cypress Dashboard ➡️ Flakiness
This comment has been generated by cypress-bot as a result of this project's GitHub integration settings. You can manage this integration in this project's settings in the Cypress Dashboard |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works well for me 👍🏻
* fix: use sourced webpack Ignore Plugin * type webpack * revert * use better types for module in source webpack * fix wds types Co-authored-by: Lachlan Miller <[email protected]>
…om/cypress-io/cypress into lmiller/21381-react-18-with-ignore
Something is not right here. I built the binary locally, works great - system tests, work great, but @astone123 and I ran into some weirdness when testing against the pre-release. I got an issue with The Vite workaround is not working for whatever reason... ✘ [ERROR] Could not resolve "react-dom/client"
node_modules/cypress/react/dist/cypress-react.esm-bundler.js:845:54:
845 │ ... : function () { return import('react-dom/client'); };
╵ ~~~~~~~~~~~~~~~~~~
You can mark the path "react-dom/client" as external to exclude it from the bundle, which will remove this error. You can also add ".catch()" here to handle this failure at run-time instead of bundle-time. Edit... removing the supportFile imports seems to fix it. import { mount } from 'cypress/react'
Cypress.Commands.add('mount', mount) And what do you know - the system tests are not doing this import! This is the problem. Weirdly enough the system tests don't exhibit this, even with the import. The problem seems to a circular import? Edit: related? vitejs/vite#8715 (comment)
|
aa72972
to
a5a043b
Compare
a5a043b
to
8c1f0ad
Compare
I'm going to leave my debugging notes, in case it helps someone. Notes 1: Sodatea from Vite team suggests looking here for 504 related:
Reproduction: https://github.com/lmiller1990/vite-react-17-error-with-cypress (uses this pre-release). This is only a problem for React 17 and Vite. And not happening in system-tests, only in prod. I don't understand why. If I add React 18, it's fine. So... related? https://github.com/facebook/react/blob/v18.0.0/packages/react/package.json#L22-L30. React 17 does not do Notes 2: if (e?.code === ERR_OUTDATED_OPTIMIZED_DEP) {
// Skip if response has already been sent
if (!res.writableEnded) {
res.statusCode = 504 // status code request timeout
res.end()
}
} I guess we either have 1) race condition or 2) loop. But why only manifesting with React 18? I guess React 18 can be optimized by Vite, but not React 17? 🤔 Notes 3: I messed with function importReactModules() {
// ...
react = (_a = react === null || react === void 0 ? void 0 : react.default) !== null && _a !== void 0 ? _a : react;
reactDomImport = isLessThan18(react)
? function () { return import('react-dom'); }
// @ts-ignore
: function () { return import('react-dom/client'); };
return [4 /*yield*/, reactDomImport()];
// ...
} I'm almost 100% sure my plugin isn't getting called and/or applied. Real question is why isn't CI failing? Notes 4: I am not sure why this works in the monorepo - maybe something to do with our symlinks. I cannot get this working in a production environment! I am starting to wonder if we should scrap the complexity and just have a Notes 5: Hmm maybe just optimizeDeps: {
exclude: ["react-dom/client"]
} Can work? It seems to work in when running against the built binary, but NOT in system tests. The different between the two is not at all clear, but we need to find out so we can reliably test this. This works in a built binary, but seems not to work in system tests. Probably due to vitejs/vite#8186 and vitejs/vite#6582. Seems Vite is quite different in prod (after deployed) vs in system tests. I got this to work! Maybe we can use this approach. We transform and eliminate the import { defineConfig } from 'vite'
import path from 'path'
import react from '@vitejs/plugin-react'
let shouldTransform = false
try {
const react = require('react')
shouldTransform = react.version.startsWith('17')
} catch (e) {
// not using react
}
function plugin () {
return {
enforce: 'pre',
transform: (code, id) => {
if (shouldTransform && id.includes('cypress_react.js')) {
// remove problematic code via transform!
return code.replace('react-dom/client', 'react-dom')
}
}
}
}
const exclude = []
if (shouldTransform) {
// So Vite won't crawl and optimize.
exclude.push('react-dom/client')
}
// https://vitejs.dev/config/
export default defineConfig({
plugins: [plugin(), react()],
optimizeDeps: {
exclude
}
}) Trying it out: 86653c7 |
43f2166
to
7ddf1d4
Compare
In response to #22633 (comment): The only reason we are concerned about the behavior of what bundlers/preprocessors will do is because of the bundler hacks we are doing in order to support React17 and React18 in a single package. Ideally, a single package is best as it provides the user with the best experience ("it just works" idealogy), but as you pointed out we are violating this since e2e tests will fail due to the webpack-preprocessor not having the included bundler hacks if it happens to import the mount. In Slack you mentioned publishing another package ( As we expand our framework support, I fear these hacks will continue to grow. @lmiller1990 what are your thoughts on proceeding with what we have now vs publishing multiple packages? If we decide on the multiple packages, we will have some things to think through with regards to versioning. |
This is the path we've gone down with the vue packages already (vue (for vue3) / vue2) - when we need to support another version, we release another module. I personally would have preferred we go with vueN (supporting version N) rather than vue (supporting vue3) and vueN (supporting older version N), but regardless of the naming, I like the idea of multiple packages when we need to support major versions of component libraries. |
I too am leaning towards two packages. I (finally) solved all the problems here, but what a mess - just because we can, doesn't mean we should, comes to mind. Main question to answer: when does Maybe we alias Also we can loop in Jordan for Angular - Angular drops a new major once every 6 months? We should fine a pattern that fits angular. |
That seems like a good way forward - don't break anyone, create universal support for a new pattern.
Hm, I know very little about angular - getting someone who does to chime in sounds like a good step forward. Shouldn't assume that every package operates the same. |
@BlueWinds ok, I'll prepare a tech brief and include you and Jordan and Zach. |
With this approach, what happens if a breaking change comes out of a minor or patch release from react/vue/angular? Will we internalize those changes in the major package, or will we create a new package for the patch/minor? |
@astone123 I'm unsure about how to handle minor breaking changes, if the ever happen. I've added this concern as an outstanding question in the technical brief (Cypress internal team only, but sure would be nice to find a way to make our technical breakdowns more public some day). Historically neither Vue or React has had breaking change w.r.t render APIs in a minor version. Makes sense - this would be a lot of apps, so it's unlikely, but definitely something we need to consider. We could likely apply what we learned in this PR to that situation if it ever occurs - runtime transform via webpack/vite, although I hope it won't come to that. |
5849470
to
42c57f8
Compare
User facing changelog
Add support for React 18 to
npm/react
.Additional details
peerDependencies
to allow installing@cypress/react
withreact@18
react-dom/client
codeThe problem and solution is described in detail in the README in this repo which is an example project used for an internal presentation at Cypress.
Steps to test
react-dom/client
API)yarn create react-app my-app
yarn create vite --template react my-vite-react-app
How has the user experience changed?
PR Tasks
cypress-documentation
?type definitions
?