fusox
Version:
Command line wrapper for fuse-box
284 lines (246 loc) • 10.2 kB
JavaScript
const fsb = require('fuse-box')
const {parseBoolean, findExistingFile, getTransparentCorsSnippet, printHeader, getFreePort} = require('../helpers')
const {existsSync} = require('fs')
const util = require('util')
const path = require('path')
const {spawn} = require('child_process')
const {YAMLPlugin} = require('fuse-box-yaml')
const requireGlobal = require('requireg')
module.exports = {parseBuildElectronFlags, buildElectronCommand}
function parseBuildElectronFlags (args, flags) {
let electron = null
try {
// try to find electron in source's node_modules directory
let electronPath = require.resolve('electron', {paths: [flags.nodeModulesPath]})
electron = require(electronPath)
} catch (err) {
try {
// try to find electron globally
electron = requireGlobal('electron')
} catch (err) {}
}
if ( ! electron) {
throw new Error('Could not find module "electron", make sure you have it installed')
}
let customMainFile = args.main
let customIndexFile = args.index
let customRendererFile = args.renderer
let assetsDestinationPath = flags.destinationPath
let assetsWebPathResolver = (f) => './' + f
let assetsMainPath = 'dist'
let assetsRendererPath = '.'
let openApplicationInBrowser = args.open === undefined ? false : parseBoolean(args.open)
let runDevServer = flags.runApplication || openApplicationInBrowser
let watchForChanges = args.watch === undefined ? runDevServer : parseBoolean(args.watch)
// let treeshakeCode = args.treeshake === undefined ? true : parseBoolean(args.treeshake)
let hashFileNames = args.hash === undefined ? false : parseBoolean(args.hash)
let customMainFilePath = customMainFile && flags.resolveSourcePath(customMainFile)
let defaultMainFilePath = flags.resolveSourcePath('index.ts')
let mainFilePath = findExistingFile(customMainFilePath, defaultMainFilePath)
if (!mainFilePath || !existsSync(mainFilePath)) {
throw new Error(util.format(
'Could not find main file at "%s" or "%s", see "--main" option',
flags.resolveSourcePathRelative(customMainFilePath),
flags.resolveSourcePathRelative(defaultMainFilePath)
))
}
let mainFile = mainFilePath && path.basename(mainFilePath)
let mainFilePathRelative = mainFilePath.replace(flags.sourcePath + '/', '')
let customRendererFilePath = customRendererFile && flags.resolveSourcePath(customRendererFile)
let defaultRendererFilePath = flags.resolveSourcePath('renderer.tsx')
let alternateRendererFilePath = flags.resolveSourcePath('renderer.ts')
let rendererFilePath = findExistingFile(customRendererFilePath, defaultRendererFilePath, alternateRendererFilePath)
let rendererFile = rendererFilePath && path.basename(rendererFilePath)
if (!rendererFilePath || !existsSync(rendererFilePath)) {
throw new Error('Could not find the renderer file, see "--renderer" option')
}
if (!rendererFilePath || !existsSync(rendererFilePath)) {
throw new Error(util.format(
'Could not find renderer file at "%s" or "%s" or "%s", see "--renderer" option',
flags.resolveSourcePathRelative(customRendererFilePath),
flags.resolveSourcePathRelative(defaultRendererFilePath),
flags.resolveSourcePathRelative(alternateRendererFilePath)
))
}
let rendererFilePathRelative = rendererFilePath.replace(flags.sourcePath + '/', '')
let customIndexFilePath = customIndexFile && flags.resolveSourcePath(customIndexFile)
let defaultIndexFilePath = flags.resolveSourcePath('index.html')
let fallbackIndexFilePath = path.resolve(__dirname, '../assets/electron.html')
let indexFilePath = findExistingFile(customIndexFilePath, defaultIndexFilePath, fallbackIndexFilePath)
let indexFile = indexFilePath && path.basename(indexFilePath)
let indexFileAssetsPath = '.'
if (!indexFilePath || !existsSync(indexFilePath)) {
throw new Error('Could not find the index file, see "--index" option')
}
let appName = flags.appName || rendererFile.replace(path.extname(rendererFile), '')
return {
...flags,
electron,
mainFile,
mainFilePath,
mainFilePathRelative,
indexFile,
indexFilePath,
indexFileAssetsPath,
rendererFile,
rendererFilePath,
rendererFilePathRelative,
assetsDestinationPath,
assetsWebPathResolver,
assetsMainPath,
appName,
assetsRendererPath,
runDevServer,
watchForChanges,
openApplicationInBrowser,
// treeshakeCode,
hashFileNames
}
}
function buildElectronCommand (flags) {
return Promise.all([
buildForElectronMain(flags),
buildForElectronRenderer(flags)
]).then(() => {
if (flags.runApplication) {
let mainBundlePath = path.resolve(flags.destinationPath, 'index.js')
let child = spawn(flags.electron, ['.'], {
shell: true,
cwd: flags.destinationPath,
stdio: 'inherit'
})
// close process if user quits electron application
child.on('close', (code) => process.exit(code))
}
})
}
function buildForElectronMain (flags) {
let fuse = fsb.FuseBox.init({
target: 'server',
homeDir: flags.sourcePath,
modulesFolder: flags.nodeModulesPath,
output: util.format('%s/$name.js', flags.destinationPath),
tsConfig: flags.tsconfigPath,
sourceMaps: flags.generateSourceMaps,
hash: flags.hashFileNames,
cache: flags.useCache,
ensureTsConfig: false,
plugins: [
YAMLPlugin(),
// fsb.EnvPlugin(flags.envConfig),
fsb.CopyPlugin({
useDefault: false,
files: flags.assetFilesExtensions,
dest: '.',
resolve: flags.assetsMainPath
}),
fsb.ReplacePlugin(flags.processEnvConfig),
flags.mode === 'production' && flags.uglifyCode && fsb.UglifyESPlugin(),
// flags.mode === 'production' && fsb.QuantumPlugin({
// target: 'server',
// treeshake: flags.treeshakeCode,
// uglify: flags.uglifyCode,
// bakeApiIntoBundle: 'main',
// })
]
})
let mainBundle = fuse.bundle('index')
.target('server')
.instructions(util.format('> [%s]', flags.mainFilePathRelative))
if (flags.watchForChanges) {
mainBundle.watch()
}
printHeader('Launching fuse-box for "electron main"')
return fuse.run()
}
function buildForElectronRenderer (flags) {
return getFreePort(flags.defaultDevServerPort)
.then((devServerPort) => {
flags.devServerPort = devServerPort
if (flags.globalName) {
printHeader('Renderer package exported as window["%s"] in browser', flags.globalName)
}
let fuse = fsb.FuseBox.init({
homeDir: flags.sourcePath,
modulesFolder: flags.nodeModulesPath,
output: util.format('%s/$name.js', flags.destinationPath),
tsConfig: flags.tsconfigPath,
sourceMaps: flags.generateSourceMaps,
hash: flags.hashFileNames,
cache: flags.useCache,
ensureTsConfig: false,
globals: flags.globalName ? {default: flags.globalName} : null,
plugins: [
YAMLPlugin(),
fsb.WebIndexPlugin({
template: flags.indexFilePath,
path: flags.indexFileAssetsPath
}),
[fsb.StylusPlugin(), fsb.PostCSSPlugin(flags.postCssConfig), fsb.CSSResourcePlugin({
dist: flags.assetsDestinationPath,
resolve: flags.assetsWebPathResolver
}), fsb.CSSPlugin()],
[fsb.SassPlugin(), fsb.PostCSSPlugin(flags.postCssConfig), fsb.CSSResourcePlugin({
dist: flags.assetsDestinationPath,
resolve: flags.assetsWebPathResolver
}), fsb.CSSPlugin()],
[fsb.LESSPlugin(), fsb.PostCSSPlugin(flags.postCssConfig), fsb.CSSResourcePlugin({
dist: flags.assetsDestinationPath,
resolve: flags.assetsWebPathResolver
}), fsb.CSSPlugin()],
[fsb.PostCSSPlugin(flags.postCssConfig), fsb.CSSResourcePlugin({
dist: flags.assetsDestinationPath,
resolve: flags.assetsWebPathResolver
}), fsb.CSSPlugin()],
// fsb.EnvPlugin(flags.envConfig),
fsb.CopyPlugin({
useDefault: false,
files: flags.assetFilesExtensions,
dest: '.',
resolve: flags.assetsRendererPath
}),
fsb.JSONPlugin(),
fsb.ReplacePlugin(flags.processEnvConfig),
flags.mode === 'production' && flags.uglifyCode && fsb.UglifyESPlugin(),
// flags.mode === 'production' && fsb.QuantumPlugin({
// target: 'browser',
// treeshake: flags.treeshakeCode,
// uglify: flags.uglifyCode,
// bakeApiIntoBundle: flags.appName
// })
]
})
// todo: bundle splitting disabled until a fix is available https://github.com/fuse-box/fuse-box/issues/1119
// let rendererVendorsBundle = fuse.bundle('vendors')
// .target('browser')
// .instructions(util.format('~ %s', flags.rendererFilePathRelative))
//
// let rendererBundle = fuse.bundle('renderer')
// .target('browser')
// .instructions(util.format('!> [%s]', flags.rendererFilePathRelative))
let rendererBundle = fuse.bundle('renderer')
.target('browser')
.instructions(util.format('> %s %s', flags.rendererFilePathRelative, flags.dynamicFilesInstructions))
if (flags.runCorsProxy) {
rendererBundle.plugin(fsb.BannerPlugin(getTransparentCorsSnippet(
flags.envConfig.CORS_PROXY_HOST,
flags.envConfig.CORS_PROXY_PORT,
flags.envConfig.NODE_ENV
)))
}
if (flags.runDevServer) {
if (flags.defaultDevServerPort !== flags.devServerPort) {
printHeader('Dev server port "%s" already in use, fallback to "%s"', flags.defaultDevServerPort, flags.devServerPort)
}
fuse.dev({
port: flags.devServerPort,
open: flags.openApplicationInBrowser
})
}
if (flags.watchForChanges) {
rendererBundle.watch().hmr({port: flags.devServerPort})
}
printHeader('Launching fuse-box for "electron renderer"')
return fuse.run()
})
}