Closed heymartinadams closed 2 years ago
I haven't spent any time with Preact, but certainly its smaller size is appealing. Can you help me understand what the limitations are, and what we'd have to change in Redwood to support it? It's possible we could make it an option, instead of React, if it didn't mean massive changes to the framework.
So far our startup has been developing a PWA using Preact instead of React and we’ve encountered 0 issues, even though our app uses the following React-centric dependencies: @mdi/react
, @react-google-maps/api
, @react-spring/web
(that’s a big one, for animation), @uploadcare/react-widget
, among others (I think that’s because the creators/maintainers have been putting in care to make it cross-compatible). We use the latest ES6 and hooks.
The one thing that might make this more difficult is that our app requires a preact.config.js
file, since Preact uses Webpack. Here’s some of what’s in our config file:
import CopyWebpackPlugin from 'copy-webpack-plugin'
import envVars from 'preact-cli-plugin-env-vars'
export default (config, env, helpers) => {
// Copies any files (but not folders) located in the `/assets` folder directly into the build folder; useful for robots.txt
config.plugins.push(new CopyWebpackPlugin([{ context: `${__dirname}/src/assets`, from: `*.*` }]))
// environment variables
envVars(config, env, helpers)
}
Tagging @developit, @marvinhagemeister (Preact creators/maintainers) in case they’d like to comment as well.
@heymartinadams Thanks for tagging me :+1:
Looking at the frontend architecture of redwood it seems to be as easy as setting up the proper aliases for Preact. Adding these few lines to redwood's webpack config will do the trick :tada:
// inside webpack.config.js
"resolve": {
"alias": {
"react": "preact/compat",
"react-dom/test-utils": "preact/test-utils",
"react-dom": "preact/compat",
},
}
Note that Preact the framework is independent from our cli. Preact can run without any build tools right in the browser :100:
Hot off the press we have the capability (and docs!) to extend default Webpack config within a Redwood app: https://github.com/redwoodjs/redwood/blob/master/docs/webpack.md
Could someone take @marvinhagemeister's Preact config for a spin and report back?
Bonus points for an example deployed on Netlify 🚀
Nice! I think just like Next.js this should be done in userland
@thedavidprice there you go. I have been fiddling with this and managed to get a working Preact redwood app. The code is here and a deployed version is here
What is still not done:
Also this goes a bit on my other issue #288. If a user wanted it to go through this he/she would have the opportunity of getting this example through the cli, like so many others frameworks allow.
@thedavidprice i circled back to this and it seems that the testing will not be so streamlined, a bit of work might be required to get this working properly.
What i did was the following:
@testing-library/react
so i searched and it seems that the @testing
library has a equivalent for preact. So i added it to my project.jest
field to the main package.json file aliasing the preact testing like described in here.@testing-library/preact
. I'm going to leave in only one example for brevity purposes ( in web/src/pages/HomePage/HomePage.test.js
):/* import { render, cleanup } from '@testing-library/react' */
import { h } from 'preact'
import { render, cleanup } from '@testing-library/preact'
import HomePage from './HomePage'
describe('HomePage', () => {
afterEach(() => {
cleanup()
})
it('renders successfully', () => {
expect(() => {
render(<HomePage />)
}).not.toThrow()
})
})
Fired up the testing environment and i'm presented with:
yarn rw test web
yarn run v1.21.1
$ C:\Users\MyUser\MyFolder\redwood_fork\templates\redwood-with-preact\node_modules\.bin\rw test web
[19:04:39] Running 'web' jest tests [started]
$ C:\Users\MyUser\MyFolder\redwood_fork\templates\redwood-with-preact\node_modules\.bin\jest --passWithNoTests --config ../node_modules/@redwoodjs/core/config/jest.config.web.js
FAIL src/pages/BoopPage/BoopPage.test.js
● Test suite failed to run
Cannot find module 'react' from 'DummyLayout.js'
Require stack:
src/layouts/DummyLayout/DummyLayout.js
src/pages/BoopPage/BoopPage.js
src/pages/BoopPage/BoopPage.test.js
11 | </li>
12 | </ul>
> 13 | </nav>
| ^
14 | </header>
15 | <main>{children}</main>
16 | </>
at Resolver.resolveModule (../node_modules/jest-resolve/build/index.js:296:11)
at Object.<anonymous> (src/layouts/DummyLayout/DummyLayout.js:13:37)
FAIL src/pages/HomePage/HomePage.test.js
● Test suite failed to run
Cannot find module 'react' from 'HomePage.js'
Require stack:
src/pages/HomePage/HomePage.js
src/pages/HomePage/HomePage.test.js
11 | <Link to={routes.about()}>About</Link>
12 | </li>
> 13 | <li>
| ^
14 | <Link to={routes.boop()}>Boop</Link>
15 | </li>
16 | </ul>
at Resolver.resolveModule (../node_modules/jest-resolve/build/index.js:296:11)
at Object.<anonymous> (src/pages/HomePage/HomePage.js:13:37)
FAIL src/layouts/DummyLayout/DummyLayout.test.js
● Test suite failed to run
Cannot find module 'react' from 'DummyLayout.js'
Require stack:
src/layouts/DummyLayout/DummyLayout.js
src/layouts/DummyLayout/DummyLayout.test.js
11 | </li>
12 | </ul>
> 13 | </nav>
| ^
14 | </header>
15 | <main>{children}</main>
16 | </>
at Resolver.resolveModule (../node_modules/jest-resolve/build/index.js:296:11)
at Object.<anonymous> (src/layouts/DummyLayout/DummyLayout.js:13:37)
FAIL src/pages/AboutPage/AboutPage.test.js
● Test suite failed to run
Cannot find module 'react' from 'util.js'
Require stack:
C:/Users/MyUser/MyFolder/redwood_fork/templates/redwood-with-preact/node_modules/@redwoodjs/router/dist/util.js
C:/Users/MyUser/MyFolder/redwood_fork/templates/redwood-with-preact/node_modules/@redwoodjs/router/dist/internal.js
C:/Users/MyUser/MyFolder/redwood_fork/templates/redwood-with-preact/node_modules/@redwoodjs/router/dist/index.js
src/pages/AboutPage/AboutPage.js
src/pages/AboutPage/AboutPage.test.js
at Resolver.resolveModule (../node_modules/jest-resolve/build/index.js:296:11)
at Object.<anonymous> (../node_modules/@redwoodjs/router/dist/util.js:45:37)
Test Suites: 4 failed, 4 total Tests: 0 total Snapshots: 0 total Time: 8.943s Ran all test suites. error Command failed with exit code 1. info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command. [19:04:50] Running 'web' jest tests [failed] [19:04:50] → Command failed with ENOENT: yarn jest --passWithNoTests --config ../node_modules/@redwoodjs/core/config/jest.config.web.js spawn yarn jest ENOENT Command failed with ENOENT: yarn jest --passWithNoTests --config ../node_modules/@redwoodjs/core/config/jest.config.web.js spawn yarn jest ENOENT Done in 12.18s.
- I thought of making the same approach for setting preact by overriding the configuration by setting up a file `jest.config.web.js` with the necessary configuration and see if it worked, it didn't. It yields the same result.
- Did a bit of digging and it seems that part of the problem lies [here](https://github.com/redwoodjs/redwood/blob/master/packages/cli/src/commands/test.js#L25) it's hardcoding the location of the configuration.
It could be more than this involved, but it seems that this is a good place to start changing. Possibly allow the configuration to be something that the user can pass in as a argument.
If that argument is not injected then use the default one.
Feel free to provide feedback
Apologies for the delayed reply here. I truly appreciate your work on this and I know a lot of people will be excited to take this for a spin once you have it working.
Jest tests have been an increasingly uphill battle. And we aren't actually able to get them working yet -- the current place we're stuck is on Page imports (Route object), which I believe is similar to what you see above.
The original Tracking Issue for tests is #181 And where we left off is #265
Peter did a substantial amount of Babel/Webpack/ESlint (re)work to even get Jest able to run. I can only hope all of this will work for Preact as is.
re: yarn rw jest config Yes, currently it's hard-coded into the command to use the core config files. But that could be easy to modify as needed and you'll see it's mentioned in the Tracking Issue -- e.g. adding an option to the command for a path to custom config.
As of now, I'd suggest you just work around this by:
yarn jest --passWithNoTests --config [path]
(you don't necessarily need passWithNoTests)Here's the web config you could copy to start with: https://github.com/redwoodjs/redwood/blob/master/packages/core/config/jest.config.web.js
@thedavidprice i made some progress regarding this. Here are the steps taken and the mixed results i got.
Going to start with the steps, going by your comment.
web
folder i've added the following files, jest-config.web.js
and jest.setup.web.js
with the folowing code respectively:
const path = require('path')
module.exports = {
resolver: 'jest-directory-named-resolver',
rootDir: process.cwd(),
globals: {
__REDWOOD__API_PROXY_PATH: '/',
},
setupFilesAfterEnv: [path.resolve(__dirname, './jest.setup.web.js')],
moduleNameMapper: {
'^react$': 'preact/compat',
'^react-dom/test-utils$': 'preact/test-utils',
'^react-dom$': 'preact/compat',
},
}
And:
```js
require('@testing-library/jest-dom')
web
:
"scripts": {
"test:web": "jest --passWithNoTests --config=config/jest.config.web.js --watch"
},
"scripts": {
"jest": "yarn workspace web test:web"
},
Samplecomponent
and it's contents and test file look like this:
//import { h } from 'preact'
const Samplecomponent = () => {
return (
<div>
<h1>Oingo Bongo</h1>
</div>
)
}
export default Samplecomponent
And:
```js
import { h } from 'preact'
import { render, cleanup } from '@testing-library/preact'
import Samplecomponent from './Samplecomponent'
describe('Samplecomponent', () => {
afterEach(() => {
cleanup()
})
it('renders successfully', () => {
const { getByText } = render(<Samplecomponent />)
expect(getByText('Oingo Bongo')).toBeInTheDocument()
})
})
And one page called OnemorePage
with the following content and test respectively:
//import { h } from 'preact'
import Samplecomponent from 'src/components/Samplecomponent/Samplecomponent'
const OnemorePage = () => {
return (
<div>
<h1>OnemorePage</h1>
<Samplecomponent />
</div>
)
}
export default OnemorePage
And
import { h } from 'preact'
import { render, cleanup } from '@testing-library/preact'
import OnemorePage from './OnemorePage'
describe('OnemorePage', () => {
afterEach(() => {
cleanup()
})
it('renders successfully', () => {
expect(() => {
render(<OnemorePage />)
}).not.toThrow()
})
})
Issuing yarn jest
as is yelds the following (i'm just leaving in the component error message, to keep it short).
jest --passWithNoTests --config=config/jest.config.web.js --watch
FAIL src/components/Samplecomponent/Samplecomponent.test.js (17.841s)
● Samplecomponent › renders successfully
ReferenceError: h is not defined
1 | //import { h } from 'preact'
2 | const Samplecomponent = () => {
> 3 | return (
| ^
4 | <div>
5 | <h1>Oingo Bongo</h1>
6 | </div>
at d.parentDom [as constructor] (src/components/Samplecomponent/Samplecomponent.js:3:3)
at d.Array [as render] (../node_modules/preact/src/render.js:31:47)
at push (../node_modules/preact/src/diff/index.js:171:7)
at children (../node_modules/preact/src/diff/children.js:117:11)
at _ (../node_modules/preact/src/diff/children.js:262:25)
at key (../node_modules/preact/src/diff/children.js:260:30)
at k (../node_modules/preact/src/diff/children.js:76:34)
at childNodes (../node_modules/preact/src/diff/index.js:205:15)
at E (../node_modules/preact/src/render.js:48:37)
at resolve (../node_modules/@testing-library/preact/dist/pure.js:79:26)
at Object.<anonymous>.exports.act (../node_modules/preact/test-utils/src/index.js:78:17)
at render (../node_modules/@testing-library/preact/dist/pure.js:75:22)
at Object.<anonymous> (src/components/Samplecomponent/Samplecomponent.test.js:11:27)
Uncommenting out the line import { h } from 'preact'
yelds the following:
PASS src/pages/OnemorePage/OnemorePage.test.js (6.525s)
PASS src/components/Samplecomponent/Samplecomponent.test.js (6.557s)
Test Suites: 2 passed, 2 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 8.941s, estimated 9s
Ran all test suites related to changed files.
At least we're getting some progress. I've checked both issues that you mentioned and tried some stuff around to the extent of trying to mock the entire "tree" (Router/Link/Links) and see if it could work, but alas i'm getting the same error you've described here.
Regarding the import error, probably it could be solved by adding the necessary config for preact in babel.config.js
, probably extending your own here and see if it will work.
EDIT: As of a recent commit the import issue i was experiencing is fixed. Testing can be done minus the usage of the redwood router for instance.
Feel free to provide feedback.
@jonniebigodes looks like you're making some great progress here! Hodgepodge of items related to testing:
//import { h } from 'preact' Redwood uses Webpack to handle React auto-importing. For tests, has to be emulated through babel config. Here is the specific setting: https://github.com/redwoodjs/redwood/blob/4f1cc1d26a65b6342245a9d6e3ad7848441a19c2/packages/core/config/babel-preset.js#L108-L115
RW Jest test support There's a lot of current momentum happening thanks to Robert Broersma. Want to make sure you’re following things in progress:
All of this is aligned with the Tracking Issue #181 and last place we got stuck #265
Hopefully, the result of all this being fixed will be config and tooling easily consumable in the case of Preact.
yarn rw test --config
Your current workaround creating custom scripts and manually copy+paste config is what I would do as well.
Once tests are (finally!) passing, next up will be making config extensible (or at the very least pass your own config file). Per tracking issue:
if additional config is needed, capability for simple config extension managed from either App root or specific to App sides (e.g. web/, api/, etc.).
Ideally this would automatically include a config file if present at a specific path.
Anything else? Overall, this is looking like it's in a good place and just waiting for more core support from Redwood itself. What's next? What, if anything, is still missing and/or blocking your next steps?
Is there anything keeping you from creating an initial NPM Package, e.g. redwoodjs-preact
? At this time it would just be config. But once generator templates are "pluggable", it could include those as well. Along with more over time like specific helpers, extensions, etc.
I'd encourage you to do so if you are interested! Someone's going to eventually do it if not you. And don't worry about it still having rough edges -- there's nothing like getting feedback, help, and momentum from a community excited about what you're trying to do. Just don't overpromise, spend extra time on a good README doc, and make sure the manual setup steps are clear. 😁
🚀
Most of all excited you're excited about Redwood.
@thedavidprice i thought about what you said in your previous comment and i managed to create a small cli tooling that will help streamline the process of adding preact into redwood. It isn't published yet. But it's already in a repo. The reason i went with this cli for starters is to make the configuration more easy.
Going to expand a bit more on this.
Feel free to provide feedback.
Thanks for experimenting with us way back when @jonniebigodes! It's been quite a while, and now it seems highly unlikely that we'll focus on adding Preact support. There is quite a lot of discussion around adding other sides though, and that may tie in / indirectly make it possible, though it'd still mostly be up to the user.
Hi @peterp @thedavidprice and @mojombo, been following redwoodjs with great excitement — also enthusiastically support Preact and Prisma. Might adopt Redwood.
Noticed you support React out of the box, but not Preact. Been using Preact and been achieving a fantastic Lighthouse score as opposed React, which I use in another project; it’s quite bloated.
Would you consider switching to Preact?