Skip to content

Commit

Permalink
working refactor, make project:sync ignore more
Browse files Browse the repository at this point in the history
  • Loading branch information
jtoar committed Jun 10, 2023
1 parent 708902d commit 4ff1e87
Show file tree
Hide file tree
Showing 3 changed files with 361 additions and 186 deletions.
323 changes: 246 additions & 77 deletions tasks/framework-tools/frameworkSyncToProject.mjs
Original file line number Diff line number Diff line change
@@ -1,129 +1,298 @@
#!/usr/bin/env node
/* eslint-env node */
// @ts-check

import fs from 'node:fs'
import { execSync } from 'node:child_process'
import path from 'node:path'

import c from 'ansi-colors'
import chokidar from 'chokidar'
import fs from 'fs-extra'
import { hideBin } from 'yargs/helpers'
import yargs from 'yargs/yargs'

import {
REDWOOD_PACKAGES_PATH,
packageJsonName,
getPackageJsonName,
resolvePackageJsonPath,
buildPackages,
REDWOOD_FRAMEWORK_PATH,
} from './lib/framework.mjs'
import { cleanPackages } from './lib/framework.mjs'
import {
installProjectPackages,
addDependenciesToPackageJson,
copyFrameworkFilesToProject,
} from './lib/project.mjs'

const projectPath = process.argv?.[2] ?? process.env.RWJS_CWD
const IGNORE_EXTENSIONS = ['.DS_Store']

