Nuxt/build/package.js

227 lines
5.7 KiB
JavaScript

import { resolve } from 'path'
import EventEmitter from 'events'
import { sync as spawnSync } from 'cross-spawn'
import consola from 'consola'
import { readFileSync, existsSync, readJSONSync, writeFileSync, copySync, removeSync } from 'fs-extra'
import _ from 'lodash'
import { builtinsMap } from './builtins'
const DEFAULTS = {
distDir: 'dist',
buildSuffix: process.env.BUILD_SUFFIX
}
const sortObjectKeys = obj => _(obj).toPairs().sortBy(0).fromPairs().value()
export default class Package extends EventEmitter {
constructor(options) {
super()
// Assign options
Object.assign(this, DEFAULTS, options)
this.rootDir = this.rootDir || process.cwd()
this.distDir = this.resolvePath(this.distDir)
this.packageJS = this.resolvePath('package.js')
this.packageJSON = this.resolvePath('package.json')
// Initialize
this.init()
}
init() {
// Try to read package.json if not provided
this._readPackage()
// Init logger
this.logger = consola.withScope(this.packageObj.name)
// Try to load package.js
this._loadPackageJS()
}
resolvePath(...args) {
return resolve(this.rootDir, ...args)
}
_readPackage() {
this.packageObj = readJSONSync(this.packageJSON)
}
_loadPackageJS() {
if (existsSync(this.packageJS)) {
let fn = require(this.packageJS)
fn = fn.default || fn
if (typeof fn === 'function') {
fn(this, {
load: (relativeRootDir, opts) => new Package(Object.assign({
rootDir: resolve(this.rootDir, relativeRootDir)
}, opts))
})
}
}
}
writePackage() {
this.logger.debug('Writing', this.packageJSON)
writeFileSync(this.packageJSON, JSON.stringify(this.packageObj, null, 2) + '\n')
}
generateVersion() {
const date = Math.round(Date.now() / (1000 * 60))
const gitCommit = this.gitShortCommit()
const baseVersion = this.packageObj.version.split('-')[0]
this.packageObj.version = `${baseVersion}-${date}.${gitCommit}`
}
convertTo(suffix) {
this.logger.info(`Converting to ${suffix} package`)
this.addNameSuffix(`-${suffix}`)
this.generateVersion()
this.writePackage()
}
addNameSuffix(suffix) {
if (!this.packageObj.name.includes(suffix)) {
this.packageObj.name += suffix
}
}
build() {
this.emit('build:before')
if (this.buildSuffix) {
this.convertTo(this.buildSuffix)
}
this.logger.info('Cleaning up')
removeSync(this.distDir)
this.logger.info('Building')
this.exec('rollup', '-c')
this.emit('build:done')
}
publish(tag = 'latest') {
this.logger.info(`publishing ${this.packageObj.name}@${this.packageObj.version} with tag ${tag}`)
this.exec('npm', `publish --tag ${tag}`)
}
copyFieldsFrom(source, fields = []) {
for (const field of fields) {
this.packageObj[field] = source.packageObj[field]
}
}
copyFilesFrom(source, files) {
for (const file of files || source.packageObj.files || []) {
const src = resolve(source.rootDir, file)
const dst = resolve(this.rootDir, file)
copySync(src, dst)
}
}
sortDependencies() {
if (this.packageObj.dependencies) {
this.packageObj.dependencies = sortObjectKeys(this.packageObj.dependencies)
}
if (this.packageObj.devDependencies) {
this.packageObj.devDependencies = sortObjectKeys(this.packageObj.devDependencies)
}
}
updateDependencies({ dist, sources = [], extras = [], exclude = [] }) {
const dependencies = {}
const requireRegex = /require\('([-@/\w]+)'\)/g
// Extras
for (const name of extras) {
dependencies[name] = null
}
// Scan require() calls inside dist
const distSource = readFileSync(resolve(this.rootDir, dist))
let match = requireRegex.exec(distSource)
while (match) {
const name = match[1]
dependencies[name] = null
match = requireRegex.exec(distSource)
}
// Exclude
for (const name of exclude) {
delete dependencies[name]
}
const builtins = builtinsMap()
// Resolve dependency versions
for (const name in dependencies) {
// Ignore builtin modules
if (builtins[name]) {
delete dependencies[name]
continue
}
// Try sources
for (const source of sources) {
const sourceDeps = source.packageObj.dependencies
if (sourceDeps && sourceDeps[name]) {
dependencies[name] = sourceDeps[name]
break
}
}
// Try to require package.json of dependency
if (dependencies[name] === null) {
try {
const _pkg = require(`${name}/package.json`)
if (!_pkg.version) {
throw Error('No version specified')
}
dependencies[name] = `^${_pkg.version}`
} catch (e) {
this.logger.warn(e)
delete dependencies[name]
}
}
}
this.packageObj.dependencies = dependencies
}
exec(command, args, silent = false) {
const r = spawnSync(command, args.split(' '), { cwd: this.rootDir }, { env: process.env })
if (!silent) {
const fullCommand = command + ' ' + args
if (r.error) {
this.logger.error(fullCommand, r.error)
} else {
this.logger.success(fullCommand, r.output)
}
}
return {
error: r.error,
pid: r.pid,
status: r.status,
signal: r.signal,
stdout: String(r.stdout).trim(),
stderr: String(r.stderr).trim(),
output: (r.output || [])
.map(l => String(l).trim())
.filter(l => l.length)
.join('\n')
}
}
gitShortCommit() {
return this.exec('git', 'rev-parse --short HEAD', true).stdout
}
gitBranch() {
return this.exec('git', 'rev-parse --abbrev-ref HEAD', true).stdout
}
}