diff --git a/.eslintrc.js b/.eslintrc.js index 699c3a42ec98..fa757edc821d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -76,6 +76,38 @@ module.exports = { window: 'off', // Developers should use `global` instead of window. Since window is undefined in NodeJS. }, }, + // Prevent @redwoodjs/internal imports in runtime (web+api) packages + { + files: [ + 'packages/auth/src/**', + 'packages/forms/src/**', + 'packages/prerender/src/browserUtils/**', + 'packages/router/src/**', + 'packages/web/src/**', + 'packages/api/src/**', + 'packages/graphql-server/src/**', + 'packages/record/src/**', + ], + rules: { + 'no-restricted-imports': [ + 'error', + { + patterns: [ + { + group: ['@redwoodjs/internal', '@redwoodjs/internal/*'], + message: + 'Do not import "@redwoodjs/internal" or subpackages in runtime modules, because it leads to MASSIVE bundle sizes', + }, + { + group: ['@redwoodjs/structure', '@redwoodjs/structure/*'], + message: + 'Do not import "@redwoodjs/structure" or subpackages in runtime modules, because it leads to MASSIVE bundle sizes', + }, + ], + }, + ], + }, + }, // Entry.js rules { files: ['packages/web/src/entry/index.js'], @@ -109,5 +141,31 @@ module.exports = { node: true, }, }, + // Prevent bad imports in Node packages - cli and api packages + { + files: [ + 'packages/api/src/**', + 'packages/api-server/src/**', + 'packages/cli/src/**', + 'packages/internal/src/**', + 'packages/prerender/src/**', + 'packages/structure/src/**', + 'packages/testing/src/**', + 'packages/testing/config/**', + 'packages/eslint-config/*.js', + 'packages/record/src/**', + 'packages/telemetry/src/**', + ], + rules: { + 'no-restricted-imports': [ + 'error', + { + name: '@redwoodjs/internal', + message: + 'To prevent bloat in CLI, do not import "@redwoodjs/internal" directly. Instead import like @redwoodjs/internal/dist/, or await import', + }, + ], + }, + }, ], } diff --git a/packages/api-server/src/__tests__/withWebServer.test.ts b/packages/api-server/src/__tests__/withWebServer.test.ts index 6a6fd97bd1a7..6a65202d2d09 100644 --- a/packages/api-server/src/__tests__/withWebServer.test.ts +++ b/packages/api-server/src/__tests__/withWebServer.test.ts @@ -11,9 +11,9 @@ const FIXTURE_PATH = path.resolve( // Mock the dist folder from fixtures, // because its gitignored -jest.mock('@redwoodjs/internal', () => { +jest.mock('@redwoodjs/internal/dist/files', () => { return { - ...jest.requireActual('@redwoodjs/internal'), + ...jest.requireActual('@redwoodjs/internal/dist/files'), findPrerenderedHtml: () => { return ['about.html', 'mocked.html', 'posts/new.html', 'index.html'] }, diff --git a/packages/api-server/src/cliHandlers.ts b/packages/api-server/src/cliHandlers.ts index 120a051ea185..190cd9be66d7 100644 --- a/packages/api-server/src/cliHandlers.ts +++ b/packages/api-server/src/cliHandlers.ts @@ -4,7 +4,8 @@ import path from 'path' import c from 'ansi-colors' import { FastifyServerOptions } from 'fastify' -import { getConfig, getPaths } from '@redwoodjs/internal' +import { getConfig } from '@redwoodjs/internal/dist/config' +import { getPaths } from '@redwoodjs/internal/dist/paths' import createApp from './app' import withApiProxy from './plugins/withApiProxy' diff --git a/packages/api-server/src/plugins/withFunctions.ts b/packages/api-server/src/plugins/withFunctions.ts index 370fd88dfce0..967d54a3e051 100644 --- a/packages/api-server/src/plugins/withFunctions.ts +++ b/packages/api-server/src/plugins/withFunctions.ts @@ -12,7 +12,7 @@ import { import fastifyRawBody from 'fastify-raw-body' import escape from 'lodash.escape' -import { findApiDistFunctions } from '@redwoodjs/internal' +import { findApiDistFunctions } from '@redwoodjs/internal/dist/files' import { requestHandler } from '../requestHandlers/awsLambdaFastify' diff --git a/packages/api-server/src/plugins/withWebServer.ts b/packages/api-server/src/plugins/withWebServer.ts index 10b5a3b6dae4..9781e3f1bd3b 100644 --- a/packages/api-server/src/plugins/withWebServer.ts +++ b/packages/api-server/src/plugins/withWebServer.ts @@ -4,7 +4,8 @@ import path from 'path' import fastifyStatic from '@fastify/static' import { FastifyInstance, FastifyReply } from 'fastify' -import { findPrerenderedHtml, getPaths } from '@redwoodjs/internal' +import { findPrerenderedHtml } from '@redwoodjs/internal/dist/files' +import { getPaths } from '@redwoodjs/internal/dist/paths' export const getFallbackIndexPath = () => { const prerenderIndexPath = path.join(getPaths().web.dist, '/200.html') diff --git a/packages/api-server/src/watch.ts b/packages/api-server/src/watch.ts index effb2a576f64..e78e295b3ea6 100644 --- a/packages/api-server/src/watch.ts +++ b/packages/api-server/src/watch.ts @@ -11,13 +11,10 @@ import { debounce } from 'lodash' import { hideBin } from 'yargs/helpers' import yargs from 'yargs/yargs' -import { - getPaths, - buildApi, - getConfig, - ensurePosixPath, - loadAndValidateSdls, -} from '@redwoodjs/internal' +import { buildApi } from '@redwoodjs/internal/dist/build/api' +import { getConfig } from '@redwoodjs/internal/dist/config' +import { getPaths, ensurePosixPath } from '@redwoodjs/internal/dist/paths' +import { loadAndValidateSdls } from '@redwoodjs/internal/dist/validateSchema' const argv = yargs(hideBin(process.argv)) .option('debug-port', { diff --git a/packages/cli/src/commands/__tests__/build.test.js b/packages/cli/src/commands/__tests__/build.test.js index ba86eafd4ddf..48ac5c96029c 100644 --- a/packages/cli/src/commands/__tests__/build.test.js +++ b/packages/cli/src/commands/__tests__/build.test.js @@ -1,4 +1,4 @@ -jest.mock('@redwoodjs/internal', () => { +jest.mock('@redwoodjs/internal/dist/paths', () => { return { getPaths: () => { return { @@ -10,6 +10,11 @@ jest.mock('@redwoodjs/internal', () => { }, } }, + } +}) + +jest.mock('@redwoodjs/internal/dist/config', () => { + return { getConfig: () => {}, } }) @@ -25,8 +30,8 @@ import { handler } from '../build' afterEach(() => jest.clearAllMocks()) -test('the build tasks are in the correct sequence', () => { - handler({}) +test('the build tasks are in the correct sequence', async () => { + await handler({}) expect(Listr.mock.calls[0][0].map((x) => x.title)).toMatchInlineSnapshot(` Array [ "Generating Prisma Client...", @@ -43,7 +48,7 @@ jest.mock('@redwoodjs/prerender/detection', () => { }) test('Should run prerender for web', async () => { - handler({ side: ['web'], prerender: true }) + await handler({ side: ['web'], prerender: true }) expect(Listr.mock.calls[0][0].map((x) => x.title)).toMatchInlineSnapshot(` Array [ "Cleaning Web...", diff --git a/packages/cli/src/commands/__tests__/dev.test.js b/packages/cli/src/commands/__tests__/dev.test.js index d9b545041095..c0b7452318d4 100644 --- a/packages/cli/src/commands/__tests__/dev.test.js +++ b/packages/cli/src/commands/__tests__/dev.test.js @@ -1,3 +1,5 @@ +import '../../lib/mockTelemetry' + jest.mock('concurrently', () => ({ __esModule: true, // this property makes it work default: jest.fn().mockReturnValue({ @@ -16,8 +18,21 @@ jest.mock('fs', () => { } }) -jest.mock('@redwoodjs/internal', () => { +jest.mock('@redwoodjs/internal/dist/config', () => { + return { + getConfig: jest.fn(), + } +}) + +jest.mock('@redwoodjs/internal/dist/dev', () => { return { + shutdownPort: jest.fn(), + } +}) + +jest.mock('@redwoodjs/internal/dist/paths', () => { + return { + getConfigPath: () => '/mocked/project/redwood.toml', getPaths: () => { return { api: { @@ -31,9 +46,6 @@ jest.mock('@redwoodjs/internal', () => { }, } }, - getConfig: jest.fn(), - getConfigPath: () => '/mocked/project/redwood.toml', - shutdownPort: jest.fn(), } }) @@ -46,7 +58,7 @@ jest.mock('../../lib/generatePrismaClient', () => { import concurrently from 'concurrently' import { find } from 'lodash' -import { getConfig } from '@redwoodjs/internal' +import { getConfig } from '@redwoodjs/internal/dist/config' import { generatePrismaClient } from '../../lib/generatePrismaClient' import { handler } from '../dev' diff --git a/packages/cli/src/commands/__tests__/prisma.test.js b/packages/cli/src/commands/__tests__/prisma.test.js index d6b2475daedc..f61959b8d881 100644 --- a/packages/cli/src/commands/__tests__/prisma.test.js +++ b/packages/cli/src/commands/__tests__/prisma.test.js @@ -1,4 +1,4 @@ -jest.mock('@redwoodjs/internal', () => { +jest.mock('@redwoodjs/internal/dist/paths', () => { return { getPaths: () => { return { diff --git a/packages/cli/src/commands/__tests__/serve.test.js b/packages/cli/src/commands/__tests__/serve.test.js index ffe59f6492c0..daae38fa90a0 100644 --- a/packages/cli/src/commands/__tests__/serve.test.js +++ b/packages/cli/src/commands/__tests__/serve.test.js @@ -1,7 +1,7 @@ global.__dirname = __dirname // We mock these to skip the check for web/dist and api/dist -jest.mock('@redwoodjs/internal', () => { +jest.mock('@redwoodjs/internal/dist/paths', () => { return { getPaths: () => { return { @@ -13,6 +13,11 @@ jest.mock('@redwoodjs/internal', () => { }, } }, + } +}) + +jest.mock('@redwoodjs/internal/dist/config', () => { + return { getConfig: () => { return { api: {}, diff --git a/packages/cli/src/commands/build.js b/packages/cli/src/commands/build.js index b155f95c28af..7669c6187a9a 100644 --- a/packages/cli/src/commands/build.js +++ b/packages/cli/src/commands/build.js @@ -1,45 +1,18 @@ -import fs from 'fs' -import path from 'path' - -import execa from 'execa' -import Listr from 'listr' -import VerboseRenderer from 'listr-verbose-renderer' -import rimraf from 'rimraf' import terminalLink from 'terminal-link' -import { buildApi, loadAndValidateSdls } from '@redwoodjs/internal' -import { detectPrerenderRoutes } from '@redwoodjs/prerender/detection' -import { timedTelemetry, errorTelemetry } from '@redwoodjs/telemetry' - -import { getPaths } from '../lib' -import c from '../lib/colors' -import { generatePrismaCommand } from '../lib/generatePrismaClient' +import { sides } from '../lib/project' import checkForBabelConfig from '../middleware/checkForBabelConfig' -import { getTasks as getPrerenderTasks } from './prerender' - export const command = 'build [side..]' export const description = 'Build for production' export const builder = (yargs) => { - const apiExists = fs.existsSync(getPaths().api.src) - const webExists = fs.existsSync(getPaths().web.src) - - const optionDefault = (apiExists, webExists) => { - let options = [] - if (apiExists) { - options.push('api') - } - if (webExists) { - options.push('web') - } - return options - } + const choices = sides() yargs .positional('side', { - choices: ['api', 'web'], - default: optionDefault(apiExists, webExists), + choices, + default: choices, description: 'Which side(s) to build', type: 'array', }) @@ -83,131 +56,7 @@ export const builder = (yargs) => { ) } -export const handler = async ({ - side = ['api', 'web'], - verbose = false, - performance = false, - stats = false, - prisma = true, - prerender, -}) => { - const rwjsPaths = getPaths() - - if (performance) { - console.log('Measuring Web Build Performance...') - execa.sync( - `yarn cross-env NODE_ENV=production webpack --config ${require.resolve( - '@redwoodjs/core/config/webpack.perf.js' - )}`, - { stdio: 'inherit', shell: true, cwd: rwjsPaths.web.base } - ) - // We do not want to continue building... - return - } - - if (stats) { - console.log('Building Web Stats...') - execa.sync( - `yarn cross-env NODE_ENV=production webpack --config ${require.resolve( - '@redwoodjs/core/config/webpack.stats.js' - )}`, - { stdio: 'inherit', shell: true, cwd: rwjsPaths.web.base } - ) - // We do not want to continue building... - return - } - - const tasks = [ - side.includes('api') && - prisma && { - title: 'Generating Prisma Client...', - task: async () => { - const { cmd, args } = generatePrismaCommand(rwjsPaths.api.dbSchema) - return execa(cmd, args, { - stdio: verbose ? 'inherit' : 'pipe', - shell: true, - cwd: rwjsPaths.api.base, - }) - }, - }, - side.includes('api') && { - title: 'Verifying graphql schema...', - task: loadAndValidateSdls, - }, - side.includes('api') && { - title: 'Building API...', - task: () => { - const { errors, warnings } = buildApi() - - if (errors.length) { - console.error(errors) - } - if (warnings.length) { - console.warn(warnings) - } - }, - }, - side.includes('web') && { - // Clean web - title: 'Cleaning Web...', - task: () => { - rimraf.sync(rwjsPaths.web.dist) - }, - }, - side.includes('web') && { - title: 'Building Web...', - task: async () => { - await execa( - `yarn cross-env NODE_ENV=production webpack --config ${require.resolve( - '@redwoodjs/core/config/webpack.production.js' - )}`, - { - stdio: verbose ? 'inherit' : 'pipe', - shell: true, - cwd: rwjsPaths.web.base, - } - ) - - console.log('Creating 200.html...') - - const indexHtmlPath = path.join(getPaths().web.dist, 'index.html') - - fs.copyFileSync( - indexHtmlPath, - path.join(getPaths().web.dist, '200.html') - ) - }, - }, - side.includes('web') && - prerender && { - title: 'Prerendering Web...', - task: async () => { - const prerenderRoutes = detectPrerenderRoutes() - if (prerenderRoutes.length === 0) { - return `You have not marked any "prerender" in your ${terminalLink( - 'Routes', - 'file://' + rwjsPaths.web.routes - )}.` - } - return new Listr(await getPrerenderTasks(), { - renderer: verbose && VerboseRenderer, - concurrent: true, // Re-use prerender tasks, but run them in parallel to speed things up - }) - }, - }, - ].filter(Boolean) - - const jobs = new Listr(tasks, { - renderer: verbose && VerboseRenderer, - }) - - try { - await timedTelemetry(process.argv, { type: 'build' }, async () => { - await jobs.run() - }) - } catch (e) { - console.log(c.error(e.message)) - errorTelemetry(process.argv, e.message) - process.exit(1) - } +export const handler = async (options) => { + const { handler } = await import('./buildHandler') + return handler(options) } diff --git a/packages/cli/src/commands/buildHandler.js b/packages/cli/src/commands/buildHandler.js new file mode 100644 index 000000000000..35960730daa3 --- /dev/null +++ b/packages/cli/src/commands/buildHandler.js @@ -0,0 +1,148 @@ +import fs from 'fs' +import path from 'path' + +import execa from 'execa' +import Listr from 'listr' +import VerboseRenderer from 'listr-verbose-renderer' +import rimraf from 'rimraf' +import terminalLink from 'terminal-link' + +import { buildApi } from '@redwoodjs/internal/dist/build/api' +import { loadAndValidateSdls } from '@redwoodjs/internal/dist/validateSchema' +import { detectPrerenderRoutes } from '@redwoodjs/prerender/detection' +import { timedTelemetry, errorTelemetry } from '@redwoodjs/telemetry' + +import { getPaths } from '../lib' +import c from '../lib/colors' +import { generatePrismaCommand } from '../lib/generatePrismaClient' + +import { getTasks as getPrerenderTasks } from './prerenderHandler' + +export const handler = async ({ + side = ['api', 'web'], + verbose = false, + performance = false, + stats = false, + prisma = true, + prerender, +}) => { + const rwjsPaths = getPaths() + + if (performance) { + console.log('Measuring Web Build Performance...') + execa.sync( + `yarn cross-env NODE_ENV=production webpack --config ${require.resolve( + '@redwoodjs/core/config/webpack.perf.js' + )}`, + { stdio: 'inherit', shell: true, cwd: rwjsPaths.web.base } + ) + // We do not want to continue building... + return + } + + if (stats) { + console.log('Building Web Stats...') + execa.sync( + `yarn cross-env NODE_ENV=production webpack --config ${require.resolve( + '@redwoodjs/core/config/webpack.stats.js' + )}`, + { stdio: 'inherit', shell: true, cwd: rwjsPaths.web.base } + ) + // We do not want to continue building... + return + } + + const tasks = [ + side.includes('api') && + prisma && { + title: 'Generating Prisma Client...', + task: async () => { + const { cmd, args } = generatePrismaCommand(rwjsPaths.api.dbSchema) + return execa(cmd, args, { + stdio: verbose ? 'inherit' : 'pipe', + shell: true, + cwd: rwjsPaths.api.base, + }) + }, + }, + side.includes('api') && { + title: 'Verifying graphql schema...', + task: loadAndValidateSdls, + }, + side.includes('api') && { + title: 'Building API...', + task: () => { + const { errors, warnings } = buildApi() + + if (errors.length) { + console.error(errors) + } + if (warnings.length) { + console.warn(warnings) + } + }, + }, + side.includes('web') && { + // Clean web + title: 'Cleaning Web...', + task: () => { + rimraf.sync(rwjsPaths.web.dist) + }, + }, + side.includes('web') && { + title: 'Building Web...', + task: async () => { + await execa( + `yarn cross-env NODE_ENV=production webpack --config ${require.resolve( + '@redwoodjs/core/config/webpack.production.js' + )}`, + { + stdio: verbose ? 'inherit' : 'pipe', + shell: true, + cwd: rwjsPaths.web.base, + } + ) + + console.log('Creating 200.html...') + + const indexHtmlPath = path.join(getPaths().web.dist, 'index.html') + + fs.copyFileSync( + indexHtmlPath, + path.join(getPaths().web.dist, '200.html') + ) + }, + }, + side.includes('web') && + prerender && { + title: 'Prerendering Web...', + task: async () => { + const prerenderRoutes = detectPrerenderRoutes() + if (prerenderRoutes.length === 0) { + return `You have not marked any "prerender" in your ${terminalLink( + 'Routes', + 'file://' + rwjsPaths.web.routes + )}.` + } + return new Listr(await getPrerenderTasks(), { + renderer: verbose && VerboseRenderer, + concurrent: true, // Re-use prerender tasks, but run them in parallel to speed things up + }) + }, + }, + ].filter(Boolean) + + const jobs = new Listr(tasks, { + renderer: verbose && VerboseRenderer, + }) + + try { + await timedTelemetry(process.argv, { type: 'build' }, async () => { + await jobs.run() + }) + } catch (e) { + console.log(c.error(e.message)) + errorTelemetry(process.argv, e.message) + process.exit(1) + } +} diff --git a/packages/cli/src/commands/console.js b/packages/cli/src/commands/console.js index 3bf2427b5fe5..119acd0dbe75 100644 --- a/packages/cli/src/commands/console.js +++ b/packages/cli/src/commands/console.js @@ -1,85 +1,8 @@ -import fs from 'fs' -import path from 'path' -import repl from 'repl' - -import { registerApiSideBabelHook } from '@redwoodjs/internal' - -import { getPaths } from '../lib' - export const command = 'console' export const aliases = ['c'] export const description = 'Launch an interactive Redwood shell (experimental)' -const paths = getPaths() - -const loadPrismaClient = (replContext) => { - const { db } = require(path.join(paths.api.lib, 'db')) - replContext.db = db -} - -const consoleHistoryFile = path.join(paths.generated.base, 'console_history') -const persistConsoleHistory = (r) => { - fs.appendFileSync( - consoleHistoryFile, - r.lines.filter((line) => line.trim()).join('\n') + '\n', - 'utf8' - ) -} - -const loadConsoleHistory = async (r) => { - try { - const history = await fs.promises.readFile(consoleHistoryFile, 'utf8') - history - .split('\n') - .reverse() - .map((line) => r.history.push(line)) - } catch (e) { - // We can ignore this -- it just means the user doesn't have any history yet - } -} - -export const handler = () => { - // Transpile on the fly - registerApiSideBabelHook({ - plugins: [ - [ - 'babel-plugin-module-resolver', - { - alias: { - src: paths.api.src, - }, - }, - 'rwjs-console-module-resolver', - ], - ], - }) - - const r = repl.start() - - // always await promises. - // source: https://github.com/nodejs/node/issues/13209#issuecomment-619526317 - const defaultEval = r.eval - r.eval = (cmd, context, filename, callback) => { - defaultEval(cmd, context, filename, async (err, result) => { - if (err) { - // propagate errors. - callback(err) - } else { - // await the promise and either return the result or error. - try { - callback(null, await Promise.resolve(result)) - } catch (err) { - callback(err) - } - } - }) - } - - // Persist console history to .redwood/console_history. See - // https://tjwebb.medium.com/a-custom-node-repl-with-history-is-not-as-hard-as-it-looks-3eb2ca7ec0bd - loadConsoleHistory(r) - r.addListener('close', () => persistConsoleHistory(r)) - - // Make the project's db (i.e. Prisma Client) available - loadPrismaClient(r.context) +export const handler = async (options) => { + const { handler } = await import('./consoleHandler') + return handler(options) } diff --git a/packages/cli/src/commands/consoleHandler.js b/packages/cli/src/commands/consoleHandler.js new file mode 100644 index 000000000000..3aa33008eaa9 --- /dev/null +++ b/packages/cli/src/commands/consoleHandler.js @@ -0,0 +1,81 @@ +import fs from 'fs' +import path from 'path' +import repl from 'repl' + +import { registerApiSideBabelHook } from '@redwoodjs/internal/dist/build/babel/api' + +import { getPaths } from '../lib' + +const paths = getPaths() + +const loadPrismaClient = (replContext) => { + const { db } = require(path.join(paths.api.lib, 'db')) + replContext.db = db +} + +const consoleHistoryFile = path.join(paths.generated.base, 'console_history') +const persistConsoleHistory = (r) => { + fs.appendFileSync( + consoleHistoryFile, + r.lines.filter((line) => line.trim()).join('\n') + '\n', + 'utf8' + ) +} + +const loadConsoleHistory = async (r) => { + try { + const history = await fs.promises.readFile(consoleHistoryFile, 'utf8') + history + .split('\n') + .reverse() + .map((line) => r.history.push(line)) + } catch (e) { + // We can ignore this -- it just means the user doesn't have any history yet + } +} + +export const handler = () => { + // Transpile on the fly + registerApiSideBabelHook({ + plugins: [ + [ + 'babel-plugin-module-resolver', + { + alias: { + src: paths.api.src, + }, + }, + 'rwjs-console-module-resolver', + ], + ], + }) + + const r = repl.start() + + // always await promises. + // source: https://github.com/nodejs/node/issues/13209#issuecomment-619526317 + const defaultEval = r.eval + r.eval = (cmd, context, filename, callback) => { + defaultEval(cmd, context, filename, async (err, result) => { + if (err) { + // propagate errors. + callback(err) + } else { + // await the promise and either return the result or error. + try { + callback(null, await Promise.resolve(result)) + } catch (err) { + callback(err) + } + } + }) + } + + // Persist console history to .redwood/console_history. See + // https://tjwebb.medium.com/a-custom-node-repl-with-history-is-not-as-hard-as-it-looks-3eb2ca7ec0bd + loadConsoleHistory(r) + r.addListener('close', () => persistConsoleHistory(r)) + + // Make the project's db (i.e. Prisma Client) available + loadPrismaClient(r.context) +} diff --git a/packages/cli/src/commands/dataMigrate/up.js b/packages/cli/src/commands/dataMigrate/up.js index ae57d861ccfb..3983f1ca198d 100644 --- a/packages/cli/src/commands/dataMigrate/up.js +++ b/packages/cli/src/commands/dataMigrate/up.js @@ -5,7 +5,7 @@ import Listr from 'listr' import VerboseRenderer from 'listr-verbose-renderer' import terminalLink from 'terminal-link' -import { registerApiSideBabelHook } from '@redwoodjs/internal' +import { registerApiSideBabelHook } from '@redwoodjs/internal/dist/build/babel/api' import { errorTelemetry } from '@redwoodjs/telemetry' import { getPaths } from '../../lib' diff --git a/packages/cli/src/commands/deploy/__tests__/baremetal.test.js b/packages/cli/src/commands/deploy/__tests__/baremetal.test.js index 1bec95eb99cb..5569bbedc439 100644 --- a/packages/cli/src/commands/deploy/__tests__/baremetal.test.js +++ b/packages/cli/src/commands/deploy/__tests__/baremetal.test.js @@ -1,6 +1,6 @@ import Listr from 'listr' -jest.mock('@redwoodjs/internal', () => { +jest.mock('@redwoodjs/internal/dist/paths', () => { return { getPaths: () => ({ base: `${__dirname}/fixtures`, diff --git a/packages/cli/src/commands/deploy/__tests__/nftPack.test.js b/packages/cli/src/commands/deploy/__tests__/nftPack.test.js index 46acc0cdea0c..a3f79a6e8572 100644 --- a/packages/cli/src/commands/deploy/__tests__/nftPack.test.js +++ b/packages/cli/src/commands/deploy/__tests__/nftPack.test.js @@ -1,7 +1,8 @@ import fs from 'fs' import path from 'path' -import { buildApi, findApiDistFunctions } from '@redwoodjs/internal' +import { buildApi } from '@redwoodjs/internal/dist/build/api' +import { findApiDistFunctions } from '@redwoodjs/internal/dist/files' import nftPacker from '../packing/nft' diff --git a/packages/cli/src/commands/deploy/flightcontrol.js b/packages/cli/src/commands/deploy/flightcontrol.js index b76bc3102abd..add272e919e7 100644 --- a/packages/cli/src/commands/deploy/flightcontrol.js +++ b/packages/cli/src/commands/deploy/flightcontrol.js @@ -4,7 +4,7 @@ import execa from 'execa' import terminalLink from 'terminal-link' import { apiServerHandler } from '@redwoodjs/api-server' -import { getConfig } from '@redwoodjs/internal' +import { getConfig } from '@redwoodjs/internal/dist/config' import { getPaths } from '../../lib' diff --git a/packages/cli/src/commands/deploy/helpers/helpers.js b/packages/cli/src/commands/deploy/helpers/helpers.js index 45f559f559e4..94a11c9205f9 100644 --- a/packages/cli/src/commands/deploy/helpers/helpers.js +++ b/packages/cli/src/commands/deploy/helpers/helpers.js @@ -1,7 +1,7 @@ import execa from 'execa' import terminalLink from 'terminal-link' -import { getPaths } from '@redwoodjs/internal' +import { getPaths } from '@redwoodjs/internal/dist/paths' import c from '../../../lib/colors' diff --git a/packages/cli/src/commands/deploy/layer0.js b/packages/cli/src/commands/deploy/layer0.js index 701743b9a1db..5e1413f80f16 100644 --- a/packages/cli/src/commands/deploy/layer0.js +++ b/packages/cli/src/commands/deploy/layer0.js @@ -5,7 +5,7 @@ import fs from 'fs-extra' import omit from 'lodash/omit' import terminalLink from 'terminal-link' -import { getPaths } from '@redwoodjs/internal' +import { getPaths } from '@redwoodjs/internal/dist/paths' import c from '../../lib/colors' diff --git a/packages/cli/src/commands/deploy/packing/nft.js b/packages/cli/src/commands/deploy/packing/nft.js index e48b6edc5947..eb4bf3d1894e 100644 --- a/packages/cli/src/commands/deploy/packing/nft.js +++ b/packages/cli/src/commands/deploy/packing/nft.js @@ -4,11 +4,8 @@ import { nodeFileTrace } from '@vercel/nft' import archiver from 'archiver' import fse from 'fs-extra' -import { - ensurePosixPath, - findApiDistFunctions, - getPaths, -} from '@redwoodjs/internal' +import { findApiDistFunctions } from '@redwoodjs/internal/dist/files' +import { ensurePosixPath, getPaths } from '@redwoodjs/internal/dist/paths' const ZIPBALL_DIR = './api/dist/zipball' diff --git a/packages/cli/src/commands/deploy/render.js b/packages/cli/src/commands/deploy/render.js index 400e195c86f0..a597d581835c 100644 --- a/packages/cli/src/commands/deploy/render.js +++ b/packages/cli/src/commands/deploy/render.js @@ -4,7 +4,7 @@ import execa from 'execa' import terminalLink from 'terminal-link' import { apiServerHandler } from '@redwoodjs/api-server' -import { getConfig } from '@redwoodjs/internal' +import { getConfig } from '@redwoodjs/internal/dist/config' import { getPaths } from '../../lib' diff --git a/packages/cli/src/commands/dev.js b/packages/cli/src/commands/dev.js index c20d700fecb4..3c86f4272707 100644 --- a/packages/cli/src/commands/dev.js +++ b/packages/cli/src/commands/dev.js @@ -1,18 +1,7 @@ -import fs from 'fs' -import { argv } from 'process' - -import concurrently from 'concurrently' import terminalLink from 'terminal-link' -import { getConfig, getConfigPath, shutdownPort } from '@redwoodjs/internal' -import { errorTelemetry } from '@redwoodjs/telemetry' - -import { getPaths } from '../lib' -import c from '../lib/colors' -import { generatePrismaClient } from '../lib/generatePrismaClient' import checkForBabelConfig from '../middleware/checkForBabelConfig' -const defaultApiDebugPort = 18911 export const command = 'dev [side..]' export const description = 'Start development servers for api, and web' export const builder = (yargs) => { @@ -52,122 +41,7 @@ export const builder = (yargs) => { ) } -export const handler = async ({ - side = ['api', 'web'], - forward = '', - generate = true, - watchNodeModules = process.env.RWJS_WATCH_NODE_MODULES === '1', - apiDebugPort, -}) => { - const rwjsPaths = getPaths() - - if (side.includes('api')) { - try { - await generatePrismaClient({ - verbose: false, - force: false, - schema: rwjsPaths.api.dbSchema, - }) - } catch (e) { - errorTelemetry( - process.argv, - `Error generating prisma client: ${e.message}` - ) - console.error(c.error(e.message)) - } - - try { - await shutdownPort(getConfig().api.port) - } catch (e) { - errorTelemetry(process.argv, `Error shutting down "api": ${e.message}`) - console.error( - `Error whilst shutting down "api" port: ${c.error(e.message)}` - ) - } - } - - if (side.includes('web')) { - try { - await shutdownPort(getConfig().web.port) - } catch (e) { - errorTelemetry(process.argv, `Error shutting down "web": ${e.message}`) - console.error( - `Error whilst shutting down "web" port: ${c.error(e.message)}` - ) - } - } - - const webpackDevConfig = require.resolve( - '@redwoodjs/core/config/webpack.development.js' - ) - - const getApiDebugFlag = () => { - // Passed in flag takes precedence - if (apiDebugPort) { - return `--debug-port ${apiDebugPort}` - } else if (argv.includes('--apiDebugPort')) { - return `--debug-port ${defaultApiDebugPort}` - } - - const apiDebugPortInToml = getConfig().api.debugPort - if (apiDebugPortInToml) { - return `--debug-port ${apiDebugPortInToml}` - } - - // Dont pass in debug port flag, unless configured - return '' - } - - const redwoodConfigPath = getConfigPath() - - /** @type {Record} */ - const jobs = { - api: { - name: 'api', - command: `yarn cross-env NODE_ENV=development NODE_OPTIONS=--enable-source-maps yarn nodemon --quiet --watch "${redwoodConfigPath}" --exec "yarn rw-api-server-watch ${getApiDebugFlag()} | rw-log-formatter"`, - prefixColor: 'cyan', - runWhen: () => fs.existsSync(rwjsPaths.api.src), - }, - web: { - name: 'web', - command: `cd "${ - rwjsPaths.web.base - }" && yarn cross-env NODE_ENV=development RWJS_WATCH_NODE_MODULES=${ - watchNodeModules ? '1' : '' - } webpack serve --config "${webpackDevConfig}" ${forward}`, - prefixColor: 'blue', - runWhen: () => fs.existsSync(rwjsPaths.web.src), - }, - gen: { - name: 'gen', - command: 'yarn rw-gen-watch', - prefixColor: 'green', - runWhen: () => generate, - }, - } - - // TODO: Convert jobs to an array and supply cwd command. - const { result } = concurrently( - Object.keys(jobs) - .map((job) => { - if (side.includes(job) || job === 'gen') { - return jobs[job] - } - }) - .filter((job) => job && job.runWhen()), - { - prefix: '{name} |', - timestampFormat: 'HH:mm:ss', - } - ) - result.catch((e) => { - if (typeof e?.message !== 'undefined') { - errorTelemetry( - process.argv, - `Error concurrently starting sides: ${e.message}` - ) - console.error(c.error(e.message)) - process.exit(1) - } - }) +export const handler = async (options) => { + const { handler } = await import('./devHandler') + return handler(options) } diff --git a/packages/cli/src/commands/devHandler.js b/packages/cli/src/commands/devHandler.js new file mode 100644 index 000000000000..6d43cf1f7b2c --- /dev/null +++ b/packages/cli/src/commands/devHandler.js @@ -0,0 +1,135 @@ +import fs from 'fs' +import { argv } from 'process' + +import concurrently from 'concurrently' + +import { getConfig } from '@redwoodjs/internal/dist/config' +import { shutdownPort } from '@redwoodjs/internal/dist/dev' +import { getConfigPath } from '@redwoodjs/internal/dist/paths' +import { errorTelemetry } from '@redwoodjs/telemetry' + +import { getPaths } from '../lib' +import c from '../lib/colors' +import { generatePrismaClient } from '../lib/generatePrismaClient' + +const defaultApiDebugPort = 18911 + +export const handler = async ({ + side = ['api', 'web'], + forward = '', + generate = true, + watchNodeModules = process.env.RWJS_WATCH_NODE_MODULES === '1', + apiDebugPort, +}) => { + const rwjsPaths = getPaths() + + if (side.includes('api')) { + try { + await generatePrismaClient({ + verbose: false, + force: false, + schema: rwjsPaths.api.dbSchema, + }) + } catch (e) { + errorTelemetry( + process.argv, + `Error generating prisma client: ${e.message}` + ) + console.error(c.error(e.message)) + } + + try { + await shutdownPort(getConfig().api.port) + } catch (e) { + errorTelemetry(process.argv, `Error shutting down "api": ${e.message}`) + console.error( + `Error whilst shutting down "api" port: ${c.error(e.message)}` + ) + } + } + + if (side.includes('web')) { + try { + await shutdownPort(getConfig().web.port) + } catch (e) { + errorTelemetry(process.argv, `Error shutting down "web": ${e.message}`) + console.error( + `Error whilst shutting down "web" port: ${c.error(e.message)}` + ) + } + } + + const webpackDevConfig = require.resolve( + '@redwoodjs/core/config/webpack.development.js' + ) + + const getApiDebugFlag = () => { + // Passed in flag takes precedence + if (apiDebugPort) { + return `--debug-port ${apiDebugPort}` + } else if (argv.includes('--apiDebugPort')) { + return `--debug-port ${defaultApiDebugPort}` + } + + const apiDebugPortInToml = getConfig().api.debugPort + if (apiDebugPortInToml) { + return `--debug-port ${apiDebugPortInToml}` + } + + // Dont pass in debug port flag, unless configured + return '' + } + + const redwoodConfigPath = getConfigPath() + + /** @type {Record} */ + const jobs = { + api: { + name: 'api', + command: `yarn cross-env NODE_ENV=development NODE_OPTIONS=--enable-source-maps yarn nodemon --quiet --watch "${redwoodConfigPath}" --exec "yarn rw-api-server-watch ${getApiDebugFlag()} | rw-log-formatter"`, + prefixColor: 'cyan', + runWhen: () => fs.existsSync(rwjsPaths.api.src), + }, + web: { + name: 'web', + command: `cd "${ + rwjsPaths.web.base + }" && yarn cross-env NODE_ENV=development RWJS_WATCH_NODE_MODULES=${ + watchNodeModules ? '1' : '' + } webpack serve --config "${webpackDevConfig}" ${forward}`, + prefixColor: 'blue', + runWhen: () => fs.existsSync(rwjsPaths.web.src), + }, + gen: { + name: 'gen', + command: 'yarn rw-gen-watch', + prefixColor: 'green', + runWhen: () => generate, + }, + } + + // TODO: Convert jobs to an array and supply cwd command. + const { result } = concurrently( + Object.keys(jobs) + .map((job) => { + if (side.includes(job) || job === 'gen') { + return jobs[job] + } + }) + .filter((job) => job && job.runWhen()), + { + prefix: '{name} |', + timestampFormat: 'HH:mm:ss', + } + ) + result.catch((e) => { + if (typeof e?.message !== 'undefined') { + errorTelemetry( + process.argv, + `Error concurrently starting sides: ${e.message}` + ) + console.error(c.error(e.message)) + process.exit(1) + } + }) +} diff --git a/packages/cli/src/commands/exec.js b/packages/cli/src/commands/exec.js index 0b6e25b1309a..2eefa62a2191 100644 --- a/packages/cli/src/commands/exec.js +++ b/packages/cli/src/commands/exec.js @@ -1,33 +1,5 @@ -import path from 'path' - -import Listr from 'listr' -import VerboseRenderer from 'listr-verbose-renderer' import terminalLink from 'terminal-link' -import { - findScripts, - getWebSideDefaultBabelConfig, - registerApiSideBabelHook, -} from '@redwoodjs/internal' - -import { getPaths } from '../lib' -import c from '../lib/colors' -import { generatePrismaClient } from '../lib/generatePrismaClient' - -const runScript = async (scriptPath, scriptArgs) => { - const script = await import(scriptPath) - await script.default({ args: scriptArgs }) - - try { - const { db } = await import(path.join(getPaths().api.lib, 'db')) - db.$disconnect() - } catch (e) { - // silence - } - - return -} - export const command = 'exec [name]' export const description = 'Run scripts generated with yarn generate script' export const builder = (yargs) => { @@ -56,121 +28,7 @@ export const builder = (yargs) => { ) } -const printAvailableScriptsToConsole = () => { - console.log('Available scripts:') - findScripts().forEach((scriptPath) => { - const { name } = path.parse(scriptPath) - console.log(c.info(`- ${name}`)) - }) - console.log() -} - -export const handler = async (args) => { - const { name, prisma, list, ...scriptArgs } = args - if (list || !name) { - printAvailableScriptsToConsole() - return - } - - const scriptPath = path.join(getPaths().scripts, name) - - const { - overrides: _overrides, - plugins: webPlugins, - ...otherWebConfig - } = getWebSideDefaultBabelConfig() - - // Import babel config for running script - registerApiSideBabelHook({ - plugins: [ - [ - 'babel-plugin-module-resolver', - { - alias: { - $api: getPaths().api.base, - $web: getPaths().web.base, - api: getPaths().api.base, - web: getPaths().web.base, - }, - loglevel: 'silent', // to silence the unnecessary warnings - }, - 'exec-$side-module-resolver', - ], - ], - overrides: [ - { - test: ['./api/'], - plugins: [ - [ - 'babel-plugin-module-resolver', - { - alias: { - src: getPaths().api.src, - }, - loglevel: 'silent', - }, - 'exec-api-src-module-resolver', - ], - ], - }, - { - test: ['./web/'], - plugins: [ - ...webPlugins, - [ - 'babel-plugin-module-resolver', - { - alias: { - src: getPaths().web.src, - }, - loglevel: 'silent', - }, - 'exec-web-src-module-resolver', - ], - ], - ...otherWebConfig, - }, - ], - }) - - try { - require.resolve(scriptPath) - } catch { - console.error( - c.error(`\nNo script called ${c.underline(name)} in ./scripts folder.\n`) - ) - - printAvailableScriptsToConsole() - process.exit(1) - } - - const scriptTasks = [ - { - title: 'Generating Prisma client', - enabled: () => prisma, - task: () => generatePrismaClient({ force: false }), - }, - { - title: 'Running script', - task: async () => { - try { - await runScript(scriptPath, scriptArgs) - } catch (e) { - console.error(c.error(`Error in script: ${e.message}`)) - } - }, - }, - ] - - const tasks = new Listr(scriptTasks, { - collapse: false, - renderer: VerboseRenderer, - }) - - try { - await tasks.run() - } catch (e) { - console.error(c.error(`The script exited with errors.`)) - process.exit(e?.exitCode || 1) - } +export const handler = async (options) => { + const { handler } = await import('./execHandler') + return handler(options) } diff --git a/packages/cli/src/commands/execHandler.js b/packages/cli/src/commands/execHandler.js new file mode 100644 index 000000000000..65f7a50801ac --- /dev/null +++ b/packages/cli/src/commands/execHandler.js @@ -0,0 +1,144 @@ +import path from 'path' + +import Listr from 'listr' +import VerboseRenderer from 'listr-verbose-renderer' + +import { registerApiSideBabelHook } from '@redwoodjs/internal/dist/build/babel/api' +import { getWebSideDefaultBabelConfig } from '@redwoodjs/internal/dist/build/babel/web' +import { findScripts } from '@redwoodjs/internal/dist/files' + +import { getPaths } from '../lib' +import c from '../lib/colors' +import { generatePrismaClient } from '../lib/generatePrismaClient' + +const runScript = async (scriptPath, scriptArgs) => { + const script = await import(scriptPath) + await script.default({ args: scriptArgs }) + + try { + const { db } = await import(path.join(getPaths().api.lib, 'db')) + db.$disconnect() + } catch (e) { + // silence + } + + return +} +const printAvailableScriptsToConsole = () => { + console.log('Available scripts:') + findScripts().forEach((scriptPath) => { + const { name } = path.parse(scriptPath) + console.log(c.info(`- ${name}`)) + }) + console.log() +} + +export const handler = async (args) => { + const { name, prisma, list, ...scriptArgs } = args + if (list || !name) { + printAvailableScriptsToConsole() + return + } + + const scriptPath = path.join(getPaths().scripts, name) + + const { + overrides: _overrides, + plugins: webPlugins, + ...otherWebConfig + } = getWebSideDefaultBabelConfig() + + // Import babel config for running script + registerApiSideBabelHook({ + plugins: [ + [ + 'babel-plugin-module-resolver', + { + alias: { + $api: getPaths().api.base, + $web: getPaths().web.base, + api: getPaths().api.base, + web: getPaths().web.base, + }, + loglevel: 'silent', // to silence the unnecessary warnings + }, + 'exec-$side-module-resolver', + ], + ], + overrides: [ + { + test: ['./api/'], + plugins: [ + [ + 'babel-plugin-module-resolver', + { + alias: { + src: getPaths().api.src, + }, + loglevel: 'silent', + }, + 'exec-api-src-module-resolver', + ], + ], + }, + { + test: ['./web/'], + plugins: [ + ...webPlugins, + [ + 'babel-plugin-module-resolver', + { + alias: { + src: getPaths().web.src, + }, + loglevel: 'silent', + }, + 'exec-web-src-module-resolver', + ], + ], + ...otherWebConfig, + }, + ], + }) + + try { + require.resolve(scriptPath) + } catch { + console.error( + c.error(`\nNo script called ${c.underline(name)} in ./scripts folder.\n`) + ) + + printAvailableScriptsToConsole() + process.exit(1) + } + + const scriptTasks = [ + { + title: 'Generating Prisma client', + enabled: () => prisma, + task: () => generatePrismaClient({ force: false }), + }, + { + title: 'Running script', + task: async () => { + try { + await runScript(scriptPath, scriptArgs) + } catch (e) { + console.error(c.error(`Error in script: ${e.message}`)) + } + }, + }, + ] + + const tasks = new Listr(scriptTasks, { + collapse: false, + renderer: VerboseRenderer, + }) + + try { + await tasks.run() + } catch (e) { + console.error(c.error(`The script exited with errors.`)) + process.exit(e?.exitCode || 1) + } +} diff --git a/packages/cli/src/commands/generate.js b/packages/cli/src/commands/generate.js index b5e57a41339b..8eccb28be92e 100644 --- a/packages/cli/src/commands/generate.js +++ b/packages/cli/src/commands/generate.js @@ -1,7 +1,7 @@ import execa from 'execa' import terminalLink from 'terminal-link' -import { getProject } from '@redwoodjs/structure' +import { isTypeScriptProject } from '../lib/project' export const command = 'generate ' export const aliases = ['g'] @@ -40,7 +40,7 @@ export const yargsDefaults = { }, typescript: { alias: 'ts', - default: getProject().isTypeScriptProject, + default: isTypeScriptProject(), description: 'Generate TypeScript files', type: 'boolean', }, diff --git a/packages/cli/src/commands/generate/cell/cell.js b/packages/cli/src/commands/generate/cell/cell.js index b9023d294de8..e0c4843b4950 100644 --- a/packages/cli/src/commands/generate/cell/cell.js +++ b/packages/cli/src/commands/generate/cell/cell.js @@ -1,6 +1,6 @@ import pascalcase from 'pascalcase' -import { generate as generateTypes } from '@redwoodjs/internal' +import { generate as generateTypes } from '@redwoodjs/internal/dist/generate/generate' import { nameVariants, transformTSToJS } from '../../../lib' import { isWordPluralizable } from '../../../lib/pluralHelpers' diff --git a/packages/cli/src/commands/generate/cell/utils/utils.js b/packages/cli/src/commands/generate/cell/utils/utils.js index 36e818a20c9e..67fbfa8ee40f 100644 --- a/packages/cli/src/commands/generate/cell/utils/utils.js +++ b/packages/cli/src/commands/generate/cell/utils/utils.js @@ -1,6 +1,6 @@ import pascalcase from 'pascalcase' -import { listQueryTypeFieldsInProject } from '@redwoodjs/internal' +import { listQueryTypeFieldsInProject } from '@redwoodjs/internal/dist/gql' export const getCellOperationNames = async () => { const { getProject } = await import('@redwoodjs/structure') diff --git a/packages/cli/src/commands/generate/directive/directive.js b/packages/cli/src/commands/generate/directive/directive.js index e3dd31d612d0..a9bba3ac4014 100644 --- a/packages/cli/src/commands/generate/directive/directive.js +++ b/packages/cli/src/commands/generate/directive/directive.js @@ -5,7 +5,7 @@ import execa from 'execa' import Listr from 'listr' import prompts from 'prompts' -import { getConfig } from '@redwoodjs/internal' +import { getConfig } from '@redwoodjs/internal/dist/config' import { getPaths, writeFilesTask, transformTSToJS } from '../../../lib' import c from '../../../lib/colors' diff --git a/packages/cli/src/commands/generate/helpers.js b/packages/cli/src/commands/generate/helpers.js index 9bb803d5a4a1..99d0e0d0a501 100644 --- a/packages/cli/src/commands/generate/helpers.js +++ b/packages/cli/src/commands/generate/helpers.js @@ -7,7 +7,8 @@ import { paramCase } from 'param-case' import pascalcase from 'pascalcase' import terminalLink from 'terminal-link' -import { ensurePosixPath, getConfig } from '@redwoodjs/internal' +import { getConfig } from '@redwoodjs/internal/dist/config' +import { ensurePosixPath } from '@redwoodjs/internal/dist/paths' import { errorTelemetry } from '@redwoodjs/telemetry' import { generateTemplate, getPaths, writeFilesTask } from '../../lib' diff --git a/packages/cli/src/commands/generate/page/__tests__/page.test.js b/packages/cli/src/commands/generate/page/__tests__/page.test.js index 2ea9890e6c9e..cce3fce68961 100644 --- a/packages/cli/src/commands/generate/page/__tests__/page.test.js +++ b/packages/cli/src/commands/generate/page/__tests__/page.test.js @@ -42,7 +42,7 @@ import path from 'path' // Load mocks import '../../../../lib/test' -import { ensurePosixPath } from '@redwoodjs/internal' +import { ensurePosixPath } from '@redwoodjs/internal/dist/paths' import { getPaths } from '../../../../lib' import { pathName } from '../../helpers' diff --git a/packages/cli/src/commands/generate/page/page.js b/packages/cli/src/commands/generate/page/page.js index b614f058580e..59e1c275cb4d 100644 --- a/packages/cli/src/commands/generate/page/page.js +++ b/packages/cli/src/commands/generate/page/page.js @@ -4,7 +4,8 @@ import camelcase from 'camelcase' import Listr from 'listr' import pascalcase from 'pascalcase' -import { getConfig, generate as generateTypes } from '@redwoodjs/internal' +import { getConfig } from '@redwoodjs/internal/dist/config' +import { generate as generateTypes } from '@redwoodjs/internal/dist/generate/generate' import { errorTelemetry } from '@redwoodjs/telemetry' import { diff --git a/packages/cli/src/commands/generate/scaffold/scaffold.js b/packages/cli/src/commands/generate/scaffold/scaffold.js index cc12d8a206e2..e5f99cb257d0 100644 --- a/packages/cli/src/commands/generate/scaffold/scaffold.js +++ b/packages/cli/src/commands/generate/scaffold/scaffold.js @@ -8,7 +8,8 @@ import { paramCase } from 'param-case' import pascalcase from 'pascalcase' import terminalLink from 'terminal-link' -import { getConfig, generate as generateTypes } from '@redwoodjs/internal' +import { getConfig } from '@redwoodjs/internal/dist/config' +import { generate as generateTypes } from '@redwoodjs/internal/dist/generate/generate' import { generateTemplate, diff --git a/packages/cli/src/commands/generate/sdl/__tests__/sdl.test.js b/packages/cli/src/commands/generate/sdl/__tests__/sdl.test.js index b4e6c4e06ab7..50bf79c476d7 100644 --- a/packages/cli/src/commands/generate/sdl/__tests__/sdl.test.js +++ b/packages/cli/src/commands/generate/sdl/__tests__/sdl.test.js @@ -32,7 +32,7 @@ import prompts from 'prompts' // Load mocks import '../../../../lib/test' -import { ensurePosixPath } from '@redwoodjs/internal' +import { ensurePosixPath } from '@redwoodjs/internal/dist/paths' import { getDefaultArgs } from '../../../../lib' import * as sdl from '../sdl' diff --git a/packages/cli/src/commands/generate/sdl/sdl.js b/packages/cli/src/commands/generate/sdl/sdl.js index 5cc139254ea6..4b6170216c89 100644 --- a/packages/cli/src/commands/generate/sdl/sdl.js +++ b/packages/cli/src/commands/generate/sdl/sdl.js @@ -6,7 +6,8 @@ import chalk from 'chalk' import Listr from 'listr' import terminalLink from 'terminal-link' -import { getConfig, generate as generateTypes } from '@redwoodjs/internal' +import { getConfig } from '@redwoodjs/internal/dist/config' +import { generate as generateTypes } from '@redwoodjs/internal/dist/generate/generate' import { errorTelemetry } from '@redwoodjs/telemetry' import { diff --git a/packages/cli/src/commands/prerender.js b/packages/cli/src/commands/prerender.js index 445c0ba2fdd0..259803f57946 100644 --- a/packages/cli/src/commands/prerender.js +++ b/packages/cli/src/commands/prerender.js @@ -1,16 +1,3 @@ -import fs from 'fs' -import path from 'path' - -import Listr from 'listr' -import VerboseRenderer from 'listr-verbose-renderer' - -import { getPaths } from '@redwoodjs/internal' -import { runPrerender, writePrerenderedHtmlFile } from '@redwoodjs/prerender' -import { detectPrerenderRoutes } from '@redwoodjs/prerender/detection' -import { errorTelemetry } from '@redwoodjs/telemetry' - -import c from '../lib/colors' - export const command = 'prerender' export const aliases = ['render'] export const description = 'Prerender pages of your Redwood app at build time' @@ -39,180 +26,7 @@ export const builder = (yargs) => { }) } -const mapRouterPathToHtml = (routerPath) => { - if (routerPath === '/') { - return 'web/dist/index.html' - } else { - return `web/dist${routerPath}.html` - } -} - -// This is used directly in build.js for nested ListrTasks -export const getTasks = async (dryrun, routerPathFilter = null) => { - const prerenderRoutes = detectPrerenderRoutes() - const indexHtmlPath = path.join(getPaths().web.dist, 'index.html') - if (prerenderRoutes.length === 0) { - console.log('\nSkipping prerender...') - console.log( - c.warning( - 'You have not marked any routes as `prerender` in `Routes.{js,tsx}` \n' - ) - ) - - // Don't error out - return [] - } - - if (!fs.existsSync(indexHtmlPath)) { - console.error( - 'You must run `yarn rw build web` before trying to prerender.' - ) - process.exit(1) - // TODO: Run this automatically at this point. - } - - const listrTasks = prerenderRoutes - .filter((route) => route.path) - .flatMap((routeToPrerender) => { - // Filter out routes that don't match the supplied routePathFilter - if (routerPathFilter && routeToPrerender.path !== routerPathFilter) { - return [] - } - - const outputHtmlPath = mapRouterPathToHtml(routeToPrerender.path) - - return [ - { - title: `Prerendering ${routeToPrerender.path} -> ${outputHtmlPath}`, - task: async () => { - try { - const prerenderedHtml = await runPrerender({ - routerPath: routeToPrerender.path, - }) - - if (!dryrun) { - writePrerenderedHtmlFile(outputHtmlPath, prerenderedHtml) - } - } catch (e) { - console.log() - console.log( - c.warning('You can use `yarn rw prerender --dry-run` to debug') - ) - console.log() - - console.log( - `${c.info('-'.repeat(10))} Error rendering path "${ - routeToPrerender.path - }" ${c.info('-'.repeat(10))}` - ) - - errorTelemetry(process.argv, `Error prerendering: ${e.message}`) - - console.error(c.error(e.stack)) - console.log() - - throw new Error(`Failed to render "${routeToPrerender.filePath}"`) - } - }, - }, - ] - }) - - return listrTasks -} - -const diagnosticCheck = () => { - const checks = [ - { - message: 'Duplicate React version found in web/node_modules', - failure: fs.existsSync( - path.join(getPaths().web.base, 'node_modules/react') - ), - }, - { - message: 'Duplicate react-dom version found in web/node_modules', - failure: fs.existsSync( - path.join(getPaths().web.base, 'node_modules/react-dom') - ), - }, - { - message: 'Duplicate core-js version found in web/node_modules', - failure: fs.existsSync( - path.join(getPaths().web.base, 'node_modules/core-js') - ), - }, - { - message: 'Duplicate @redwoodjs/web version found in web/node_modules', - failure: fs.existsSync( - path.join(getPaths().web.base, 'node_modules/@redwoodjs/web') - ), - }, - ] - console.log('Running diagnostic checks') - - if (checks.some((checks) => checks.failure)) { - console.error(c.error('node_modules are being duplicated in `./web` \n')) - console.log('⚠️ Issues found: ') - console.log('-'.repeat(50)) - - checks - .filter((check) => check.failure) - .forEach((check, i) => { - console.log(`${i + 1}. ${check.message}`) - }) - - console.log('-'.repeat(50)) - - console.log( - 'Diagnostic check found issues. See the Redwood Forum link below for help:' - ) - - console.log( - c.underline( - 'https://community.redwoodjs.com/search?q=duplicate%20package%20found' - ) - ) - - console.log() - - // Exit, no need to show other messages - process.exit(1) - } else { - console.log('✔ Diagnostics checks passed \n') - } -} - -export const handler = async ({ path: routerPath, dryRun, verbose }) => { - const listrTasks = await getTasks(dryRun, routerPath) - - const tasks = new Listr(listrTasks, { - renderer: verbose ? VerboseRenderer : 'default', - }) - - try { - if (dryRun) { - console.log(c.info('::: Dry run, not writing changes :::')) - } - - await tasks.run() - } catch (e) { - console.log() - await diagnosticCheck() - - console.log(c.warning('Tips:')) - console.log( - c.info( - `- This could mean that a library you're using does not support SSR.` - ) - ) - console.log( - c.info( - '- Avoid using `window` in the initial render path through your React components without checks. \n See https://redwoodjs.com/docs/prerender#prerender-utils' - ) - ) - - console.log() - - process.exit(1) - } +export const handler = async (options) => { + const { handler } = await import('./prerenderHandler.js') + return handler(options) } diff --git a/packages/cli/src/commands/prerenderHandler.js b/packages/cli/src/commands/prerenderHandler.js new file mode 100644 index 000000000000..ce2919a60ce9 --- /dev/null +++ b/packages/cli/src/commands/prerenderHandler.js @@ -0,0 +1,190 @@ +import fs from 'fs' +import path from 'path' + +import Listr from 'listr' +import VerboseRenderer from 'listr-verbose-renderer' + +import { getPaths } from '@redwoodjs/internal/dist/paths' +import { runPrerender, writePrerenderedHtmlFile } from '@redwoodjs/prerender' +import { detectPrerenderRoutes } from '@redwoodjs/prerender/detection' +import { errorTelemetry } from '@redwoodjs/telemetry' + +import c from '../lib/colors' + +// This is used directly in build.js for nested ListrTasks +export const getTasks = async (dryrun, routerPathFilter = null) => { + const prerenderRoutes = detectPrerenderRoutes() + const indexHtmlPath = path.join(getPaths().web.dist, 'index.html') + if (prerenderRoutes.length === 0) { + console.log('\nSkipping prerender...') + console.log( + c.warning( + 'You have not marked any routes as `prerender` in `Routes.{js,tsx}` \n' + ) + ) + + // Don't error out + return [] + } + + if (!fs.existsSync(indexHtmlPath)) { + console.error( + 'You must run `yarn rw build web` before trying to prerender.' + ) + process.exit(1) + // TODO: Run this automatically at this point. + } + + const listrTasks = prerenderRoutes + .filter((route) => route.path) + .flatMap((routeToPrerender) => { + // Filter out routes that don't match the supplied routePathFilter + if (routerPathFilter && routeToPrerender.path !== routerPathFilter) { + return [] + } + + const outputHtmlPath = mapRouterPathToHtml(routeToPrerender.path) + + return [ + { + title: `Prerendering ${routeToPrerender.path} -> ${outputHtmlPath}`, + task: async () => { + try { + const prerenderedHtml = await runPrerender({ + routerPath: routeToPrerender.path, + }) + + if (!dryrun) { + writePrerenderedHtmlFile(outputHtmlPath, prerenderedHtml) + } + } catch (e) { + console.log() + console.log( + c.warning('You can use `yarn rw prerender --dry-run` to debug') + ) + console.log() + + console.log( + `${c.info('-'.repeat(10))} Error rendering path "${ + routeToPrerender.path + }" ${c.info('-'.repeat(10))}` + ) + + errorTelemetry(process.argv, `Error prerendering: ${e.message}`) + + console.error(c.error(e.stack)) + console.log() + + throw new Error(`Failed to render "${routeToPrerender.filePath}"`) + } + }, + }, + ] + }) + + return listrTasks +} + +const diagnosticCheck = () => { + const checks = [ + { + message: 'Duplicate React version found in web/node_modules', + failure: fs.existsSync( + path.join(getPaths().web.base, 'node_modules/react') + ), + }, + { + message: 'Duplicate react-dom version found in web/node_modules', + failure: fs.existsSync( + path.join(getPaths().web.base, 'node_modules/react-dom') + ), + }, + { + message: 'Duplicate core-js version found in web/node_modules', + failure: fs.existsSync( + path.join(getPaths().web.base, 'node_modules/core-js') + ), + }, + { + message: 'Duplicate @redwoodjs/web version found in web/node_modules', + failure: fs.existsSync( + path.join(getPaths().web.base, 'node_modules/@redwoodjs/web') + ), + }, + ] + console.log('Running diagnostic checks') + + if (checks.some((checks) => checks.failure)) { + console.error(c.error('node_modules are being duplicated in `./web` \n')) + console.log('⚠️ Issues found: ') + console.log('-'.repeat(50)) + + checks + .filter((check) => check.failure) + .forEach((check, i) => { + console.log(`${i + 1}. ${check.message}`) + }) + + console.log('-'.repeat(50)) + + console.log( + 'Diagnostic check found issues. See the Redwood Forum link below for help:' + ) + + console.log( + c.underline( + 'https://community.redwoodjs.com/search?q=duplicate%20package%20found' + ) + ) + + console.log() + + // Exit, no need to show other messages + process.exit(1) + } else { + console.log('✔ Diagnostics checks passed \n') + } +} + +const mapRouterPathToHtml = (routerPath) => { + if (routerPath === '/') { + return 'web/dist/index.html' + } else { + return `web/dist${routerPath}.html` + } +} + +export const handler = async ({ path: routerPath, dryRun, verbose }) => { + const listrTasks = await getTasks(dryRun, routerPath) + + const tasks = new Listr(listrTasks, { + renderer: verbose ? VerboseRenderer : 'default', + }) + + try { + if (dryRun) { + console.log(c.info('::: Dry run, not writing changes :::')) + } + + await tasks.run() + } catch (e) { + console.log() + await diagnosticCheck() + + console.log(c.warning('Tips:')) + console.log( + c.info( + `- This could mean that a library you're using does not support SSR.` + ) + ) + console.log( + c.info( + '- Avoid using `window` in the initial render path through your React components without checks. \n See https://redwoodjs.com/docs/prerender#prerender-utils' + ) + ) + + console.log() + + process.exit(1) + } +} diff --git a/packages/cli/src/commands/prisma.js b/packages/cli/src/commands/prisma.js index 7b8d36e6fde9..db746dc0dbcc 100644 --- a/packages/cli/src/commands/prisma.js +++ b/packages/cli/src/commands/prisma.js @@ -1,14 +1,3 @@ -import fs from 'fs' -import path from 'path' - -import boxen from 'boxen' -import execa from 'execa' - -import { getPaths } from '@redwoodjs/internal' -import { errorTelemetry } from '@redwoodjs/telemetry' - -import c from '../lib/colors' - export const command = 'prisma [commands..]' export const description = 'Run Prisma CLI with experimental features' @@ -29,94 +18,7 @@ export const builder = (yargs) => { .version(false) } -// eslint-disable-next-line no-unused-vars -export const handler = async ({ _, $0, commands = [], ...options }) => { - const rwjsPaths = getPaths() - - // Prisma only supports '--help', but Redwood CLI supports `prisma help` - const helpIndex = commands.indexOf('help') - if (helpIndex !== -1) { - options.help = true - commands.splice(helpIndex, 1) - } - - // Automatically inject options for some commands. - const hasHelpOption = options.help || options.h - if (!hasHelpOption) { - if ( - ['generate', 'introspect', 'db', 'migrate', 'studio', 'format'].includes( - commands[0] - ) - ) { - if (!fs.existsSync(rwjsPaths.api.dbSchema)) { - console.error() - console.error(c.error('No Prisma Schema found.')) - console.error(`Redwood searched here '${rwjsPaths.api.dbSchema}'`) - console.error() - process.exit(1) - } - options.schema = `${rwjsPaths.api.dbSchema}` - - if (['seed', 'diff'].includes(commands[1])) { - delete options.schema - } - } - } - - // Convert command and options into a string that's run via execa - const args = commands - for (const [name, value] of Object.entries(options)) { - // Allow both long and short form commands, e.g. --name and -n - args.push(name.length > 1 ? `--${name}` : `-${name}`) - if (typeof value !== 'boolean') { - // Make sure options that take multiple quoted words - // like `-n "create user"` are passed to prisma with quotes. - value.split(' ').length > 1 ? args.push(`"${value}"`) : args.push(value) - } - } - - console.log() - console.log(c.green('Running Prisma CLI...')) - console.log(c.underline('$ yarn prisma ' + args.join(' '))) - console.log() - - try { - execa.sync( - `"${path.join(rwjsPaths.base, 'node_modules/.bin/prisma')}"`, - args, - { - shell: true, - cwd: rwjsPaths.base, - stdio: 'inherit', - cleanup: true, - } - ) - - if (hasHelpOption || commands.length === 0) { - printWrapInfo() - } - } catch (e) { - errorTelemetry(process.argv, `Error generating prisma client: ${e.message}`) - process.exit(e?.exitCode || 1) - } -} - -const printWrapInfo = () => { - const message = [ - c.bold('Redwood CLI wraps Prisma CLI'), - '', - 'Use `yarn rw prisma` to automatically pass `--schema` and `--preview-feature` options.', - 'Use `yarn prisma` to skip Redwood CLI automatic options.', - '', - 'Find more information in our docs:', - c.underline('https://redwoodjs.com/docs/cli-commands#prisma'), - ] - - console.log( - boxen(message.join('\n'), { - padding: { top: 0, bottom: 0, right: 1, left: 1 }, - margin: 1, - borderColor: 'gray', - }) - ) +export const handler = async (options) => { + const { handler } = await import('./prismaHandler.js') + return handler(options) } diff --git a/packages/cli/src/commands/prismaHandler.js b/packages/cli/src/commands/prismaHandler.js new file mode 100644 index 000000000000..cf388c8436a7 --- /dev/null +++ b/packages/cli/src/commands/prismaHandler.js @@ -0,0 +1,102 @@ +import fs from 'fs' +import path from 'path' + +import boxen from 'boxen' +import execa from 'execa' + +import { errorTelemetry } from '@redwoodjs/telemetry' + +import c from '../lib/colors' +import { getPaths } from '../lib/index' + +// eslint-disable-next-line no-unused-vars +export const handler = async ({ _, $0, commands = [], ...options }) => { + const rwjsPaths = getPaths() + + // Prisma only supports '--help', but Redwood CLI supports `prisma help` + const helpIndex = commands.indexOf('help') + if (helpIndex !== -1) { + options.help = true + commands.splice(helpIndex, 1) + } + + // Automatically inject options for some commands. + const hasHelpOption = options.help || options.h + if (!hasHelpOption) { + if ( + ['generate', 'introspect', 'db', 'migrate', 'studio', 'format'].includes( + commands[0] + ) + ) { + if (!fs.existsSync(rwjsPaths.api.dbSchema)) { + console.error() + console.error(c.error('No Prisma Schema found.')) + console.error(`Redwood searched here '${rwjsPaths.api.dbSchema}'`) + console.error() + process.exit(1) + } + options.schema = `${rwjsPaths.api.dbSchema}` + + if (['seed', 'diff'].includes(commands[1])) { + delete options.schema + } + } + } + + // Convert command and options into a string that's run via execa + const args = commands + for (const [name, value] of Object.entries(options)) { + // Allow both long and short form commands, e.g. --name and -n + args.push(name.length > 1 ? `--${name}` : `-${name}`) + if (typeof value !== 'boolean') { + // Make sure options that take multiple quoted words + // like `-n "create user"` are passed to prisma with quotes. + value.split(' ').length > 1 ? args.push(`"${value}"`) : args.push(value) + } + } + + console.log() + console.log(c.green('Running Prisma CLI...')) + console.log(c.underline('$ yarn prisma ' + args.join(' '))) + console.log() + + try { + execa.sync( + `"${path.join(rwjsPaths.base, 'node_modules/.bin/prisma')}"`, + args, + { + shell: true, + cwd: rwjsPaths.base, + stdio: 'inherit', + cleanup: true, + } + ) + + if (hasHelpOption || commands.length === 0) { + printWrapInfo() + } + } catch (e) { + errorTelemetry(process.argv, `Error generating prisma client: ${e.message}`) + process.exit(e?.exitCode || 1) + } +} + +const printWrapInfo = () => { + const message = [ + c.bold('Redwood CLI wraps Prisma CLI'), + '', + 'Use `yarn rw prisma` to automatically pass `--schema` and `--preview-feature` options.', + 'Use `yarn prisma` to skip Redwood CLI automatic options.', + '', + 'Find more information in our docs:', + c.underline('https://redwoodjs.com/docs/cli-commands#prisma'), + ] + + console.log( + boxen(message.join('\n'), { + padding: { top: 0, bottom: 0, right: 1, left: 1 }, + margin: 1, + borderColor: 'gray', + }) + ) +} diff --git a/packages/cli/src/commands/serve.js b/packages/cli/src/commands/serve.js index ab13b9d88090..aac364daddba 100644 --- a/packages/cli/src/commands/serve.js +++ b/packages/cli/src/commands/serve.js @@ -11,8 +11,8 @@ import { webServerHandler, bothServerHandler, } from '@redwoodjs/api-server' -import { getPaths } from '@redwoodjs/internal' +import { getPaths } from '../lib' import c from '../lib/colors' export const command = 'serve [side]' diff --git a/packages/cli/src/commands/setup/auth/__tests__/addAuthConfigToApp.test.js b/packages/cli/src/commands/setup/auth/__tests__/addAuthConfigToApp.test.js index 6b0dfb0b10c3..bd0e5af5a5a3 100644 --- a/packages/cli/src/commands/setup/auth/__tests__/addAuthConfigToApp.test.js +++ b/packages/cli/src/commands/setup/auth/__tests__/addAuthConfigToApp.test.js @@ -25,6 +25,10 @@ jest.mock('../../../../lib', () => { } }) +jest.mock('../../../../lib/project', () => ({ + isTypeScriptProject: () => false, +})) + // This function checks output matches const writeFileSyncSpy = jest.fn((_, content) => { // Line breaks cause an issue on windows snapshots diff --git a/packages/cli/src/commands/setup/auth/__tests__/authHandler.test.js b/packages/cli/src/commands/setup/auth/__tests__/authHandler.test.js index d1907cd79a5a..6d1ba6b72a10 100644 --- a/packages/cli/src/commands/setup/auth/__tests__/authHandler.test.js +++ b/packages/cli/src/commands/setup/auth/__tests__/authHandler.test.js @@ -9,6 +9,9 @@ jest.mock('../../../../lib', () => ({ web: { src: '' }, }), })) +jest.mock('../../../../lib/project', () => ({ + isTypeScriptProject: () => false, +})) jest.mock('execa') jest.mock('listr') diff --git a/packages/cli/src/commands/setup/auth/auth.js b/packages/cli/src/commands/setup/auth/auth.js index d775972df3a2..59786f83dd82 100644 --- a/packages/cli/src/commands/setup/auth/auth.js +++ b/packages/cli/src/commands/setup/auth/auth.js @@ -6,7 +6,6 @@ import Listr from 'listr' import prompts from 'prompts' import terminalLink from 'terminal-link' -import { getProject } from '@redwoodjs/structure' import { errorTelemetry } from '@redwoodjs/telemetry' import { @@ -17,17 +16,18 @@ import { graphFunctionDoesExist, } from '../../../lib' import c from '../../../lib/colors' +import { isTypeScriptProject } from '../../../lib/project' const AUTH_PROVIDER_IMPORT = `import { AuthProvider } from '@redwoodjs/auth'` const OUTPUT_PATHS = { auth: path.join( getPaths().api.lib, - getProject().isTypeScriptProject ? 'auth.ts' : 'auth.js' + isTypeScriptProject() ? 'auth.ts' : 'auth.js' ), function: path.join( getPaths().api.functions, - getProject().isTypeScriptProject ? 'auth.ts' : 'auth.js' + isTypeScriptProject() ? 'auth.ts' : 'auth.js' ), } @@ -220,7 +220,7 @@ export const files = ({ provider, webAuthn }) => { OUTPUT_PATHS[path.basename(templateFile).split('.')[1]] const content = fs.readFileSync(templateFile).toString() files = Object.assign(files, { - [outputPath]: getProject().isTypeScriptProject + [outputPath]: isTypeScriptProject() ? content : transformTSToJS(outputPath, content), }) @@ -233,7 +233,7 @@ export const files = ({ provider, webAuthn }) => { if (Object.keys(files).length === 0) { const content = fs.readFileSync(templates.base[0]).toString() files = { - [OUTPUT_PATHS.auth]: getProject().isTypeScriptProject + [OUTPUT_PATHS.auth]: isTypeScriptProject() ? content : transformTSToJS(templates.base[0], content), } diff --git a/packages/cli/src/commands/setup/auth/providers/dbAuth.js b/packages/cli/src/commands/setup/auth/providers/dbAuth.js index eeaef15a64e8..b1b02279c50a 100644 --- a/packages/cli/src/commands/setup/auth/providers/dbAuth.js +++ b/packages/cli/src/commands/setup/auth/providers/dbAuth.js @@ -3,7 +3,7 @@ import path from 'path' import password from 'secure-random-password' -import { getPaths } from '@redwoodjs/internal' +import { getPaths } from '@redwoodjs/internal/dist/paths' import c from '../../../../lib/colors' diff --git a/packages/cli/src/commands/setup/auth/providers/dbAuth.webAuthn.js b/packages/cli/src/commands/setup/auth/providers/dbAuth.webAuthn.js index 0c1bd8fa1b9e..8264dbfd00d9 100644 --- a/packages/cli/src/commands/setup/auth/providers/dbAuth.webAuthn.js +++ b/packages/cli/src/commands/setup/auth/providers/dbAuth.webAuthn.js @@ -1,6 +1,6 @@ import path from 'path' -import { getPaths } from '@redwoodjs/internal' +import { getPaths } from '@redwoodjs/internal/dist/paths' import c from '../../../../lib/colors' diff --git a/packages/cli/src/commands/setup/deploy/__tests__/deploy.test.js b/packages/cli/src/commands/setup/deploy/__tests__/deploy.test.js deleted file mode 100644 index 50d5342cc991..000000000000 --- a/packages/cli/src/commands/setup/deploy/__tests__/deploy.test.js +++ /dev/null @@ -1,8 +0,0 @@ -global.__dirname = __dirname -// import { loadGeneratorFixture } from 'src/lib/test' - -// import * as auth from '../auth' - -test('true', () => { - expect(true).toEqual(true) -}) diff --git a/packages/cli/src/commands/setup/graphiql/__tests__/graphiqlHandler.test.js b/packages/cli/src/commands/setup/graphiql/__tests__/graphiqlHandler.test.js index c6d43f1665b5..ada9a6f2edf0 100644 --- a/packages/cli/src/commands/setup/graphiql/__tests__/graphiqlHandler.test.js +++ b/packages/cli/src/commands/setup/graphiql/__tests__/graphiqlHandler.test.js @@ -2,7 +2,7 @@ global.__dirname = __dirname import '../../../../lib/mockTelemetry' -jest.mock('@redwoodjs/internal', () => { +jest.mock('@redwoodjs/internal/dist/build/babel/api', () => { return { registerApiSideBabelHook: () => null, } @@ -13,6 +13,9 @@ jest.mock('../../../../lib', () => ({ }), existsAnyExtensionSync: () => false, })) +jest.mock('../../../../lib/project', () => ({ + isTypeScriptProject: () => false, +})) jest.mock('listr') import chalk from 'chalk' diff --git a/packages/cli/src/commands/setup/graphiql/graphiql.js b/packages/cli/src/commands/setup/graphiql/graphiql.js index 0699ad663dc3..b08a0a0ef33a 100644 --- a/packages/cli/src/commands/setup/graphiql/graphiql.js +++ b/packages/cli/src/commands/setup/graphiql/graphiql.js @@ -7,8 +7,7 @@ import Listr from 'listr' import terminalLink from 'terminal-link' import { v4 as uuidv4 } from 'uuid' -import { registerApiSideBabelHook } from '@redwoodjs/internal' -import { getProject } from '@redwoodjs/structure' +import { registerApiSideBabelHook } from '@redwoodjs/internal/dist/build/babel/api' import { errorTelemetry } from '@redwoodjs/telemetry' import { @@ -22,6 +21,7 @@ import { graphFunctionDoesExist, } from '../../../lib' import c from '../../../lib/colors' +import { isTypeScriptProject } from '../../../lib/project' // tests if id, which is always a string from cli, is actually a number or uuid const isNumeric = (id) => { @@ -141,7 +141,7 @@ const addHeaderOption = () => { export const getOutputPath = () => { return path.join( getPaths().api.lib, - getProject().isTypeScriptProject + isTypeScriptProject() ? 'generateGraphiQLHeader.ts' : 'generateGraphiQLHeader.js' ) @@ -238,7 +238,7 @@ export const handler = async ({ provider, id, token, expiry, view }) => { return writeFilesTask( { - [outputPath]: getProject().isTypeScriptProject + [outputPath]: isTypeScriptProject() ? content : transformTSToJS(outputPath, content), }, diff --git a/packages/cli/src/commands/storybook.js b/packages/cli/src/commands/storybook.js index 18cc70de181f..05c7e3e83363 100644 --- a/packages/cli/src/commands/storybook.js +++ b/packages/cli/src/commands/storybook.js @@ -3,7 +3,7 @@ import path from 'path' import execa from 'execa' import terminalLink from 'terminal-link' -import { getPaths } from '@redwoodjs/internal' +import { getPaths } from '@redwoodjs/internal/dist/paths' import { errorTelemetry } from '@redwoodjs/telemetry' import c from '../lib/colors' diff --git a/packages/cli/src/commands/test.js b/packages/cli/src/commands/test.js index ac2fc3ea9c4a..dcdde9a22dc5 100644 --- a/packages/cli/src/commands/test.js +++ b/packages/cli/src/commands/test.js @@ -1,55 +1,7 @@ -import fs from 'fs' -import path from 'path' - -import execa from 'execa' import terminalLink from 'terminal-link' -import { ensurePosixPath } from '@redwoodjs/internal' -import { getProject } from '@redwoodjs/structure' -import { errorTelemetry, timedTelemetry } from '@redwoodjs/telemetry' - -import { getPaths } from '../lib' import c from '../lib/colors' - -// https://github.com/facebook/create-react-app/blob/cbad256a4aacfc3084be7ccf91aad87899c63564/packages/react-scripts/scripts/test.js#L39 -function isInGitRepository() { - try { - execa.commandSync('git rev-parse --is-inside-work-tree') - return true - } catch (e) { - return false - } -} - -function isInMercurialRepository() { - try { - execa.commandSync('hg --cwd . root') - return true - } catch (e) { - return false - } -} - -function isJestConfigFile(sides) { - for (let side of sides) { - try { - if (sides.includes(side)) { - if (!fs.existsSync(path.join(side, 'jest.config.js'))) { - console.error( - c.error( - `\nError: Missing Jest config file ${side}/jest.config.js` + - '\nTo add this file, run `npx @redwoodjs/codemods update-jest-config`\n' - ) - ) - throw new Error(`Error: Jest config file not found in ${side} side`) - } - } - } catch (e) { - errorTelemetry(process.argv, e.message) - process.exit(e?.exitCode || 1) - } - } -} +import { sides } from '../lib/project' export const command = 'test [filter..]' export const description = 'Run Jest tests. Defaults to watch mode' @@ -57,7 +9,7 @@ export const builder = (yargs) => { yargs .strict(false) // so that we can forward arguments to jest .positional('filter', { - default: getProject().sides, + default: sides(), description: 'Which side(s) to test, and/or a regular expression to match against your test files to filter by', type: 'array', @@ -90,111 +42,7 @@ export const builder = (yargs) => { ) } -export const handler = async ({ - filter: filterParams = [], - watch = true, - collectCoverage = false, - dbPush = true, - ...others -}) => { - const rwjsPaths = getPaths() - const forwardJestFlags = Object.keys(others).flatMap((flagName) => { - if ( - ['watch', 'collect-coverage', 'db-push', '$0', '_'].includes(flagName) - ) { - // filter out flags meant for the rw test command only - return [] - } else { - // and forward on the other flags - const flagValue = others[flagName] - - if (Array.isArray(flagValue)) { - // jest does not collapse flags e.g. --coverageReporters=html --coverageReporters=text - // so we pass it on. Yargs collapses these flags into an array of values - return flagValue.flatMap((val) => { - return [flagName.length > 1 ? `--${flagName}` : `-${flagName}`, val] - }) - } else { - return [ - flagName.length > 1 ? `--${flagName}` : `-${flagName}`, - flagValue, - ] - } - } - }) - - // Only the side params - const sides = filterParams.filter((filterString) => - getProject().sides.includes(filterString) - ) - - // All the other params, apart from sides - const jestFilterArgs = [ - ...filterParams.filter( - (filterString) => !getProject().sides.includes(filterString) - ), - ] - - const jestArgs = [ - ...jestFilterArgs, - ...forwardJestFlags, - collectCoverage ? '--collectCoverage' : null, - '--passWithNoTests', - ].filter((flagOrValue) => flagOrValue !== null) // Filter out nulls, not booleans because user may have passed a --something false flag - - // If the user wants to watch, set the proper watch flag based on what kind of repo this is - // because of https://github.com/facebook/create-react-app/issues/5210 - if (watch && !process.env.CI && !collectCoverage) { - const hasSourceControl = isInGitRepository() || isInMercurialRepository() - jestArgs.push(hasSourceControl ? '--watch' : '--watchAll') - } - - // if no sides declared with yargs, default to all sides - if (!sides.length) { - getProject().sides.forEach((side) => sides.push(side)) - } - - if (sides.length > 0) { - jestArgs.push('--projects', ...sides) - } - - //checking if Jest config files exists in each of the sides - isJestConfigFile(sides) - - try { - const cacheDirDb = `file:${ensurePosixPath( - rwjsPaths.generated.base - )}/test.db` - const DATABASE_URL = process.env.TEST_DATABASE_URL || cacheDirDb - - if (sides.includes('api') && !dbPush) { - // @NOTE - // DB push code now lives in packages/testing/config/jest/api/jest-preset.js - process.env.SKIP_DB_PUSH = '1' - } - - // **NOTE** There is no official way to run Jest programmatically, - // so we're running it via execa, since `jest.run()` is a bit unstable. - // https://github.com/facebook/jest/issues/5048 - const runCommand = async () => { - await execa('yarn jest', jestArgs, { - cwd: rwjsPaths.base, - shell: true, - stdio: 'inherit', - env: { DATABASE_URL }, - }) - } - - if (watch) { - await runCommand() - } else { - await timedTelemetry(process.argv, { type: 'test' }, async () => { - await runCommand() - }) - } - } catch (e) { - // Errors already shown from execa inherited stderr - errorTelemetry(process.argv, e.message) - process.exit(e?.exitCode || 1) - } +export const handler = async (options) => { + const { handler } = await import('./testHandler') + return handler(options) } diff --git a/packages/cli/src/commands/testHandler.js b/packages/cli/src/commands/testHandler.js new file mode 100644 index 000000000000..548fdde17e26 --- /dev/null +++ b/packages/cli/src/commands/testHandler.js @@ -0,0 +1,160 @@ +import fs from 'fs' +import path from 'path' + +import execa from 'execa' + +import { ensurePosixPath } from '@redwoodjs/internal/dist/paths' +import { errorTelemetry, timedTelemetry } from '@redwoodjs/telemetry' + +import { getPaths } from '../lib' +import c from '../lib/colors' +import * as project from '../lib/project' + +// https://github.com/facebook/create-react-app/blob/cbad256a4aacfc3084be7ccf91aad87899c63564/packages/react-scripts/scripts/test.js#L39 +function isInGitRepository() { + try { + execa.commandSync('git rev-parse --is-inside-work-tree') + return true + } catch (e) { + return false + } +} + +function isInMercurialRepository() { + try { + execa.commandSync('hg --cwd . root') + return true + } catch (e) { + return false + } +} + +function isJestConfigFile(sides) { + for (let side of sides) { + try { + if (sides.includes(side)) { + if (!fs.existsSync(path.join(side, 'jest.config.js'))) { + console.error( + c.error( + `\nError: Missing Jest config file ${side}/jest.config.js` + + '\nTo add this file, run `npx @redwoodjs/codemods update-jest-config`\n' + ) + ) + throw new Error(`Error: Jest config file not found in ${side} side`) + } + } + } catch (e) { + errorTelemetry(process.argv, e.message) + process.exit(e?.exitCode || 1) + } + } +} + +export const handler = async ({ + filter: filterParams = [], + watch = true, + collectCoverage = false, + dbPush = true, + ...others +}) => { + const rwjsPaths = getPaths() + const forwardJestFlags = Object.keys(others).flatMap((flagName) => { + if ( + ['watch', 'collect-coverage', 'db-push', '$0', '_'].includes(flagName) + ) { + // filter out flags meant for the rw test command only + return [] + } else { + // and forward on the other flags + const flagValue = others[flagName] + + if (Array.isArray(flagValue)) { + // jest does not collapse flags e.g. --coverageReporters=html --coverageReporters=text + // so we pass it on. Yargs collapses these flags into an array of values + return flagValue.flatMap((val) => { + return [flagName.length > 1 ? `--${flagName}` : `-${flagName}`, val] + }) + } else { + return [ + flagName.length > 1 ? `--${flagName}` : `-${flagName}`, + flagValue, + ] + } + } + }) + + // Only the side params + const sides = filterParams.filter((filterString) => + project.sides().includes(filterString) + ) + + // All the other params, apart from sides + const jestFilterArgs = [ + ...filterParams.filter( + (filterString) => !project.sides().includes(filterString) + ), + ] + + const jestArgs = [ + ...jestFilterArgs, + ...forwardJestFlags, + collectCoverage ? '--collectCoverage' : null, + '--passWithNoTests', + ].filter((flagOrValue) => flagOrValue !== null) // Filter out nulls, not booleans because user may have passed a --something false flag + + // If the user wants to watch, set the proper watch flag based on what kind of repo this is + // because of https://github.com/facebook/create-react-app/issues/5210 + if (watch && !process.env.CI && !collectCoverage) { + const hasSourceControl = isInGitRepository() || isInMercurialRepository() + jestArgs.push(hasSourceControl ? '--watch' : '--watchAll') + } + + // if no sides declared with yargs, default to all sides + if (!sides.length) { + project.sides().forEach((side) => sides.push(side)) + } + + if (sides.length > 0) { + jestArgs.push('--projects', ...sides) + } + + //checking if Jest config files exists in each of the sides + isJestConfigFile(sides) + + try { + const cacheDirDb = `file:${ensurePosixPath( + rwjsPaths.generated.base + )}/test.db` + const DATABASE_URL = process.env.TEST_DATABASE_URL || cacheDirDb + + if (sides.includes('api') && !dbPush) { + // @NOTE + // DB push code now lives in packages/testing/config/jest/api/jest-preset.js + process.env.SKIP_DB_PUSH = '1' + } + + // **NOTE** There is no official way to run Jest programmatically, + // so we're running it via execa, since `jest.run()` is a bit unstable. + // https://github.com/facebook/jest/issues/5048 + const runCommand = async () => { + await execa('yarn jest', jestArgs, { + cwd: rwjsPaths.base, + shell: true, + stdio: 'inherit', + env: { DATABASE_URL }, + }) + } + + if (watch) { + await runCommand() + } else { + await timedTelemetry(process.argv, { type: 'test' }, async () => { + await runCommand() + }) + } + } catch (e) { + // Errors already shown from execa inherited stderr + errorTelemetry(process.argv, e.message) + process.exit(e?.exitCode || 1) + } +} diff --git a/packages/cli/src/commands/ts-to-js.js b/packages/cli/src/commands/ts-to-js.js index 3929fa3dd6ac..4f01a9259a89 100644 --- a/packages/cli/src/commands/ts-to-js.js +++ b/packages/cli/src/commands/ts-to-js.js @@ -1,8 +1,8 @@ +import { getPaths } from '@redwoodjs/internal/dist/paths' import { - getPaths, convertTsProjectToJs, convertTsScriptsToJs, -} from '@redwoodjs/internal' +} from '@redwoodjs/internal/dist/ts2js' export const command = 'ts-to-js' export const description = 'Convert a TypeScript project to JavaScript' diff --git a/packages/cli/src/commands/type-check.js b/packages/cli/src/commands/type-check.js index fc5eb91b415e..4efec3af8bd9 100644 --- a/packages/cli/src/commands/type-check.js +++ b/packages/cli/src/commands/type-check.js @@ -1,17 +1,6 @@ -import path from 'path' - -import concurrently from 'concurrently' -import execa from 'execa' -import Listr from 'listr' import terminalLink from 'terminal-link' -import { getProject } from '@redwoodjs/structure' -import { errorTelemetry } from '@redwoodjs/telemetry' - -import { getCmdMajorVersion } from '../commands/upgrade' -import { getPaths } from '../lib' -import c from '../lib/colors' -import { generatePrismaClient } from '../lib/generatePrismaClient' +import { sides } from '../lib/project' export const command = 'type-check [sides..]' export const aliases = ['tsc', 'tc'] @@ -20,7 +9,7 @@ export const builder = (yargs) => { yargs .strict(false) // so that we can forward arguments to tsc .positional('sides', { - default: getProject().sides, + default: sides(), description: 'Which side(s) to run a typecheck on', type: 'array', }) @@ -48,70 +37,7 @@ export const builder = (yargs) => { ) } -export const handler = async ({ sides, verbose, prisma, generate }) => { - /** - * Check types for the project directory : [web, api] - */ - - const typeCheck = async () => { - let conclusiveExitCode = 0 - - const yarnVersion = await getCmdMajorVersion('yarn') - - const tscForAllSides = sides.map((side) => { - const projectDir = path.join(getPaths().base, side) - // -s flag to suppress error output from yarn. For example yarn doc link on non-zero status. - // Since it'll be printed anyways after the whole execution. - return { - cwd: projectDir, - command: `yarn ${ - yarnVersion > 1 ? '' : '-s' - } tsc --noEmit --skipLibCheck`, - } - }) - - const { result } = concurrently(tscForAllSides, { - group: true, - raw: true, - }) - try { - await result - } catch (err) { - if (err.length) { - // Non-null exit codes - const exitCodes = err.map((e) => e?.exitCode).filter(Boolean) - conclusiveExitCode = Math.max(...exitCodes) - } - } - - return conclusiveExitCode - } - - try { - if (generate && prisma) { - await generatePrismaClient({ - verbose: verbose, - schema: getPaths().api.dbSchema, - }) - } - if (generate) { - await new Listr([ - { - title: 'Generating types', - task: () => - execa('yarn rw-gen', { - shell: true, - stdio: verbose ? 'inherit' : 'ignore', - }), - }, - ]).run() - } - - const exitCode = await typeCheck() - exitCode > 0 && process.exit(exitCode) - } catch (e) { - errorTelemetry(process.argv, e.message) - console.log(c.error(e.message)) - process.exit(e?.exitCode || 1) - } +export const handler = async (options) => { + const { handler } = await import('./type-checkHandler.js') + return handler(options) } diff --git a/packages/cli/src/commands/type-checkHandler.js b/packages/cli/src/commands/type-checkHandler.js new file mode 100644 index 000000000000..01a9c743852e --- /dev/null +++ b/packages/cli/src/commands/type-checkHandler.js @@ -0,0 +1,80 @@ +import path from 'path' + +import concurrently from 'concurrently' +import execa from 'execa' +import Listr from 'listr' + +import { errorTelemetry } from '@redwoodjs/telemetry' + +import { getCmdMajorVersion } from '../commands/upgrade' +import { getPaths } from '../lib' +import c from '../lib/colors' +import { generatePrismaClient } from '../lib/generatePrismaClient' + +export const handler = async ({ sides, verbose, prisma, generate }) => { + /** + * Check types for the project directory : [web, api] + */ + + const typeCheck = async () => { + let conclusiveExitCode = 0 + + const yarnVersion = await getCmdMajorVersion('yarn') + + const tscForAllSides = sides.map((side) => { + const projectDir = path.join(getPaths().base, side) + // -s flag to suppress error output from yarn. For example yarn doc link on non-zero status. + // Since it'll be printed anyways after the whole execution. + return { + cwd: projectDir, + command: `yarn ${ + yarnVersion > 1 ? '' : '-s' + } tsc --noEmit --skipLibCheck`, + } + }) + + const { result } = concurrently(tscForAllSides, { + group: true, + raw: true, + }) + try { + await result + } catch (err) { + if (err.length) { + // Non-null exit codes + const exitCodes = err.map((e) => e?.exitCode).filter(Boolean) + conclusiveExitCode = Math.max(...exitCodes) + } + } + + return conclusiveExitCode + } + + try { + if (generate && prisma) { + await generatePrismaClient({ + verbose: verbose, + schema: getPaths().api.dbSchema, + }) + } + if (generate) { + await new Listr([ + { + title: 'Generating types', + task: () => + execa('yarn rw-gen', { + shell: true, + stdio: verbose ? 'inherit' : 'ignore', + }), + }, + ]).run() + } + + const exitCode = await typeCheck() + exitCode > 0 && process.exit(exitCode) + } catch (e) { + errorTelemetry(process.argv, e.message) + console.log(c.error(e.message)) + process.exit(e?.exitCode || 1) + } +} diff --git a/packages/cli/src/index.js b/packages/cli/src/index.js index de523f84f76f..76831c21adde 100644 --- a/packages/cli/src/index.js +++ b/packages/cli/src/index.js @@ -5,9 +5,32 @@ import path from 'path' import { config } from 'dotenv-defaults' import yargs from 'yargs' -import { getPaths, getConfigPath } from '@redwoodjs/internal' +import { getConfigPath } from '@redwoodjs/internal/dist/paths' import { telemetryMiddleware } from '@redwoodjs/telemetry' +import * as buildCommand from './commands/build' +import * as checkCommand from './commands/check' +import * as consoleCommand from './commands/console' +import * as dataMigrateCommand from './commands/data-migrate' +import * as deployCommand from './commands/deploy' +import * as destroyCommand from './commands/destroy' +import * as devCommand from './commands/dev' +import * as execCommand from './commands/exec' +import * as generateCommand from './commands/generate' +import * as infoCommand from './commands/info' +import * as lintCommand from './commands/lint' +import * as prerenderCommand from './commands/prerender' +import * as prismaCommand from './commands/prisma' +import * as recordCommand from './commands/record' +import * as serveCommand from './commands/serve' +import * as setupCommand from './commands/setup' +import * as storybookCommand from './commands/storybook' +import * as testCommand from './commands/test' +import * as tstojsCommand from './commands/ts-to-js' +import * as typeCheckCommand from './commands/type-check' +import * as upgradeCommand from './commands/upgrade' +import { getPaths } from './lib' + /** * The current working directory can be set via: * 1. A `--cwd` option @@ -71,7 +94,27 @@ yargs .option('cwd', { describe: 'Working directory to use (where `redwood.toml` is located.)', }) - .commandDir('./commands') + .command(buildCommand) + .command(checkCommand) + .command(consoleCommand) + .command(dataMigrateCommand) + .command(deployCommand) + .command(destroyCommand) + .command(devCommand) + .command(execCommand) + .command(generateCommand) + .command(infoCommand) + .command(lintCommand) + .command(prerenderCommand) + .command(prismaCommand) + .command(recordCommand) + .command(serveCommand) + .command(setupCommand) + .command(storybookCommand) + .command(testCommand) + .command(tstojsCommand) + .command(typeCheckCommand) + .command(upgradeCommand) .example( 'yarn rw g page home /', "\"Create a page component named 'Home' at path '/'\"" diff --git a/packages/cli/src/lib/__tests__/index.test.js b/packages/cli/src/lib/__tests__/index.test.js index 01aaaa29e1ba..ab156896ea1e 100644 --- a/packages/cli/src/lib/__tests__/index.test.js +++ b/packages/cli/src/lib/__tests__/index.test.js @@ -1,8 +1,8 @@ global.__dirname = __dirname -jest.mock('@redwoodjs/internal', () => { +jest.mock('@redwoodjs/internal/dist/paths', () => { const path = require('path') return { - ...jest.requireActual('@redwoodjs/internal'), + ...jest.requireActual('@redwoodjs/internal/dist/paths'), getPaths: () => { const BASE_PATH = path.join(global.__dirname, 'fixtures') return { diff --git a/packages/cli/src/lib/__tests__/schemaHelpers.test.js b/packages/cli/src/lib/__tests__/schemaHelpers.test.js index c7d6557e66a2..c157d9233a8f 100644 --- a/packages/cli/src/lib/__tests__/schemaHelpers.test.js +++ b/packages/cli/src/lib/__tests__/schemaHelpers.test.js @@ -1,8 +1,8 @@ global.__dirname = __dirname -jest.mock('@redwoodjs/internal', () => { +jest.mock('@redwoodjs/internal/dist/paths', () => { const path = require('path') return { - ...jest.requireActual('@redwoodjs/internal'), + ...jest.requireActual('@redwoodjs/internal/dist/paths'), getPaths: () => { const BASE_PATH = path.join(global.__dirname, 'fixtures') return { diff --git a/packages/cli/src/lib/index.js b/packages/cli/src/lib/index.js index 1b0c6b17f7f4..d33cb44c71f0 100644 --- a/packages/cli/src/lib/index.js +++ b/packages/cli/src/lib/index.js @@ -8,16 +8,17 @@ import decamelize from 'decamelize' import execa from 'execa' import Listr from 'listr' import VerboseRenderer from 'listr-verbose-renderer' +import { memoize } from 'lodash' import lodash from 'lodash/string' import { paramCase } from 'param-case' import pascalcase from 'pascalcase' import { format } from 'prettier' +import { getConfig as getRedwoodConfig } from '@redwoodjs/internal/dist/config' import { getPaths as getRedwoodPaths, - getConfig as getRedwoodConfig, resolveFile, -} from '@redwoodjs/internal' +} from '@redwoodjs/internal/dist/paths' import c from './colors' import { pluralize, singularize } from './rwPluralize' @@ -183,7 +184,7 @@ export const bytes = (contents) => Buffer.byteLength(contents, 'utf8') * This wraps the core version of getPaths into something that catches the exception * and displays a helpful error message. */ -export const getPaths = () => { +export const _getPaths = () => { try { return getRedwoodPaths() } catch (e) { @@ -191,6 +192,7 @@ export const getPaths = () => { process.exit(1) } } +export const getPaths = memoize(_getPaths) export const getGraphqlPath = () => resolveFile(path.join(getPaths().api.functions, 'graphql')) diff --git a/packages/cli/src/lib/project.js b/packages/cli/src/lib/project.js new file mode 100644 index 000000000000..deb1d019a7c6 --- /dev/null +++ b/packages/cli/src/lib/project.js @@ -0,0 +1,25 @@ +import fs from 'fs' +import path from 'path' + +import { getPaths } from '.' + +export const isTypeScriptProject = () => { + const paths = getPaths() + return ( + fs.existsSync(path.join(paths.web.base, 'tsconfig.json')) || + fs.existsSync(path.join(paths.api.base, 'tsconfig.json')) + ) +} + +export const sides = () => { + const paths = getPaths() + + let sides = [] + if (fs.existsSync(path.join(paths.web.base, 'package.json'))) { + sides = [...sides, 'web'] + } + if (fs.existsSync(path.join(paths.api.base, 'package.json'))) { + sides = [...sides, 'api'] + } + return sides +} diff --git a/packages/cli/src/lib/test.js b/packages/cli/src/lib/test.js index 79cdfac0668b..0495f54229ff 100644 --- a/packages/cli/src/lib/test.js +++ b/packages/cli/src/lib/test.js @@ -13,11 +13,16 @@ import path from 'path' import './mockTelemetry' -jest.mock('@redwoodjs/internal', () => { - const path = require('path') +jest.mock('@redwoodjs/internal/dist/generate/generate', () => { return { - ...jest.requireActual('@redwoodjs/internal'), generate: () => {}, + } +}) + +jest.mock('@redwoodjs/internal/dist/paths', () => { + const path = require('path') + return { + ...jest.requireActual('@redwoodjs/internal/dist/paths'), getPaths: () => { const BASE_PATH = '/path/to/project' return { @@ -56,6 +61,11 @@ jest.mock('@redwoodjs/internal', () => { } }) +jest.mock('./project', () => ({ + isTypeScriptProject: () => false, + sides: () => ['web', 'api'], +})) + global.__prettierPath = path.resolve( __dirname, './__tests__/fixtures/prettier.config.js' diff --git a/packages/cli/src/middleware/checkForBabelConfig.js b/packages/cli/src/middleware/checkForBabelConfig.js index cfb013622d9b..dbe922e5fe1a 100644 --- a/packages/cli/src/middleware/checkForBabelConfig.js +++ b/packages/cli/src/middleware/checkForBabelConfig.js @@ -1,8 +1,7 @@ import boxen from 'boxen' import fg from 'fast-glob' -import { getPaths } from '@redwoodjs/internal' - +import { getPaths } from '../lib' import c from '../lib/colors' const isUsingBabelRc = () => { @@ -13,9 +12,8 @@ const isUsingBabelRc = () => { }).length > 0 ) } -const BABEL_SETTINGS_LINK = c.warning( +const BABEL_SETTINGS_LINK = 'https://redwoodjs.com/docs/project-configuration-dev-test-build' -) const checkForBabelConfig = () => { if (isUsingBabelRc()) { @@ -24,7 +22,9 @@ const checkForBabelConfig = () => { 'These settings will be ignored, unless you use a babel.config.js file', '', 'Your plugins and settings will be automatically merged with', - `the Redwood built-in config, more details here: ${BABEL_SETTINGS_LINK}`, + `the Redwood built-in config, more details here: ${c.warning( + BABEL_SETTINGS_LINK + )}`, ] console.log( diff --git a/packages/cli/src/rwfw.js b/packages/cli/src/rwfw.js index a6de655c8d3e..3a06ac9036c4 100644 --- a/packages/cli/src/rwfw.js +++ b/packages/cli/src/rwfw.js @@ -7,7 +7,7 @@ import Configstore from 'configstore/index' import execa from 'execa' import TerminalLink from 'terminal-link' -import { getConfigPath } from '@redwoodjs/internal' +import { getConfigPath } from '@redwoodjs/internal/dist/paths' const config = new Configstore('@redwoodjs/cli') diff --git a/packages/prerender/src/__tests__/detectRoutes.test.ts b/packages/prerender/src/__tests__/detectRoutes.test.ts index 17b307d63cab..6a88df14c8f7 100644 --- a/packages/prerender/src/__tests__/detectRoutes.test.ts +++ b/packages/prerender/src/__tests__/detectRoutes.test.ts @@ -1,6 +1,6 @@ import { detectPrerenderRoutes } from '../detection' -jest.mock('@redwoodjs/internal', () => { +jest.mock('@redwoodjs/internal/dist/paths', () => { return { getPaths: jest.fn(() => { return { diff --git a/packages/prerender/src/babelPlugins/__tests__/babel-plugin-redwood-prerender-media-imports.test.ts b/packages/prerender/src/babelPlugins/__tests__/babel-plugin-redwood-prerender-media-imports.test.ts index 1e6ac134434a..88aa3760cd82 100644 --- a/packages/prerender/src/babelPlugins/__tests__/babel-plugin-redwood-prerender-media-imports.test.ts +++ b/packages/prerender/src/babelPlugins/__tests__/babel-plugin-redwood-prerender-media-imports.test.ts @@ -6,10 +6,9 @@ import plugin from '../babel-plugin-redwood-prerender-media-imports' const mockDistDir = path.resolve(__dirname, './__fixtures__/distDir') -jest.mock('@redwoodjs/internal', () => { +jest.mock('@redwoodjs/internal/dist/paths', () => { return { - // @ts-expect-error Definitely can be spread.. - ...jest.requireActual('@redwoodjs/internal'), + ...jest.requireActual('@redwoodjs/internal/dist/paths'), getPaths: () => { return { web: { diff --git a/packages/prerender/src/babelPlugins/babel-plugin-redwood-prerender-media-imports.ts b/packages/prerender/src/babelPlugins/babel-plugin-redwood-prerender-media-imports.ts index 8e217e258af2..5311ecda4ae5 100644 --- a/packages/prerender/src/babelPlugins/babel-plugin-redwood-prerender-media-imports.ts +++ b/packages/prerender/src/babelPlugins/babel-plugin-redwood-prerender-media-imports.ts @@ -2,7 +2,7 @@ import { extname, basename, join } from 'path' import type { PluginObj, types, NodePath } from '@babel/core' -import { getPaths } from '@redwoodjs/internal' +import { getPaths } from '@redwoodjs/internal/dist/paths' import { convertToDataUrl } from './utils' diff --git a/packages/prerender/src/detection/index.ts b/packages/prerender/src/detection/index.ts index fe45f5c050ac..9b658c41e876 100644 --- a/packages/prerender/src/detection/index.ts +++ b/packages/prerender/src/detection/index.ts @@ -1,4 +1,4 @@ -import { getPaths } from '@redwoodjs/internal' +import { getPaths } from '@redwoodjs/internal/dist/paths' import { getProject } from '@redwoodjs/structure' export const detectPrerenderRoutes = () => { diff --git a/packages/prerender/src/internal.ts b/packages/prerender/src/internal.ts index 52814f09c242..c1218e9198b0 100644 --- a/packages/prerender/src/internal.ts +++ b/packages/prerender/src/internal.ts @@ -4,7 +4,8 @@ import path from 'path' import { fetch } from 'cross-undici-fetch' import type { AuthContextInterface } from '@redwoodjs/auth' -import { getConfig, getPaths } from '@redwoodjs/internal' +import { getConfig } from '@redwoodjs/internal/dist/config' +import { getPaths } from '@redwoodjs/internal/dist/paths' const INDEX_FILE = path.join(getPaths().web.dist, 'index.html') const DEFAULT_INDEX = path.join(getPaths().web.dist, '200.html') diff --git a/packages/prerender/src/runPrerender.tsx b/packages/prerender/src/runPrerender.tsx index 156c1b6ace9b..6f9712b9702c 100644 --- a/packages/prerender/src/runPrerender.tsx +++ b/packages/prerender/src/runPrerender.tsx @@ -6,7 +6,8 @@ import React from 'react' import cheerio from 'cheerio' import ReactDOMServer from 'react-dom/server' -import { getPaths, registerWebSideBabelHook } from '@redwoodjs/internal' +import { registerWebSideBabelHook } from '@redwoodjs/internal/dist/build/babel/web' +import { getPaths } from '@redwoodjs/internal/dist/paths' import { LocationProvider } from '@redwoodjs/router' import mediaImportsPlugin from './babelPlugins/babel-plugin-redwood-prerender-media-imports' diff --git a/packages/record/src/tasks/parse.js b/packages/record/src/tasks/parse.js index 8b401890c77a..702ea8173573 100644 --- a/packages/record/src/tasks/parse.js +++ b/packages/record/src/tasks/parse.js @@ -4,7 +4,7 @@ import path from 'path' import { getDMMF } from '@prisma/sdk' import * as esbuild from 'esbuild' -import { getPaths } from '@redwoodjs/internal' +import { getPaths } from '@redwoodjs/internal/dist/paths' const DATAMODEL_PATH = path.join(getPaths().api.models, 'datamodel.js') const MODELS_PATH = path.join(getPaths().api.src, 'models') diff --git a/packages/telemetry/src/telemetry.ts b/packages/telemetry/src/telemetry.ts index 629599636d3e..88d2b28be3a1 100644 --- a/packages/telemetry/src/telemetry.ts +++ b/packages/telemetry/src/telemetry.ts @@ -2,7 +2,7 @@ import { spawn } from 'child_process' import os from 'os' import path from 'path' -import { getPaths } from '@redwoodjs/internal' +import { getPaths } from '@redwoodjs/internal/dist/paths' const APP_ROOT = getPaths().base