From cb1305c54cd002ef9d12643ee08e9a2cb477d630 Mon Sep 17 00:00:00 2001 From: Alex Pshul Date: Sat, 20 Apr 2024 18:35:06 -0400 Subject: [PATCH] Made the apps be compatible with multi-level folder structure --- e2e/func-e2e/tests/func.spec.ts | 45 +++++++++++++++++-- .../src/executors/common/prepare-build.ts | 5 ++- .../func/src/generators/init/generator.ts | 6 ++- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/e2e/func-e2e/tests/func.spec.ts b/e2e/func-e2e/tests/func.spec.ts index 1667862..d320a83 100644 --- a/e2e/func-e2e/tests/func.spec.ts +++ b/e2e/func-e2e/tests/func.spec.ts @@ -3,7 +3,7 @@ import { ensureNxProject, readJson, runCommand, runNxCommandAsync, uniq, updateF import { CompilerOptions } from 'typescript'; describe('Project initialization and build', () => { - const TEST_TIMEOUT = 120000; + const TEST_TIMEOUT = 180000; // Setting up individual workspaces per // test can cause e2e runs to take a long time. // For this reason, we recommend each suite only @@ -31,7 +31,7 @@ describe('Project initialization and build', () => { }); it( - 'should init & build and empty workspace with a functions app', + 'should init & build an empty workspace with a functions app', async () => { const project = uniq('func'); await runNxCommandAsync(`generate @nxazure/func:init ${project}`); @@ -58,7 +58,7 @@ describe('Project initialization and build', () => { ); it( - 'should init & build a workspace with a js lib functions app and a function', + 'should init & build a workspace with a js lib and, a functions app and a function that uses that lib', async () => { const project = uniq('func'); const lib = uniq('lib'); @@ -96,6 +96,45 @@ describe('Project initialization and build', () => { TEST_TIMEOUT, ); + it( + 'should init & build a workspace with a js lib, a nested functions app (apps/test/my-app) and a function that uses that lib', + async () => { + const project = `sub-app/${uniq('func')}`; + const lib = uniq('lib'); + const func = 'hello'; + + await runNxCommandAsync(`generate @nxazure/func:init ${project}`); + await runNxCommandAsync(`generate @nxazure/func:new ${func} --project=${project} --template="HTTP trigger"`); + await runNxCommandAsync(`generate @nx/js:library ${lib}`); + + const funcFilePath = `apps/${project}/${func}/index.ts`; + + updateFile( + funcFilePath, + ` import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions"; + import { ${lib} } from "@proj/${lib}"; + + export async function hello(request: HttpRequest, context: InvocationContext): Promise { + const name = request.query.get('name') || await request.text() || 'world'; + + return { body: ${lib}() }; + }; + + app.http('hello', { + methods: ['GET', 'POST'], + authLevel: 'anonymous', + handler: hello + }); + `, + ); + + const buildResult = await runNxCommandAsync(`build ${project}`); + + expect(buildResult.stdout).toContain(`Done compiling TypeScript files for project "${project}"`); + }, + TEST_TIMEOUT, + ); + it( 'Use strict mode', async () => { diff --git a/packages/func/src/executors/common/prepare-build.ts b/packages/func/src/executors/common/prepare-build.ts index 47397d1..233919b 100644 --- a/packages/func/src/executors/common/prepare-build.ts +++ b/packages/func/src/executors/common/prepare-build.ts @@ -1,4 +1,4 @@ -import { ExecutorContext, readJsonFile, writeJsonFile } from '@nx/devkit'; +import { ExecutorContext, offsetFromRoot, readJsonFile, writeJsonFile } from '@nx/devkit'; import { execSync } from 'child_process'; import path from 'path'; import { CompilerOptions } from 'typescript'; @@ -6,6 +6,7 @@ import { TS_CONFIG_BASE_FILE, TS_CONFIG_BUILD_FILE } from '../../common'; export const prepareBuild = (context: ExecutorContext) => { const appRoot = context.workspace?.projects[context.projectName].root; + const relativePathToRoot = offsetFromRoot(appRoot); const configPath = path.join(appRoot, TS_CONFIG_BUILD_FILE); const config = readJsonFile<{ compilerOptions: CompilerOptions }>(configPath); @@ -14,7 +15,7 @@ export const prepareBuild = (context: ExecutorContext) => { const baseConfig = readJsonFile<{ compilerOptions: CompilerOptions }>(baseConfigPath); config.compilerOptions.paths = Object.keys(baseConfig.compilerOptions.paths ?? {}).reduce((acc, key) => { - acc[key] = baseConfig.compilerOptions.paths[key].map(path => `../../${path}`); + acc[key] = baseConfig.compilerOptions.paths[key].map(path => `${relativePathToRoot}${path}`); return acc; }, config.compilerOptions.paths ?? {}); diff --git a/packages/func/src/generators/init/generator.ts b/packages/func/src/generators/init/generator.ts index 07b7929..1400197 100644 --- a/packages/func/src/generators/init/generator.ts +++ b/packages/func/src/generators/init/generator.ts @@ -176,12 +176,13 @@ const copyFilesFromTemp = (tree: Tree, { appRoot }: NormalizedOptions, tempFolde }); }; -const createRegisterPathsFile = (tree: Tree, { appRoot }: NormalizedOptions) => +const createRegisterPathsFile = (tree: Tree, { appRoot }: NormalizedOptions) => { + const relativePathToRoot = offsetFromRoot(appRoot); tree.write( path.posix.join(appRoot, `${registrationFileName}.ts`), ` import { register } from 'tsconfig-paths'; - import * as tsConfig from '../../${TS_CONFIG_BASE_FILE}'; // eslint-disable-line @nx/enforce-module-boundaries + import * as tsConfig from '${relativePathToRoot}${TS_CONFIG_BASE_FILE}'; // eslint-disable-line @nx/enforce-module-boundaries import { CompilerOptions } from 'typescript'; const compilerOptions = tsConfig.compilerOptions as unknown as CompilerOptions; // This is to avoid any problems with the typing system @@ -201,6 +202,7 @@ const createRegisterPathsFile = (tree: Tree, { appRoot }: NormalizedOptions) => } `, ); +}; const configureEslint = (tree: Tree, { appRoot, appNames: { name } }: NormalizedOptions) => { if (!tree.exists('.eslintrc.json')) return;