feat(runner): add parallel building

This commit is contained in:
Haoyu Xu
2023-01-20 17:21:08 -05:00
parent 580ad1d18d
commit 4decb3d605
9 changed files with 117 additions and 95 deletions

View File

@@ -1,18 +1,18 @@
import path from 'path' import path from 'path'
import { appendSync, readSync } from './file.js' import { appendSync, readSync } from './file.js'
export function appendReadme() { export function appendReadme(operatorName) {
const operatorConfig = __config.operators[__operator_name] const operatorConfig = __config.operators[operatorName]
const projectJson = JSON.parse(readSync(path.join(__dirname, __config.folder.operator, __operator_name, 'project.json'))) const projectJson = JSON.parse(readSync(path.join(__dirname, __config.folder.operator, operatorName, 'project.json')))
appendSync( appendSync(
`\n| ${operatorConfig.title.split(' - ')[0].split('Arknights: ')[1]} | [Link](https://arknights.halyul.dev/${operatorConfig.link}/) | [Link](https://steamcommunity.com/sharedfiles/filedetails/?id=${projectJson.workshopid}) |`, `\n| ${operatorConfig.title.split(' - ')[0].split('Arknights: ')[1]} | [Link](https://arknights.halyul.dev/${operatorConfig.link}/) | [Link](https://steamcommunity.com/sharedfiles/filedetails/?id=${projectJson.workshopid}) |`,
path.join(__dirname, 'README.md') path.join(__dirname, 'README.md')
) )
} }
export function appendMainConfig() { export function appendMainConfig(operatorName) {
appendSync( appendSync(
`\n ${__operator_name}: !include config/${__operator_name}.yaml`, `\n ${operatorName}: !include config/${operatorName}.yaml`,
path.join(__dirname, 'config.yaml') path.join(__dirname, 'config.yaml')
) )
} }

View File

