Skip to content

Commit c61fee0

Browse files
authored
chore(ci): update yarn rwfw project:tarsync to handle react resolutions (#10229)
Upgrading to the canary versions of the react packages in #10194 is confounded by the fact that a Redwood project's web-side package.json requests versions 18.2.0. Our sync commands should be setting the resolutions of those packages as well as the Redwood ones. This PR updates `yarn rwfw project:tarsync` to set resolutions for `react` and `react-dom`.
1 parent 841f003 commit c61fee0

1 file changed

Lines changed: 126 additions & 88 deletions

File tree

tasks/framework-tools/tarsync.mjs

Lines changed: 126 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#!/usr/bin/env node
2-
/* eslint-env node */
32

43
import { performance } from 'node:perf_hooks'
54
import { fileURLToPath } from 'node:url'
@@ -8,12 +7,90 @@ import { parseArgs as nodeUtilParseArgs } from 'node:util'
87
import ora from 'ora'
98
import { cd, chalk, fs, glob, path, within, $ } from 'zx'
109

11-
const mockSpinner = {
12-
text: '',
13-
succeed: () => {},
14-
}
10+
const FRAMEWORK_PATH = fileURLToPath(new URL('../../', import.meta.url))
11+
const TARBALL_DEST_DIRNAME = 'tarballs'
1512

1613
async function main() {
14+
const { projectPath, verbose } = await getOptions()
15+
$.verbose = verbose
16+
17+
cd(FRAMEWORK_PATH)
18+
performance.mark('startFramework')
19+
20+
const spinner = getFrameworkSpinner({ text: 'building and packing packages' })
21+
await buildTarballs()
22+
23+
spinner.text = 'moving tarballs'
24+
await moveTarballs(projectPath)
25+
26+
spinner.text = 'updating resolutions'
27+
await updateResolutions(projectPath)
28+
29+
performance.mark('endFramework')
30+
performance.measure('framework', 'startFramework', 'endFramework')
31+
const [entry] = performance.getEntriesByName('framework')
32+
spinner.succeed(`finished in ${(entry.duration / 1000).toFixed(2)} seconds`)
33+
34+
await yarnInstall(projectPath)
35+
36+
const entries = performance.getEntriesByType('measure').map((entry) => {
37+
return `• ${entry.name} => ${(entry.duration / 1000).toFixed(2)} seconds`
38+
})
39+
40+
for (const entry of entries) {
41+
verbose && console.log(entry)
42+
}
43+
}
44+
45+
main()
46+
47+
// Helpers
48+
// -------
49+
50+
async function parseArgs() {
51+
const { positionals, values } = nodeUtilParseArgs({
52+
allowPositionals: true,
53+
54+
options: {
55+
verbose: {
56+
type: 'boolean',
57+
default: false,
58+
short: 'v',
59+
},
60+
},
61+
})
62+
63+
const [projectPath] = positionals
64+
65+
const options = {
66+
verbose: values.verbose,
67+
}
68+
69+
options.projectPath = projectPath ? projectPath : process.env.RWJS_CWD
70+
71+
if (!options.projectPath) {
72+
throw new Error(
73+
[
74+
'Error: You have to provide the path to a Redwood project as',
75+
'',
76+
' 1. the first positional argument',
77+
'',
78+
chalk.gray(' yarn project:tarsync /path/to/redwood/project'),
79+
'',
80+
' 2. the `RWJS_CWD` env var',
81+
'',
82+
chalk.gray(' RWJS_CWD=/path/to/redwood/project yarn project:tarsync'),
83+
].join('\n')
84+
)
85+
}
86+
87+
// This makes `projectPath` an absolute path and throws if it doesn't exist.
88+
options.projectPath = await fs.realpath(options.projectPath)
89+
90+
return options
91+
}
92+
93+
async function getOptions() {
1794
let options
1895

1996
try {
@@ -26,33 +103,35 @@ async function main() {
26103

27104
const { projectPath, verbose } = options
28105

29-
$.verbose = verbose
30-
31-
// Closing over `verbose` here.
32-
function getProjectSpinner({ text }) {
33-
return verbose
34-
? mockSpinner
35-
: ora({ prefixText: `${chalk.green('[ project ]')}`, text }).start()
106+
return {
107+
projectPath,
108+
verbose,
36109
}
110+
}
37111

38-
function getFrameworkSpinner({ text }) {
39-
return verbose
40-
? mockSpinner
41-
: ora({ prefixText: `${chalk.cyan('[framework]')}`, text }).start()
42-
}
112+
const mockSpinner = {
113+
text: '',
114+
succeed: () => { },
115+
}
43116

44-
const frameworkPath = fileURLToPath(new URL('../../', import.meta.url))
45-
cd(frameworkPath)
46-
performance.mark('startFramework')
117+
function getProjectSpinner({ text }) {
118+
return $.verbose
119+
? mockSpinner
120+
: ora({ prefixText: `${chalk.green('[ project ]')}`, text }).start()
121+
}
47122

48-
const spinner = getFrameworkSpinner({ text: 'building and packing packages' })
123+
function getFrameworkSpinner({ text }) {
124+
return $.verbose
125+
? mockSpinner
126+
: ora({ prefixText: `${chalk.cyan('[framework]')}`, text }).start()
127+
}
49128

129+
async function buildTarballs() {
50130
await $`yarn nx run-many -t build:pack --exclude create-redwood-app`
131+
}
51132

52-
spinner.text = 'moving tarballs'
53-
54-
const tarballDestDirname = 'tarballs'
55-
const tarballDest = path.join(projectPath, tarballDestDirname)
133+
async function moveTarballs(projectPath) {
134+
const tarballDest = path.join(projectPath, TARBALL_DEST_DIRNAME)
56135
await fs.ensureDir(tarballDest)
57136

58137
const tarballs = await glob(['./packages/**/*.tgz'])
@@ -64,9 +143,25 @@ async function main() {
64143
})
65144
)
66145
)
146+
}
67147

68-
spinner.text = 'updating resolutions'
148+
async function getReactResolutions() {
149+
const packageConfig = await fs.readJson(path.join(FRAMEWORK_PATH, 'packages/web/package.json'))
150+
151+
const react = packageConfig.peerDependencies.react
152+
const reactDom = packageConfig.peerDependencies['react-dom']
153+
154+
if (!react || !reactDom) {
155+
throw new Error("Couldn't find react or react-dom in @redwoodjs/web's peerDependencies")
156+
}
69157

158+
return {
159+
react,
160+
'react-dom': reactDom,
161+
}
162+
}
163+
164+
async function updateResolutions(projectPath) {
70165
const resolutions = (await $`yarn workspaces list --json`).stdout
71166
.trim()
72167
.split('\n')
@@ -77,9 +172,8 @@ async function main() {
77172
return {
78173
...resolutions,
79174
// Turn a Redwood package name like `@redwoodjs/project-config` into `redwoodjs-project-config.tgz`.
80-
[name]: `./${tarballDestDirname}/${
81-
name.replace('@', '').replaceAll('/', '-') + '.tgz'
82-
}`,
175+
[name]: `./${TARBALL_DEST_DIRNAME}/${name.replace('@', '').replaceAll('/', '-') + '.tgz'
176+
}`,
83177
}
84178
}, {})
85179

@@ -93,20 +187,16 @@ async function main() {
93187
resolutions: {
94188
...projectPackageJson.resolutions,
95189
...resolutions,
190+
...(await getReactResolutions())
96191
},
97192
},
98193
{
99194
spaces: 2,
100195
}
101196
)
197+
}
102198

