-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
633 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,4 +32,4 @@ | |
"simple-git-hooks": { | ||
"pre-commit": "npx lint-staged" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#!/usr/bin/env node | ||
'use strict' | ||
/* eslint-disable @typescript-eslint/no-var-requires */ | ||
const path = require('path') | ||
const resolveFrom = require('resolve-from') | ||
|
||
let modulePath = '../dist/cli' | ||
try { | ||
// use local cli if exists | ||
modulePath = path.join(path.dirname(resolveFrom(process.cwd(), '@doubleshot/builder')), 'cli.js') | ||
} | ||
catch { } | ||
|
||
require(modulePath) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { cac } from 'cac' | ||
import { version } from '../package.json' | ||
import { createLogger } from './log' | ||
const cli = cac('doubleshot-build') | ||
|
||
cli | ||
.option('-c, --config <file>', '[string] use specified config file') | ||
|
||
// dev | ||
cli | ||
.command('', 'run in development mode') // default command | ||
.alias('dev') // alias to align with the script name | ||
.action(async () => { | ||
const logger = createLogger() | ||
const { dev } = await import('./dev') | ||
|
||
try { | ||
await dev() | ||
} | ||
catch (e) { | ||
logger.error('DSB', e) | ||
process.exit(1) | ||
} | ||
}) | ||
|
||
cli.help() | ||
cli.version(version) | ||
|
||
cli.parse() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import path from 'path' | ||
import JoyCon from 'joycon' | ||
import { bundleRequire } from 'bundle-require' | ||
import type { Configuration as ElectronBuilderConfiguration } from 'electron-builder' | ||
import type { Options as TsupOptions } from 'tsup' | ||
import { merge, normalizePath } from './utils' | ||
import { createLogger } from './log' | ||
|
||
export type DoubleShotBuilderConfigExport = DoubleShotBuilderConfig | Promise<DoubleShotBuilderConfig> | ||
|
||
export interface ElectronBuildConfig { | ||
/** | ||
* @default false | ||
*/ | ||
disabled?: boolean | ||
config?: string | ElectronBuilderConfiguration | ||
afterBuild?: () => Promise<void> | ||
} | ||
|
||
export type TsupBuildConfig = Pick<TsupOptions, 'entry' | 'outDir' | 'tsconfig' | 'external'> & { | ||
tsupConfig?: string | TsupOptions | ||
} | ||
|
||
export interface DoubleShotBuilderConfig extends TsupBuildConfig { | ||
/** | ||
* @default 'package.json'.main | ||
*/ | ||
main?: string | ||
electron?: { | ||
preload?: TsupBuildConfig | ||
build?: ElectronBuildConfig | ||
} | ||
afterBuild?: () => Promise<void> | ||
} | ||
|
||
export type ResolvedConfig = Readonly<{ | ||
cwd: string | ||
configFile: string | undefined | ||
tsupConfigs: TsupOptions[] | ||
electronBuild?: ElectronBuildConfig | ||
} & Pick<DoubleShotBuilderConfig, 'main' | 'afterBuild'>> | ||
|
||
export function defineConfig(config: DoubleShotBuilderConfigExport): DoubleShotBuilderConfigExport { | ||
return config | ||
} | ||
|
||
export async function resolveConfig(): Promise<ResolvedConfig> { | ||
const logger = createLogger() | ||
const cwd = process.cwd() | ||
const configJoycon = new JoyCon() | ||
const configPath = await configJoycon.resolve({ | ||
files: [ | ||
'dsb.config.ts', | ||
'dsb.config.js', | ||
'dsb.config.cjs', | ||
'dsb.config.mjs', | ||
], | ||
cwd, | ||
stopDir: path.parse(cwd).root, | ||
}) | ||
|
||
if (configPath) { | ||
logger.info('dsr', `Using doubleshot builder config: ${configPath}\n`) | ||
|
||
const { mod } = await bundleRequire({ | ||
filepath: configPath, | ||
}) | ||
|
||
const config: DoubleShotBuilderConfig = mod.default || mod | ||
|
||
const mergeTsupConfig = async (inputConfig: TsupBuildConfig, defaultConfig: TsupOptions = {}) => { | ||
let result: TsupOptions | undefined | ||
if (inputConfig.tsupConfig) { | ||
if (typeof inputConfig.tsupConfig === 'string') { | ||
const tsupConfigPath = await configJoycon.resolve({ | ||
files: [inputConfig.tsupConfig], | ||
cwd, | ||
stopDir: path.parse(cwd).root, | ||
}) | ||
if (!tsupConfigPath) { | ||
logger.warn('DSB', `tsup config file: ${config.tsupConfig} not found, ignored.\n`) | ||
} | ||
else { | ||
const { mod } = await bundleRequire({ | ||
filepath: tsupConfigPath, | ||
}) | ||
result = mod.default || mod | ||
} | ||
} | ||
else if (typeof inputConfig.tsupConfig === 'object') { | ||
result = inputConfig.tsupConfig | ||
} | ||
} | ||
|
||
const userTsupConfig: TsupOptions = merge(defaultConfig, { | ||
entry: inputConfig.entry, | ||
outDir: inputConfig.outDir, | ||
tsconfig: inputConfig.tsconfig, | ||
external: inputConfig.external, | ||
}) | ||
|
||
return result ? { ...userTsupConfig, ...result } : userTsupConfig | ||
} | ||
|
||
const tsupConfigArr: TsupOptions[] = [(await mergeTsupConfig(config))] | ||
|
||
if (config.electron?.preload) | ||
tsupConfigArr.push(await mergeTsupConfig(config.electron.preload, tsupConfigArr[0])) | ||
|
||
return { | ||
cwd, | ||
main: config.main ? normalizePath(path.resolve(cwd, config.main)) : undefined, | ||
configFile: normalizePath(configPath), | ||
tsupConfigs: tsupConfigArr, | ||
electronBuild: resoleElectronBuilderConfig(config.electron?.build, cwd), | ||
afterBuild: config.afterBuild, | ||
} | ||
} | ||
else { | ||
throw new Error('doubleshot builder needs a config file') | ||
} | ||
} | ||
|
||
function resoleElectronBuilderConfig(buildConfig: ElectronBuildConfig | undefined, cwd: string): ElectronBuildConfig { | ||
if (!buildConfig) | ||
return { disabled: true } | ||
|
||
const resolvedConfig = typeof buildConfig.config === 'string' ? normalizePath(path.resolve(cwd, buildConfig.config)) : buildConfig.config | ||
return { | ||
disabled: buildConfig.disabled === true, | ||
config: resolvedConfig, | ||
afterBuild: buildConfig.afterBuild, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { spawn } from 'child_process' | ||
import path from 'path' | ||
import fs from 'fs' | ||
import * as colorette from 'colorette' | ||
import { build as tsupBuild } from 'tsup' | ||
import electron from 'electron' | ||
import { resolveConfig } from './config' | ||
|
||
function exitMainProcess() { | ||
console.info(colorette.yellow('Main Process Exited')) | ||
process.exit(0) | ||
} | ||
|
||
function runMainProcess(mainFile: string) { | ||
return spawn(electron as any, [mainFile], { stdio: 'inherit' }).on('exit', exitMainProcess) | ||
} | ||
|
||
export async function dev() { | ||
const config = await resolveConfig() | ||
|
||
for (const tsupConfig of config.tsupConfigs) { | ||
await tsupBuild({ | ||
...tsupConfig, | ||
}) | ||
} | ||
|
||
let mainFile = config.main | ||
if (!mainFile) { | ||
const file = path.resolve(config.cwd, 'package.json') | ||
const data = require(file) | ||
delete require.cache[file] | ||
|
||
if (Object.prototype.hasOwnProperty.call(data, 'main')) | ||
mainFile = path.resolve(config.cwd, data.main) | ||
|
||
else | ||
throw new Error('package.json missing main field') | ||
} | ||
|
||
if (!fs.existsSync(mainFile)) | ||
throw new Error(`Main File Not Found: ${mainFile}`) | ||
|
||
console.info(colorette.blue(`Run Main File: ${mainFile}`)) | ||
|
||
runMainProcess(mainFile) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './config' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import * as colors from 'colorette' | ||
|
||
type LOG_TYPE = 'info' | 'success' | 'error' | 'warn' | ||
|
||
export const colorize = (type: LOG_TYPE, data: any, onlyImportant = false) => { | ||
if (onlyImportant && (type === 'info' || type === 'success')) | ||
return data | ||
|
||
const color | ||
= type === 'info' | ||
? 'blue' | ||
: type === 'error' | ||
? 'red' | ||
: type === 'warn' | ||
? 'yellow' | ||
: 'green' | ||
return colors[color](data) | ||
} | ||
|
||
export const makeLabel = ( | ||
name: string | undefined, | ||
input: string, | ||
type: LOG_TYPE, | ||
) => { | ||
return [ | ||
name && `${colors.dim('[')}${name.toUpperCase()}${colors.dim(']')}`, | ||
colorize(type, input.toUpperCase()), | ||
] | ||
.filter(Boolean) | ||
.join(' ') | ||
} | ||
|
||
export type Logger = ReturnType<typeof createLogger> | ||
|
||
export const createLogger = (name?: string) => { | ||
return { | ||
setName(_name: string) { | ||
name = _name | ||
}, | ||
|
||
success(label: string, ...args: any[]) { | ||
return this.log(label, 'success', ...args) | ||
}, | ||
|
||
info(label: string, ...args: any[]) { | ||
return this.log(label, 'info', ...args) | ||
}, | ||
|
||
error(label: string, ...args: any[]) { | ||
return this.log(label, 'error', ...args) | ||
}, | ||
|
||
warn(label: string, ...args: any[]) { | ||
return this.log(label, 'warn', ...args) | ||
}, | ||
|
||
log( | ||
label: string, | ||
type: 'info' | 'success' | 'error' | 'warn', | ||
...data: unknown[] | ||
) { | ||
switch (type) { | ||
case 'error': { | ||
return console.error( | ||
makeLabel(name, label, type), | ||
...data.map(item => colorize(type, item, true)), | ||
) | ||
} | ||
default: | ||
console.log( | ||
makeLabel(name, label, type), | ||
...data.map(item => colorize(type, item, true)), | ||
) | ||
} | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import path from 'path' | ||
import os from 'os' | ||
|
||
export const isWindows = os.platform() === 'win32' | ||
|
||
export function slash(p: string): string { | ||
return p.replace(/\\/g, '/') | ||
} | ||
|
||
export function normalizePath(id: string): string { | ||
return path.posix.normalize(isWindows ? slash(id) : id) | ||
} | ||
|
||
export function arraify<T>(target: T | T[]): T[] { | ||
return Array.isArray(target) ? target : [target] | ||
} | ||
|
||
export function merge<T>(obj1: T, obj2: T): T { | ||
const result = Object.assign({}, obj1) | ||
for (const key in obj2) { | ||
if (obj2[key] !== undefined) | ||
result[key] = obj2[key] | ||
} | ||
return result | ||
} |
Oops, something went wrong.