diff --git a/packages/api-server/src/watch.ts b/packages/api-server/src/watch.ts index 77990e89117d..611994b269f3 100644 --- a/packages/api-server/src/watch.ts +++ b/packages/api-server/src/watch.ts @@ -13,7 +13,11 @@ import { debounce } from 'lodash' import { hideBin } from 'yargs/helpers' import yargs from 'yargs/yargs' -import { buildApi, rebuildApi } from '@redwoodjs/internal/dist/build/api' +import { + buildApi, + cleanApiBuild, + rebuildApi, +} from '@redwoodjs/internal/dist/build/api' import { loadAndValidateSdls } from '@redwoodjs/internal/dist/validateSchema' import { ensurePosixPath, @@ -66,7 +70,10 @@ const validate = async () => { } } -const rebuildApiServer = async (rebuild = false) => { +const rebuildApiServer = async ({ + rebuild = false, + clean = false, +}: { rebuild?: boolean; clean?: boolean } = {}) => { try { // Shutdown API server killApiServer() @@ -74,6 +81,10 @@ const rebuildApiServer = async (rebuild = false) => { const buildTs = Date.now() process.stdout.write(c.dim(c.italic('Building... '))) + if (clean) { + await cleanApiBuild() + } + if (rebuild) { await rebuildApi() } else { @@ -152,14 +163,14 @@ const rebuildApiServer = async (rebuild = false) => { // Local writes are very fast, but writes in e2e environments are not, // so allow the default to be adjust with a env-var. const debouncedRebuild = debounce( - () => rebuildApiServer(true), + () => rebuildApiServer({ rebuild: true }), process.env.RWJS_DELAY_RESTART ? parseInt(process.env.RWJS_DELAY_RESTART, 10) : 500 ) const debouncedBuild = debounce( - () => rebuildApiServer(false), + () => rebuildApiServer({ rebuild: false }), process.env.RWJS_DELAY_RESTART ? parseInt(process.env.RWJS_DELAY_RESTART, 10) : 500 @@ -198,7 +209,11 @@ chokidar }, }) .on('ready', async () => { - await rebuildApiServer() + // First time + await rebuildApiServer({ + clean: true, + rebuild: false, + }) await validate() }) .on('all', async (eventName, filePath) => { diff --git a/packages/babel-config/package.json b/packages/babel-config/package.json index 11bca75dfbe5..1b3275eff0f9 100644 --- a/packages/babel-config/package.json +++ b/packages/babel-config/package.json @@ -47,6 +47,7 @@ "devDependencies": { "@types/babel-plugin-tester": "9.0.9", "@types/babel__core": "7.20.4", + "@types/node": "20.10.4", "babel-plugin-tester": "11.0.4", "esbuild": "0.19.9", "jest": "29.7.0" diff --git a/packages/babel-config/src/__tests__/api.test.ts b/packages/babel-config/src/__tests__/api.test.ts index a3c7af764927..f4a98eb3e5a1 100644 --- a/packages/babel-config/src/__tests__/api.test.ts +++ b/packages/babel-config/src/__tests__/api.test.ts @@ -87,7 +87,7 @@ describe('api', () => { ) const apiSideBabelConfigPath = getApiSideBabelConfigPath() - expect(ensurePosixPath(apiSideBabelConfigPath)).toMatch( + expect(ensurePosixPath(apiSideBabelConfigPath || '')).toMatch( '/redwood-app/api/babel.config.js' ) }) diff --git a/packages/babel-config/src/__tests__/prebuildApiFile.test.ts b/packages/babel-config/src/__tests__/prebuildApiFile.test.ts index cf69fb69de71..e044bb7ceb3e 100644 --- a/packages/babel-config/src/__tests__/prebuildApiFile.test.ts +++ b/packages/babel-config/src/__tests__/prebuildApiFile.test.ts @@ -18,9 +18,9 @@ let code describe('api prebuild ', () => { describe('polyfills unsupported functionality', () => { - beforeAll(() => { + beforeAll(async () => { const apiFile = path.join(RWJS_CWD, 'api/src/lib/polyfill.js') - code = prebuildApiFileWrapper(apiFile) + code = await prebuildApiFileWrapper(apiFile) }) describe('ES features', () => { @@ -393,9 +393,9 @@ describe('api prebuild ', () => { }) describe('uses core-js3 aliasing', () => { - beforeAll(() => { + beforeAll(async () => { const apiFile = path.join(RWJS_CWD, 'api/src/lib/transform.js') - code = prebuildApiFileWrapper(apiFile) + code = await prebuildApiFileWrapper(apiFile) }) it('works', () => { @@ -425,9 +425,9 @@ describe('api prebuild ', () => { }) describe('typescript', () => { - beforeAll(() => { + beforeAll(async () => { const apiFile = path.join(RWJS_CWD, 'api/src/lib/typescript.ts') - code = prebuildApiFileWrapper(apiFile) + code = await prebuildApiFileWrapper(apiFile) }) it('transpiles ts to js', () => { @@ -437,9 +437,9 @@ describe('api prebuild ', () => { }) describe('auto imports', () => { - beforeAll(() => { + beforeAll(async () => { const apiFile = path.join(RWJS_CWD, 'api/src/lib/autoImports.ts') - code = prebuildApiFileWrapper(apiFile) + code = await prebuildApiFileWrapper(apiFile) }) it('auto imports', () => { @@ -548,7 +548,7 @@ describe('api prebuild ', () => { * A copy of prebuildApiFiles from packages/internal/src/build/api.ts * This will be re-architected, but doing so now would introduce breaking changes. */ -export const prebuildApiFileWrapper = (srcFile: string) => { +export const prebuildApiFileWrapper = async (srcFile: string) => { // const redwoodProjectPaths = getPaths() const plugins = getApiSideBabelPlugins({ @@ -561,7 +561,7 @@ export const prebuildApiFileWrapper = (srcFile: string) => { // .join(redwoodProjectPaths.generated.prebuild, relativePathFromSrc) // .replace(/\.(ts)$/, '.js') - const result = transformWithBabel(srcFile, plugins) + const result = await transformWithBabel(srcFile, plugins) if (!result?.code) { throw new Error(`Couldn't prebuild ${srcFile}`) diff --git a/packages/babel-config/src/api.ts b/packages/babel-config/src/api.ts index 79b29a906009..f4937d88421e 100644 --- a/packages/babel-config/src/api.ts +++ b/packages/babel-config/src/api.ts @@ -1,19 +1,20 @@ -import fs from 'fs' +import { existsSync } from 'fs' +import fs from 'fs/promises' import path from 'path' -import { transform } from '@babel/core' import type { PluginItem, TransformOptions } from '@babel/core' +import { transformAsync } from '@babel/core' import { getPaths } from '@redwoodjs/project-config' import type { RegisterHookOptions } from './common' import { - registerBabel, CORE_JS_VERSION, RUNTIME_CORE_JS_VERSION, getCommonPlugins, - parseTypeScriptConfigFiles, getPathsFromTypeScriptConfig, + parseTypeScriptConfigFiles, + registerBabel, } from './common' export const TARGETS_NODE = '20.10' @@ -137,9 +138,10 @@ export const getApiSideBabelPlugins = ( export const getApiSideBabelConfigPath = () => { const p = path.join(getPaths().api.base, 'babel.config.js') - if (fs.existsSync(p)) { + if (existsSync(p)) { return p } else { + // Null and undefined do not have the same effect I believe return undefined } } @@ -188,14 +190,14 @@ export const registerApiSideBabelHook = ({ }) } -export const transformWithBabel = ( +export const transformWithBabel = async ( srcPath: string, plugins: TransformOptions['plugins'] ) => { - const code = fs.readFileSync(srcPath, 'utf-8') + const code = await fs.readFile(srcPath, 'utf-8') const defaultOptions = getApiSideDefaultBabelConfig() - const result = transform(code, { + const result = transformAsync(code, { ...defaultOptions, cwd: getPaths().api.base, filename: srcPath, @@ -206,5 +208,6 @@ export const transformWithBabel = ( sourceMaps: 'inline', plugins, }) + return result } diff --git a/packages/babel-config/tsconfig.json b/packages/babel-config/tsconfig.json index 91b48264c7cf..4f3efc420676 100644 --- a/packages/babel-config/tsconfig.json +++ b/packages/babel-config/tsconfig.json @@ -4,6 +4,7 @@ "baseUrl": ".", "rootDir": "src", "outDir": "dist", + "types": ["node"], }, "include": ["src"], "references": [ diff --git a/packages/cli/src/commands/buildHandler.js b/packages/cli/src/commands/buildHandler.js index 8a47f2b842c1..fa58f3cd453d 100644 --- a/packages/cli/src/commands/buildHandler.js +++ b/packages/cli/src/commands/buildHandler.js @@ -7,7 +7,7 @@ import { rimraf } from 'rimraf' import terminalLink from 'terminal-link' import { recordTelemetryAttributes } from '@redwoodjs/cli-helpers' -import { buildApi } from '@redwoodjs/internal/dist/build/api' +import { buildApi, cleanApiBuild } from '@redwoodjs/internal/dist/build/api' import { loadAndValidateSdls } from '@redwoodjs/internal/dist/validateSchema' import { detectPrerenderRoutes } from '@redwoodjs/prerender/detection' import { timedTelemetry } from '@redwoodjs/telemetry' @@ -82,6 +82,7 @@ export const handler = async ({ side.includes('api') && { title: 'Building API...', task: async () => { + await cleanApiBuild() const { errors, warnings } = await buildApi() if (errors.length) { diff --git a/packages/internal/src/__tests__/build_api.test.ts b/packages/internal/src/__tests__/build_api.test.ts index a9eda1e59038..26a7a7d018cf 100644 --- a/packages/internal/src/__tests__/build_api.test.ts +++ b/packages/internal/src/__tests__/build_api.test.ts @@ -21,26 +21,28 @@ const FIXTURE_PATH = path.resolve( // @NOTE: we no longer prebuild files into the .redwood/prebuild folder // However, prebuilding in the tests still helpful for us to validate // that everything is working as expected. -export const prebuildApiFiles = (srcFiles: string[]) => { +export const prebuildApiFiles = async (srcFiles: string[]) => { const rwjsPaths = getPaths() const plugins = getApiSideBabelPlugins() - return srcFiles.map((srcPath) => { - const relativePathFromSrc = path.relative(rwjsPaths.base, srcPath) - const dstPath = path - .join(rwjsPaths.generated.prebuild, relativePathFromSrc) - .replace(/\.(ts)$/, '.js') + return Promise.all( + srcFiles.map(async (srcPath) => { + const relativePathFromSrc = path.relative(rwjsPaths.base, srcPath) + const dstPath = path + .join(rwjsPaths.generated.prebuild, relativePathFromSrc) + .replace(/\.(ts)$/, '.js') - const result = transformWithBabel(srcPath, plugins) - if (!result?.code) { - throw new Error(`Could not prebuild ${srcPath}`) - } + const result = await transformWithBabel(srcPath, plugins) + if (!result?.code) { + throw new Error(`Could not prebuild ${srcPath}`) + } - fs.mkdirSync(path.dirname(dstPath), { recursive: true }) - fs.writeFileSync(dstPath, result.code) + fs.mkdirSync(path.dirname(dstPath), { recursive: true }) + fs.writeFileSync(dstPath, result.code) - return dstPath - }) + return dstPath + }) + ) } const cleanPaths = (p) => { @@ -51,12 +53,12 @@ const cleanPaths = (p) => { let prebuiltFiles let relativePaths -beforeAll(() => { +beforeAll(async () => { process.env.RWJS_CWD = FIXTURE_PATH cleanApiBuild() const apiFiles = findApiFiles() - prebuiltFiles = prebuildApiFiles(apiFiles) + prebuiltFiles = await prebuildApiFiles(apiFiles) relativePaths = prebuiltFiles .filter((x) => typeof x !== 'undefined') diff --git a/packages/internal/src/build/api.ts b/packages/internal/src/build/api.ts index b8eb22d060ea..9ac1ff80f297 100644 --- a/packages/internal/src/build/api.ts +++ b/packages/internal/src/build/api.ts @@ -1,6 +1,6 @@ import type { Format, Platform, PluginBuild, BuildContext } from 'esbuild' import { build, context } from 'esbuild' -import { removeSync } from 'fs-extra' +import { remove } from 'fs-extra' import { getApiSideBabelPlugins, @@ -13,9 +13,6 @@ import { findApiFiles } from '../files' let BUILD_CTX: BuildContext | null = null export const buildApi = async () => { - // @MARK: mai tong clean, overwriting already - // cleanApiBuild() - // Reset the build context for rebuildling BUILD_CTX = null @@ -36,9 +33,9 @@ export const rebuildApi = async () => { return BUILD_CTX.rebuild() } -export const cleanApiBuild = () => { +export const cleanApiBuild = async () => { const rwjsPaths = getPaths() - removeSync(rwjsPaths.api.dist) + return remove(rwjsPaths.api.dist) } const runRwBabelTransformsPlugin = { @@ -48,7 +45,7 @@ const runRwBabelTransformsPlugin = { build.onLoad({ filter: /\.(js|ts|tsx|jsx)$/ }, async (args) => { // @TODO I khitwaa implement LRU cache here - const transformedCode = transformWithBabel( + const transformedCode = await transformWithBabel( args.path, getApiSideBabelPlugins({ openTelemetry: diff --git a/packages/vite/src/buildFeServer.ts b/packages/vite/src/buildFeServer.ts index f5d01e254268..382e80dd5f48 100644 --- a/packages/vite/src/buildFeServer.ts +++ b/packages/vite/src/buildFeServer.ts @@ -80,9 +80,7 @@ export const buildFeServer = async ({ verbose, webDir }: BuildOptions = {}) => { name: 'rw-esbuild-babel-transform', setup(build: PluginBuild) { build.onLoad({ filter: /\.(js|ts|tsx|jsx)$/ }, async (args) => { - // Remove RedwoodJS "magic" from a user's code leaving JavaScript behind. - // TODO (STREAMING) We need the new transformWithBabel function in https://github.com/redwoodjs/redwood/pull/7672/files - const transformedCode = transformWithBabel(args.path, [ + const transformedCode = await transformWithBabel(args.path, [ ...getRouteHookBabelPlugins(), ]) diff --git a/yarn.lock b/yarn.lock index 975554480c4e..e71ca4fba8e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8660,6 +8660,7 @@ __metadata: "@redwoodjs/project-config": "npm:6.0.7" "@types/babel-plugin-tester": "npm:9.0.9" "@types/babel__core": "npm:7.20.4" + "@types/node": "npm:20.10.4" babel-plugin-auto-import: "npm:1.1.0" babel-plugin-graphql-tag: "npm:3.3.0" babel-plugin-module-resolver: "npm:5.0.0"