2021-03-12 09:15:39 -05:00

158 lines
3.9 KiB
TypeScript

import {
ExecutorContext,
parseTargetString,
readTargetOptions,
} from '@nrwl/devkit';
import { ChildProcess, fork } from 'child_process';
import { join } from 'path';
import { runGatsbyBuild } from '../build/build.impl';
import { GatsbyPluginBuilderSchema as BuildBuilderSchema } from '../build/schema';
import { GatsbyPluginBuilderSchema } from './schema';
export default async function* serverExecutor(
options: GatsbyPluginBuilderSchema,
context: ExecutorContext
) {
const buildTarget = parseTargetString(options.buildTarget);
const baseUrl = `${options.https ? 'https' : 'http'}://${options.host}:${
options.port
}`;
const projectRoot = context.workspace.projects[context.projectName].root;
const buildOptions = readTargetOptions<BuildBuilderSchema>(
buildTarget,
context
);
try {
if (context.configurationName === 'production') {
await runGatsbyBuild(
context.root,
projectRoot,
context.projectName,
buildOptions
);
await runGatsbyServe(context.root, projectRoot, options);
yield { baseUrl, success: true };
} else {
const success = await runGatsbyDevelop(
context.root,
projectRoot,
createGatsbyOptions(options)
);
yield {
baseUrl,
success,
};
}
// This Promise intentionally never resolves, leaving the process running
await new Promise<{ success: boolean }>(() => {});
} finally {
if (childProcess) {
childProcess.kill();
}
}
}
function createGatsbyOptions(options) {
return Object.keys(options).reduce((acc, k) => {
if (k === 'port' || k === 'host' || k === 'https' || k === 'open')
acc.push(`--${k}=${options[k]}`);
return acc;
}, []);
}
let childProcess: ChildProcess;
async function runGatsbyDevelop(workspaceRoot, projectRoot, options) {
return new Promise<boolean>((resolve, reject) => {
childProcess = fork(
require.resolve('gatsby-cli'),
['develop', ...options],
{
cwd: join(workspaceRoot, projectRoot),
env: {
...process.env,
},
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
}
);
childProcess.on('message', ({ action }: any) => {
if (
action?.type === 'ACTIVITY_END' &&
action?.payload?.status === 'SUCCESS' &&
action?.payload?.id === 'webpack-develop'
) {
resolve(true);
}
});
childProcess.on('error', (err) => {
reject(err);
});
childProcess.on('exit', (code) => {
if (code !== 0) {
reject(
new Error(
'Could not start Gatsby Development Server. See errors above.'
)
);
}
});
});
}
function runGatsbyServe(
workspaceRoot: string,
projectRoot: string,
options: GatsbyPluginBuilderSchema
) {
return new Promise((resolve, reject) => {
childProcess = fork(
require.resolve('gatsby-cli'),
['serve', ...createGatsbyServeOptions(options)],
{ cwd: join(workspaceRoot, projectRoot) }
);
childProcess.on('error', (err) => {
reject(err);
});
childProcess.on('exit', (code) => {
if (code === 0) {
resolve(code);
} else {
reject(
new Error(
'Could not start Gatsby Production Server. See errors above.'
)
);
}
});
});
}
function createGatsbyServeOptions(options: GatsbyPluginBuilderSchema) {
return Object.keys(options).reduce((acc, k) => {
const val = options[k];
if (typeof val === 'undefined') return acc;
switch (k) {
case 'host':
return val ? acc.concat([`--host`, val]) : acc;
case 'open':
return val ? acc.concat(`--open`) : acc;
case 'prefixPaths':
return val ? acc.concat(`--prefix-paths`) : acc;
case 'port':
return val ? acc.concat([`--port`, val]) : acc;
default:
return acc;
}
}, []);
}