UNPKG

flow-build

Version:
251 lines (221 loc) 6.79 kB
"use strict"; const EventEmitter = require("events"); const path = require("path"); const chalk = require("chalk"); const fs = require("fs-extra"); const cpy = require("cpy"); let _ = require("lodash"); const checkRequiredFiles = require("./utils/checkRequiredFiles"); const validateSchema = require("./schema/v"); const openBrowser = require("./utils/openBrowser"); let { getClientConfig, getServerConfig, webpack } = require("./webpack"); const Logger = require("./utils/logger"); let logger = new Logger("flow"); module.exports = class Builder extends EventEmitter { /** * * @param {*} options */ constructor(options) { super(); this.options = options; this.initHook(); //hook: entry-option this.emit("entry-option", this); //对options进行格式化校验 validateSchema(this.options); this.mode = this.options.mode; this.env = this.options.env; this.checkFiles(); this.copyFiles(); this.initWebpack(); } /** * 获取webpack配置 */ initWebpack() { this.webpack = webpack; if (this.mode == "ssr" || this.mode == "vue-prerender") { let { webpackConfig } = getServerConfig(this); this.serverWebpackConfig = webpackConfig; } let { webpackConfig } = getClientConfig(this); this.clientWebpackConfig = webpackConfig; } /** * 检测入口文件是否存在 */ checkFiles() { // logger.info("Check entry files..."); let op = this.options; let paths = []; let dealEntry = entry => { if (typeof entry == "string") { paths.push(path.resolve(process.cwd(), entry)); } else if (!Array.isArray(entry)) { Object.keys(entry).forEach(key => { paths.push(path.resolve(process.cwd(), entry[key])); }); } else { entry.forEach(key => { paths.push(path.resolve(process.cwd(), key)); }); } }; // 判断webpack的entry文件是否存在,ssr情况下,必须有client和server if (this.mode == "ssr") { if (!op.entry.client || !op.entry.server) { console.log( chalk.red( " In SSR mode, the entry.client field and the entry.server field must be included in the config file" ) ); process.exit(1); } dealEntry(op.entry.client); dealEntry(op.entry.server); } else { dealEntry(op.entry); } //判断html模板文件是否存在 if (this.mode == "multiple") { if (!Array.isArray(op.html.template)) { console.log( chalk.red( " the template field is an array in the config file" ) ); process.exit(1); } op.html.template.forEach(t => { paths.push(path.resolve(process.cwd(), t.path)); }); } else if (this.mode == "ssr") { if (Array.isArray(op.html.template)) { console.log( chalk.red( " In SSR mode, the html.template field must be object in the config file" ) ); process.exit(1); } paths.push(path.resolve(process.cwd(), op.html.template.path)); //bugs: mode为ssr时,filename不能为index.html if (op.html.template.filename == "index.html") { this.options.html.template.filename = "index.ssr.html"; } } else { paths.push(path.resolve(process.cwd(), op.html.template.path)); } if (!checkRequiredFiles(paths)) { process.exit(1); } } /** * 白名单,复制不需要编译的文件到指定的地址 */ async copyFiles() { let white = this.options.white; if (white) { try { if (Array.isArray(white)) { await Promise.all( white.map(item => { return cpy(item.from, item.to, item.options || {}); }) ); } else { await cpy(white.from, white.to, white.options || {}); } } catch (error) { logger.error("copy files error:"); logger.error(error); process.exit(1); } } } /** * 开始启动程序 */ run() { if (this.env !== "dev" && this.options.clean) { logger.info("Before packing, remove the output folder"); fs.remove( path.resolve(process.cwd(), this.options.build.outputPath) ); } this.emit("run", this); if (this.mode == "ssr") { this.build(); } else { let SpaCompontent = require("./Spa"); new SpaCompontent(this); } } /** * 开始服务端打包 * @param {*} callback */ build(callback) { let SSRCompontent = require("./SSR"); let SSRBuilder = new SSRCompontent(this); return SSRBuilder.build(callback); } /** * 初始化hook插件 */ initHook() { let hooks = Array.isArray(this.options.hooks) ? this.options.hooks : [this.options.hooks]; hooks.forEach(obj => { if (obj && obj.apply) obj.apply(this); }); } /** * 对外提供自动打开浏览器的功能 * @param {*} host * @param {*} port */ openBrowser(host, port) { openBrowser(host, port); } /** * 获取options的配置 * @param {*} path */ get(path) { return _.get(this.options, path); } /** * 设置options的配置 * @param {*} path * @param {*} val */ set(path, val) { return _.set(this.options, path, val); } /** * 更新options的配置 * @param {*} path * @param {*} updater */ update(path, updater) { this.set(path, updater(this.get(path))); } /** * 删除options的配置 * @param {*} path */ delete(path) { return _.unset(this.options, path); } /** * 在options中是否含有某项配置 * @param {*} path * @param {*} item */ has(path) { return _.has(this.options, path); } };