|
| 1 | +#!/usr/bin/env node |
| 2 | +const path = require('path') |
| 3 | +const glob = require('glob') |
| 4 | +const fse = require('fs-extra') |
| 5 | +const _ = require('lodash') |
| 6 | +const spawn = require('cross-spawn') |
| 7 | +const env = require('./env.json') |
| 8 | + |
| 9 | +const deployDir = (name = '') => path.join(__dirname, '../../dist', name) |
| 10 | +const releaseDir = path.join(__dirname, '../../release') |
| 11 | + |
| 12 | +const templateList = glob.sync('*', { |
| 13 | + cwd: releaseDir, |
| 14 | + ignore: '*.zip' |
| 15 | +}) |
| 16 | + |
| 17 | +/** |
| 18 | + *create the index.html for templates |
| 19 | + * |
| 20 | + * @param {Array} [data=[]] templateList array |
| 21 | + * @param {String} target target path |
| 22 | + */ |
| 23 | +function buildIndex(data = [], target) { |
| 24 | + let html = fse.readFileSync(path.join(__dirname, './index.html'), { encoding: 'utf-8' }) |
| 25 | + const complied = _.template(html) |
| 26 | + html = complied({ data }) |
| 27 | + fse.writeFileSync(target, html) |
| 28 | +} |
| 29 | + |
| 30 | +/** |
| 31 | + *create a child_process with promise |
| 32 | + * |
| 33 | + * @param {String} name process name for log |
| 34 | + * @param {*} args spawn arguments |
| 35 | + * @returns {Promise} |
| 36 | + */ |
| 37 | +function createPs(name, ...args) { |
| 38 | + return new Promise((resolve, reject) => { |
| 39 | + const ps = spawn(...args) |
| 40 | + ps.on('error', console.trace) |
| 41 | + ps.on('close', (code) => { |
| 42 | + if (code !== 0) { |
| 43 | + console.log(`${name} build process exited with code ${code}`) |
| 44 | + reject(code) |
| 45 | + } |
| 46 | + resolve(code) |
| 47 | + }) |
| 48 | + }) |
| 49 | +} |
| 50 | + |
| 51 | +/** |
| 52 | + * @class BuildProcess |
| 53 | + */ |
| 54 | +class BuildProcess { |
| 55 | + /** |
| 56 | + *Creates an instance of BuildProcess, which use to run nuxt build |
| 57 | + * @param {String} templateName framework tempalte name, used to a folder name |
| 58 | + * @param {Object} [options={}] spawn options |
| 59 | + * @memberof BuildProcess |
| 60 | + */ |
| 61 | + constructor(templateName, options = {}) { |
| 62 | + const { env = {}, ...opts } = options |
| 63 | + this.folderName = templateName |
| 64 | + this.options = { |
| 65 | + cwd: path.join(releaseDir, templateName), |
| 66 | + env: { |
| 67 | + API_SERVER: 'https://easy-mock.com/mock/5c1b3895fe5907404e654045/femessage-mock', |
| 68 | + ...process.env, |
| 69 | + ...env, |
| 70 | + PUBLIC_PATH: `${process.env.PUBLIC_PATH || ''}/${this.folderName}` |
| 71 | + }, |
| 72 | + ...opts |
| 73 | + } |
| 74 | + } |
| 75 | + |
| 76 | + /** |
| 77 | + *install dependents |
| 78 | + * |
| 79 | + * @param {Object} options |
| 80 | + * @returns {Promise} spawn options |
| 81 | + * @memberof BuildProcess |
| 82 | + */ |
| 83 | + installDeps(options) { |
| 84 | + const action = `${this.folderName} install` |
| 85 | + console.log(action + 'ing...') |
| 86 | + return createPs(action, 'yarn', ['install'], { ...this.options, ...options }) |
| 87 | + } |
| 88 | + |
| 89 | + /** |
| 90 | + *build nuxt project |
| 91 | + * |
| 92 | + * @param {Object} options |
| 93 | + * @returns {Promise} |
| 94 | + * @memberof BuildProcess |
| 95 | + */ |
| 96 | + build(options) { |
| 97 | + const action = `${this.folderName} build` |
| 98 | + console.log(action + 'ing...') |
| 99 | + return createPs(action, 'yarn', ['build'], { ...this.options, ...options }) |
| 100 | + } |
| 101 | + |
| 102 | + /** |
| 103 | + *move some file, because the assets path is not correct after build success |
| 104 | + * |
| 105 | + * @memberof BuildProcess |
| 106 | + */ |
| 107 | + moveToDist() { |
| 108 | + const targetDir = deployDir(this.folderName) |
| 109 | + const sourceDir = path.join(this.options.cwd, 'dist') |
| 110 | + const assetsDir = `${sourceDir}/${this.folderName}` |
| 111 | + // move assets out |
| 112 | + const assetsList = glob.sync('**', { |
| 113 | + cwd: assetsDir, |
| 114 | + nodir: true |
| 115 | + }) |
| 116 | + assetsList.forEach(file => fse.moveSync(`${assetsDir}/${file}`, `${sourceDir}/${file}`, { overwrite: true })) |
| 117 | + fse.removeSync(assetsDir) |
| 118 | + // move to dist |
| 119 | + fse.moveSync(sourceDir, targetDir, { overwrite: true }) |
| 120 | + } |
| 121 | + |
| 122 | + /** |
| 123 | + *the total process of build a nuxt project |
| 124 | + * |
| 125 | + * @returns {Promise} |
| 126 | + * @memberof BuildProcess |
| 127 | + */ |
| 128 | + run() { |
| 129 | + return this.installDeps() |
| 130 | + .then(() => this.build()) |
| 131 | + .then(() => { |
| 132 | + this.moveToDist() |
| 133 | + return this.folderName |
| 134 | + }) |
| 135 | + .catch() |
| 136 | + } |
| 137 | +} |
| 138 | + |
| 139 | +// Serial build |
| 140 | +const templateData = [] |
| 141 | + |
| 142 | +const afterBuild = templateList.reduce((p, item) => { |
| 143 | + const ps = new BuildProcess(item, { env: env[item] }) |
| 144 | + p = p.then(() => ps.run()) |
| 145 | + .then(() => templateData.push(item)) |
| 146 | + return p |
| 147 | +}, Promise.resolve()) |
| 148 | + |
| 149 | +afterBuild |
| 150 | + .then(() => buildIndex(templateData, deployDir('index.html'))) |
| 151 | + .catch((err) => { |
| 152 | + if (err) { |
| 153 | + console.trace(err) |
| 154 | + process.exit(1) |
| 155 | + } |
| 156 | + }) |
0 commit comments