diff options
Diffstat (limited to 'electron/service')
| -rw-r--r-- | electron/service/commands/build-main.js | 41 | ||||
| -rw-r--r-- | electron/service/commands/build.js | 44 | ||||
| -rw-r--r-- | electron/service/commands/dev.js | 102 | ||||
| -rw-r--r-- | electron/service/config/base.js | 126 | ||||
| -rw-r--r-- | electron/service/config/css.js | 72 | ||||
| -rw-r--r-- | electron/service/config/dev.js | 43 | ||||
| -rw-r--r-- | electron/service/config/main.js | 73 | ||||
| -rw-r--r-- | electron/service/config/prod.js | 41 | ||||
| -rw-r--r-- | electron/service/config/renderer.js | 45 | ||||
| -rw-r--r-- | electron/service/config/terserOptions.js | 42 | ||||
| -rw-r--r-- | electron/service/project.config.js | 16 | ||||
| -rw-r--r-- | electron/service/utils/getLocalIP.js | 17 | ||||
| -rw-r--r-- | electron/service/utils/loadEnv.js | 39 | ||||
| -rw-r--r-- | electron/service/utils/logger.js | 72 | ||||
| -rw-r--r-- | electron/service/utils/paths.js | 6 | ||||
| -rw-r--r-- | electron/service/utils/resolveClientEnv.js | 11 | ||||
| -rw-r--r-- | electron/service/utils/spinner.js | 57 |
17 files changed, 847 insertions, 0 deletions
diff --git a/electron/service/commands/build-main.js b/electron/service/commands/build-main.js new file mode 100644 index 00000000..1b28ef91 --- /dev/null +++ b/electron/service/commands/build-main.js @@ -0,0 +1,41 @@ +'use strict' + +const loadEnv = require('../utils/loadEnv') +loadEnv() +loadEnv('production') + +const rm = require('rimraf') +const webpack = require('webpack') + +const { error, done } = require('../utils/logger') +const { logWithSpinner, stopSpinner } = require('../utils/spinner') +const paths = require('../utils/paths') +// after renderer is built, main is next to build +const webpackConfig = require('../config/main') +const config = require('../project.config') + +logWithSpinner('Building for production...') +// removed rm function to prevent the deletion of renderer +webpack(webpackConfig, (err, stats) => { + stopSpinner(false) + + if (err) throw err + + process.stdout.write( + stats.toString({ + colors: true, + modules: false, + children: false, + chunks: false, + chunkModules: false, + }) + '\n\n' + ) + + if (stats.hasErrors()) { + error('Build failed with errors.\n') + process.exit(1) + } + + done('Build complete.\n') +}) + diff --git a/electron/service/commands/build.js b/electron/service/commands/build.js new file mode 100644 index 00000000..097f7013 --- /dev/null +++ b/electron/service/commands/build.js @@ -0,0 +1,44 @@ +'use strict' + +const loadEnv = require('../utils/loadEnv') +loadEnv() +loadEnv('production') + +const rm = require('rimraf') +const webpack = require('webpack') + +const { error, done } = require('../utils/logger') +const { logWithSpinner, stopSpinner } = require('../utils/spinner') +const paths = require('../utils/paths') +// build renderer first +const webpackConfig = require('../config/renderer') +const config = require('../project.config') + +logWithSpinner('Building for production...') + +rm(paths.resolve(config.outputDir), (err) => { + if (err) throw err + + webpack(webpackConfig, (err, stats) => { + stopSpinner(false) + + if (err) throw err + + process.stdout.write( + stats.toString({ + colors: true, + modules: false, + children: false, + chunks: false, + chunkModules: false, + }) + '\n\n' + ) + + if (stats.hasErrors()) { + error('Build failed with errors.\n') + process.exit(1) + } + + done('Build complete.\n') + }) +}) diff --git a/electron/service/commands/dev.js b/electron/service/commands/dev.js new file mode 100644 index 00000000..bea42021 --- /dev/null +++ b/electron/service/commands/dev.js @@ -0,0 +1,102 @@ +'use strict' + +const loadEnv = require('../utils/loadEnv') +loadEnv() +loadEnv('development') +const chalk = require('chalk') +const webpack = require('webpack') +const WebpackDevServer = require('webpack-dev-server') +const { info } = require('../utils/logger') +const getLocalIP = require('../utils/getLocalIP') +const devWebpackConfig = require('../config/dev') +const devServerOptions = devWebpackConfig.devServer +const { spawn } = require('node:child_process') +const electron = require('electron') +const path = require('path') +const url = require('url') +const fs = require('fs'); + +let electronProcess = null +let manualRestart = false +// disable warnings in browser console +process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'false' + +const protocol = devServerOptions.https ? 'https' : 'http' +const host = devServerOptions.host || '0.0.0.0' +const port = devServerOptions.port || 8080 + +// older code that sets the url for the path I would assume +var parseArg = process.argv[2] || "" +var yarnArg = url.parse(parseArg) + +function resetPort() { + let resetData = { "_comment1": "port should not be declared when commiting" } + fs.writeFileSync(path.join(__dirname, "../../src/lib/flaskserverport.json"), JSON.stringify(resetData), 'utf8') + console.log("Resetting the flaskport") +} + +function startElectron(webpackport) { +var wbport = webpackport + // this sends url to proper position + process.argv.shift() + process.argv.shift() + // get URL from PrintPDF + // checks if url is http + if (yarnArg.protocol) { + var args = [ + '--inspect=5858', + path.join(__dirname, '../../dist/electron/main.js') + ].concat(process.argv) + } else { + var args = [ + '--inspect=5858', + `http://0.0.0.0:${wbport}/#${process.argv}` + ].concat(process.argv) + } + // detect yarn or npm and process commandline args accordingly + if (process.env.npm_execpath.endsWith('yarn.js')) { + args = args.concat(process.argv.slice(3)) + } else if (process.env.npm_execpath.endsWith('npm-cli.js')) { + args = args.concat(process.argv.slice(2)) + } + electronProcess = spawn(electron, args) + electronProcess.on('close', () => { + if (!manualRestart) { + process.exit() + } else { + process.kill(electronProcess.pid) + } + resetPort() + }) + electronProcess.on('exit', () => { + resetPort() + }) +} + +info('Starting development server...') +const compiler = webpack(devWebpackConfig) +const server = new WebpackDevServer(devServerOptions, compiler) + +compiler.hooks.done.tap('serve', (stats) => { + console.log() + console.log() + console.log(`App running at:`) + console.log(` - Local: ${chalk.cyan(`${protocol}://${host}:${port}`)}`) + console.log(` - Network: ${chalk.cyan(`${protocol}://${getLocalIP()}:${port}`)}`) + console.log() + + // allows livereload for webpack devserver to work without multiple instances of electron + if (electronProcess) { + manualRestart = true + } else { + manualRestart = false + // starts nodejs electron commandline browser + startElectron(devServerOptions.port) + } +}) + +server.start(port, host, (err) => { + if (err) { + process.exit(0) + } +}) diff --git a/electron/service/config/base.js b/electron/service/config/base.js new file mode 100644 index 00000000..8743f364 --- /dev/null +++ b/electron/service/config/base.js @@ -0,0 +1,126 @@ +'use strict' + +const { DefinePlugin, EnvironmentPlugin } = require('webpack') +const { VueLoaderPlugin } = require('vue-loader') +const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin') +const HTMLPlugin = require('html-webpack-plugin') +const { VuetifyPlugin } = require('webpack-plugin-vuetify') + +const resolveClientEnv = require('../utils/resolveClientEnv') +const paths = require('../utils/paths') + +const config = require('../project.config') + +const isProd = process.env.NODE_ENV === 'production' + +module.exports = { + context: process.cwd(), + + output: { + path: paths.resolve(config.outputDir), + publicPath: config.dev.publicPath, + filename: '[name].js', + }, + + resolve: { + alias: { + '@': paths.resolve('src'), + }, + extensions: ['.ts', '.tsx', '.js', '.jsx', '.vue', '.json', 'html', 'ejs'], + }, + + plugins: [ + new VueLoaderPlugin(), + new EnvironmentPlugin(['NODE_ENV']), + new CaseSensitivePathsPlugin(), + new HTMLPlugin({ + template: paths.resolve('src/index.html'), + templateParameters: { + ...resolveClientEnv( + { publicPath: isProd ? config.build.publicPath : config.dev.publicPath }, + false /* raw */ + ), + }, + }), + new VuetifyPlugin({ autoImport: true }), + new DefinePlugin({ + // vue3 feature flags <http://link.vuejs.org/feature-flags> + __VUE_OPTIONS_API__: 'true', + __VUE_PROD_DEVTOOLS__: 'false', + + ...resolveClientEnv({ + publicPath: isProd ? config.build.publicPath : config.dev.publicPath, + }), + }), + ], + + module: { + noParse: /^(vue|vue-router)$/, + + rules: [ + { + test: /\.vue$/, + loader: 'vue-loader', + }, + // babel + { + test: /\.m?jsx?$/, + exclude: (file) => { + // always transpile js in vue files + if (/\.vue\.jsx?$/.test(file)) { + return false + } + // Don't transpile node_modules + return /node_modules/.test(file) + }, + use: ['thread-loader', 'babel-loader'], + }, + + // ts + { + test: /\.tsx?$/, + use: [ + 'thread-loader', + 'babel-loader', + { + loader: 'ts-loader', + options: { + transpileOnly: true, + appendTsSuffixTo: ['\\.vue$'], + happyPackMode: true, + }, + }, + ], + }, + + // images + { + test: /\.(png|jpe?g|gif|webp)(\?.*)?$/, + type: 'asset', + generator: { filename: 'img/[contenthash:8][ext][query]' }, + }, + + // do not base64-inline SVGs. + // https://github.com/facebookincubator/create-react-app/pull/1180 + { + test: /\.(svg)(\?.*)?$/, + type: 'asset/resource', + generator: { filename: 'img/[contenthash:8][ext][query]' }, + }, + + // media + { + test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, + type: 'asset', + generator: { filename: 'media/[contenthash:8][ext][query]' }, + }, + + // fonts + { + test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i, + type: 'asset', + generator: { filename: 'fonts/[contenthash:8][ext][query]' }, + }, + ], + }, +} diff --git a/electron/service/config/css.js b/electron/service/config/css.js new file mode 100644 index 00000000..3fb5893e --- /dev/null +++ b/electron/service/config/css.js @@ -0,0 +1,72 @@ +'use strict' + +const MiniCssExtractPlugin = require('mini-css-extract-plugin') + +const isProd = process.env.NODE_ENV === 'production' + +const plugins = [] +if (isProd) { + const filename = 'css/[name].[contenthash:8].css' + + plugins.push( + new MiniCssExtractPlugin({ + filename, + chunkFilename: filename, + }) + ) +} + +const genStyleRules = () => { + const cssLoader = { + loader: 'css-loader', + options: { + // how many loaders before css-loader should be applied to [@import]ed resources. + // stylePostLoader injected by vue-loader + postcss-loader + importLoaders: 1 + 1, + esModule: false, // css-loader using ES Modules as default in v4, but vue-style-loader support cjs only. + }, + } + const postcssLoader = { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [require('autoprefixer')] + }, + }, + } + const extractPluginLoader = { + loader: MiniCssExtractPlugin.loader, + } + const vueStyleLoader = { + loader: 'vue-style-loader', + } + + function createCSSRule(test, loader, loaderOptions) { + const loaders = [cssLoader, postcssLoader] + + if (isProd) { + loaders.unshift(extractPluginLoader) + } else { + loaders.unshift(vueStyleLoader) + } + + if (loader) { + loaders.push({ loader, options: loaderOptions }) + } + + return { test, use: loaders } + } + + return [ + createCSSRule(/\.css$/), + createCSSRule(/\.p(ost)?css$/), + createCSSRule(/\.scss$/, 'sass-loader') + ] +} + +module.exports = { + plugins, + module: { + rules: genStyleRules(), + }, +} diff --git a/electron/service/config/dev.js b/electron/service/config/dev.js new file mode 100644 index 00000000..42a82b37 --- /dev/null +++ b/electron/service/config/dev.js @@ -0,0 +1,43 @@ +'use strict' + +const { merge } = require('webpack-merge') + +const baseWebpackConfig = require('./base') +const cssWebpackConfig = require('./css') +const config = require('../project.config') +const { ProvidePlugin, DefinePlugin } = require('webpack') + + +module.exports = merge(baseWebpackConfig, cssWebpackConfig, { + entry: { + main: './src/renderer/main.js' + }, + + mode: 'development', + + devtool: 'eval-cheap-module-source-map', + + devServer: { + watchFiles: ['src/**/*'], + historyApiFallback: { + rewrites: [{ from: /./, to: '/index.html' }], + }, + devMiddleware: { + publicPath: config.dev.publicPath, + }, + open: false, + host: '0.0.0.0', + port: 'auto', + liveReload: true, + }, + + infrastructureLogging: { + level: 'warn', + }, + + stats: { + assets: false, + modules: false, + errorDetails: false, + }, +}) diff --git a/electron/service/config/main.js b/electron/service/config/main.js new file mode 100644 index 00000000..3083dea0 --- /dev/null +++ b/electron/service/config/main.js @@ -0,0 +1,73 @@ +'use strict' + +const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin') +const config = require('../project.config') + +const resolveClientEnv = require('../utils/resolveClientEnv') +const paths = require('../utils/paths') +const { merge } = require('webpack-merge') +const TerserPlugin = require('terser-webpack-plugin') +const cssWebpackConfig = require('./css') +const terserOptions = require('./terserOptions') +const isProd = process.env.NODE_ENV === 'production' + +module.exports = merge(cssWebpackConfig, { + context: process.cwd(), + mode: 'production', + entry: { + main: './src/main/index.js', + preload: './src/main/preload.js', + }, + + node: { + __dirname: false, + }, + + optimization: { + minimize: true, + minimizer: [new TerserPlugin(terserOptions())], + moduleIds: 'named', + }, + target: ['electron-main'], + + output: { + path: paths.resolve(config.outputDir), + publicPath: config.dev.publicPath, + filename: '[name].js', + }, + + resolve: { + alias: { + '@': paths.resolve('src'), + }, + extensions: ['.ts', '.tsx', '.js', '.jsx', '.vue', '.json', 'html', 'ejs'], + }, + + plugins: [ + new CaseSensitivePathsPlugin(), + ], + + module: { + noParse: /^(vue|vue-router)$/, + + rules: [ + // ts + { + test: /\.tsx?$/, + use: [ + 'thread-loader', + 'babel-loader', + { + loader: 'ts-loader', + options: { + transpileOnly: true, + appendTsSuffixTo: ['\\.vue$'], + happyPackMode: true, + }, + }, + ], + }, + ], + }, +} +)
\ No newline at end of file diff --git a/electron/service/config/prod.js b/electron/service/config/prod.js new file mode 100644 index 00000000..1d9e8726 --- /dev/null +++ b/electron/service/config/prod.js @@ -0,0 +1,41 @@ +'use strict' + +const { merge } = require('webpack-merge') +const TerserPlugin = require('terser-webpack-plugin') + +const baseWebpackConfig = require('./base') +const cssWebpackConfig = require('./css') +const config = require('../project.config') +const terserOptions = require('./terserOptions') + +module.exports = merge(baseWebpackConfig, cssWebpackConfig, { + mode: 'production', + + output: { + publicPath: config.build.publicPath, + }, + + optimization: { + minimize: true, + minimizer: [new TerserPlugin(terserOptions())], + moduleIds: 'deterministic', + moduleIds: 'named', + splitChunks: { + cacheGroups: { + defaultVendors: { + name: `chunk-vendors`, + test: /[\\/]node_modules[\\/]/, + priority: -10, + chunks: 'initial', + }, + common: { + name: `chunk-common`, + minChunks: 2, + priority: -20, + chunks: 'initial', + reuseExistingChunk: true, + }, + }, + }, + }, +}) diff --git a/electron/service/config/renderer.js b/electron/service/config/renderer.js new file mode 100644 index 00000000..cf3fab01 --- /dev/null +++ b/electron/service/config/renderer.js @@ -0,0 +1,45 @@ +'use strict' + +const { merge } = require('webpack-merge') +const TerserPlugin = require('terser-webpack-plugin') + +const baseWebpackConfig = require('./base') +const cssWebpackConfig = require('./css') +const config = require('../project.config') +const terserOptions = require('./terserOptions') + +module.exports = merge(baseWebpackConfig, cssWebpackConfig, { + mode: 'production', + entry: { + renderer: './src/renderer/main.js', + }, + + output: { + publicPath: config.build.publicPath, + }, + + optimization: { + minimize: true, + minimizer: [new TerserPlugin(terserOptions())], + moduleIds: 'deterministic', + moduleIds: 'named', + splitChunks: { + cacheGroups: { + defaultVendors: { + name: `chunk-vendors`, + test: /[\\/]node_modules[\\/]/, + priority: -10, + chunks: 'initial', + }, + common: { + name: `chunk-common`, + minChunks: 2, + priority: -20, + chunks: 'initial', + reuseExistingChunk: true, + }, + }, + }, + }, + target: ['electron-renderer'], +}) diff --git a/electron/service/config/terserOptions.js b/electron/service/config/terserOptions.js new file mode 100644 index 00000000..134a3258 --- /dev/null +++ b/electron/service/config/terserOptions.js @@ -0,0 +1,42 @@ +'use strict' + +module.exports = (options) => ({ + terserOptions: { + compress: { + // turn off flags with small gains to speed up minification + arrows: false, + collapse_vars: false, // 0.3kb + comparisons: false, + computed_props: false, + hoist_funs: false, + hoist_props: false, + hoist_vars: false, + inline: false, + loops: false, + negate_iife: false, + properties: false, + reduce_funcs: false, + reduce_vars: false, + switches: false, + toplevel: false, + typeofs: false, + + // a few flags with noticable gains/speed ratio + // numbers based on out of the box vendor bundle + booleans: true, // 0.7kb + if_return: true, // 0.4kb + sequences: true, // 0.7kb + unused: true, // 2.3kb + + // required features to drop conditional branches + conditionals: true, + dead_code: true, + evaluate: true, + }, + mangle: { + safari10: true, + }, + }, + // parallel: options.parallel, + extractComments: false, +}) diff --git a/electron/service/project.config.js b/electron/service/project.config.js new file mode 100644 index 00000000..7e7df9c1 --- /dev/null +++ b/electron/service/project.config.js @@ -0,0 +1,16 @@ +'use strict' + +module.exports = { + // orginal was dist + outputDir: 'dist/electron', + + dev: { + publicPath: '/', + port: 8080, + }, + + build: { + // orginal was / + publicPath: './', + }, +} diff --git a/electron/service/utils/getLocalIP.js b/electron/service/utils/getLocalIP.js new file mode 100644 index 00000000..14926ee2 --- /dev/null +++ b/electron/service/utils/getLocalIP.js @@ -0,0 +1,17 @@ +'use strict' + +const os = require('os') + +module.exports = function getLocalIP() { + const interfaces = os.networkInterfaces() + + for (const devName in interfaces) { + const iface = interfaces[devName] + for (let i = 0; i < iface.length; i++) { + const alias = iface[i] + if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) { + return alias.address + } + } + } +} diff --git a/electron/service/utils/loadEnv.js b/electron/service/utils/loadEnv.js new file mode 100644 index 00000000..3c054ff6 --- /dev/null +++ b/electron/service/utils/loadEnv.js @@ -0,0 +1,39 @@ +'use strict' + +const path = require('path') +const dotenv = require('dotenv') +const dotenvExpand = require('dotenv-expand') +const { error } = require('./logger') + +module.exports = function loadEnv(mode) { + const basePath = path.resolve(process.cwd(), `.env${mode ? `.${mode}` : ``}`) + const localPath = `${basePath}.local` + + const load = (envPath) => { + try { + const env = dotenv.config({ path: envPath, debug: process.env.DEBUG }) + dotenvExpand.expand(env) + } catch (err) { + // only ignore error if file is not found + if (err.toString().indexOf('ENOENT') < 0) { + error(err) + } + } + } + + load(localPath) + load(basePath) + + // by default, NODE_ENV and BABEL_ENV are set to "development" unless mode + // is production or test. However the value in .env files will take higher + // priority. + if (mode) { + const defaultNodeEnv = mode === 'production' || mode === 'test' ? mode : 'development' + if (process.env.NODE_ENV == null) { + process.env.NODE_ENV = defaultNodeEnv + } + if (process.env.BABEL_ENV == null) { + process.env.BABEL_ENV = defaultNodeEnv + } + } +} diff --git a/electron/service/utils/logger.js b/electron/service/utils/logger.js new file mode 100644 index 00000000..0d74c52c --- /dev/null +++ b/electron/service/utils/logger.js @@ -0,0 +1,72 @@ +'use strict' + +const chalk = require('chalk') +const stripAnsi = require('strip-ansi') +const readline = require('readline') +const EventEmitter = require('events') + +exports.events = new EventEmitter() + +function _log(type, tag, message) { + if (process.env.VUE_CLI_API_MODE && message) { + exports.events.emit('log', { + message, + type, + tag, + }) + } +} + +const format = (label, msg) => { + return msg + .split('\n') + .map((line, i) => { + return i === 0 ? `${label} ${line}` : line.padStart(stripAnsi(label).length) + }) + .join('\n') +} + +const chalkTag = (msg) => chalk.bgBlackBright.white.dim(` ${msg} `) + +exports.log = (msg = '', tag = null) => { + tag ? console.log(format(chalkTag(tag), msg)) : console.log(msg) + _log('log', tag, msg) +} + +exports.info = (msg, tag = null) => { + console.log(format(chalk.bgBlue.black(' INFO ') + (tag ? chalkTag(tag) : ''), msg)) + _log('info', tag, msg) +} + +exports.done = (msg, tag = null) => { + console.log(format(chalk.bgGreen.black(' DONE ') + (tag ? chalkTag(tag) : ''), msg)) + _log('done', tag, msg) +} + +exports.warn = (msg, tag = null) => { + console.warn( + format(chalk.bgYellow.black(' WARN ') + (tag ? chalkTag(tag) : ''), chalk.yellow(msg)) + ) + _log('warn', tag, msg) +} + +exports.error = (msg, tag = null) => { + console.error(format(chalk.bgRed(' ERROR ') + (tag ? chalkTag(tag) : ''), chalk.red(msg))) + _log('error', tag, msg) + if (msg instanceof Error) { + console.error(msg.stack) + _log('error', tag, msg.stack) + } +} + +exports.clearConsole = (title) => { + if (process.stdout.isTTY) { + const blank = '\n'.repeat(process.stdout.rows) + console.log(blank) + readline.cursorTo(process.stdout, 0, 0) + readline.clearScreenDown(process.stdout) + if (title) { + console.log(title) + } + } +} diff --git a/electron/service/utils/paths.js b/electron/service/utils/paths.js new file mode 100644 index 00000000..a3e173c3 --- /dev/null +++ b/electron/service/utils/paths.js @@ -0,0 +1,6 @@ +'use strict' + +const path = require('path') + +// gen absolute path +exports.resolve = (...args) => path.posix.join(process.cwd(), ...args) diff --git a/electron/service/utils/resolveClientEnv.js b/electron/service/utils/resolveClientEnv.js new file mode 100644 index 00000000..4a4505a6 --- /dev/null +++ b/electron/service/utils/resolveClientEnv.js @@ -0,0 +1,11 @@ +'use strict' +const prefixRE = /^VUE_APP_/ + +module.exports = function resolveClientEnv(options, raw) { + process.env.PUBLIC_PATH = options.publicPath + + if (raw) { + return env + } + +}
\ No newline at end of file diff --git a/electron/service/utils/spinner.js b/electron/service/utils/spinner.js new file mode 100644 index 00000000..d643a933 --- /dev/null +++ b/electron/service/utils/spinner.js @@ -0,0 +1,57 @@ +'use strict' + +const ora = require('ora') +const chalk = require('chalk') + +const spinner = ora() +let lastMsg = null +let isPaused = false + +exports.logWithSpinner = (symbol, msg) => { + if (!msg) { + msg = symbol + symbol = chalk.green('✔') + } + if (lastMsg) { + spinner.stopAndPersist({ + symbol: lastMsg.symbol, + text: lastMsg.text, + }) + } + spinner.text = ' ' + msg + lastMsg = { + symbol: symbol + ' ', + text: msg, + } + spinner.start() +} + +exports.stopSpinner = (persist) => { + if (lastMsg && persist !== false) { + spinner.stopAndPersist({ + symbol: lastMsg.symbol, + text: lastMsg.text, + }) + } else { + spinner.stop() + } + lastMsg = null +} + +exports.pauseSpinner = () => { + if (spinner.isSpinning) { + spinner.stop() + isPaused = true + } +} + +exports.resumeSpinner = () => { + if (isPaused) { + spinner.start() + isPaused = false + } +} + +exports.failSpinner = (text) => { + spinner.fail(text) +} |