103-
performance.mark('endFramework')
104-
performance.measure('framework', 'startFramework', 'endFramework')
105-
106-
const [entry] = performance.getEntriesByName('framework')
107-
108-
spinner.succeed(`finished in ${(entry.duration / 1000).toFixed(2)} seconds`)
109-
199+
async function yarnInstall(projectPath) {
110200
await within(async () => {
111201
cd(projectPath)
112202
performance.mark('startProject')
@@ -123,56 +213,4 @@ async function main() {
123213
spinner.succeed(`finished in ${(entry.duration / 1000).toFixed(2)} seconds`)
124214
})
125215

126-
const entries = performance.getEntriesByType('measure').map((entry) => {
127-
return `• ${entry.name} => ${(entry.duration / 1000).toFixed(2)} seconds`
128-
})
129-
130-
for (const entry of entries) {
131-
verbose && console.log(entry)
132-
}
133-
}
134-
135-
main()
136-
137-
async function parseArgs() {
138-
const { positionals, values } = nodeUtilParseArgs({
139-
allowPositionals: true,
140-
141-
options: {
142-
verbose: {
143-
type: 'boolean',
144-
default: false,
145-
short: 'v',
146-
},
147-
},
148-
})
149-
150-
const [projectPath] = positionals
151-
152-
const options = {
153-
verbose: values.verbose,
154-
}
155-
156-
options.projectPath = projectPath ? projectPath : process.env.RWJS_CWD
157-
158-
if (!options.projectPath) {
159-
throw new Error(
160-
[
161-
'Error: You have to provide the path to a Redwood project as',
162-
'',
163-
' 1. the first positional argument',
164-
'',
165-
chalk.gray(' yarn project:tarsync /path/to/redwood/project'),
166-
'',
167-
' 2. the `RWJS_CWD` env var',
168-
'',
169-
chalk.gray(' RWJS_CWD=/path/to/redwood/project yarn project:tarsync'),
170-
].join('\n')
171-
)
172-
}
173-
174-
// This makes `projectPath` an absolute path and throws if it doesn't exist.
175-
options.projectPath = await fs.realpath(options.projectPath)
176-
177-
return options
178216
}

0 commit comments

Comments
 (0)