if (!projectPath) {
console.log('Error: Please specify the path to your Redwood Project')
console.log(`Usage: ${process.argv?.[1]} /path/to/rwjs/project`)
process.exit(1)
}
// Add to this array of strings, RegExps, or functions (whichever makes the most sense)
// to ignore files that we don't want triggering package rebuilds.
const ignored = [
/node_modules/,

// Cache the original package.json and restore it when this process exits.
const projectPackageJsonPath = path.join(projectPath, 'package.json')
/dist/,

const projectPackageJson = fs.readFileSync(projectPackageJsonPath, 'utf-8')
process.on('SIGINT', () => {
console.log()
console.log(`Removing framework packages from 'package.json'...`)
fs.writeFileSync(projectPackageJsonPath, projectPackageJson)
// TODO: Delete `node_modules/@redwoodjs`
console.log("...Done. Run 'yarn install'")
process.exit(0)
})
/__fixtures__/,
/__mocks__/,
/__tests__/,
/.test./,
/jest.config.{js,ts}/,

function logStatus(m) {
console.log(c.bgYellow(c.black('rwfw ')), c.yellow(m))
}
/README.md/,

function logError(m) {
console.log(c.bgRed(c.black('rwfw ')), c.red(m))
}
// esbuild emits meta.json files that we sometimes suffix.
/meta.(\w*\.?)json/,

chokidar
.watch(REDWOOD_PACKAGES_PATH, {
ignoreInitial: true,
persistent: true,
awaitWriteFinish: true,
ignored: (file) =>
file.includes('/node_modules/') ||
file.includes('/dist/') ||
file.includes('/dist') ||
file.includes('/__tests__/') ||
file.includes('/__fixtures__/') ||
file.includes('/.test./') ||
['.DS_Store'].some((ext) => file.endsWith(ext)),
})
.on('ready', async () => {
logStatus('Cleaning Framework...')
cleanPackages()
(filePath) => IGNORE_EXTENSIONS.some((ext) => filePath.endsWith(ext)),
]

logStatus('Building Framework...')
buildPackages()
const separator = '-'.repeat(process.stdout.columns)

console.log()
logStatus('Adding dependencies...')
addDependenciesToPackageJson(projectPackageJsonPath)
installProjectPackages(projectPath)
async function main() {
const { _: positionals, ...options } = yargs(hideBin(process.argv))
.options({
cleanFramework: {
description:
'Clean any built framework packages before watching for changes',
type: 'boolean',
default: true,
},
buildFramework: {
description:
'Build all the framework packages before watching for changes',
type: 'boolean',
default: true,
},
addDependencies: {
description:
"Add the framework's dependencies to the project and yarn install before watching for changes",
type: 'boolean',
default: true,
},
copyFiles: {
description:
"Copy the framework packages' files to the project's node_modules before watching for changes",
type: 'boolean',
default: true,
},
cleanUp: {
description:
"Restore the project's package.json when this process exits",
type: 'boolean',
default: true,
},
verbose: {
description: 'Print more',
type: 'boolean',
default: true,
},
})
.parseSync()

const redwoodProjectPath = positionals[0] ?? process.env.RWJS_CWD

// Mostly just making TS happy with the second condition.
if (!redwoodProjectPath || typeof redwoodProjectPath !== 'string') {
process.exitCode = 1
console.error([
'Error: Please specify the path to your Redwood project',
`Usage: ${process.argv?.[1]} ./path/to/rw/project`,
])
return
}

if (options.cleanFramework) {
logStatus('Cleaning the Redwood framework...')
execSync('yarn build:clean', {
stdio: options.verbose ? 'inherit' : 'pipe',
cwd: REDWOOD_FRAMEWORK_PATH,
})
}

if (options.buildFramework) {
try {
logStatus('Building the Redwood framework...')
execSync('yarn build', {
stdio: options.verbose ? 'inherit' : 'pipe',
cwd: REDWOOD_FRAMEWORK_PATH,
})
console.log()
} catch (e) {
// Temporary error handling for.
// > Lerna (powered by Nx) ENOENT: no such file or directory, open '/Users/dom/projects/redwood/redwood/node_modules/lerna/node_modules/nx/package.json'
process.exitCode = 1
console.error(
[
c.bgYellow(c.black('Heads up ')),
'',
"If this failed because Nx couldn't find its package.json file in node_modules, it's a known issue. The workaround is just trying again.",
].join('\n')
)
return
}
}

// Settig up here first before we add the first SIGINT handler
// just for visual output.
process.on('SIGINT', () => {
console.log()
logStatus('Copying files...')
await copyFrameworkFilesToProject(projectPath)
})

if (options.addDependencies) {
// Save the project's package.json so that we can restore it when this process exits.
const redwoodProjectPackageJsonPath = path.join(
redwoodProjectPath,
'package.json'
)
const redwoodProjectPackageJson = fs.readFileSync(
redwoodProjectPackageJsonPath,
'utf-8'
)

if (options.cleanUp) {
logStatus('Setting up clean up on SIGINT or process exit...')

const cleanUp = createCleanUp({
redwoodProjectPackageJsonPath,
redwoodProjectPackageJson,
})

process.on('SIGINT', cleanUp)
process.on('exit', cleanUp)
}

logStatus("Adding the Redwood framework's dependencies...")
addDependenciesToPackageJson(redwoodProjectPackageJsonPath)

try {
execSync('yarn install', {
cwd: redwoodProjectPath,
stdio: options.verbose ? 'inherit' : 'pipe',
})
console.log()
} catch (e) {
process.exitCode = 1
console.error(e)
return
}
}

if (options.copyFiles) {
logStatus('Copying the Redwood framework files...')
await copyFrameworkFilesToProject(redwoodProjectPath)
console.log()
logStatus('Done, and waiting for changes...')
console.log('-'.repeat(80))
}

logStatus('Waiting for changes')
console.log(separator)

const watcher = chokidar.watch(REDWOOD_PACKAGES_PATH, {
ignored,
// We don't want chokidar to emit events as it discovers paths, only as they change.
ignoreInitial: true,
// Debounce the events.
awaitWriteFinish: true,
})
.on('all', async (_event, filePath) => {

let closedWatcher = false

async function closeWatcher() {
if (closedWatcher) {
return
}

logStatus('Closing the watcher...')
await watcher.close()
closedWatcher = true
}

process.on('SIGINT', closeWatcher)
process.on('exit', closeWatcher)

watcher.on('all', async (_event, filePath) => {
logStatus(filePath)

if (filePath.endsWith('package.json')) {
logStatus(
`${c.red(
'Warning:'
)} You modified a package.json file. If you've modified the ${c.underline(
'dependencies'
)}, then you must run ${c.underline('yarn rwfw project:sync')} again.`
[
`${c.red('Warning:')} You modified a package.json file.`,
`If you've modified the ${c.underline('dependencies')}`,
`then you must run ${c.underline('yarn rwfw project:sync')} again.`,
].join(' ')
)
}

const packageJsonPath = resolvePackageJsonPath(filePath)
const packageName = packageJsonName(packageJsonPath)
const packageName = getPackageJsonName(packageJsonPath)
logStatus(c.magenta(packageName))
console.log()

let hasHadError = false
let errored = false

try {
console.log()
logStatus(`Cleaning ${packageName}...`)
cleanPackages([packageJsonPath])

console.log()
logStatus(`Building ${packageName}...`)
buildPackages([packageJsonPath])

console.log()
logStatus(`Copying ${packageName}...`)
await copyFrameworkFilesToProject(projectPath, [packageJsonPath])
} catch (error) {
hasHadError = true
console.log(error)
await copyFrameworkFilesToProject(redwoodProjectPath, [packageJsonPath])
console.log()
logError(`Error building ${packageName}...`)
} catch (error) {
errored = true
}

if (!hasHadError) {
console.log()
logStatus(`Done, and waiting for changes...`)
console.log('-'.repeat(80))
if (errored) {
logError(`Error building ${packageName}`)
}

logStatus(`Done, and waiting for changes...`)
console.log(separator)
})
}

/**
* @param {string} m
*/
function logStatus(m) {
console.log(c.bgYellow(c.black('rwfw ')), c.yellow(m))
}

/**
* @param {string} m
*/
function logError(m) {
console.error(c.bgRed(c.black('rwfw ')), c.red(m))
}

function createCleanUp({
redwoodProjectPackageJsonPath,
redwoodProjectPackageJson,
}) {
let cleanedUp = false

return function () {
if (cleanedUp) {
return
}

logStatus("Restoring the Redwood project's package.json...")

fs.writeFileSync(redwoodProjectPackageJsonPath, redwoodProjectPackageJson)

console.log(
[
'',
'To get your project back to its original state...',
"- undo the changes to project's your yarn.lock file",
"- remove your project's node_modules directory",
"- run 'yarn install'",
'',
].join('\n')
)

cleanedUp = true
}
}

// ------------------------

main()
Loading

0 comments on commit 4ff1e87

Please sign in to comment.