@artegha/create-node-server
Version:
Create Node servers with no build configuration.
251 lines (215 loc) • 7.55 kB
text/typescript
import chalk from 'chalk'
import fs from 'fs-extra'
import os from 'os'
import path from 'path'
import spawn from 'cross-spawn'
import tools from '../utils/tools'
import packageJson from '../package.json'
export default (server: Server) => {
const appPackage: { [key: string]: any } = packageJson
server.useYarn = fs.existsSync(path.join(server.root, 'yarn.lock'))
if (!server.templateName) {
console.log('')
console.error(
`A template was not provided. Using default template ${chalk.cyan('cns-template-typescript-express')}.`
)
}
const templatePath = path.dirname(require.resolve(`${server.templateName}/package.json`, { paths: [server.root] }))
const templateJsonPath = path.join(templatePath, 'template.json')
let templateJson: { [key: string]: any } = {}
if (fs.existsSync(templateJsonPath)) {
templateJson = require(templateJsonPath)
}
const templatePackage = templateJson.package || {}
if (templateJson.dependencies) {
templatePackage.dependencies = templateJson.dependencies
}
if (templateJson.scripts) {
templatePackage.scripts = templateJson.scripts
}
if (templateJson.devDependencies) {
templatePackage.devDependencies = templateJson.devDependencies
}
// Keys to ignore in templatePackage
const templatePackageBlacklist = [
'name',
'version',
'description',
'keywords',
'bugs',
'license',
'author',
'contributors',
'files',
'browser',
'bin',
'man',
'directories',
'repository',
'peerDependencies',
'bundledDependencies',
'optionalDependencies',
'engineStrict',
'os',
'cpu',
'preferGlobal',
'private',
'publishConfig',
]
// Keys from templatePackage that will be merged with appPackage
const templatePackageToMerge = ['dependencies', 'scripts', 'devDependencies']
// Keys from templatePackage that will be added to appPackage,
// replacing any existing entries.
const templatePackageToReplace = Object.keys(templatePackage).filter((key) => {
return !templatePackageBlacklist.includes(key) && !templatePackageToMerge.includes(key)
})
// Copy over some of the dependencies
appPackage.dependencies = appPackage.dependencies || {}
// Setup the script rules
appPackage.scripts = templatePackage.scripts || {}
// Copy over some of the devDependencies
appPackage.devDependencies = appPackage.devDependencies || {}
// Update scripts for Yarn users
if (server.useYarn) {
appPackage.scripts = Object.entries(appPackage.scripts).reduce(
(acc, [key, value]: any) => ({
...acc,
[key]: value.replace(/(npm run |npm )/, 'yarn '),
}),
{}
)
}
// Add templatePackage keys/values to appPackage, replacing existing entries
templatePackageToReplace.forEach((key) => {
appPackage[key] = templatePackage[key]
})
// Overwrite the package.json
fs.writeFileSync(path.join(server.root, 'package.json'), JSON.stringify(appPackage, null, 2) + os.EOL)
// Replace README.md and remane the old one
const readmeExists = fs.existsSync(path.join(server.root, 'README.md'))
if (readmeExists) {
fs.renameSync(path.join(server.root, 'README.md'), path.join(server.root, 'README.old.md'))
}
// Copy the files from template/ the user
const templateDir = path.join(templatePath, 'template')
if (fs.existsSync(templateDir)) {
fs.copySync(templateDir, server.root)
} else {
throw new Error(`Could not locate supplied template: ${chalk.green(templateDir)}`)
}
// modifies README.md commands based on user used package manager.
if (server.useYarn) {
try {
const readme = fs.readFileSync(path.join(server.root, 'README.md'), 'utf8')
fs.writeFileSync(path.join(server.root, 'README.md'), readme.replace(/(npm run |npm )/g, 'yarn '), 'utf8')
} catch (err) {
throw new Error(err)
}
}
const gitignoreExists = fs.existsSync(path.join(server.root, '.gitignore'))
if (gitignoreExists) {
// Append if there's already a `.gitignore` file there
const data = fs.readFileSync(path.join(server.root, 'gitignore'))
fs.appendFileSync(path.join(server.root, '.gitignore'), data)
fs.unlinkSync(path.join(server.root, '.npmignore'))
} else {
// Rename gitignore after the fact to prevent npm from renaming it to .npmignore
// See: https://github.com/npm/npm/issues/1862
fs.moveSync(path.join(server.root, '.npmignore'), path.join(server.root, '.gitignore'), [] as never)
}
// Initialize git repo
const initializedGit = false
// if (tools.tryGitInit()) {
// initializedGit = true
// console.log()
// console.log('Initialized a git repository.')
// }
let command
let remove
let args
if (server.useYarn) {
command = 'yarnpkg'
remove = 'remove'
args = ['add']
} else {
command = 'npm'
remove = 'uninstall'
args = ['install', '--save', server.verbose && '--verbose'].filter((e) => e)
}
// Install additional template dependencies, if present.
const dependenciesToInstall = Object.entries({
...templatePackage.dependencies,
...templatePackage.devDependencies,
})
if (dependenciesToInstall.length) {
args = args.concat(
dependenciesToInstall.map(([dependency, version]) => {
return `${dependency}@${version}`
})
)
}
// Install template dependencies
if (server.templateName && args.length > 1) {
console.log()
console.log(`Installing template dependencies using ${command}...`)
const proc = spawn.sync(command, args, { stdio: 'inherit' })
if (proc.status !== 0) {
throw new Error(`\`${command} ${args.join(' ')}\` failed`)
}
}
// if (args.find(arg => arg.includes('typescript'))) {
// console.log();
// verifyTypeScriptSetup();
// }
// Remove template
console.log(`Removing template package using ${command}...`)
console.log()
const proc = spawn.sync(command, [remove, server.templateName], {
stdio: 'inherit',
})
if (proc.status !== 0) {
throw new Error(`\`${command} ${args.join(' ')}\` failed`)
}
// Create git commit if git repo was initialized
if (initializedGit && tools.tryGitCommit(server.root)) {
console.log()
console.log('Created git commit.')
}
// Display the most elegant way to cd.
// This needs to handle an undefined server.originalRoot for
// backward compatibility with old global-cli's.
let cdpath
if (server.originalRoot && path.join(server.originalRoot, server.name) === server.root) {
cdpath = server.name
} else {
cdpath = server.root
}
// Change displayed command to yarn instead of yarnpkg
const displayedCommand = server.useYarn ? 'yarn' : 'npm'
console.log()
console.log(`Success! Created ${chalk.cyan(`${server.name}`)} at ${chalk.cyan(`${server.root}`)} `)
console.log('Inside that directory, you can run several commands:')
console.log()
console.log(chalk.cyan(` ${displayedCommand} start`))
console.log(' Starts the development server.')
console.log()
console.log(chalk.cyan(` ${displayedCommand} ${server.useYarn ? '' : 'run '}build`))
console.log(' Bundles the server for production.')
console.log()
console.log(chalk.cyan(` ${displayedCommand} ${server.useYarn ? '' : 'run '}prod`))
console.log(' Bundles and starts the server for production.')
// console.log();
// console.log(chalk.cyan(` ${displayedCommand} test`));
// console.log(' Starts the test runner.');
console.log()
console.log('We suggest that you begin by typing:')
console.log()
console.log(chalk.cyan(' cd'), cdpath)
console.log(` ${chalk.cyan(`${displayedCommand} start`)}`)
if (readmeExists) {
console.log()
console.log(chalk.yellow('You had a `README.md` file, we renamed it to `README.old.md`'))
}
console.log()
console.log('Happy hacking!')
}