Skip to content
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

RSC: Fix server build root #10076

Merged
merged 7 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
2 changes: 1 addition & 1 deletion packages/vite/src/rsc/rscBuildServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export async function rscBuildServer(

const serverBuildOutput = await viteBuild({
// ...configFileConfig,
root: rwPaths.web.base,
root: rwPaths.web.src,
envPrefix: 'REDWOOD_ENV_',
publicDir: path.join(rwPaths.web.base, 'public'),
envFile: false,
Expand Down
Loading