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: Remove unused code. Improve code organization #9631

Merged
merged 4 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
RSC: Remove unused code, and move things around to improve code organ…
…ization
  • Loading branch information
Tobbe committed Dec 5, 2023
commit 30db6a2a1198e7a98caea8e59df8ec856b5a5b52
3 changes: 2 additions & 1 deletion packages/vite/src/rsc/rscBuildAnalyze.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { build as viteBuild } from 'vite'
import { getPaths } from '@redwoodjs/project-config'

import { onWarn } from '../lib/onWarn'
import { rscAnalyzePlugin } from '../waku-lib/vite-plugin-rsc'

import { rscAnalyzePlugin } from './rscVitePlugins'

/**
* RSC build. Step 1.
Expand Down
3 changes: 2 additions & 1 deletion packages/vite/src/rsc/rscBuildClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { build as viteBuild } from 'vite'
import { getConfig, getPaths } from '@redwoodjs/project-config'

import { onWarn } from '../lib/onWarn'
import { rscIndexPlugin } from '../waku-lib/vite-plugin-rsc'

import { rscIndexPlugin } from './rscVitePlugins'

/**
* RSC build. Step 2.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// TODO (RSC) Take ownership of this file and move it out ouf the waku-lib folder
import path from 'node:path'

import * as swc from '@swc/core'
Expand All @@ -7,10 +6,19 @@ import type { Plugin } from 'vite'
import * as RSDWNodeLoader from '../react-server-dom-webpack/node-loader'
import type { ResolveFunction } from '../react-server-dom-webpack/node-loader'

import { codeToInject } from './rsc-utils.js'

// Used in Step 2 of the build process, for the client bundle
export function rscIndexPlugin(): Plugin {
const codeToInject = `
globalThis.__rw_module_cache__ = new Map();

globalThis.__webpack_chunk_load__ = (id) => {
return import(id).then((m) => globalThis.__rw_module_cache__.set(id, m))
};

globalThis.__webpack_require__ = (id) => {
return globalThis.__rw_module_cache__.get(id)
};\n `

return {
name: 'rsc-index-plugin',
async transformIndexHtml() {
Expand Down
189 changes: 40 additions & 149 deletions packages/vite/src/rsc/rscWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,31 @@
// `--condition react-server`. If we did try to do that the main process
// couldn't do SSR because it would be missing client-side React functions
// like `useState` and `createContext`.

import { Buffer } from 'node:buffer'
import path from 'node:path'
import { Writable } from 'node:stream'
import { Transform, Writable } from 'node:stream'
import { parentPort } from 'node:worker_threads'

import { createElement } from 'react'

import RSDWServer from 'react-server-dom-webpack/server'
import { createServer } from 'vite'
import type { ResolvedConfig } from 'vite'
import { createServer, resolveConfig } from 'vite'

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

import type { defineEntries } from '../entries'
import { StatusError } from '../lib/StatusError'
import { configFileConfig, resolveConfig } from '../waku-lib/config'
import { transformRsfId } from '../waku-lib/rsc-utils'
import {
rscTransformPlugin,
rscReloadPlugin,
} from '../waku-lib/vite-plugin-rsc'

// import type { unstable_GetCustomModules } from '../waku-server'
import { rscTransformPlugin, rscReloadPlugin } from './rscVitePlugins'
import type {
RenderInput,
MessageRes,
MessageReq,
} from './rscWorkerCommunication'

// import type { unstable_GetCustomModules } from '../waku-server'
// import type { RenderInput, MessageReq, MessageRes } from './rsc-handler'
// import { transformRsfId, generatePrefetchCode } from './rsc-utils'

Expand Down Expand Up @@ -153,7 +152,6 @@ const handleRender = async ({ id, input }: MessageReq & { type: 'render' }) => {
// }

const vitePromise = createServer({
...configFileConfig,
plugins: [
rscTransformPlugin(),
rscReloadPlugin((type) => {
Expand Down Expand Up @@ -208,7 +206,9 @@ parentPort.on('message', (message: MessageReq) => {
}
})

const configPromise = resolveConfig('serve')
// Let me re-assign root
type ConfigType = Omit<ResolvedConfig, 'root'> & { root: string }
const configPromise: Promise<ConfigType> = resolveConfig({}, 'serve')

const getEntriesFile = async (
config: Awaited<ReturnType<typeof resolveConfig>>,
Expand All @@ -217,11 +217,9 @@ const getEntriesFile = async (
const rwPaths = getPaths()

if (isBuild) {
return path.join(
config.root,
config.build.outDir,
config.framework.entriesJs
)
// TODO (RSC): Should we make this path configurable? Or at least read
// from getPaths()?
return path.join(config.root, config.build.outDir, 'entries.js')
}

return rwPaths.web.distServerEntries
Expand Down Expand Up @@ -386,137 +384,30 @@ async function renderRsc(input: RenderInput): Promise<PipeableStream> {
throw new Error('Unexpected input')
}

// async function getCustomModulesRSC(): Promise<{ [name: string]: string }> {
// const config = await configPromise
// const entriesFile = await getEntriesFile(config, false)
// const {
// default: { unstable_getCustomModules: getCustomModules },
// } = await (loadServerFile(entriesFile) as Promise<{
// default: Entries['default'] & {
// unstable_getCustomModules?: unstable_GetCustomModules
// }
// }>)
// if (!getCustomModules) {
// return {}
// }
// const modules = await getCustomModules()
// return modules
// }

// // FIXME this may take too much responsibility
// async function buildRSC(): Promise<void> {
// const config = await resolveConfig('build')
// const basePath = config.base + config.framework.rscPrefix
// const distEntriesFile = await getEntriesFile(config, true)
// const {
// default: { getBuilder },
// } = await (loadServerFile(distEntriesFile) as Promise<Entries>)
// if (!getBuilder) {
// console.warn(
// "getBuilder is undefined. It's recommended for optimization and sometimes required."
// )
// return
// }
// HACK Patching stream is very fragile.
function transformRsfId(prefixToRemove: string) {
// Should be something like /home/runner/work/redwood/test-project-rsa
console.log('prefixToRemove', prefixToRemove)

// // FIXME this doesn't seem an ideal solution
// const decodeId = (encodedId: string): [id: string, name: string] => {
// const [filePath, name] = encodedId.split('#') as [string, string]
// const id = resolveClientEntry(config, filePath)
// return [id, name]
// }

// const pathMap = await getBuilder(decodeId)
// const clientModuleMap = new Map<string, Set<string>>()
// const addClientModule = (pathStr: string, id: string) => {
// let idSet = clientModuleMap.get(pathStr)
// if (!idSet) {
// idSet = new Set()
// clientModuleMap.set(pathStr, idSet)
// }
// idSet.add(id)
// }
// await Promise.all(
// Object.entries(pathMap).map(async ([pathStr, { elements }]) => {
// for (const [rscId, props] of elements || []) {
// // FIXME we blindly expect JSON.stringify usage is deterministic
// const serializedProps = JSON.stringify(props)
// const searchParams = new URLSearchParams()
// searchParams.set('props', serializedProps)
// const destFile = path.join(
// config.root,
// config.build.outDir,
// config.framework.outPublic,
// config.framework.rscPrefix,
// decodeURIComponent(rscId),
// decodeURIComponent(`${searchParams}`)
// )
// fs.mkdirSync(path.dirname(destFile), { recursive: true })
// const bundlerConfig = new Proxy(
// {},
// {
// get(_target, encodedId: string) {
// const [id, name] = decodeId(encodedId)
// addClientModule(pathStr, id)
// return { id, chunks: [id], name, async: true }
// },
// }
// )
// const component = await getFunctionComponent(rscId, config, true)
// const pipeable = renderToPipeableStream(
// createElement(component, props as any),
// bundlerConfig
// ).pipe(transformRsfId(path.join(config.root, config.build.outDir)))
// await new Promise<void>((resolve, reject) => {
// const stream = fs.createWriteStream(destFile)
// stream.on('finish', resolve)
// stream.on('error', reject)
// pipeable.pipe(stream)
// })
// }
// })
// )

// const publicIndexHtmlFile = path.join(
// config.root,
// config.build.outDir,
// config.framework.outPublic,
// config.framework.indexHtml
// )
// const publicIndexHtml = fs.readFileSync(publicIndexHtmlFile, {
// encoding: 'utf8',
// })
// await Promise.all(
// Object.entries(pathMap).map(async ([pathStr, { elements, customCode }]) => {
// const destFile = path.join(
// config.root,
// config.build.outDir,
// config.framework.outPublic,
// pathStr,
// pathStr.endsWith('/') ? 'index.html' : ''
// )
// let data = ''
// if (fs.existsSync(destFile)) {
// data = fs.readFileSync(destFile, { encoding: 'utf8' })
// } else {
// fs.mkdirSync(path.dirname(destFile), { recursive: true })
// data = publicIndexHtml
// }
// const code =
// generatePrefetchCode(
// basePath,
// Array.from(elements || []).flatMap(([rscId, props, skipPrefetch]) => {
// if (skipPrefetch) {
// return []
// }
// return [[rscId, props]]
// }),
// clientModuleMap.get(pathStr) || []
// ) + (customCode || '')
// if (code) {
// // HACK is this too naive to inject script code?
// data = data.replace(/<\/body>/, `<script>${code}</script></body>`)
// }
// fs.writeFileSync(destFile, data, { encoding: 'utf8' })
// })
// )
// }
return new Transform({
transform(chunk, encoding, callback) {
if (encoding !== ('buffer' as any)) {
throw new Error('Unknown encoding')
}
const data = chunk.toString()
const lines = data.split('\n')
console.log('lines', lines)
let changed = false
for (let i = 0; i < lines.length; ++i) {
const match = lines[i].match(
new RegExp(`^([0-9]+):{"id":"${prefixToRemove}(.*?)"(.*)$`)
Dismissed Show dismissed Hide dismissed
)
if (match) {
lines[i] = `${match[1]}:{"id":"${match[2]}"${match[3]}`
changed = true
}
}
callback(null, changed ? Buffer.from(lines.join('\n')) : chunk)
},
})
}
Loading
Loading