Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI responsiveness #6028

Merged
merged 28 commits into from
Jul 28, 2022
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7662761
Move build handler.
peterp Jul 23, 2022
c2c3883
Move dev handler.
peterp Jul 23, 2022
eed679c
move console handler.
peterp Jul 23, 2022
aeb1345
Do not import structure.
peterp Jul 24, 2022
b342b90
Use local getPaths.
peterp Jul 24, 2022
0315342
Attempt to directly import methods.
peterp Jul 24, 2022
55450fc
Make prerender async.
peterp Jul 24, 2022
5a36057
Rename file, add "sides."
peterp Jul 24, 2022
e6c51c7
Use renamed file.
peterp Jul 24, 2022
0b559ba
Use new-sides.
peterp Jul 24, 2022
47001b7
Remove unused imports.
peterp Jul 24, 2022
11de5cf
Async exec handler.
peterp Jul 24, 2022
53373b1
Async prisma handler.
peterp Jul 24, 2022
e52f3ed
Async type check.
peterp Jul 24, 2022
3c86aab
Make build use sides.
peterp Jul 24, 2022
dda90f9
Make serve use getPaths.
peterp Jul 24, 2022
245dc06
Return of the middleware.
peterp Jul 24, 2022
2db74ad
revert internal import change to see if tests pass
jtoar Jul 26, 2022
a49e20c
fix type-check by fixing sides import
jtoar Jul 26, 2022
c262aad
Revert "revert internal import change to see if tests pass"
jtoar Jul 27, 2022
6d14cba
update mocking for cli tests accordingly
jtoar Jul 27, 2022
e5f1636
fix import to getConigPath
jtoar Jul 27, 2022
9172342
Merge branch 'main' into pp/cli-performance-improvements
dac09 Jul 27, 2022
4b2f0a2
Add lint rule to prevent direct import of redwoodjs/internal inside f…
dac09 Jul 27, 2022
e4bc640
Fix all lint errors and tests
dac09 Jul 27, 2022
45e3163
Update eslint comments
dac09 Jul 27, 2022
6ec4599
Import prerender tasks from the correct place
dac09 Jul 27, 2022
3b13aba
Merge branch 'main' into pp/cli-performance-improvements
jtoar Jul 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions packages/cli/src/commands/__tests__/build.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
jest.mock('@redwoodjs/internal', () => {
jest.mock('@redwoodjs/internal/dist/paths', () => {
return {
getPaths: () => {
return {
Expand All @@ -10,6 +10,11 @@ jest.mock('@redwoodjs/internal', () => {
},
}
},
}
})

jest.mock('@redwoodjs/internal/dist/config', () => {
return {
getConfig: () => {},
}
})
Expand All @@ -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...",
Expand All @@ -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...",
Expand Down
13 changes: 10 additions & 3 deletions packages/cli/src/commands/__tests__/dev.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import '../../lib/mockTelemetry'

jest.mock('concurrently', () => ({
__esModule: true, // this property makes it work
default: jest.fn().mockReturnValue({
Expand All @@ -17,6 +19,14 @@ jest.mock('fs', () => {
})

jest.mock('@redwoodjs/internal', () => {
return {
getConfig: jest.fn(),
getConfigPath: () => '/mocked/project/redwood.toml',
shutdownPort: jest.fn(),
}
})

jest.mock('@redwoodjs/internal/dist/paths', () => {
return {
getPaths: () => {
return {
Expand All @@ -31,9 +41,6 @@ jest.mock('@redwoodjs/internal', () => {
},
}
},
getConfig: jest.fn(),
getConfigPath: () => '/mocked/project/redwood.toml',
shutdownPort: jest.fn(),
}
})

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/commands/__tests__/prisma.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
jest.mock('@redwoodjs/internal', () => {
jest.mock('@redwoodjs/internal/dist/paths', () => {
return {
getPaths: () => {
return {
Expand Down
7 changes: 6 additions & 1 deletion packages/cli/src/commands/__tests__/serve.test.js
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -13,6 +13,11 @@ jest.mock('@redwoodjs/internal', () => {
},
}
},
}
})

jest.mock('@redwoodjs/internal/dist/config', () => {
return {
getConfig: () => {
return {
api: {},
Expand Down
165 changes: 7 additions & 158 deletions packages/cli/src/commands/build.js
Original file line number Diff line number Diff line change
@@ -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',
})
Expand Down Expand Up @@ -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)
}
Loading