This commit is contained in:
Lewis Liu 2021-11-25 07:39:25 +05:30 committed by GitHub
commit 9ae1b138a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 17 deletions

View file

@ -6,6 +6,9 @@
these types virtually unusable in practice.
[#8449](https://github.com/pulumi/pulumi/pull/8449)
- [sdk/nodejs] Support using native ES modules as Pulumi scripts
[#7764](https://github.com/pulumi/pulumi/pull/7764)
### Bug Fixes
- [codegen/go] - Respect default values in Pulumi object types.

View file

@ -13,6 +13,7 @@
// limitations under the License.
import * as fs from "fs";
import * as url from "url";
import * as minimist from "minimist";
import * as path from "path";
import * as tsnode from "ts-node";
@ -38,6 +39,25 @@ function reportModuleLoadFailure(program: string, error: Error): never {
return process.exit(mod.nodeJSProcessExitedAfterLoggingUserActionableMessage);
}
function projectRootFromProgramPath(program: string): string {
const stat = fs.lstatSync(program);
if (stat.isDirectory()) {
return program;
} else {
return path.dirname(program);
}
}
function packageObjectFromProjectRoot(projectRoot: string): Record<string, any> {
try {
const packageJson = path.join(projectRoot, "package.json");
return require(packageJson);
} catch {
// This is all best-effort so if we can't load the package.json file, that's
// fine.
return {};
}
}
function throwOrPrintModuleLoadError(program: string, error: Error): void {
// error is guaranteed to be a Node module load error. Node emits a very
@ -72,23 +92,8 @@ function throwOrPrintModuleLoadError(program: string, error: Error): void {
//
// The first step of this is trying to slurp up a package.json for this program, if
// one exists.
const stat = fs.lstatSync(program);
let projectRoot: string;
if (stat.isDirectory()) {
projectRoot = program;
} else {
projectRoot = path.dirname(program);
}
let packageObject: Record<string, any>;
try {
const packageJson = path.join(projectRoot, "package.json");
packageObject = require(packageJson);
} catch {
// This is all best-effort so if we can't load the package.json file, that's
// fine.
return;
}
const projectRoot = projectRootFromProgramPath(program);
const packageObject = packageObjectFromProjectRoot(projectRoot);
console.error("Here's what we think went wrong:");
@ -251,6 +256,24 @@ ${defaultMessage}`);
// Now go ahead and execute the code. The process will remain alive until the message loop empties.
log.debug(`Running program '${program}' in pwd '${process.cwd()}' w/ args: ${programArgs}`);
try {
const packageObject = packageObjectFromProjectRoot(projectRootFromProgramPath(program));
// We use dynamic import instead of require for projects using native ES modules instead of commonjs
if (packageObject["type"] === "module") {
// Workaround for typescript transpiling dynamic import into `Promise.resolve().then(() => require`
// Follow this issue for progress on when we can remove this:
// https://github.com/microsoft/TypeScript/issues/43329
//
// Workaround inspired by es-module-shims:
// https://github.com/guybedford/es-module-shims/blob/main/src/common.js#L21
// eslint-disable-next-line no-eval
const dynamicImport = (0, eval)("u=>import(u)");
// Import the module and capture any module outputs it exported. Finally, await the value we get
// back. That way, if it is async and throws an exception, we properly capture it here
// and handle it.
return await dynamicImport(url.pathToFileURL(program).toString());
}
// Execute the module and capture any module outputs it exported. If the exported value
// was itself a Function, then just execute it. This allows for exported top level
// async functions that pulumi programs can live in. Finally, await the value we get

View file

@ -0,0 +1,12 @@
// This tests the basic creation of a single propertyless resource using a native ES module
import pulumi from "../../../../../index.js";
class MyResource extends pulumi.CustomResource {
constructor(name) {
super("test:index:MyResource", name);
}
}
new MyResource("testResource1");

View file

@ -0,0 +1 @@
{ "type": "module" }

View file

@ -1181,6 +1181,17 @@ describe("rpc", () => {
};
},
},
// A program that allocates a single resource using a native ES module
"native_es_module": {
// Dynamic import won't automatically resolve to /index.js on a directory, specifying explicitly
program: path.join(base, "067.native_es_module/index.js"),
expectResourceCount: 1,
registerResource: (ctx: any, dryrun: boolean, t: string, name: string, res: any) => {
assert.strictEqual(t, "test:index:MyResource");
assert.strictEqual(name, "testResource1");
return { urn: makeUrn(t, name), id: undefined, props: undefined };
},
},
};
for (const casename of Object.keys(cases)) {