const fsExtra = require('fs-extra') const path = require('path') const {exec} = require('child_process') const inquirer = require("inquirer"); const chalk = require('chalk') const fs = require('fs') /** * 将函数封装成promise */ const promisify = fn => { return function () { let args = arguments; return new Promise(function (resolve, reject) { [].push.call(args, function (err, result) { if (err) { console.log(err) reject(err); } else { resolve(result); } }); fn.apply(null, args); }); } } const readdir = promisify(fs.readdir) const stat = promisify(fs.stat) /** * 封装打印工具 */ const {log} = console const chalkTag = { info: msg => log([chalk.bgBlue.black(' INFO '), msg].join(' ')), done: msg => log([chalk.bgGreen.black(' DONE '), msg].join(' ')), warn: msg => log([chalk.bgYellow.black(' WARN '), msg].join(' ')), error: msg => log([chalk.bgRed.black(' ERROR '), msg].join(' ')), } const start = () => { let cores, apps //询问打包哪个项目 init().then(async choices => { return await inquirer.prompt([{ name: "PROJECT", type: 'list', message: "要打包发布哪一个项目?", choices }]) }).then(res => new Promise(resolve => { const {PROJECT} = res let install = path.join(__dirname, PROJECT, 'index.js') fsExtra.ensureFile(install) const coreLib = path.join(__dirname, PROJECT, 'core.import.json') fsExtra.readJson(coreLib, (err, data) => { chalkTag.info("加载核心库配置..") cores = [] if (data) { findApp('core/apps', file => { let fileName = file.replace(/.*\\(.+)\.vue/g, '$1') if (Object.keys(data).includes(fileName)) { cores.push({name: fileName, component: file.replace(/\\/g, "/")}) log(">>>正在打包核心库...%s", fileName) } }).then(() => { chalkTag.done('核心库打包完毕') resolve(PROJECT) }) } else { chalkTag.done('核心库无打包') resolve(PROJECT) } }) })).then(prj => new Promise(resolve => { const appLib = path.join(__dirname, prj.toString(), 'apps.import.json') fsExtra.readJson(appLib, (err, data) => { chalkTag.info('加载业务应用配置...') apps = [] let appDir = "packages" if (data) { findApp(appDir, file => { let fileName = file.replace(/.*\\(.+)\.vue/g, '$1') if (Object.keys(data).includes(fileName)) { apps.push({name: fileName, component: file.replace(/\\/g, "/")}) log(">>>正在打包业务应用...%s", fileName) } }).then(() => { chalkTag.done('业务应用打包完毕') resolve(prj) }) } else { inquirer.prompt([{ name: "CONFIRM", type: 'confirm', message: "未读取到业务应用配置文件,是否要打包整个packages?", }]).then(res => { if (res.CONFIRM) { findApp(appDir, file => { if (/.*\\(App[^\\]+)\.vue/g.test(file)) { let fileName = file.replace(/.*\\(App[^\\]+)\.vue/g, '$1') apps.push({name: fileName, component: file.replace(/\\/g, "/")}) log(">>>正在打包业务应用...%s", fileName) } }).then(() => { chalkTag.done('业务应用打包完毕') resolve(prj) }) } else { chalkTag.done('业务应用无打包') resolve(prj) } }) } }) })).then(prj => new Promise(resolve => { if (prj == 'dvui') { return resolve(prj) } chalkTag.info('正在生成打包文件...') let bin = path.join(__dirname, prj.toString(), 'index.js'), coreApps = cores.map(e => `{name:'${e.name}',component:require('../../${e.component}').default}`), bizApps = apps.map(e => `{name:'${e.name}',component:require('../../${e.component}').default}`), comps = [...coreApps, ...bizApps], content = ` const apps = [${comps.toString()}] const install = function (Vue) { if (install.installed) return Promise.resolve() else{ let contexts = require.context('.', true, /(\\/.+)\\/App[^\\/]+\\.vue$/) if (contexts) { contexts.keys().map(e => { if (contexts(e).default) { let mod = apps.find(a=>a.name==contexts(e).default.name) if(mod){ mod.component = contexts(e).default }else{ apps.push({name:contexts(e).default.name,component:contexts(e).default}) } } }) } apps.map(e=>{ Vue.component(e.name,e.component) }) } } // 判断是否是直接引入文件 if (typeof window !== 'undefined' && window.Vue) { install(window.Vue) } export default { // 导出的对象必须具有 install,才能被 Vue.use() 方法安装 install } ` fsExtra.outputFile(bin, content, err => { if (err) { chalkTag.error(err) reject() } else chalkTag.done('生成打包文件') resolve(prj) }) })).then(project => new Promise((resolve, reject) => { fsExtra.readJson(path.join(__dirname, project.toString(), 'package.json'), (err, json) => { let cmd = `vue-cli-service build --target lib --dest project/${project}/dist project/${project}/${project == 'dvui' ? 'entries' : 'index'}.js --name ${json.name}` chalkTag.info('正在压缩文件中...') exec(cmd, { cwd: path.join(__dirname, '..') }, (err, stdout) => { log(stdout); if (!err) { chalkTag.done('打包成功!') resolve(project) } else { chalkTag.error(err) reject() } }) }) })).then(project => { chalkTag.info('正在发布中...') let cmd = `cd ${project}&npm unpublish --force&npm publish` exec(cmd, { cwd: path.join(__dirname, '.') }, (err, stdout) => { log(stdout); if (!err) { chalkTag.done('发布成功!') } else chalkTag.error(err) }) }) } /** * 遍历应用的方法 */ const findApp = (dir, cb) => { return readdir(dir).then(apps => { return Promise.all(apps.map(e => { let cPath = path.join(dir, e) return stat(cPath).then(state => { if (state.isDirectory()) { return findApp(cPath, cb) } else if (state.isFile()) { cb && cb(cPath) } }) }) || []) }) } /** * 初始化打包配置文件 */ const init = () => { chalkTag.info('开始运行项目打包工具...') return new Promise(resolve => fs.readdir('./project', (err, files) => { resolve(files.filter(e => e.indexOf('.') < 0)) })) } start();