Skip to content

Commit

Permalink
Merge branch 'main' into tobbe-rsc-babel-router-plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
Tobbe committed Feb 29, 2024
2 parents c2ea888 + d83d52d commit 65f28dc
Show file tree
Hide file tree
Showing 19 changed files with 104 additions and 156 deletions.
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
"peacock.color": "#b85833",
"cSpell.words": [
"autoplay",
"corepack",
"execa",
"Fastify",
"Flightcontrol",
"graphiql",
"opentelemetry",
"pino",
Expand Down
37 changes: 6 additions & 31 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,6 @@

## Unreleased

- fix(coherence): update setup command to detect server file

The `yarn rw setup deploy coherence` command now detects if your project has the server file and configures the api prod command accordingly:

```yml
# coherence.yml

api:
# ...
prod:
command: ["yarn", "rw", "build", "api", "&&", "yarn", "node", "api/dist/server.js", "--apiRootPath=/api"]
```
- Update jsdoc for ScenarioData type (#29166)
Fix formatting of JSDocs in `scenario.ts`

- fix(deps): update opentelemetry-js monorepo (#10065)

Updates our opentelemetry packages. This is a breaking change for users of
Expand Down Expand Up @@ -69,25 +52,17 @@
Note that this feature is mainly for local scripting. Most deploy providers don't let you upload dotfiles and usually have their own way of determining environments.

- fix(render): reduce memory and handle server file

This PR improves Render deploys by reducing memory consumption and fixing it so that it uses the server file if it's present.

Render deploys seems to consistently run out of memory during the data migration step. This step is configurable and its doubtful that every deploy has data migrations to apply, but it's enabled by default so it runs every time. The main issue is that the data migrate functionality is a plugin so a yarn install kicks off in Render's deploy container which must be more memory-constrained than the build container. (Assuming there are two different containers, which seems to be the case.)
## v7.0.5

Instead of running data migrations, this PR issues a warning that if you want to run data migrations, you need to first add the `@redwoodjs/cli-data-migrate` package as a devDependency:

```
yarn add -D @redwoodjs/cli-data-migrate
```
- See https://github.com/redwoodjs/redwood/releases/tag/v7.0.5

That way a `yarn install` won't be necessary to run data migrations.
## v7.0.4

Although this PR fixes Render deploy so that it uses the server file if present, realtime features still don't seem to work. We're still investigating; in the meantime, consider using another provider like Coherence if you're just getting started and want to try out realtime features.
- See https://github.com/redwoodjs/redwood/releases/tag/v7.0.4

- Update MetaTags to be Metadata in Docs (#10053)
## v7.0.3

The tutorial still used the `MetaTags` component instead of the newer `Metadata` component that the generator templates use. This PR updates all instances of `MetaTags` with `Metadata`.
- See https://github.com/redwoodjs/redwood/releases/tag/v7.0.3

## v7.0.2

Expand Down
2 changes: 1 addition & 1 deletion __fixtures__/test-project/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"@types/react-dom": "^18.2.19",
"autoprefixer": "^10.4.17",
"postcss": "^8.4.35",
"postcss-loader": "^8.1.0",
"postcss-loader": "^8.1.1",
"prettier-plugin-tailwindcss": "0.4.1",
"tailwindcss": "^3.4.1"
}
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Redwood has a simple API to integrate any auth provider you can think of. But to
- [Firebase](./auth/firebase.md)
- [Netlify](./auth/netlify.md)
- [Supabase](./auth/supabase.md)
- SuperTokens
- [SuperTokens](./auth/supertokens.md)

:::tip how to tell if an integration is official

Expand Down
75 changes: 19 additions & 56 deletions packages/babel-config/src/plugins/babel-plugin-redwood-cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,38 +32,18 @@ const EXPECTED_EXPORTS_FROM_CELL = [
]

export default function ({ types: t }: { types: typeof types }): PluginObj {
// This array will
// - collect exports from the Cell file during ExportNamedDeclaration
// This array will collect exports from the Cell file during
// ExportNamedDeclaration
// - collected exports will then be passed to `createCell`
// - be cleared after Program exit to prepare for the next file
// - The array is reset every time we `enter` a new Program
let exportNames: string[] = []
let hasDefaultExport = false

// TODO (RSC):
// This code relies on the fact that all cells first become client side
// cells. And then we do a second pass over all cells and transform them to
// server cells if applicable
// It'd be better if we could only do one pass over all cells. So the real
// todo here is to first figure out why we do two passes, and then update
// this code to directly generate `createCell` or `createServerCell` HoCs

return {
name: 'babel-plugin-redwood-cell',
visitor: {
ExportDefaultDeclaration(path) {
ExportDefaultDeclaration() {
hasDefaultExport = true

// This is for RSC cells:
// Determine if this is `export default createCell(...)`
// If it is, then we change it to `export default createServerCell(...)`
const declaration = path.node.declaration
if (
t.isCallExpression(declaration) &&
t.isIdentifier(declaration.callee) &&
declaration.callee.name === 'createCell'
) {
declaration.callee.name = 'createServerCell'
}
},
ExportNamedDeclaration(path) {
const declaration = path.node.declaration
Expand All @@ -85,34 +65,6 @@ export default function ({ types: t }: { types: typeof types }): PluginObj {
exportNames.push(name)
}
},
ImportDeclaration(path) {
// This is for RSC cells:
// Change createCell imports to createServerCell
const source = path.node.source.value
if (source === '@redwoodjs/web') {
const specifiers = path.node.specifiers
const createCellSpecifier: types.ImportSpecifier | undefined =
specifiers.find((specifier): specifier is types.ImportSpecifier => {
return (
t.isImportSpecifier(specifier) &&
t.isIdentifier(specifier.imported) &&
specifier.imported.name === 'createCell'
)
})

if (
createCellSpecifier &&
t.isIdentifier(createCellSpecifier.imported)
) {
createCellSpecifier.imported.name = 'createServerCell'
createCellSpecifier.local.name = 'createServerCell'

// Also update where we import from
path.node.source.value =
'@redwoodjs/web/dist/components/cell/createServerCell.js'
}
}
},
Program: {
enter() {
// Reset variables as they're still in scope from the previous file
Expand All @@ -134,25 +86,36 @@ export default function ({ types: t }: { types: typeof types }): PluginObj {
return
}

// TODO (RSC): When we want to support `data = async () => {}` in
// client cells as well, we'll need a different heuristic here
// If we want to support `QUERY` (gql) cells on the server we'll
// also need a different heuristic
const createCellHookName = exportNames.includes('data')
? 'createServerCell'
: 'createCell'
const importFrom = exportNames.includes('data')
? '@redwoodjs/web/dist/components/cell/createServerCell'
: '@redwoodjs/web'

// Insert at the top of the file:
// + import { createCell } from '@redwoodjs/web'
path.node.body.unshift(
t.importDeclaration(
[
t.importSpecifier(
t.identifier('createCell'),
t.identifier('createCell')
t.identifier(createCellHookName),
t.identifier(createCellHookName)
),
],
t.stringLiteral('@redwoodjs/web')
t.stringLiteral(importFrom)
)
)

// Insert at the bottom of the file:
// + export default createCell({ QUERY?, Loading?, Success?, Failure?, Empty?, beforeQuery?, isEmpty, afterQuery?, displayName? })
path.node.body.push(
t.exportDefaultDeclaration(
t.callExpression(t.identifier('createCell'), [
t.callExpression(t.identifier(createCellHookName), [
t.objectExpression([
...exportNames.map((name) =>
t.objectProperty(
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/src/commands/__tests__/dev.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@ vi.mock('@redwoodjs/project-config', async () => {
getPaths: () => {
return {
api: {
base: '/mocked/project/api',
src: '/mocked/project/api/src',
dist: '/mocked/project/api/dist',
},
web: {
base: '/mocked/project/web',
dist: '/mocked/project/web/dist',
},
generated: {
Expand Down
5 changes: 3 additions & 2 deletions packages/cli/src/commands/__tests__/serve.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ vi.mock('@redwoodjs/project-config', async (importOriginal) => {
return {
api: {
base: '/mocked/project/api',
src: '/mocked/project/api/src',
dist: '/mocked/project/api/dist',
},
web: {
Expand All @@ -39,8 +40,8 @@ vi.mock('fs-extra', async (importOriginal) => {
default: {
...originalFsExtra,
existsSync: (p) => {
// Don't detect the experimental server file, can't use path.sep here so the replaceAll is used
if (p.replaceAll('\\', '/') === '/mocked/project/api/dist/server.js') {
// Don't detect the server file, can't use path.sep here so the replaceAll is used
if (p.replaceAll('\\', '/') === '/mocked/project/api/src/server.ts') {
return false
}
return true
Expand Down
63 changes: 35 additions & 28 deletions packages/cli/src/commands/deploy/flightcontrol.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
import path from 'path'

import execa from 'execa'
import fs from 'fs-extra'
import terminalLink from 'terminal-link'

import { handler as apiServerHandler } from '@redwoodjs/api-server/dist/apiCLIConfigHandler'
import { recordTelemetryAttributes } from '@redwoodjs/cli-helpers'
import { getConfig } from '@redwoodjs/project-config'

import { getPaths } from '../../lib'
import { getPaths } from '@redwoodjs/project-config'

export const command = 'flightcontrol <side>'
export const alias = 'fc'
export const description =
'Build, Migrate, and Serve commands for Flightcontrol deploy'

export const builder = (yargs) => {
yargs
.positional('side', {
choices: ['api', 'web'],
description: 'select side to build',
description: 'Side to deploy',
type: 'string',
})
.option('prisma', {
Expand All @@ -31,7 +30,7 @@ export const builder = (yargs) => {
default: false,
})
.option('data-migrate', {
description: 'Migrate the data in your database',
description: 'Apply data migrations',
type: 'boolean',
default: true,
alias: 'dm',
Expand All @@ -55,45 +54,53 @@ export const handler = async ({ side, serve, prisma, dm: dataMigrate }) => {
const rwjsPaths = getPaths()

const execaConfig = {
cwd: rwjsPaths.base,
shell: true,
stdio: 'inherit',
cwd: rwjsPaths.base,
extendEnv: true,
cleanup: true,
}

async function runApiCommands() {
if (serve) {
console.log('\nStarting api...')
await apiServerHandler({
port: getConfig().api?.port || 8911,
apiRootPath: '/',
})
} else {
console.log('\nBuilding api...')
execa.sync('yarn rw build api', execaConfig)
if (!serve) {
console.log('Building api...')
execa.commandSync('yarn rw build api --verbose', execaConfig)

prisma &&
execa.sync(
path.join(rwjsPaths.base, 'node_modules/.bin/prisma'),
['migrate', 'deploy', '--schema', `"${rwjsPaths.api.dbSchema}"`],
if (prisma) {
console.log('Running database migrations...')
execa.commandSync(
`node_modules/.bin/prisma migrate deploy --schema "${rwjsPaths.api.dbSchema}"`,
execaConfig
)
dataMigrate && execa.sync('yarn rw dataMigrate up', execaConfig)
}

if (dataMigrate) {
console.log('Running data migrations...')
execa.commandSync('yarn rw dataMigrate up', execaConfig)
}

return
}

const serverFilePath = path.join(rwjsPaths.api.dist, 'server.js')
const hasServerFile = fs.pathExistsSync(serverFilePath)

if (hasServerFile) {
execa(`yarn node ${serverFilePath}`, execaConfig)
} else {
const { handler } = await import(
'@redwoodjs/api-server/dist/apiCLIConfigHandler.js'
)
handler()
}
}

async function runWebCommands() {
execa.sync('yarn rw build web', execaConfig)
console.log('Building web...')
execa.commandSync('yarn rw build web --verbose', execaConfig)
}

if (side === 'api') {
runApiCommands()
} else if (side === 'web') {
console.log('\nBuilding web...')
runWebCommands()
} else {
console.log('Error with arguments provided')
// you broke something, which should be caught by Yargs
}
}
10 changes: 3 additions & 7 deletions packages/cli/src/commands/devHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,15 @@ import fs from 'fs-extra'

import { recordTelemetryAttributes } from '@redwoodjs/cli-helpers'
import { shutdownPort } from '@redwoodjs/internal/dist/dev'
import {
getConfig,
getConfigPath,
resolveFile,
} from '@redwoodjs/project-config'
import { getConfig, getConfigPath } from '@redwoodjs/project-config'
import { errorTelemetry } from '@redwoodjs/telemetry'

import { getPaths } from '../lib'
import c from '../lib/colors'
import { exitWithError } from '../lib/exit'
import { generatePrismaClient } from '../lib/generatePrismaClient'
import { getFreePort } from '../lib/ports'
import { serverFileExists } from '../lib/project'

const defaultApiDebugPort = 18911

Expand All @@ -36,8 +33,7 @@ export const handler = async ({

const rwjsPaths = getPaths()

// Check if experimental server file exists
const serverFile = resolveFile(`${rwjsPaths.api.dist}/server`)
const serverFile = serverFileExists()

// Starting values of ports from config (redwood.toml)
let apiPreferredPort = parseInt(getConfig().api.port)
Expand Down
Loading

0 comments on commit 65f28dc

Please sign in to comment.