Skip to content

Commit

Permalink
fix: cross-packages esm load with pnpm
Browse files Browse the repository at this point in the history
  • Loading branch information
ocombe committed Feb 19, 2024
1 parent ae7923e commit 73aa8f7
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 11 deletions.
4 changes: 1 addition & 3 deletions angular/app-types/angular-app-type/application.bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
ApplicationOptions,
dedupPaths,
getLoggerApi,
loadEsmModule,
normalizePath
} from '@bitdev/angular.dev-services.common';
import {
Expand All @@ -19,7 +18,7 @@ import { outputFileSync, removeSync } from 'fs-extra';
import type { NitroConfig } from 'nitropack';
import { basename, extname, join, posix, relative, resolve } from 'path';
import definePlugin from './plugins/define.plugin';
import { getIndexInputFile } from './utils';
import { getIndexInputFile, loadEsmModule } from './utils';

export type BuildApplicationOptions = {
angularOptions: Partial<ApplicationOptions>;
Expand Down Expand Up @@ -238,7 +237,6 @@ async function buildNitro(options: BuildApplicationOptions): Promise<void> {
prerender
} = await loadEsmModule<typeof import('nitropack')>('nitropack');


const nitro = await createNitro({
dev: false,
...nitroConfig
Expand Down
8 changes: 2 additions & 6 deletions angular/app-types/angular-app-type/application.dev-server.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
/* eslint-disable no-param-reassign */
import { executeDevServerBuilder, OutputHashing } from '@angular-devkit/build-angular';
import { VERSION } from '@angular/cli';
import {
dedupPaths,
getLoggerApi,
loadEsmModule,
normalizePath
} from '@bitdev/angular.dev-services.common';
import { dedupPaths, getLoggerApi, normalizePath } from '@bitdev/angular.dev-services.common';
import {
type ApplicationBuilderOptions,
type DevServerBuilderOptions
Expand All @@ -20,6 +15,7 @@ import { join, posix, relative, resolve } from 'path';
// @ts-ignore
import type { Connect } from 'vite';
import definePlugin from './plugins/define.plugin';
import { loadEsmModule } from './utils';

export type ServeApplicationOptions = {
angularOptions: Partial<ApplicationBuilderOptions & DevServerBuilderOptions>;
Expand Down
21 changes: 21 additions & 0 deletions angular/app-types/angular-app-type/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,24 @@ export function getIndexInputFile(index: ApplicationOptions['index']): string {
}
return (index as any).input;
}

/**
* This uses a dynamic import to load a module which may be ESM.
* CommonJS code can load ESM code via a dynamic import. Unfortunately, TypeScript
* will currently, unconditionally downlevel dynamic import into a require call.
* require calls cannot load ESM code and will result in a runtime error. To work around
* this, a Function constructor is used to prevent TypeScript from changing the dynamic import.
* Once TypeScript provides support for keeping the dynamic import, this workaround can
* be dropped.
*
* @param modulePath The path of the module to load.
* @returns A Promise that resolves to the dynamically imported module.
*/
export async function loadEsmModule<T>(modulePath: string): Promise<T> {
try {
return await import(modulePath);
} catch (e) {
// eslint-disable-next-line @typescript-eslint/no-implied-eval
return new Function('modulePath', `return import(modulePath)`)(modulePath) as Promise<T>;
}
}
24 changes: 22 additions & 2 deletions angular/devkit/compiler/ng-packagr/ng-packagr.compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import {
AngularEnvOptions,
componentIsApp,
getNodeModulesPaths,
getWorkspace,
loadEsmModule
getWorkspace
} from '@bitdev/angular.dev-services.common';
import { ApplicationAspect, ApplicationMain } from '@teambit/application';
import {
Expand Down Expand Up @@ -44,6 +43,27 @@ export function isFatalDiagnosticError(err: any): err is FatalDiagnosticError {
return err._isFatalDiagnosticError === true;
}

/**
* This uses a dynamic import to load a module which may be ESM.
* CommonJS code can load ESM code via a dynamic import. Unfortunately, TypeScript
* will currently, unconditionally downlevel dynamic import into a require call.
* require calls cannot load ESM code and will result in a runtime error. To work around
* this, a Function constructor is used to prevent TypeScript from changing the dynamic import.
* Once TypeScript provides support for keeping the dynamic import, this workaround can
* be dropped.
*
* @param modulePath The path of the module to load.
* @returns A Promise that resolves to the dynamically imported module.
*/
export async function loadEsmModule<T>(modulePath: string): Promise<T> {
try {
return await import(modulePath);
} catch (e) {
// eslint-disable-next-line @typescript-eslint/no-implied-eval
return new Function('modulePath', `return import(modulePath)`)(modulePath) as Promise<T>;
}
}

export async function createDiagnosticsReporter(logger: Logger): Promise<DiagnosticsReporter> {
const { formatDiagnostics } = await loadEsmModule(`@angular/compiler-cli`);
const formatter = (diagnostic: Diagnostic) => formatDiagnostics([diagnostic]);
Expand Down

0 comments on commit 73aa8f7

Please sign in to comment.