@@ -5,19 +5,21 @@ import AlphaComposite from './alpha_composite.js'
export default class AssetsProcessor { export default class AssetsProcessor {
#operatorSourceFolder #operatorSourceFolder
#alphaCompositer #alphaCompositer
#operatorName
constructor() { constructor(operatorName) {
this.#operatorSourceFolder = path.join(__dirname, __config.folder.operator) this.#operatorSourceFolder = path.join(__dirname, __config.folder.operator)
this.#alphaCompositer = new AlphaComposite() this.#alphaCompositer = new AlphaComposite()
this.#operatorName = operatorName
} }
async process(extractedDir) { async process(extractedDir) {
const BASE64_BINARY_PREFIX = 'data:application/octet-stream;base64,' const BASE64_BINARY_PREFIX = 'data:application/octet-stream;base64,'
const BASE64_PNG_PREFIX = 'data:image/png;base64,' const BASE64_PNG_PREFIX = 'data:image/png;base64,'
const assetsJson = {} const assetsJson = {}
const skelFilename = `${__config.operators[__operator_name].filename}.skel` const skelFilename = `${__config.operators[this.#operatorName].filename}.skel`
const skel = await read(path.join(extractedDir, skelFilename), null) const skel = await read(path.join(extractedDir, skelFilename), null)
const atlasFilename = `${__config.operators[__operator_name].filename}.atlas` const atlasFilename = `${__config.operators[this.#operatorName].filename}.atlas`
const atlas = await read(path.join(extractedDir, atlasFilename)) const atlas = await read(path.join(extractedDir, atlasFilename))
const dimensions = atlas.match(new RegExp(/^size:(.*),(.*)/gm))[0].replace('size: ', '').split(',') const dimensions = atlas.match(new RegExp(/^size:(.*),(.*)/gm))[0].replace('size: ', '').split(',')
const matches = atlas.match(new RegExp(/(.*).png/g)) const matches = atlas.match(new RegExp(/(.*).png/g))
@@ -28,9 +30,9 @@ export default class AssetsProcessor {
assetsJson[`./assets/${skelFilename.replace('#', '%23')}`] = BASE64_BINARY_PREFIX + skel.toString('base64') assetsJson[`./assets/${skelFilename.replace('#', '%23')}`] = BASE64_BINARY_PREFIX + skel.toString('base64')
assetsJson[`./assets/${atlasFilename.replace('#', '%23')}`] = BASE64_BINARY_PREFIX + Buffer.from(atlas).toString('base64') assetsJson[`./assets/${atlasFilename.replace('#', '%23')}`] = BASE64_BINARY_PREFIX + Buffer.from(atlas).toString('base64')
const fallbackFilename = `${__config.operators[__operator_name].fallback_name}.png` const fallbackFilename = `${__config.operators[this.#operatorName].fallback_name}.png`
const fallbackBuffer = await this.#alphaCompositer.process(fallbackFilename, extractedDir) const fallbackBuffer = await this.#alphaCompositer.process(fallbackFilename, extractedDir)
await write(fallbackBuffer, path.join(this.#operatorSourceFolder, __operator_name, fallbackFilename)) await write(fallbackBuffer, path.join(this.#operatorSourceFolder, this.#operatorName, fallbackFilename))
return { return {
dimensions, dimensions,
assetsJson assetsJson

View File

@@ -2,8 +2,5 @@ import path from 'path'
import { read } from './yaml.js' import { read } from './yaml.js'
export default function () { export default function () {
return { return read(path.join(__dirname, 'config.yaml'))
basedir: __dirname,
...read(path.join(__dirname, 'config.yaml'))
}
} }

View File

@@ -2,8 +2,8 @@ export default class EnvGenerator {
#assets #assets
#operatorConfig #operatorConfig
constructor(assets) { constructor(operatorName, assets) {
this.#operatorConfig = __config.operators[__operator_name] this.#operatorConfig = __config.operators[operatorName]
this.#assets = assets this.#assets = assets
} }

View File

@@ -4,12 +4,12 @@ import { read as readYAML } from './yaml.js'
import { mkdir, writeSync } from './file.js' import { mkdir, writeSync } from './file.js'
import { appendMainConfig } from './append.js' import { appendMainConfig } from './append.js'
export default function init(extractedDir) { export default function init(operatorName, extractedDir) {
mkdir(extractedDir) mkdir(extractedDir)
const date = new Date() const date = new Date()
const template = readYAML(path.join(__dirname, 'config', '_template.yaml')) const template = readYAML(path.join(__dirname, 'config', '_template.yaml'))
template.link = __operator_name template.link = operatorName
template.date = `${date.getFullYear()}/${(date.getMonth() + 1).toString().padStart(2, '0') }` template.date = `${date.getFullYear()}/${(date.getMonth() + 1).toString().padStart(2, '0') }`
writeSync(stringify(template), path.join(__dirname, 'config', `${__operator_name}.yaml`)) writeSync(stringify(template), path.join(__dirname, 'config', `${operatorName}.yaml`))
appendMainConfig(__operator_name, __dirname) appendMainConfig(operatorName)
} }

View File

@@ -5,15 +5,14 @@ import { read as readYAML } from './yaml.js'
export default class ProjectJson { export default class ProjectJson {
#json #json
#config
#operatorName #operatorName
#operatorSourceFolder #operatorSourceFolder
#operatorShareFolder #operatorShareFolder
#assets #assets
#rootDir
#template #template
constructor(operatorShareFolder, assets) { constructor(operatorName, operatorShareFolder, assets) {
this.#operatorName = operatorName
this.#operatorSourceFolder = path.join(__dirname, __config.folder.operator) this.#operatorSourceFolder = path.join(__dirname, __config.folder.operator)
this.#operatorShareFolder = operatorShareFolder this.#operatorShareFolder = operatorShareFolder
this.#assets = assets this.#assets = assets
@@ -29,7 +28,7 @@ export default class ProjectJson {
#getPath() { #getPath() {
// if exists, do not use the template // if exists, do not use the template
const defaultPath = path.join(this.#operatorSourceFolder, __operator_name, 'project.json') const defaultPath = path.join(this.#operatorSourceFolder, this.#operatorName, 'project.json')
if (exists(defaultPath)) { if (exists(defaultPath)) {
return defaultPath return defaultPath
} else { } else {
@@ -41,7 +40,7 @@ export default class ProjectJson {
this.#json = { this.#json = {
...this.#json, ...this.#json,
description: this.#template.description, description: this.#template.description,
title: __config.operators[__operator_name].title, title: __config.operators[this.#operatorName].title,
general: { general: {
...this.#json.general, ...this.#json.general,
localization: this.#template.localization, localization: this.#template.localization,
@@ -54,7 +53,7 @@ export default class ProjectJson {
} }
#processYAML(template) { #processYAML(template) {
const matcher = new Matcher(template.description, '${', '}', __config.operators[__operator_name]) const matcher = new Matcher(template.description, '${', '}', __config.operators[this.#operatorName])
if (matcher.match() !== null) { if (matcher.match() !== null) {
template.description = matcher.process() template.description = matcher.process()
} }
@@ -74,25 +73,25 @@ export default class ProjectJson {
{ {
key: "paddingleft", key: "paddingleft",
value: { value: {
value: __config.operators[__operator_name].viewport_left value: __config.operators[this.#operatorName].viewport_left
}, },
}, },
{ {
key: "paddingright", key: "paddingright",
value: { value: {
value: __config.operators[__operator_name].viewport_right value: __config.operators[this.#operatorName].viewport_right
}, },
}, },
{ {
key: "paddingtop", key: "paddingtop",
value: { value: {
value: __config.operators[__operator_name].viewport_top value: __config.operators[this.#operatorName].viewport_top
}, },
}, },
{ {
key: "paddingbottom", key: "paddingbottom",
value: { value: {
value: __config.operators[__operator_name].viewport_bottom value: __config.operators[this.#operatorName].viewport_bottom
}, },
}, },
] ]

View File

@@ -1,39 +0,0 @@
import path from 'path'
import { createServer, build } from 'vite'
export default class Vite {
dev() {
; (async () => {
const server = await createServer(this.#viteConfig)
await server.listen()
server.printUrls()
})()
}
async build() {
await build(this.#viteConfig)
}
get #viteConfig() {
return {
base: "",
publicDir: path.resolve(__dirname, __config.folder.release, __operator_name),
root: path.resolve(__dirname),
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'!': path.resolve(__dirname, __config.folder.operator, __operator_name),
'#': path.resolve(__config.basedir, __config.folder.operator, __operator_name, `${__config.operators[__operator_name].filename}.json`),
},
},
build: {
outDir: path.resolve(__dirname, __config.folder.release, __operator_name),
emptyOutDir: false,
chunkSizeWarningLimit: 10000,
},
}
}
}

View File

@@ -1,14 +1,14 @@
import assert from 'assert' import assert from 'assert'
import path from 'path' import path from 'path'
import { fileURLToPath } from 'url' import { fileURLToPath } from 'url'
import { fork } from 'child_process';
import getConfig from './libs/config.js' import getConfig from './libs/config.js'
import ProjectJson from './libs/project_json.js' import ProjectJson from './libs/project_json.js'
import EnvGenerator from './libs/env_generator.js' import EnvGenerator from './libs/env_generator.js'
import { write, rmdir, copy, writeSync, rm } from './libs/file.js' import { write, rmdir, copy, writeSync } from './libs/file.js'
import AssetsProcessor from './libs/assets_processor.js' import AssetsProcessor from './libs/assets_processor.js'
import init from './libs/initializer.js' import init from './libs/initializer.js'
import directory from './libs/directory.js' import directory from './libs/directory.js'
import Vite from './libs/vite.js'
import { appendReadme } from './libs/append.js' import { appendReadme } from './libs/append.js'
import Background from './libs/background.js' import Background from './libs/background.js'
@@ -44,7 +44,6 @@ async function main() {
assert(OPERATOR_NAMES.length !== 0, 'Please set the operator name.') assert(OPERATOR_NAMES.length !== 0, 'Please set the operator name.')
for (const OPERATOR_NAME of OPERATOR_NAMES) { for (const OPERATOR_NAME of OPERATOR_NAMES) {
global.__operator_name = OPERATOR_NAME
const OPERATOR_SOURCE_FOLDER = path.join(__dirname, __config.folder.operator) const OPERATOR_SOURCE_FOLDER = path.join(__dirname, __config.folder.operator)
const OPERATOR_RELEASE_FOLDER = path.join(__dirname, __config.folder.release, OPERATOR_NAME) const OPERATOR_RELEASE_FOLDER = path.join(__dirname, __config.folder.release, OPERATOR_NAME)
const SHOWCASE_PUBLIC_ASSSETS_FOLDER = path.join(OPERATOR_RELEASE_FOLDER, "assets") const SHOWCASE_PUBLIC_ASSSETS_FOLDER = path.join(OPERATOR_RELEASE_FOLDER, "assets")
@@ -58,10 +57,10 @@ async function main() {
*/ */
switch (op) { switch (op) {
case 'init': case 'init':
init(EXTRACTED_FOLDER) init(OPERATOR_NAME, EXTRACTED_FOLDER)
process.exit(0) process.exit(0)
case 'readme': case 'readme':
appendReadme() appendReadme(OPERATOR_NAME)
process.exit(0) process.exit(0)
default: default:
break break
@@ -69,14 +68,14 @@ async function main() {
rmdir(OPERATOR_RELEASE_FOLDER) rmdir(OPERATOR_RELEASE_FOLDER)
const projectJson = new ProjectJson(OPERATOR_SHARE_FOLDER, { const projectJson = new ProjectJson(OPERATOR_NAME, OPERATOR_SHARE_FOLDER, {
backgrounds backgrounds
}) })
projectJson.load().then((content) => { projectJson.load().then((content) => {
write(JSON.stringify(content, null, 2), path.join(OPERATOR_RELEASE_FOLDER, 'project.json')) write(JSON.stringify(content, null, 2), path.join(OPERATOR_RELEASE_FOLDER, 'project.json'))
}) })
const assetsProcessor = new AssetsProcessor() const assetsProcessor = new AssetsProcessor(OPERATOR_NAME)
assetsProcessor.process(EXTRACTED_FOLDER).then((content) => { assetsProcessor.process(EXTRACTED_FOLDER).then((content) => {
write(JSON.stringify(content.assetsJson, null), path.join(OPERATOR_SOURCE_FOLDER, OPERATOR_NAME, `${__config.operators[OPERATOR_NAME].filename}.json`)) write(JSON.stringify(content.assetsJson, null), path.join(OPERATOR_SOURCE_FOLDER, OPERATOR_NAME, `${__config.operators[OPERATOR_NAME].filename}.json`))
}) })
@@ -108,27 +107,11 @@ async function main() {
copy(path.join(file.source, file.filename), path.join(file.target, file.filename)) copy(path.join(file.source, file.filename), path.join(file.target, file.filename))
}) })
const envPath = path.join(__dirname, '.env') const envPath = path.join(OPERATOR_SOURCE_FOLDER, OPERATOR_NAME, '.env')
writeSync((new EnvGenerator({ writeSync((new EnvGenerator(OPERATOR_NAME, {
backgrounds backgrounds
})).generate(), envPath) })).generate(), envPath)
/** fork(path.join(__dirname, 'vite.js'), [op, OPERATOR_NAME])
* dev: run dev server
* build: build assets
*/
const vite = new Vite(__config, OPERATOR_NAME, __dirname)
switch (op) {
case 'dev':
vite.dev()
break
case 'build':
case 'build-all':
await vite.build()
rm(envPath)
break
default:
break
}
} }
} }

80
vite.js Normal file
View File

@@ -0,0 +1,80 @@
import path from 'path'
import { fileURLToPath } from 'url'
import { createServer, build, loadEnv } from 'vite'
import getConfig from './libs/config.js'
import { rm } from './libs/file.js'
global.__dirname = path.dirname(fileURLToPath(import.meta.url))
export default class Vite {
#operatorName = process.argv[3]
#config = getConfig()
dev() {
; (async () => {
this.#loadEnvFromEnvFile('development')
const server = await createServer(this.#viteConfig)
await server.listen()
server.printUrls()
})()
}
build() {
; (async () => {
this.#loadEnvFromEnvFile('production')
console.log("Building", this.#operatorName, "...")
await build({
...this.#viteConfig,
logLevel: 'silent',
})
})()
}
#loadEnvFromEnvFile(mode) {
const envPath = path.join(__dirname, this.#config.folder.operator, this.#operatorName)
process.env = { ...loadEnv(mode, envPath) }
rm(path.join(envPath, '.env'))
}
get #viteConfig() {
return {
base: "",
publicDir: path.resolve(__dirname, this.#config.folder.release, this.#operatorName),
root: path.resolve(__dirname),
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'!': path.resolve(__dirname, this.#config.folder.operator, this.#operatorName),
'#': path.resolve(__dirname, this.#config.folder.operator, this.#operatorName, `${this.#config.operators[this.#operatorName].filename}.json`),
},
},
build: {
outDir: path.resolve(__dirname, this.#config.folder.release, this.#operatorName),
emptyOutDir: false,
chunkSizeWarningLimit: 10000,
},
}
}
}
function main() {
const MODE = process.argv[2]
const vite = new Vite()
switch (MODE) {
case 'dev':
vite.dev()
break
case 'build':
case 'build-all':
vite.build()
break
default:
break
}
}
main()