| | |
| | |
| | import { Container } from '@n8n/di'; |
| | import { spawn } from 'child_process'; |
| | import glob from 'fast-glob'; |
| | import { copyFile, mkdir, readFile, writeFile } from 'fs/promises'; |
| | import { InstanceSettings } from 'n8n-core'; |
| | import { jsonParse } from 'n8n-workflow'; |
| | import { join, dirname, resolve as resolvePath } from 'path'; |
| | import { file as tmpFile } from 'tmp-promise'; |
| |
|
| | import type { IBuildOptions } from './Interfaces'; |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | export async function createCustomTsconfig() { |
| | |
| | const tsconfigPath = join(dirname(require.resolve('n8n-node-dev/src')), 'tsconfig-build.json'); |
| |
|
| | |
| | const tsConfigString = await readFile(tsconfigPath, { encoding: 'utf8' }); |
| |
|
| | const tsConfig = jsonParse<{ include: string[] }>(tsConfigString); |
| |
|
| | |
| | const newIncludeFiles = []; |
| |
|
| | for (const includeFile of tsConfig.include) { |
| | newIncludeFiles.push(join(process.cwd(), includeFile)); |
| | } |
| | tsConfig.include = newIncludeFiles; |
| |
|
| | |
| | const { path, cleanup } = await tmpFile(); |
| | await writeFile(path, JSON.stringify(tsConfig, null, 2)); |
| |
|
| | return { |
| | path, |
| | cleanup, |
| | }; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | export async function buildFiles({ |
| | destinationFolder = Container.get(InstanceSettings).customExtensionDir, |
| | watch, |
| | }: IBuildOptions): Promise<string> { |
| | const tscPath = join(dirname(require.resolve('typescript')), 'tsc'); |
| | const tsconfigData = await createCustomTsconfig(); |
| |
|
| | await Promise.all( |
| | ['*.svg', '*.png', '*.node.json'].map(async (filenamePattern) => { |
| | const files = await glob(`**/${filenamePattern}`); |
| | for (const file of files) { |
| | const src = resolvePath(process.cwd(), file); |
| | const dest = resolvePath(destinationFolder, file); |
| | await mkdir(dirname(dest), { recursive: true }); |
| | await copyFile(src, dest); |
| | } |
| | }), |
| | ); |
| |
|
| | |
| | const nodeModulesPath = join(__dirname, '../../node_modules/'); |
| | let buildCommand = `${tscPath} --p ${ |
| | tsconfigData.path |
| | } --outDir ${destinationFolder} --rootDir ${process.cwd()} --baseUrl ${nodeModulesPath}`; |
| | if (watch) { |
| | buildCommand += ' --watch'; |
| | } |
| |
|
| | try { |
| | const buildProcess = spawn('node', buildCommand.split(' '), { |
| | windowsVerbatimArguments: true, |
| | cwd: process.cwd(), |
| | }); |
| |
|
| | |
| | |
| | buildProcess.stdout.pipe(process.stdout); |
| | buildProcess.stderr.pipe(process.stderr); |
| |
|
| | |
| | |
| | process.on('exit', () => buildProcess.kill()); |
| |
|
| | await new Promise<void>((resolve) => { |
| | buildProcess.on('exit', resolve); |
| | }); |
| | } catch (error) { |
| | |
| | let errorMessage = error.message; |
| |
|
| | if (error.stdout !== undefined) { |
| | errorMessage = `${errorMessage}\nGot following output:\n${error.stdout}`; |
| | } |
| |
|
| | throw new Error(errorMessage); |
| | } finally { |
| | |
| | await tsconfigData.cleanup(); |
| | } |
| |
|
| | return destinationFolder; |
| | } |
| |
|