Skip to content

Commit

Permalink
Update to spawn soffice in serial
Browse files Browse the repository at this point in the history
  • Loading branch information
yhatt committed Jan 15, 2025
1 parent bc5e938 commit 41ab005
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 50 deletions.
18 changes: 15 additions & 3 deletions src/converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export class Converter {

private _sOffice: SOffice | undefined = undefined
private _firefoxPDFConversionWarning = false
private _experimentalEditablePPTXWarning = false

constructor(opts: ConverterOption) {
this.options = opts
Expand Down Expand Up @@ -601,9 +602,13 @@ export class Converter {
file: File
): Promise<File> {
// Experimental warning
warn(
`${chalk.yellow`[EXPERIMENTAL]`} Converting to editable PPTX is experimental feature. The output depends on LibreOffice and slide reproducibility is not fully guaranteed.`
)
if (this._experimentalEditablePPTXWarning === false) {
this._experimentalEditablePPTXWarning = true

warn(
`${chalk.yellow`[EXPERIMENTAL]`} Converting to editable PPTX is experimental feature. The output depends on LibreOffice and slide reproducibility is not fully guaranteed.`
)
}

// Convert to PDF
const pdf = await this.convertFileToPDF(tpl, file, { postprocess: false })
Expand Down Expand Up @@ -731,6 +736,13 @@ export class Converter {
await page.goto('data:text/html,', waitForOptions)
await page.setContent(baseFile.buffer!.toString(), waitForOptions)
}

// Wait for next frame (In parallel rendering, it may be needed to wait for the first rendering)
await page.evaluate(async () => {
await new Promise<void>((resolve) =>
window.requestAnimationFrame(() => resolve())
)

Check warning on line 744 in src/converter.ts

View check run for this annotation

Codecov / codecov/patch

src/converter.ts#L742-L744

Added lines #L742 - L744 were not covered by tests
})
}

try {
Expand Down
101 changes: 54 additions & 47 deletions src/soffice/soffice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import chalk from 'chalk'
import { nanoid } from 'nanoid'
import { error } from '../cli'
import { debug } from '../utils/debug'
import { createMemoizedPromiseContext } from '../utils/memoized-promise'
import { getWindowsEnv, isWSL, translateWindowsPathToWSL } from '../utils/wsl'
import { findSOffice } from './finder'

Expand All @@ -22,62 +23,68 @@ export class SOffice {
preferredPath?: string
#profileDirName: string

private _path?: string
private _profileDir?: string
private _path = createMemoizedPromiseContext<string>()
private _profileDir = createMemoizedPromiseContext<string>()

private static _spawnQueue: Promise<void> = Promise.resolve()

constructor(opts: SOfficeOptions = {}) {
this.#profileDirName = `marp-cli-soffice-${nanoid(10)}`
this.preferredPath = opts.path
}

get path(): Promise<string> {
if (this._path) return Promise.resolve(this._path)

return (async () => {
const found = await findSOffice({ preferredPath: this.preferredPath })

this._path = found.path
return found.path
})()
return this._path.init(
async () =>
(await findSOffice({ preferredPath: this.preferredPath })).path
)
}

get profileDir(): Promise<string> {
if (this._profileDir) return Promise.resolve(this._profileDir)

return this.setProfileDir()
return this._profileDir.init(async () => await this.setProfileDir())
}

async spawn(args: string[]) {
const spawnArgs = [
`-env:UserInstallation=${pathToFileURL(await this.profileDir).toString()}`,
...args,
]

debug(`[soffice] Spawning soffice with args: %o`, spawnArgs)

const childProcess = spawn(await this.path, spawnArgs, { stdio: 'pipe' })

childProcess.stdout.on('data', (data) => {
debug(`[soffice:stdout] %s`, data.toString())
})

childProcess.stderr.on('data', (data) => {
const output = data.toString()

debug(`[soffice:stderr] %s`, output)
error(`${chalk.yellow`[soffice]`} ${output.trim()}`, { singleLine: true })
})

return new Promise<void>((resolve, reject) => {
childProcess.on('close', (code) => {
debug(`[soffice] soffice exited with code %d`, code)

if (code === 0) {
resolve()
} else {
reject(new Error(`soffice exited with code ${code}.`))
}
})
SOffice._spawnQueue = SOffice._spawnQueue
.then(async () => {
const spawnArgs = [
`-env:UserInstallation=${pathToFileURL(await this.profileDir).toString()}`,
...args,
]

debug(`[soffice] Spawning soffice with args: %o`, spawnArgs)

const childProcess = spawn(await this.path, spawnArgs, {
stdio: 'pipe',
})

childProcess.stdout.on('data', (data) => {
debug(`[soffice:stdout] %s`, data.toString())
})

childProcess.stderr.on('data', (data) => {
const output = data.toString()

debug(`[soffice:stderr] %s`, output)
error(`${chalk.yellow`[soffice]`} ${output.trim()}`, {
singleLine: true,
})

Check warning on line 72 in src/soffice/soffice.ts

View check run for this annotation

Codecov / codecov/patch

src/soffice/soffice.ts#L67-L72

Added lines #L67 - L72 were not covered by tests
})

return new Promise<void>((resolve, reject) => {
childProcess.on('close', (code) => {
debug(`[soffice] soffice exited with code %d`, code)

if (code === 0) {
resolve()
} else {
reject(new Error(`soffice exited with code ${code}.`))
}

Check warning on line 83 in src/soffice/soffice.ts

View check run for this annotation

Codecov / codecov/patch

src/soffice/soffice.ts#L82-L83

Added lines #L82 - L83 were not covered by tests
})
})
})
.then(resolve, reject)
})
}

Expand All @@ -88,7 +95,7 @@ export class SOffice {
private async setProfileDir(): Promise<string> {
let needToTranslateWindowsPathToWSL = false

this._profileDir = await (async () => {
const dir = await (async () => {
// In WSL environment, Marp CLI may use Chrome on Windows. If Chrome has
// located in host OS (Windows), we have to specify Windows path.
if (await this.binaryInWSLHost()) {
Expand All @@ -101,16 +108,16 @@ export class SOffice {
return path.resolve(os.tmpdir(), this.#profileDirName)
})()

debug(`soffice data directory: %s`, this._profileDir)
debug(`soffice data directory: %s`, dir)

// Ensure the data directory is created
const mkdirPath = needToTranslateWindowsPathToWSL
? await translateWindowsPathToWSL(this._profileDir)
: this._profileDir
? await translateWindowsPathToWSL(dir)
: dir

await fs.promises.mkdir(mkdirPath, { recursive: true })
debug(`Created data directory: %s`, mkdirPath)

return this._profileDir
return dir
}
}

0 comments on commit 41ab005

Please sign in to comment.