Skip to content

Commit

Permalink
support .cjs and .mjs
Browse files Browse the repository at this point in the history
  • Loading branch information
fengmk2 committed Jun 16, 2024
1 parent 841d26d commit e444095
Show file tree
Hide file tree
Showing 22 changed files with 199 additions and 112 deletions.
12 changes: 8 additions & 4 deletions src/loader/egg_loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1024,12 +1024,15 @@ export class EggLoader {
const filepaths = this.getExtendFilePaths(name);
// if use mm.env and serverEnv is not unittest
const needUnittest = 'EGG_MOCK_SERVER_ENV' in process.env && this.serverEnv !== 'unittest';
for (const filepath of filepaths) {
const length = filepaths.length;
for (let i = 0; i < length; i++) {
const filepath = filepaths[i];
filepaths.push(filepath + `.${this.serverEnv}`);
if (needUnittest) {
filepaths.push(filepath + '.unittest');
}
}
debug('loadExtend %s, filepaths: %j', name, filepaths);

const mergeRecord = new Map();
for (let filepath of filepaths) {
Expand All @@ -1044,7 +1047,6 @@ export class EggLoader {
}

const ext = await this.requireFile(filepath);

const properties = Object.getOwnPropertyNames(ext)
.concat(Object.getOwnPropertySymbols(ext) as any[]);

Expand Down Expand Up @@ -1403,7 +1405,9 @@ export class EggLoader {
}

// function(arg1, args, ...) {}
if (inject.length === 0) inject = [ this.app ];
if (inject.length === 0) {
inject = [ this.app ];
}
let mod = await this.requireFile(fullpath);
if (typeof mod === 'function' && !isClass(mod)) {
mod = mod(...inject);
Expand Down Expand Up @@ -1547,7 +1551,7 @@ export class EggLoader {
resolveModule(filepath: string) {
let fullPath;
try {
fullPath = require.resolve(filepath);
fullPath = utils.resolvePath(filepath);
} catch (e) {
return undefined;
}
Expand Down
43 changes: 33 additions & 10 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { debuglog } from 'node:util';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import fs from 'node:fs';
import BuiltinModule from 'node:module';
import { createRequire } from 'node:module';

const debug = debuglog('egg-core:utils');
const debug = debuglog('@eggjs/core:utils');

export type Fun = (...args: any[]) => any;

Expand All @@ -15,16 +15,38 @@ const Module = typeof module !== 'undefined' && module.constructor.length > 1
: BuiltinModule;

const extensions = (Module as any)._extensions;
debug('Module extensions: %j', Object.keys(extensions));
const extensionNames = Object.keys(extensions).concat([ '.cjs', '.mjs' ]);
debug('Module extensions: %j', extensionNames);

let _customRequire: NodeRequire;
function getCustomRequire() {
if (!_customRequire) {
_customRequire = createRequire(import.meta.url);
}
return _customRequire;
}

export default {
extensions,

// async _importOrRequire(filepath: string) {
// // try import first
// let obj: any;
// try {
// obj = await import(filepath);
// } catch (err: any) {
// debug('await import error, use require instead, %s', err);
// // use custom require
// obj = getCustomRequire()(filepath);
// }
// return obj;
// },

async loadFile(filepath: string) {
try {
// if not js module, just return content buffer
const extname = path.extname(filepath);
if (extname && !extensions[extname]) {
if (extname && !extensionNames.includes(extname)) {
return fs.readFileSync(filepath);
}
let obj: any;
Expand All @@ -38,8 +60,9 @@ export default {
}
} else {
// esm
debug('await import %s start', filepath);
obj = await import(filepath);
debug('await import %s => %o', filepath, obj);
debug('await import %o', obj);
isESM = true;
if (obj && 'default' in obj) {
// default: { default: [Function (anonymous)] }
Expand All @@ -50,18 +73,18 @@ export default {
// it's es module, use default export
if (isESM) return 'default' in obj ? obj.default : obj;
return obj;
} catch (err: any) {
err.message = `[@eggjs/core] load file: ${filepath}, error: ${err.message}`;
} catch (e: any) {
const err = new Error(`[@eggjs/core] load file: ${filepath}, error: ${e.message}`);
err.cause = e;
throw err;
}
},

resolvePath(filepath: string, options?: { paths?: string[] }) {
if (typeof require?.resolve === 'function') {
if (typeof require !== 'undefined') {
return require.resolve(filepath, options);
}
const fileUrl = import.meta.resolve(filepath);
return fileURLToPath(fileUrl);
return getCustomRequire().resolve(filepath, options);
},

methods: [ 'head', 'options', 'get', 'put', 'patch', 'post', 'delete' ],
Expand Down
9 changes: 8 additions & 1 deletion src/utils/timing.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { EOL } from 'node:os';
import { debuglog } from 'node:util';
import assert from 'node:assert';

const debug = debuglog('@eggjs/core:utils:timing');

interface TimingItem {
name: string;
start: number;
Expand Down Expand Up @@ -38,7 +41,9 @@ export class Timing {
start(name?: string, start?: number) {
if (!name || !this.#enable) return;

if (this.#map.has(name)) this.end(name);
if (this.#map.has(name)) {
this.end(name);
}

start = start || Date.now();
if (this.#startTime === null) {
Expand All @@ -52,6 +57,7 @@ export class Timing {
};
this.#map.set(name, item);
this.#list.push(item);
debug('start %j', item);
return item;
}

Expand All @@ -62,6 +68,7 @@ export class Timing {
const item = this.#map.get(name)!;
item.end = Date.now();
item.duration = item.end - item.start;
debug('end %j', item);
return item;
}

Expand Down
6 changes: 5 additions & 1 deletion test/asyncLocalStorage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ describe('test/asyncLocalStorage.test.ts', () => {

it('should start app with asyncLocalStorage = true by default', async () => {
assert.equal(app.currentContext, undefined);
const res = await request(app.callback())
let res = await request(app.callback())
.get('/status');
assert.equal(res.status, 200);
assert.equal(res.text, '');
res = await request(app.callback())
.get('/');
assert.equal(res.status, 200);
// console.log(res.body);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
'use strict';

module.exports = function() {
return (ctx, next) => {
export default function() {
return (ctx: any, next: any) => {
ctx.traceId = `trace:${Date.now()}`;
if (ctx.path === '/status') {
ctx.body = 'egg status';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
'use strict';

module.exports = {
export default {
coreMiddleware: ['status'],

urllib: {
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/loadfile-esm/es-module-default-null.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default null;
3 changes: 3 additions & 0 deletions test/fixtures/loadfile-esm/es-module-default.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
fn() {}
};
3 changes: 3 additions & 0 deletions test/fixtures/loadfile-esm/es-module.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function fn() {
console.log(fn);
}
4 changes: 4 additions & 0 deletions test/fixtures/loadfile-esm/no-js.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
map:
a: 1
b: 2
1 change: 1 addition & 0 deletions test/fixtures/loadfile-esm/null.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default null;
1 change: 1 addition & 0 deletions test/fixtures/loadfile-esm/object.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default { a: 1 };
3 changes: 3 additions & 0 deletions test/fixtures/loadfile-esm/object2.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
'use strict';

module.exports = { a: 1 };
3 changes: 3 additions & 0 deletions test/fixtures/loadfile-esm/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
1 change: 1 addition & 0 deletions test/fixtures/loadfile-esm/zero.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default 0;
1 change: 1 addition & 0 deletions test/fixtures/loadfile/object2.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default { a: 1 };
3 changes: 3 additions & 0 deletions test/fixtures/loadfile/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "commonjs"
}
1 change: 1 addition & 0 deletions test/fixtures/session-cache-app/config/config.default.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default {}
37 changes: 0 additions & 37 deletions test/loader/load_file.test.js

This file was deleted.

39 changes: 39 additions & 0 deletions test/loader/load_file.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { strict as assert } from 'node:assert';
import mm from 'mm';
import { createApp, Application, getFilepath } from '../utils.js';

describe('test/loader/load_file.test.ts', () => {
let app: Application;
afterEach(mm.restore);
afterEach(() => app.close());

it.only('should load file', async () => {

Check warning on line 10 in test/loader/load_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 18.19.0)

it.only not permitted

Check warning on line 10 in test/loader/load_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 22)

it.only not permitted

Check warning on line 10 in test/loader/load_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 20)

it.only not permitted

Check warning on line 10 in test/loader/load_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 18)

it.only not permitted

Check warning on line 10 in test/loader/load_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 18.19.0)

it.only not permitted

Check warning on line 10 in test/loader/load_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 22)

it.only not permitted

Check warning on line 10 in test/loader/load_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 18)

it.only not permitted

Check warning on line 10 in test/loader/load_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 20)

it.only not permitted

Check warning on line 10 in test/loader/load_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 18.19.0)

it.only not permitted

Check warning on line 10 in test/loader/load_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 22)

it.only not permitted

Check warning on line 10 in test/loader/load_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 18)

it.only not permitted

Check warning on line 10 in test/loader/load_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 20)

it.only not permitted
app = createApp('load_file');
const exports = await app.loader.loadFile(getFilepath('load_file/obj.js'));
assert.deepEqual(exports, { a: 1 });
const exports2 = await app.loader.loadFile(getFilepath('load_file/obj'));
assert.deepEqual(exports2, { a: 1 });
});

it('should load file when exports is function', async () => {
app = createApp('load_file');
const exports = await app.loader.loadFile(getFilepath('load_file/function.js'), 1, 2);
assert.deepEqual(exports, [ 1, 2 ]);
});

it('should throw with filepath when file syntax error', async () => {
await assert.rejects(async () => {
app = createApp('syntaxerror');
await app.loader.loadCustomApp();
}, /error: Unexpected end of input/);
});

it('should load custom file', async () => {
app = createApp('load_file');
let result = (await app.loader.loadFile(getFilepath('load_file/no-js.yml'))).toString();
if (process.platform === 'win32') {
result = result.replace(/\r\n/g, '\n');
}
assert.equal(result, '---\nmap:\n a: 1\n b: 2');
});
});
6 changes: 4 additions & 2 deletions test/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@ import { fileURLToPath } from 'node:url';
import { EggCore } from '../src/index.js';
import { Application, EggCoreInitOptions } from './fixtures/egg/index.js';

export { Application } from './fixtures/egg/index.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

export function getFilepath(name: string) {
return path.join(__dirname, 'fixtures', name);
}

export function createApp(name: string, options?: EggCoreInitOptions & { Application?: typeof EggCore }) {
export function createApp(name: string, options?: EggCoreInitOptions & { Application?: typeof EggCore }): Application {
const baseDir = getFilepath(name);
options = options ?? {};
options.baseDir = baseDir;
options.type = options.type ?? 'application';

const CustomApplication = options.Application ?? Application;
return new CustomApplication(options);
return new CustomApplication(options) as Application;
}

export const symbol = {
Expand Down
Loading

0 comments on commit e444095

Please sign in to comment.