Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(build/booter): support esm #10745

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/boot/src/__tests__/fixtures/cjs.artifact.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export class DummyCJSClass {}
1 change: 1 addition & 0 deletions packages/boot/src/__tests__/fixtures/esm.artifact.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export class DummyESMClass {}
24 changes: 24 additions & 0 deletions packages/boot/src/__tests__/fixtures/multiple.artifact.cts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright IBM Corp. and LoopBack contributors 2019. All Rights Reserved.
// Node module: @loopback/boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {get} from '@loopback/rest';

export class ArtifactOne {
@get('/one')
one() {
return 'ControllerOne.one()';
}
}

export class ArtifactTwo {
@get('/two')
two() {
return 'ControllerTwo.two()';
}
}

export function hello() {
return 'hello world';
}
24 changes: 24 additions & 0 deletions packages/boot/src/__tests__/fixtures/multiple.artifact.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright IBM Corp. and LoopBack contributors 2019. All Rights Reserved.
// Node module: @loopback/boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {get} from '@loopback/rest';

export class ArtifactOne {
@get('/one')
one() {
return 'ControllerOne.one()';
}
}

export class ArtifactTwo {
@get('/two')
two() {
return 'ControllerTwo.two()';
}
}

export function hello() {
return 'hello world';
}
40 changes: 35 additions & 5 deletions packages/boot/src/__tests__/unit/booters/booter-utils.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,37 @@ describe('booter-utils unit tests', () => {
const files = [resolve(sandbox.path, 'multiple.artifact.js')];
const NUM_CLASSES = 2; // Number of classes in above file

const classes = loadClassesFromFiles(files, sandbox.path);
const classes = await loadClassesFromFiles(files, sandbox.path);
expect(classes).to.have.lengthOf(NUM_CLASSES);
expect(classes[0]).to.be.a.Function();
expect(classes[1]).to.be.a.Function();
});

it('loads classes from CJS files', async () => {
const artifactFilename = 'multiple.artifact.cjs';
await sandbox.copyFile(
resolve(__dirname, '../../fixtures/multiple.artifact.cjs'),
);
const NUM_CLASSES = 2;
const classes = await loadClassesFromFiles(
[resolve(sandbox.path, artifactFilename)],
sandbox.path,
);
expect(classes).to.have.lengthOf(NUM_CLASSES);
expect(classes[0]).to.be.a.Function();
expect(classes[1]).to.be.a.Function();
});

it('loads classes from ESM files', async () => {
const artifactFilename = 'multiple.artifact.mjs';
await sandbox.copyFile(
resolve(__dirname, '../../fixtures/multiple.artifact.mjs'),
);
const NUM_CLASSES = 2;
const classes = await loadClassesFromFiles(
[resolve(sandbox.path, artifactFilename)],
sandbox.path,
);
expect(classes).to.have.lengthOf(NUM_CLASSES);
expect(classes[0]).to.be.a.Function();
expect(classes[1]).to.be.a.Function();
Expand All @@ -78,16 +108,16 @@ describe('booter-utils unit tests', () => {
);
const files = [resolve(sandbox.path, 'empty.artifact.js')];

const classes = loadClassesFromFiles(files, sandbox.path);
const classes = await loadClassesFromFiles(files, sandbox.path);
expect(classes).to.be.an.Array();
expect(classes).to.be.empty();
});

it('throws an error given a non-existent file', async () => {
const files = [resolve(sandbox.path, 'fake.artifact.js')];
expect(() => loadClassesFromFiles(files, sandbox.path)).to.throw(
/Cannot find module/,
);
await expect(
loadClassesFromFiles(files, sandbox.path),
).to.be.rejectedWith(/Cannot find module/);
});
});
});
5 changes: 4 additions & 1 deletion packages/boot/src/booters/base-artifact.booter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ export class BaseArtifactBooter implements Booter {
* and then process the artifact classes as appropriate.
*/
async load() {
this.classes = loadClassesFromFiles(this.discovered, this.projectRoot);
this.classes = await loadClassesFromFiles(
this.discovered,
this.projectRoot,
);
}
}
6 changes: 3 additions & 3 deletions packages/boot/src/booters/booter-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ export function isClass(target: any): target is Constructor<any> {
* @param projectRootDir - The project root directory
* @returns An array of Class constructors from a file
*/
export function loadClassesFromFiles(
export async function loadClassesFromFiles(
files: string[],
projectRootDir: string,
): Constructor<{}>[] {
): Promise<Constructor<{}>[]> {
const classes: Constructor<{}>[] = [];
for (const file of files) {
debug('Loading artifact file %j', path.relative(projectRootDir, file));
const moduleObj = require(file);
const moduleObj = await import(file);
for (const k in moduleObj) {
const exported = moduleObj[k];
if (isClass(exported)) {
Expand Down
4 changes: 2 additions & 2 deletions packages/build/config/tsconfig.common.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
"incremental": true,

"lib": ["es2020"],
"module": "commonjs",
"module": "node16",
"esModuleInterop": true,
"moduleResolution": "node",
"moduleResolution": "node16",
"target": "es2018",
"sourceMap": true,
"declaration": true,
Expand Down
Loading